Hallo, ich habe ein µC- Problem und komme alleine nicht mehr weiter. Ich arbeite mit dem AT90CAN128 µC und wollte den Piepser per Output Compare Interrupt im CTC mode ansteuern. Der Piepser soll nicht durchgehend, sondern 2x kurz ein- und ausgeschaltet werden. Beim Ausschalten liegt das eine Problem, denn er bleibt einfach an. Das wollte ich erreichen, indem ich den Prescaler auf 0 (inaktiv) stelle. Ist das der falsche Ansatz? Ich habe versucht, meinen Code zu simulieren, da bin ich mir schon nicht sicher, ob das Simulieren von Interrupts möglich ist, jedenfalls geht das total schief. Ich verwende Timer1 für einen 100ms Task, der mitzählt, wie lange der Piepser ein- oder aus ist. Und Timer3 zur Erzeugung der gewünschten Frequenz für den Piepser. Jedesmal, wenn ich in die ISR von Timer1 komme, sind die globalen Zähler wieder auf dem Anfangswert, wie sie global initialisiert wurden. Wenn ich den µC flashe, wird der Piepser aktiviert, aber nicht mehr ausgeschaltet. Ich steh total auf dem Schlauch, weiß jemand wo das Problem liegt? Gibt es eine bessere/einfachere Möglichkeit, den Piepser anzusteuern?
Bei Verdacht auf Probleme mit der Hardware: Wie ist der Piepser an den AT90CAN128 µC angeschlossen, direkt an PE3 (Schaltplan, Vcc)? Kommt der Piepser mit den elektrischen Werten am Ausgang PE3 aus, also max (Datenblatt)? Bei Verdacht auf Probleme mit PWM/Timer in der Software: Funktioniert die Ansteuerung ohne Timer mit einfachen Warteschleifen in Software (delay_ms oder delay_us)? K.I.S.S.: Man braucht bestimmt keine drei Timer um einen Piepser anzusteuern.
Hi Ich würde einfach behaupten, das du ihn nach dem Ausschalten mit > BeeperActive = 0; > --NumberOfBeeps; > } > } > if(BeeperActive == 0) gleich wieder einschaltest. MfG Spess
@ Krapao Der Piepser befindet sich auf einer externen Platine. Ich habe den Ausgang von PE3 direkt an Spkr 1 (siehe Schematic) angelötet. Der kann auch über die Relays angesteuert werden (bis zu 24V). Da PE3 ja nur 5V ausgibt, dachte ich, löte ich den Ausgang direkt an den Speaker, der mit 3,3V und 5V angesteuert werden kann laut Datenblatt. Ich habe ihn bisher nur zum Dauerpiepen gebracht mit verschiedenen Frequenzen. Dann wollte ich zwei kurze Warntöne erzeugen und diese in ein anderes Programm einbauen, das bereits diesen 100ms Task (Timer1) und Timer2 schon verwendet. Deshalb verwende ich ja nur 1 weiteren Timer für die Tonfrequenz.. (ist doch okay so oder?) Ich versuch das mal mit den Warteschleifen, allerdings versteh ich nicht, warum im Simulator die globalen Flags/Zähler bei jedem Eintreten in die ISR wieder auf Initialwerten sind. @ spess53 Der wird nicht gleich wieder eingeschaltet, sondern BeeperTime wird 5 mal (100ms) dekrementiert bis 0, und dann wieder eingeschaltet oder seh ich das falsch!?
Ich würde versuchen das Programm zu vereinfachen. In etwa so (ohne Simulation/Test)
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <stdint.h> |
4 | |
5 | // ### GLOBALS ###
|
6 | uint16_t delay = 10; |
7 | volatile int BeeperTime; |
8 | volatile int BeeperActive; |
9 | volatile int NumberOfBeeps; |
10 | |
11 | #define BEEPERTIMER 5
|
12 | #define NUMBEROFBEEPS 2
|
13 | |
14 | void initBeeper(void) |
15 | {
|
16 | DDRE = (1 << DDE3); // Pin PE3 (Piepser) Ausgang |
17 | // Timer 3 für Piepser Frequenz
|
18 | // toggle Channel A, CTC (Mode 4) WGM:0100
|
19 | TCCR3A = (1 << COM3A0); |
20 | // TCCR3B (Mode & Prescaler) wird in beeper_on()/beeper_off() gesetzt
|
21 | beeper_off(); |
22 | // in CTC mode TCNT3 (counter) and OCR3A will be compared consequently,
|
23 | // if equal, Channel A is toggled and TCNT3 is set to 0
|
24 | OCR3AH = 0x00; |
25 | OCR3AL = 0x10; // f = 16Mhz / (2N (1 + OCR3)) |
26 | TIMSK3 &= ~(1<<OCIE3A); // KEINE Interrupts auf Comp Wert A zulassen |
27 | }
|
28 | |
29 | void beeperOn(void) |
30 | {
|
31 | TCCR3B = (1 << WGM32)|(1<<CS02)|(1<<CS00); // Timer3 Prescaler 1024 |
32 | BeeperTime = BEEPERTIMER; |
33 | BeeperActive = 1; |
34 | }
|
35 | |
36 | void beeperOff(void) |
37 | {
|
38 | TCCR3B = (1 << WGM32); // Timer3 Prescaler 0 (off) |
39 | BeeperTime = BEEPERTIMER; |
40 | BeeperActive = 0; |
41 | }
|
42 | |
43 | void beep(void) |
44 | {
|
45 | NumberOfBeeps = NUMBEROFBEEPS; |
46 | beeperOn(); |
47 | }
|
48 | |
49 | void warte_5s(void) |
50 | {
|
51 | for (int i = 0; i < 50; i++) |
52 | delay_ms(100); |
53 | }
|
54 | |
55 | // ####################### MAIN ##################################
|
56 | int main(void) |
57 | {
|
58 | initBeeper(); |
59 | |
60 | // 100 ms Timer1: CTC-Mode, Top-Value OCR1A, Prescaler 256
|
61 | TCCR1B |= (1<<WGM12)|(1<<CS12); |
62 | OCR1A = 6250-1; |
63 | TIMSK1 |= (1<<OCIE1A); |
64 | |
65 | sei(); |
66 | |
67 | while(1) |
68 | {
|
69 | beep(); |
70 | warte_5s(); |
71 | }
|
72 | }
|
73 | |
74 | // ### Interrupt ###
|
75 | ISR (TIMER1_COMPA_vect) //100ms Task |
76 | {
|
77 | if(NumberOfBeeps > 0) |
78 | {
|
79 | if(BeeperActive == 1) |
80 | {
|
81 | if(--BeeperTime == 0) |
82 | {
|
83 | beeperOff(); |
84 | --NumberOfBeeps; |
85 | }
|
86 | } else { |
87 | if(--BeeperTime == 0) |
88 | {
|
89 | beeperOn(); |
90 | }
|
91 | }
|
92 | }
|
93 | }
|
Ersetze beeper_off() noch durch beeperOff()
Ja wunderbar, funktioniert wie gewollt.. Ich erkenne nur nicht genau die Ursache des nun gelösten Problems. Trotzdem danke :-)
Ahh, es lag an dem TIMER1_COMPA_vect, da habe ich den COMPB_vect verwendet.. Kann ich den COMPB_vect beibehalten, indem ich Channel B toggle? Statt "TCCR3A = (1 << COM3A0);" einfach "TCCR3A = (1 << COM3B0);" ??? Das mit den Channels ist mir nicht ganz klar, steht auch nichts unter AVR - Interrupts.. Aber ich denke das war das Problem.
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.