Hallo,
ich arbeite im Moment an einem Sägezahnwellen-Tongenerator mit Atmega8
als Kernstück. Nun möchte ich einen Frequenzwechsel per Schalter
realisieren.
Wenn der Schalter gedrückt wird, wird der INT0 Interrupt über
Falling-Edge ausgelöst, das funktioniert auch soweit.
Die Entprellung funktioniert bei mir über Timer0, bei dem ein Overflow
auslöst, dass eine Variable (buttonChangeAllowed) auf 1 gesetzt wird,
diese wird bei der ersten fallenden Flanke auf INT0 auf 0 gesetzt.
Der Timer0 Overflow Interrupt löst aber nie aus, d.h. im AVR Simulator
wird zwar TOV0 im TIFR Register gesetzt, aber der Breakpoint im
Interrupt nicht erreicht, obwohl Global Interrupts enabled sind (über
sei() ) und TOIE0 im TIMSK Register gesetzt ist.
In Hardware macht sich dies bemerkbar dadurch, dass nur einmal der Ton
gewechselt wird, danach gibt es keine Reaktion mehr auf die Betätigung
des Schalters (eigentlich sollte jeder Druck des Schalters den jeweils
nächsten Ton auf einer C-Dur-Tonleiter abspielen).
TL;DR: ISR(TIMER0_OVF_vect) löst nie aus, halp! ;)
Vielen Dank schonmal für eure Hilfe!
Hier noch der Code:
1 | #include <stdint.h>
|
2 | #include <avr/io.h>
|
3 | #include <avr/wdt.h>
|
4 | #include <avr/interrupt.h>
|
5 | #include <math.h>
|
6 |
|
7 | #define F_CPU 1000000
|
8 | #define SAMPLING_TIME 32
|
9 | #define MAXVAL_16 65536
|
10 |
|
11 | volatile uint16_t voutFull=0;
|
12 | volatile uint16_t deltaM;
|
13 | volatile uint8_t buttonChangeAllowed=1; //is 1 if at least 256 timer0 updates have passed since last button interrupt
|
14 | static uint16_t frequencies[8]= {131,147,165,175,196,220,247,262};
|
15 | volatile uint8_t currFreq=0;
|
16 | volatile float freq=131.0f;
|
17 |
|
18 | void recalculateFreq() {
|
19 | deltaM=(uint16_t)(((SAMPLING_TIME*freq)/F_CPU)*MAXVAL_16);
|
20 | }
|
21 |
|
22 | ISR(TIMER0_OVF_vect) {
|
23 | buttonChangeAllowed=1;
|
24 | TCCR0=0; //stop the timer
|
25 | TCNT0=0; //reset the timer
|
26 | }
|
27 |
|
28 |
|
29 | ISR(TIMER1_COMPA_vect) {
|
30 | voutFull+=deltaM;
|
31 |
|
32 | uint8_t vout=voutFull>>8;
|
33 |
|
34 | PORTD=(vout & 0b11110000) + (PORTD & 0b00001111);
|
35 | PORTC=(vout & 0b00001111) + (PORTB & 0b11110000);
|
36 | }
|
37 |
|
38 |
|
39 | ISR(INT0_vect) {
|
40 | //if the button gets pressed:
|
41 |
|
42 | if (buttonChangeAllowed) { //if enough time has passed since last change
|
43 | TCCR0=(1<<CS02)|(1<<CS00); //set timer 0 to a 1024 prescaler, thus reenabling it.
|
44 |
|
45 | ++currFreq;
|
46 | if (currFreq>7) currFreq=0; //reset after the maximum tuneheight
|
47 | freq=(float)(frequencies[currFreq]);
|
48 | recalculateFreq();
|
49 | }
|
50 | }
|
51 |
|
52 | void setup() {
|
53 | DDRD=0b11110000;
|
54 | DDRC=0b00001111;
|
55 | DDRD&=~(1<<2); //set switch pin to 'in'
|
56 | PORTD=(1<<2); //Enable pull-up resistor
|
57 |
|
58 | TCCR0 = 0; //Disable timer 0 for now.
|
59 | TCCR1B=(1<<CS10); // prescaler for timer 1 is set to 1
|
60 | TCCR1B|=(1<<WGM12); //Timer Compare Match mode on
|
61 |
|
62 | TCNT1=0x0; //Initialise timer 1 with 0.
|
63 | TCNT0=0x0; //Initialise timer 0 with 0.
|
64 |
|
65 | OCR1A=SAMPLING_TIME-1; //Timer Compare Value set to x Ticks.
|
66 |
|
67 | TIMSK=(1<<TOIE0)|(1<<OCIE1A); //Enable timer0 overflow interrupt and timer1A CTC interrupt
|
68 | MCUCR=(1<<ISC01); //Set interrupt on falling edge on INT0, that is PIND2
|
69 |
|
70 | GICR=(1<<INT0); //Enable interrupt for INT0
|
71 | }
|
72 |
|
73 | int main(void)
|
74 | {
|
75 | wdt_disable();
|
76 |
|
77 | cli();
|
78 |
|
79 | setup();
|
80 |
|
81 | recalculateFreq();
|
82 |
|
83 | sei(); //Enable Interrupts.
|
84 |
|
85 | while (1) {
|
86 |
|
87 | }
|
88 | }
|