1 | //**************************************************************
|
2 | // Beschreibung: Das Programm merkt sich wieviel Zeit zwischen
|
3 | // zwei Tastendrücken vergangen ist und schaltet
|
4 | // in diesem Interval eine LED (Scheibenwischer)
|
5 | // ein und aus.
|
6 | // Nach einem Tastendruck wird ein Interrupt mit
|
7 | // hoher Priorität generiert. Der parallel
|
8 | // laufende Timer erzeugt Interrupts mit
|
9 | // niedriger Priorität.
|
10 | //
|
11 | // Anmerkung: Beim Debuggen mit einem Debugger (z.B. ICD2/3)
|
12 | // muss der Codeoffset auf 0 gestellt sein, da
|
13 | // sonst die Interruptroutinen nicht an der
|
14 | // richtigen Stelle stehen.
|
15 | //
|
16 | //**************************************************************
|
17 | //
|
18 | // Dateiname: Scheibenwischer.c
|
19 | // Datum: 01.05.2011
|
20 | // Version: V1.0
|
21 | //
|
22 | // Autor: Michael Hofmann
|
23 | // Internet: www.edmh.de
|
24 | // e-mail: info@edmh.de
|
25 | //
|
26 | //**************************************************************
|
27 |
|
28 |
|
29 | /** I N C L U D E S *******************************************/
|
30 | #include <htc.h>
|
31 | #include <p18f23k22.h>
|
32 | #include "Config.h" //Konfigurationsbits
|
33 |
|
34 | /** D E F I N E S *********************************************/
|
35 | #define TASTER PORTBbits.RB0 //Taster liegt an Port B RB0
|
36 | #define LED LATAbits.LATA4 //LED liegt an Port A RA4
|
37 |
|
38 | #define WISCHEN LATAbits.LATA0 //Scheibenwischer
|
39 | #define MAX_TIME 100 //maximales Interval
|
40 | //10s = 100*100ms
|
41 |
|
42 | //Zustände für die Statemachine
|
43 | #define STOP 0
|
44 | #define WIPE 1
|
45 | #define RECORD_START 2
|
46 | #define RECORD_END 3
|
47 |
|
48 | /** P R O T O T Y P E S ***************************************/
|
49 | void interrupt isr_high(void);
|
50 | void interrupt low_priority isr_low(void);
|
51 | void delay( int ms );
|
52 | void delayInt( int ms100 );
|
53 | void initTimer0( void );
|
54 | void restartTimer0( void );
|
55 | void stopTimer0( void );
|
56 |
|
57 | /** V A R I A B L E N *****************************************/
|
58 | char state=STOP;
|
59 | int timeInterval=0;
|
60 |
|
61 | /** I N T E R R U P T S ***************************************/
|
62 | void interrupt isr_high(void) {
|
63 |
|
64 | INTCONbits.INT0IF = 0; //Interruptflag zurücksetzen
|
65 | INTCONbits.INT0IE = 0; //Interrupt vorrübergehend disablen
|
66 | //damit das Prellen des Tasters keine
|
67 | //neuen Interrupts ausführt
|
68 | switch( state ) {
|
69 | case STOP:
|
70 | state = RECORD_START; //Nächster Zustand RECORD_START
|
71 | break;
|
72 | case WIPE:
|
73 | state = RECORD_START; //Nächster Zustand RECORD_START
|
74 | break;
|
75 | case RECORD_START:
|
76 | state = RECORD_END; //Nächster Zustand ist RECORD_END
|
77 | break;
|
78 | case RECORD_END:
|
79 | state = WIPE; //Nächster Zustand ist WIPE
|
80 | break;
|
81 | default:
|
82 | break;
|
83 | }
|
84 | return;
|
85 | }
|
86 |
|
87 | void interrupt low_priority isr_low(void) {
|
88 |
|
89 | INTCONbits.TMR0IF = 0; //Interruptflag zurücksetzen
|
90 | timeInterval++;
|
91 | if( timeInterval >= MAX_TIME ) {
|
92 | //Maximales Interval wurde überschritten, es soll nicht
|
93 | //mehr gewischt werden
|
94 | timeInterval = 0;
|
95 | state = STOP;
|
96 | stopTimer0();
|
97 | INTCONbits.INT0IF = 0; //Interruptflag zurücksetzen
|
98 | INTCONbits.INT0IE = 1; //Taster-Interrupt freischalten
|
99 | } else {
|
100 | LATAbits.LATA1 = 1; //Für Debugzwecke. Ausgang ist
|
101 | //High, wenn der Timer läuft
|
102 | restartTimer0();
|
103 | }
|
104 | return;
|
105 | }
|
106 |
|
107 | /** H A U P T P R O G R A M M *********************************/
|
108 | void main(void)
|
109 | {
|
110 | char wiped=0;
|
111 |
|
112 | //Port A
|
113 | LATA = 0x00;
|
114 | TRISA = 0x00; //Alle Pins von Port A sind Ausgänge
|
115 | ANSELA = 0x00; //Alle Pins von Port A sind digitale I/O's
|
116 | //Port B
|
117 | LATB = 0x00;
|
118 | TRISB = 0xFF; //Alle Pins von Port B sind Eingänge
|
119 | ANSELB = 0x00; //Alle Pins von Port A sind digitale I/O's
|
120 | //Port C
|
121 | LATC = 0x00;
|
122 | TRISC = 0xF0; //RC0..RC3 = Ausgänge, RC4..RC7 = Eingänge
|
123 | ANSELC = 0x30; //nur RC4 und RC5 sind analoge Eingänge
|
124 |
|
125 | //Es soll ein Interrupt ausgelöst werden, wenn der Taster
|
126 | //gedrückt wurde.
|
127 | INTCON2bits.INTEDG0 = 0;//Interrupt bei der fallenden Flanke
|
128 | INTCONbits.INT0IF = 0; //Interruptflag zurücksetzen
|
129 | INTCONbits.INT0IE = 1; //externen Interrupt enablen
|
130 | INTCONbits.GIE = 1; //globale Interrupts enablen
|
131 |
|
132 | initTimer0();
|
133 | state = STOP;
|
134 | timeInterval = 0; //Interval auf den Startzustand setzen
|
135 |
|
136 | while(1) { //Hauptschleife
|
137 | switch( state ) {
|
138 | case STOP:
|
139 | LATCbits.LATC0 = 1; //Für Debugzwecke, damit man
|
140 | LATCbits.LATC1 = 0; //erkennt in welchem Zustand sich
|
141 | LATCbits.LATC2 = 0; //das Programm befindet
|
142 | wiped = 0;
|
143 | WISCHEN = 0;
|
144 | break;
|
145 | case WIPE:
|
146 | LATCbits.LATC0 = 0; //Für Debugzwecke, damit man
|
147 | LATCbits.LATC1 = 1; //erkennt in welchem Zustand sich
|
148 | LATCbits.LATC2 = 0; //das Programm befindet
|
149 | wiped = 0;
|
150 | stopTimer0();
|
151 | WISCHEN = 1;
|
152 | delay( 500 ); //Wischer für 0,5 s an
|
153 | WISCHEN = 0;
|
154 | INTCONbits.INT0IF = 0; //Interruptflag zurücksetzen
|
155 | INTCONbits.INT0IE = 1; //Taster-Interrupt freischalten
|
156 | delayInt( timeInterval ); //Interval zwischen zwei
|
157 | //Wischzyklen
|
158 | break;
|
159 | case RECORD_START:
|
160 | LATCbits.LATC0 = 0; //Für Debugzwecke, damit man
|
161 | LATCbits.LATC1 = 0; //erkennt in welchem Zustand sich
|
162 | LATCbits.LATC2 = 1; //das Programm befindet
|
163 | delay( 100 ); //Tasterentprellung
|
164 | while( TASTER == 0 ); //Warten, bis der Taster
|
165 | //wieder losgelassen wurde
|
166 | //Nur Einmal wischen
|
167 | if( wiped == 0 ) {
|
168 | WISCHEN = 1;
|
169 | delay( 500 ); //Wischer für 0,5 s an
|
170 | WISCHEN = 0;
|
171 | wiped = 1;
|
172 | timeInterval = 0; //Interval auf Startzustand setzen
|
173 | restartTimer0();
|
174 | } else {
|
175 | delay( 100 );
|
176 | }
|
177 | INTCONbits.INT0IF = 0; //Interruptflag zurücksetzen
|
178 | INTCONbits.INT0IE = 1; //Taster-Interrupt freischalten
|
179 | break;
|
180 | case RECORD_END:
|
181 | LATCbits.LATC0 = 1; //Für Debugzwecke, damit man
|
182 | LATCbits.LATC1 = 1; //erkennt in welchem Zustand sich
|
183 | LATCbits.LATC2 = 1; //das Programm befindet
|
184 | stopTimer0();
|
185 | delay( 100 ); //Tasterentprellung
|
186 | while( TASTER == 0 ); //Warten, bis der Taster
|
187 | //wieder losgelassen wurde
|
188 | state = WIPE;
|
189 | break;
|
190 | default:
|
191 | break;
|
192 | }
|
193 | }
|
194 | }
|
195 |
|
196 | void delay( int ms ) {
|
197 | int i=0;
|
198 | //1 ms = 4000 Befehlstakte (16 MHz Quarz / 4)
|
199 | for( i=0; i<ms; i++ ) {
|
200 | _delay(4000); //Verzögerung von 1ms
|
201 | }
|
202 | }
|
203 |
|
204 | void delayInt( int ms100 ) {
|
205 | int i=0, j=0;
|
206 | //1 ms = 4000 Befehlstakte (16 MHz Quarz / 4)
|
207 | for( i=0; i<ms100; i++ ) {
|
208 | for( j=0; j<100; j++ ) { //Schleife dauert 100ms
|
209 | _delay(4000); //Verzögerung von 1ms
|
210 | }
|
211 | if( state == RECORD_START ) {
|
212 | //Die Verzögerung soll abgebrochen werden, wenn ein
|
213 | //neuer Zyklus generiert wird.
|
214 | return;
|
215 | }
|
216 | }
|
217 | }
|
218 |
|
219 | //Initialisiert den Timer 0 für einen 100ms-Takt
|
220 | void initTimer0( void ) {
|
221 | //Timer 0 ist ein 16-bit-Timer
|
222 | //Prescaler = 1:128
|
223 | T0CON = 0b00000110;
|
224 | TMR0H = 0x00;
|
225 | TMR0L = 0x00;
|
226 | INTCONbits.TMR0IF = 0; //Interruptflag zurücksetzen
|
227 | INTCON2bits.TMR0IP = 0; //niedrige Priorität
|
228 | INTCONbits.TMR0IE = 1; //Interrupt für Timer 0 enablen
|
229 | RCONbits.IPEN = 1;
|
230 | INTCONbits.PEIE = 1; //Peripheral Interrupts enablen
|
231 | return;
|
232 | }
|
233 |
|
234 | //Startet den Timer neu
|
235 | void restartTimer0( void ) {
|
236 | //mit einem Prescaler von 1:128 ensteht nach 100ms
|
237 | //ein Überlauf (4 MHz / 128 = 31250 Hz)
|
238 | T0CON = 0b00000110;
|
239 | INTCONbits.TMR0IF = 0; //Interruptflag zurücksetzen
|
240 | INTCON2bits.TMR0IP = 0; //niedrige Priorität
|
241 | //Timer Wert für 100ms = 65535 - 3125 = 62410 = 0xF3CA
|
242 | TMR0H = 0xF3; //Das Highbyte muss zuerst
|
243 | //geschrieben werden.
|
244 | TMR0L = 0xCA; //Wenn das Lowbyte geschrieben wird,
|
245 | //wird das Highbyte aktuallisiert.
|
246 | //Dadurch wird es ermöglicht alle
|
247 | //16 bit auf einmal zu beschreiben
|
248 | //TMR0 = 0xF3CA; funktioniert an
|
249 | //Stelle nicht, da zuerst das
|
250 | //Lowbyte und dann das Highbyte
|
251 | //geschrieben wird.
|
252 | INTCONbits.TMR0IE = 1; //Interrupt für Timer 0 enablen
|
253 | RCONbits.IPEN = 1; //Interrupts mit niedriger Priorität
|
254 | INTCONbits.PEIE = 1; //Peripheral Interrupts enablen
|
255 |
|
256 | T0CONbits.TMR0ON = 1; //Timer starten
|
257 | return;
|
258 | }
|
259 |
|
260 | //Stoppt den Timer
|
261 | void stopTimer0( void ) {
|
262 | LATAbits.LATA1 = 0;
|
263 | T0CON = 0b00000110; //Timer ausschalten
|
264 | TMR0H = 0x00;
|
265 | TMR0L = 0x00;
|
266 | INTCONbits.TMR0IF = 0; //Interruptflag zurücksetzen
|
267 | INTCONbits.TMR0IE = 0; //Interrupt für Timer 0 disablen
|
268 | return;
|
269 | }
|