Forum: Mikrocontroller und Digitale Elektronik kein konstanter Sendeaufruf ATmega8


von Adrian (Gast)


Lesenswert?

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

von Adrian (Gast)


Angehängte Dateien:

Lesenswert?

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

von Otto (Gast)


Lesenswert?

Hallo Adrian,

hast Du die fuses richtig gesetzt ?

Gruss Otto

von Jörg X. (Gast)


Lesenswert?

- 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

von Simon K. (simon) Benutzerseite


Lesenswert?

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.

von Adrian (Gast)


Lesenswert?

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

von Adrian (Gast)


Lesenswert?

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

von Adrian (Gast)


Lesenswert?

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

von Jörg X. (Gast)


Angehängte Dateien:

Lesenswert?

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

von Adrian (Gast)


Lesenswert?

Vielen Dank Jörg!
Gruß
adrian

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
Noch kein Account? Hier anmelden.