Hallo zusammen, ich nutze einen Atmega8 zur AD-Wandlung. Dieser soll konstant alle 20ms einen digitalisierten Messwert über die USATR versenden. Wie aus dem Anhang (Code) ersichtlich: Taktrate=7372800Hz; Vorteiler 1024; Timer0= 256 Takte/Overflow; Timerwert=112 (gesetzt) => 50 Overflows/sec. Der Eingang PinB0 liegt die ganze Zeit auf low. Warum kann ich nicht alle 20ms einen Wert am UART, empfangen??? DAs Oszilloskop zeigt nicht kontinuierlich, immer mit Aussetzern, die Werte. Hilfe, bin schon den ganzen tag auf fehler suche! Danke Adrian
oh, datei vergessen .include "m8def.inc" .equ CLOCK = 7372800 .equ BAUD = 38400 .equ UBRRVAL = CLOCK/(BAUD*16)-1 .equ timer=112 ;;;;;;;;;;;;;;;;;;;Interrupt Handler;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .org 0x000 rjmp main ; main-jump .org OVF0addr rjmp TIM0_OVF ; Timer 0 Overflow Handler .org URXCaddr rjmp USART_RXC ; USART RX Complete Handler ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; main: ;Stackpointer initialisieren ldi r16, LOW(RAMEND) out SPL, r16 ldi r16, HIGH(RAMEND) out SPH, r16 ;PORTB & PORTD als Ausgang (LED) konfigurieren ldi r16,0b11111110 out DDRB, r16 ldi r16,0b11111111 out DDRD, r16 cbi PortB,1 ;Empfangsbereitschaft mikroC ;UART initialisieren ldi r16, LOW(UBRRVAL) ;Baudrate einstellen out UBRRL, r16 ldi r16, HIGH(UBRRVAL) out UBRRH, r16 ldi r16, (1<<URSEL)|(3<<UCSZ0) ;Frame Format out UCSRC, r16 sbi UCSRB, TXEN ; TX (Senden) aktiv sbi UCSRB, RXEN ; RX (Empfang) aktiv sbi UCSRB, RXCIE ; Interrupt bei Empfang ;ADMUX initialisieren ldi r16,0b00100010 ; Vref extern,Kanal ADC2 out ADMUX,r16 sbi PortD, 4 ; LED Temperatur an ;TIMER0 initialisieren ldi r16, 1<<TOIE0 ; Interrupt bei OVF Timer0 out TIMSK, r16 ldi r16, (1<<CS02)|(0<<CS01)|(1<<CS00); Vorteiler 1024 out TCCR0, r16 ldi r16, timer ; Startwert setzen out TCNT0,r16 ;Interrupt global an sei Hauptschleife: rjmp Hauptschleife ;;;;;;;;;;;;;TimerInterrupt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TIM0_OVF: sei ; Interrupt global an ldi r16, timer ; Timer erneut setzen out TCNT0,r16 ldi r16, ((1<<ADEN)|(1<<ADSC)|(0<<ADFR)|(1<<ADIF)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0 )) ;ADC einschalten out ADCSR, r16 loop: sbis ADCSR, ADIF ; ADIF flag gelöscht = ADC abgeschlossen rjmp loop in r16, ADCH ; Umwandlungsergebnisregister ADCH einlesen: rcall busy ; Empfänger bereit prüfen rcall serout ; Subroutine serout 'Daten senden' aufrufen reti ; Interrupt Routine verlassen ;UART bereit loop & SENDEN serout: sbis UCSRA,UDRE rjmp serout out UDR, r16 ret ;Empfänger bereit loop busy: sbic PinB,0 ;PortB Pin0 Busyleitung Empfänger (ist immer auf low) rjmp busy ret ;;;;;;;;;;;;;;;;;;USART RX_Interrupt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; USART_RXC: cli push r16 ; Arbeitsregister auf Stack sichern in r16,udr ; Register UDR einlesen EmpfangA: cpi r16,'A' ; überprüft ob ein A gesendet wurde brne EmpfangB ; wenn kein A empfangen wurde springe EmpfangenB ldi r16, 0b00100000 ; AD Eingang ADC0 Beschleu.x-Achse out ADMUX, r16 cbi PortD,3 ; Anzeige LED cbi PortD,4 sbi PortD,2 rjmp weiter ; springe zu weiter EmpfangB: cpi r16,'B' ; überprüfen ob ein B empfangen wurde brne EmpfangC ; wenn kein B empfangen wurde springe EmpfangenC ldi r16, 0b00100001 ; AD Eingang ADC1 Beschleu.y-Achse out ADMUX, r16 cbi PortD,2 ; Anzeige LED cbi PortD,4 sbi PortD,3 rjmp weiter ; springe zu weiter EmpfangC: cpi r16,'C' ; überprüfen ob ein C empfangen wurde brne weiter ; wenn kein C empfangen wurde springe weiter ldi r16, 0b00100010 ; AD Eingang ADC2 Temperatur out ADMUX, r16 cbi PortD,2 ; Anzeige LED cbi PortD,3 sbi PortD,4 weiter: pop r16 ; Arbeitsregister aus Stack laden reti ; Interruptroutine verlassen
Hallo Adrian, hast Du die fuses richtig gesetzt ? Gruss Otto
- Sichere in den ISRs das SREG (!!!) - Lass in der Timer ISR die interrupts aus und - Benutz den ADC-Interrupt für das Senden des ADC-Werts, oder - setz in der Timer-ISR ein Flag (Register oder SRAM), dass von der Main-Loop abgefragt wird und die macht dann die Messung - du solltest wahrscheinlich nicht einfach so das ADMUX-Register ändern (hier: in der Receive-ISR) hth. Jörg
Jörg X. wrote: > - Sichere in den ISRs das SREG (!!!) > - Lass in der Timer ISR die interrupts aus und > - Benutz den ADC-Interrupt für das Senden des ADC-Werts, oder > - setz in der Timer-ISR ein Flag (Register oder SRAM), dass von der > Main-Loop abgefragt wird und die macht dann die Messung > - du solltest wahrscheinlich nicht einfach so das ADMUX-Register ändern > (hier: in der Receive-ISR) > > hth. Jörg Wenn du nur ein Bit setzt in der ISR brauchst du kein SREG zu sichern :-)) EDIT: Grrrr. Moment: Galt das nur für SBI/CBI und nicht für SBR/CBR? Ich ziehe meine Aussage erstmal zurück ;) EDIT2: Jap, SBR ist ja nur ein ORI -> SREG sichern.
hallo, die fuses-bits sind richtig gesetzt (habe ihc dem Datenblatt entnommen). Werde das Prog.umschreiben, kann es erst wieder am Mo. am System ausprobieren, aber schon mal vielen Dank!!! Wenn es nicht funk.sollte dann melde ich mich am Mo. wieder. Aber die Vorschläge klingen gut! Wenn noch jemanden was auffällt, immer raus mit der Sprache! Noch mal Danke und schönes We. Adrian
Hallo Leute, spez.Jörg X., habe grade das Prog. umgeschrieben. Mir ist aber nicht klar, was mit: > - du solltest wahrscheinlich nicht einfach so das ADMUX-Register ändern > (hier: in der Receive-ISR) gemeint ist. Wie soll ich denn die ADU Eingänge sonst umschalten??? Aktuelles Prog. im Anhang. gruß adrian
Wieder der Anhang nicht dabei, sorry! .include "m8def.inc" .equ CLOCK = 7372800 .equ BAUD = 38400 .equ UBRRVAL = CLOCK/(BAUD*16)-1 .equ timer=112 ;;;;;;;;;;;;;;;;;;;Interrupt Handler;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .org 0x000 rjmp main ; main-jump .org OVF0addr rjmp TIM0_OVF ; Timer 0 Overflow Handler .org URXCaddr rjmp USART_RXC ; USART RX Complete Handler ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; main: ;Stackpointer initialisieren ldi r16, LOW(RAMEND) out SPL, r16 ldi r16, HIGH(RAMEND) out SPH, r16 ;PORTB & PORTD als Ausgang (LED) konfigurieren ldi r16,0b11111110 out DDRB, r16 ldi r16,0b11111111 out DDRD, r16 cbi PortB,1 ;Empfangsbereitschaft mikroC ;UART initialisieren ldi r16, LOW(UBRRVAL) ;Baudrate einstellen out UBRRL, r16 ldi r16, HIGH(UBRRVAL) out UBRRH, r16 ldi r16, (1<<URSEL)|(3<<UCSZ0) ;Frame Format out UCSRC, r16 sbi UCSRB, TXEN ; TX (Senden) aktiv sbi UCSRB, RXEN ; RX (Empfang) aktiv sbi UCSRB, RXCIE ; Interrupt bei Empfang ;ADMUX initialisieren ldi r16,0b00100010 ; Vref extern,Kanal ADC2 out ADMUX,r16 sbi PortD, 4 ; LED Temperatur an ;TIMER0 initialisieren ldi r16, 1<<TOIE0 ; Interrupt bei OVF Timer0 out TIMSK, r16 ldi r16, (1<<CS02)|(0<<CS01)|(1<<CS00); Vorteiler 1024 out TCCR0, r16 ldi r16, timer ; Startwert setzen out TCNT0,r16 ;Interrupt global an sei Hauptschleife: sbis TIFR,TOV0 rjmp Hauptschleife ldi r16, ((1<<ADEN)|(1<<ADSC)|(0<<ADFR)|(1<<ADIF)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0 )) ;ADC einschalten out ADCSR, r16 loop: sbis ADCSR, ADIF ; ADIF flag gelöscht = ADC abgeschlossen rjmp loop in r16, ADCH ; Umwandlungsergebnisregister ADCH einlesen: ;Empfänger bereit loop busy: sbic PinB,0 ;PortB Pin0 Busyleitung Empfänger (ist immer auf low) rjmp busy ;UART bereit loop & SENDEN serout: sbis UCSRA,UDRE rjmp serout out UDR, r16 rjmp Hauptschleife ;;;;;;;;;;;;;TimerInterrupt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TIM0_OVF: push r16 ; Arbeitsregister auf Stack sichern in r16, SREG ; SREG Sichern push r16 ldi r16, timer ; Timer erneut setzen out TCNT0,r16 pop r16 out SREG, r16 ; SREG laden pop r16 ; Arbeitsregister aus Stack laden reti ; Interrupt Routine verlassen ;;;;;;;;;;;;;;;;;;USART RX_Interrupt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; USART_RXC: cli push r16 ; Arbeitsregister auf Stack sichern in r16, SREG ; SREG Sichern push r16 in r16,udr ; Register UDR einlesen EmpfangA: cpi r16,'A' ; überprüft ob ein A gesendet wurde brne EmpfangB ; wenn kein A empfangen wurde springe EmpfangenB ldi r16, 0b00100000 ; AD Eingang ADC0 Beschleu.x-Achse out ADMUX, r16 cbi PortD,3 ; Anzeige LED cbi PortD,4 sbi PortD,2 rjmp weiter ; springe zu weiter EmpfangB: cpi r16,'B' ; überprüfen ob ein B empfangen wurde brne EmpfangC ; wenn kein B empfangen wurde springe EmpfangenC ldi r16, 0b00100001 ; AD Eingang ADC1 Beschleu.y-Achse out ADMUX, r16 cbi PortD,2 ; Anzeige LED cbi PortD,4 sbi PortD,3 rjmp weiter ; springe zu weiter EmpfangC: cpi r16,'C' ; überprüfen ob ein C empfangen wurde brne weiter ; wenn kein C empfangen wurde springe weiter ldi r16, 0b00100010 ; AD Eingang ADC2 Temperatur out ADMUX, r16 cbi PortD,2 ; Anzeige LED cbi PortD,3 sbi PortD,4 weiter: pop r16 ; Arbeitsregister aus Stack laden out SREG, r16 ; SREG laden pop r16 reti ; Interruptroutine verlassen
Ich habe mal versucht meine ASM-Kenntnisse auszupacken (programmiere lieber in C). Ergebnis siehe Anhang (der Anhang geht nur ohne Vorschau, btw.). Mein Programm nutzt ein Flag-Register 'flags' und ein Byte im SRAM für den nächsten ADC-Kanal. Sowohl bei der Messung, als auch beim Senden des Messwerts gibt's Busy-Wait, was sicher unpraktisch für größere/kompliziertere Anwendungen ist. hth. Jörg (der das aus Spass an der Freud' gemacht hat) ps.: die Kanalauswahl könnte man mit (UDR - 'A') stark vereinfachen ;) pps.: das Programm ist nur im Simulator getestet, scheint(!) aber zu funktionieren, was die Interrupts angeht
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.