Forum: Mikrocontroller und Digitale Elektronik ATmega8: Counter1 tut nicht so, wie ich will


von Frank Muen (Gast)


Lesenswert?

Hallo,

ich möchte gerne den Abstand zwischen zwei mal (entprellter) Taster 
drückn (angeschlossen an PORTB.0) messen:
1
.include  "AVR.H"
2
;------------------------------------------------------------------------
3
;Reset and Interruptvectoren  ;VNr.  Beschreibung
4
begin:  rjmp  main  ;1     POWER ON RESET
5
  reti    ;2     Int0-Interrupt
6
  reti    ;3     Int1-Interrupt
7
  reti    ;4     TC2 Compare Match
8
  reti    ;5     TC2 Overflow
9
  rjmp  on_ICP  ;6     TC1 Capture
10
  reti    ;7     TC1 Compare Match A
11
  reti    ;8     TC1 Compare Match B
12
  rjmp  on_TC1  ;9     TC1 Overflow
13
  reti    ;10    TC0 Overflow
14
  reti    ;11    SPI, STC Serial Transfer Complete
15
  reti    ;12    UART Rx Complete
16
  reti    ;13    UART Data Register Empty
17
  reti    ;14    UART Tx Complete
18
  reti    ;15    ADC Conversion Complete
19
  reti    ;16    EEPROM Ready
20
  reti    ;17    Analog Comperator
21
  reti    ;18    TWI (I²C) Serial Interface
22
  reti    ;19    Store Program Memory Ready
23
;------------------------------------------------------------------------
24
25
26
;Start, Power ON, Reset
27
main:  ldi  r16,lo8(RAMEND)
28
  out  SPL,r16  ;Init Stackpointer LO
29
  ldi  r16,hi8(RAMEND)
30
  out  SPH,r16  ;Init Stackpointer HI
31
32
  sbi  UCSRB,4  ;UCR=UCSRB=0x0B RXEN=Bit4 RX aktivieren
33
  sbi  UCSRB,3  ;UCR=UCSRB=0x0B UDRE=Bit3 TX aktiv
34
  ldi  r16,3686400/(38400*16)-1  ;Baudrate 38400 einstellen
35
  out  UBRRL,r16
36
37
  ldi  r16,0b00000001
38
  out  DDRB,r16
39
  ldi  r16,0b00000001
40
  out  PORTB,r16
41
42
  ldi  r16,0
43
  out  TCCR1A,r16
44
  ldi  r16,0b01000001
45
  out  TCCR1B,r16  ;Timer1 setup Clock
46
  ldi  r16,0b00100100
47
  out  TIMSK,r16  ;Interrupt Timer1 bei overflow
48
49
  ldi  r26,0
50
  ldi  r27,hi8(RAMEND)
51
  subi  r27,2
52
  ldi  r28,0
53
  ldi  r29,hi8(RAMEND)
54
  subi  r29,2
55
  sei    ;erlaube Interrupts
56
;------------------------------------------------------------------------
57
mainloop:  wdr
58
59
  rjmp  mainloop
60
;------------------------------------------------------------------------
61
putChar:  sbis  UCSRA,5  ;USR Bit5 =  UDRC
62
  rjmp  putChar  ;warten, bis UDR bereit
63
  out  UDR,r16
64
  ret    ;zurück zum Hauptprogramm
65
;------------------------------------------------------------------------
66
on_TC1:  cli
67
  push   r16
68
  ldi  r16,129
69
  rjmp   putChar
70
  pop  r16
71
  sei
72
  reti
73
74
;------------------------------------------------------------------------
75
on_ICP:  cli
76
  push  r16
77
  ldi  r16,ICR1L
78
  rjmp   putChar
79
  ldi  r16,ICR1H
80
  rjmp  putChar
81
  pop  r16
82
  sei
83
  ret
Meine Idee ist:
Bei jedem Overflow des Counter1 wird ein Interrupt ausgeführt, dieser 
gibt 0h81 an die serielle Schnittstelle aus. Das scheint auch ganz gut 
zu funktionieren.

Wenn der Taster gedrückt wurde (ich würde hier gerne auf die steigende 
Flanke triggern), soll der aktuelle Wert des Counters ausgegeben werden. 
Hier hakt es jedoch und der µC gibt nur Mist aus (meist nur ein Wert, 
und zwar 0h26). Kann mir da jemand helfen?

von Jörg X. (Gast)


Lesenswert?

Was mir beim schnellen durchsehen aufgefallen ist ;)
> rjmp   putChar
"rcall putChar" ist bestimmt besser...

in den ISRs solltest du das SREG sichern, kannst ja z.B. eins der 
Register r2-r15 entbehren:
1
.def sreg_bak = R2
2
;...
3
on_TC1:  
4
    ; cli, sei  sind in den ISR i.d.R. unnoetig!
5
    IN sreg_bak, SREG
6
    push   r16
7
    ldi  r16,129
8
    RCALL   putChar
9
    pop  r16
10
    OUT SREG, sregbak
11
    reti
- ich hab die Zugriffsreihenfolge bei den 16-Bit Registern (TCNT1, ICR1, 
etc.) grad nicht im Kopf, schau das lieber nochmal nach ;)
> sbis  UCSRA,5
"sbis UCSRA, UDRE " liest sich besser, benutz das ruhig bei allen 
I/O-Registern

hth. Jörg

von Johannes M. (johnny-m)


Lesenswert?

> ldi  r16,ICR1L
> rjmp   putChar
> ldi  r16,ICR1H
Du weißt, was ldi macht? Dann weißt Du vermutlich auch, dass ldi hier 
sicher nicht das macht, was Du willst. Versuch es mal mit
1
in r16, ICR1L

Übrigens: ICR1L hat die Adresse 0x26. Jetzt weißt Du auch, wo die 26 
herkommt...

von Johannes M. (johnny-m)


Lesenswert?

> on_TC1:  cli
> ...
> on_ICP:  cli
Das cli kannste Dir sparen. Das macht der Controller automatisch beim 
Einsprung in den Interrupt-Vektor.

> sei
> ret
Und das ebenfalls unsinnig. Dafür gibts reti.

Also: Das I-Bit im SREG wird beim Sprung in einen Interrupt-Vektor 
automatisch von der Hardware gelöscht. Zum Rücksprung aus dem Interrupt 
Handler gibt es den Befehl reti, der im Unterschied zu ret (ohne i) 
dafür sorgt, dass beim Rücksprung das I-Bit wieder gesetzt wird.

von Frank Muen (Gast)


Lesenswert?

Ich danke euch!!! Er macht jetzt das, was ich will! VIELEN DANK!

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.