Hallo! Ich bin gerade dabei ein LCD-Menü mithilfe eines ATMega32 zu realisieren und stoße da so langsam an meine Grenzen. Ziel ist es, gewisse Unterprogramme über ein Potentiometer anzuwählen,welche dann über einen Taster gestartet werden und genauso mit dem gleichen Taster auch wieder beendet werden sollen. [spoiler]
1 | #include <avr/io.h> |
2 | #include <stdlib.h> |
3 | #include <util/delay.h> |
4 | #include "lcd-routines.h" |
5 | #include <avr/interrupt.h> |
6 | |
7 | #define L1 2 |
8 | #define L2 3 |
9 | #define L3 6 |
10 | #define T1 2 |
11 | |
12 | #define D4 1 |
13 | #define D5 2 |
14 | #define D6 3 |
15 | #define D7 4 |
16 | #define RS 6 |
17 | #define E 5 |
18 | |
19 | #define F_CPU 1000000UL |
20 | |
21 | |
22 | int uart_putc(unsigned char c) //Eine Konstante über UART ausgeben |
23 | { |
24 | while (!(UCSRA & (1<<UDRE))) //warten bis Senden moeglich |
25 | { |
26 | } |
27 | |
28 | UDR = c; //sende Zeichen |
29 | return 0; |
30 | } |
31 | void uart_puts (char *s) //Einen String über UART ausgeben |
32 | { |
33 | while (*s) |
34 | { |
35 | uart_putc(*s); |
36 | s++; |
37 | } |
38 | } |
39 | int ADC_init(uint8_t channel) |
40 | { |
41 | ADMUX = (1<<REFS0)|channel; //AVCC als Referenzspannung nutzen & channel entspricht dem Kanal (0-7) |
42 | ADCSRA = (1<<ADPS1) | (1<<ADPS0); //Frequenzvorteiler=8 -> 1mHz/8=125 kHz |
43 | ADCSRA |= (1<<ADEN); //ADC verfügbar machen |
44 | } |
45 | int ADC_m(uint8_t channel) |
46 | { |
47 | ADCSRA |= (1<<ADSC); // Wandlung starten |
48 | while (ADCSRA & (1<<ADSC) ) // auf Abschluss der Wandlung warten |
49 | {} |
50 | return ADCW; |
51 | } |
52 | |
53 | volatile uint8_t state=0; |
54 | |
55 | ISR(INT2_vect) |
56 | { |
57 | _delay_ms(40); |
58 | if(!(PINB & (1<<T1))) |
59 | { |
60 | state=1; |
61 | } |
62 | } |
63 | |
64 | int main(void) |
65 | { |
66 | GICR |= (1<<INT2); |
67 | MCUCSR &= ~(1<<ISC2); |
68 | cli(); |
69 | |
70 | uint8_t menus=2; |
71 | |
72 | //LED + Taster initialisieren |
73 | DDRD |= (1<<L1)|(1<<L2)|(1<<L3); |
74 | DDRB &= ~(1<<T1); |
75 | PORTB |= (1<<T1); |
76 | |
77 | |
78 | lcd_init(); |
79 | ADC_init(7); |
80 | |
81 | while(1) |
82 | { |
83 | if(ADC_m(7)>1024/menus) |
84 | { |
85 | lcd_setcursor( 0, 1 ); |
86 | lcd_string("LED-Test"); |
87 | if(!(PINB & (1<<T1))) |
88 | { |
89 | _delay_ms(40); |
90 | while(!(PINB & (1<<T1))){} |
91 | _delay_ms(40); |
92 | sei(); |
93 | while(state==0) |
94 | { |
95 | LedTest(); |
96 | } |
97 | state=0; |
98 | cli(); |
99 | } |
100 | } |
101 | else |
102 | { |
103 | lcd_setcursor( 0, 1 ); |
104 | lcd_string("Menu 2 "); |
105 | } |
106 | |
107 | } |
108 | } |
109 | |
110 | void LedTest() |
111 | { |
112 | PORTD |= (1<<L1); |
113 | _delay_ms(100); |
114 | PORTD &= ~(1<<L1); |
115 | PORTD |= (1<<L2); |
116 | _delay_ms(100); |
117 | PORTD &= ~(1<<L2); |
118 | PORTD |= (1<<L3); |
119 | _delay_ms(100); |
120 | PORTD &= ~(1<<L3); |
121 | PORTD |= (1<<L2); |
122 | _delay_ms(100); |
123 | PORTD &= ~(1<<L2); |
124 | } |
[/spoiler] Genau beim beenden des Programms liegt nun mein Problem: über einen Interrupt kann ja der Tastendruck auch mitten im Programmdurchlauf erkannt werden. In meinem Fall wird dann eine Variable verändert, welche am Ende des Programms abgefragt wird. Wie kann ich aber nun direkt beim Ausführen der ISR das laufende Programm beenden, und sofort ins "Hauptmenü" zurückspringen? Theoretisch müsste dafür ja der Stack Pointer um eins zurückgesetzt werden. oder ist das ein völlig falscher Ansatz? ich würde mich freuen, wenn mir hier jemand helfen kann! MfG Lukas