#include #include #include #include #include #include #include #include #define F_CPU 4000000UL // Systemtakt in Hz #define DEBOUNCE 256L // debounce clock (256Hz = 4msec) // LCD #define CLEAR_DISPLAY 0x01 // Display Inhalt komplett mit Null überschreiben #define CURSOR_HOME 0x02 // Coursor an Anfangsposition setzen #define LCD_PORT PORTD // Port an dem das LCD angeschlossen ist #define LCD_DDR DDRD // Datenpins an denen das LCD angeschlossen ist #define LCD_RS PD4 // Ausgang an dem der RS-Pin des LCD hängt #define LCD_EN PD5 // Ausgang an dem der EN-Pin des LCD hängt uint8_t act_min = 0; // Aktuelle Zeit - Minuten uint8_t act_sec = 0; // Aktuelle Zeit - Sekunden volatile uint8_t act_msec = 0; // Aktuelle Zeit - Millisekunden uint8_t best_min = 0; // Bestzeit - Minuten uint8_t best_sec = 0; // Bestzeit - Sekunden uint8_t best_msec = 0; // Bestzeit - Milisekunden struct show_data { uint8_t LAP_act_min; // Aktuelle Zeit - Minuten uint8_t LAP_act_sec; // Aktuelle Zeit - Sekunden uint8_t LAP_act_msec; // Aktuelle Zeit - Millisekunden uint8_t LAP_best_min; // Bestzeit - Minuten uint8_t LAP_best_sec; // Bestzeit - Sekunden uint8_t LAP_best_msec; // Bestzeit - Milisekunden } LCD_struct; /******** ISR des Laptimers ********/ ISR(TIMER1_COMPA_vect) // Aufruf bei Compare Match von Timer2 (8 Bit) { uint8_t tmpSREG; // temporärer Speicher fuer das Statusregister tmpSREG = SREG; // Statusregister (also auch das I-Flag darin) sichern cli(); // Interupts Global deaktivieren act_msec++; // Millisekunden um eins erhöhen SREG = tmpSREG; // Status-Register wieder herstellen } /*************************************** LCD ***********************************************/ /******** erzeugt den Enable-Puls ********/ void LCD_enable(void) { LCD_PORT |= (1 << LCD_EN); // LCD_ENABLED = 1 an LCD Port senden _delay_us(2); // kurze Pause zum verarbeiten des Befehls LCD_PORT &= ~(1 << LCD_EN); // LCD_ENABLED = 0 an LCD Port senden } /******** Befehl an das LCD senden ********/ void LCD_command(unsigned char temp1) { unsigned char temp2 = temp1; LCD_PORT &= ~(1 << LCD_RS); // Register Select auf "Transferring Instruction Data" setzen temp1 = temp1 >> 4; // Oberes Nibble holen temp1 = temp1 & 0x0F; // Maskieren LCD_PORT &= 0xF0; LCD_PORT |= temp1; // Daten Bits setzen LCD_enable(); temp2 = temp2 & 0x0F; // unteres Nibble holen und maskieren LCD_PORT &= 0xF0; LCD_PORT |= temp2; // Daten Bits setzen LCD_enable(); _delay_us(42); } /******** LCD löschen ********/ void LCD_clear(void) { LCD_command(CLEAR_DISPLAY); _delay_ms(5); } /******** LCD Cursor Home ********/ void LCD_home(void) { LCD_command(CURSOR_HOME); _delay_ms(5); } /******** Datenbyte an das LCD senden ********/ void LCD_data(unsigned char temp1) { unsigned char temp2 = temp1; LCD_PORT |= (1 << LCD_RS); // Register Select auf "Transferring Display Data" setzen temp1 = temp1 >> 4; temp1 = temp1 & 0x0F; LCD_PORT &= 0xF0; LCD_PORT |= temp1; // Daten Bits setzen LCD_enable(); temp2 = temp2 & 0x0F; LCD_PORT &= 0xF0; LCD_PORT |= temp2; // Daten Bits setzen LCD_enable(); _delay_us(42); } /******** LCD initialisieren ********/ void LCD_init(void) { LCD_DDR = LCD_DDR | 0x0F | (1 << LCD_RS) | (1 << LCD_EN); // Port auf Ausgang schalten _delay_ms(15); LCD_PORT &= 0xF0; LCD_PORT |= 0x03; LCD_PORT &= ~(1 << LCD_RS); // Register Select auf "Transferring Instruction Data" setzen LCD_enable(); _delay_ms(5); LCD_enable(); _delay_ms(1); LCD_enable(); _delay_ms(1); // 4 Bit Modus aktivieren LCD_PORT &= 0xF0; LCD_PORT |= 0x02; LCD_enable(); _delay_ms(1); LCD_command(0x28); // 4Bit / 2 Zeilen / 5x7 LCD_command(0x0C); // Display ein / Cursor aus / kein Blinken LCD_command(0x06); // inkrement / kein Scrollen LCD_clear(); } /******** setzt Cursor in Zeile y (1..4) Spalte x (0..15) ********/ void LCD_set_cursor(uint8_t x, uint8_t y) { uint8_t tmp; switch (y) { case 1: tmp = 0x80 + 0x00 + x; break; // 1. Zeile case 2: tmp = 0x80 + 0x40 + x; break; // 2. Zeile case 3: tmp = 0x80 + 0x10 + x; break; // 3. Zeile case 4: tmp = 0x80 + 0x50 + x; break; // 4. Zeile default: return; // für den Fall einer falschen Zeile } LCD_command(tmp); } /******** schreibt String auf LCD ********/ void LCD_string(char *data) { while(*data) { LCD_data(*data); data++; } } void LCD_showLaptime(show_data) { char buffer[4] = ""; // Puffer für LCD Anzeige LCD_home(); // Setze die Cursor Position an den Anfang LCD_string("AKT: "); // "ACT:" auf dem Display anzeigen LCD_string(itoa(LCD_struct.LAP_act_min, buffer, 10)); LCD_string(":"); if(LCD_struct.LAP_act_sec < 10) { LCD_string("0"); LCD_string(itoa(LCD_struct.LAP_act_sec, buffer, 10)); } else { LCD_string(itoa(LCD_struct.LAP_act_sec, buffer, 10)); } LCD_string("."); if(LCD_struct.LAP_act_msec < 10) { LCD_string("0"); LCD_string(itoa(LCD_struct.LAP_act_msec, buffer, 10)); } else { LCD_string(itoa(LCD_struct.LAP_act_msec, buffer, 10)); } /* LCD_set_cursor(0, 2); // Cursor auf Position setzen LCD_string("BEST: "); // "ACT:" auf dem Display anzeigen LCD_string(itoa(LCD_struct.LAP_best_min, buffer, 10)); LCD_string(":"); if(LCD_struct.LAP_best_sec < 10) { LCD_string("0"); LCD_string(itoa(LCD_struct.LAP_best_sec, buffer, 10)); } else { LCD_string(itoa(LCD_struct.LAP_best_sec, buffer, 10)); } LCD_string("."); if(LCD_struct.LAP_best_msec < 10) { LCD_string("0"); LCD_string(itoa(LCD_struct.LAP_best_msec, buffer, 10)); } else { LCD_string(itoa(LCD_struct.LAP_best_msec, buffer, 10)); } */ } /********************************** MAIN ******************************************/ int main() { DDRB = 0x02; PORTD = 0x02; LCD_init(); // LCD Anzeige initialisieren LCD_clear(); // LCD Anzeige komplett leeren cli(); // Globale Interrupts ausschalten TCCR1B = (1 << WGM12) | (1 << CS10) | (1 << ICES1); // Timer1 (16Bit): CTC (Lösche Timer bei positiven Vergleich), Kein Vorteiler TCCR1A = (1 << FOC1A); OCR1A = 25536; // Vegleichswert wenn übereinstimmung mit TCNT1 Compare Match Interrupt auslösen TIMSK = (1 << OCIE1A) | (1 << TICIE1); // Wenn Vergleichswert übereinstimmt Interrupt auslösen, Input Capture Interrupt setzen TIFR |= (1 << OCF1A) | (1 << ICF1); // Output Compare Falge setzen, Input Capture Flag setzen sei(); // Globale Interrupts einschalten while(1) { /*if(!(PINB & (1 << PB0))) { PORTB |= (1 << PB1); //FirstEdge = 1; }*/ /*else { PORTB &= ~(1 << PB1); }*/ if(act_msec == 100) // Wenn eine Sekunde erreicht { act_msec = 0; // Millisekunden zurücksetzen act_sec++; // Sekunden um eins erhöhen } if(act_sec == 60) // Wenn eine Minute erreicht { act_sec = 0; // Sekunden zurücksetzen act_min++; // Minuten um eins erhöhen } LCD_struct.LAP_act_min = (uint8_t) act_min; LCD_struct.LAP_act_sec = (uint8_t) act_sec; LCD_struct.LAP_act_msec = (uint8_t) act_msec; //LCD_struct.LAP_best_min = (uint8_t) best_min; //LCD_struct.LAP_best_sec = (uint8_t) best_sec; //LCD_struct.LAP_best_msec = (uint8_t) best_msec; LCD_showLaptime(&LCD_struct); // Rundenzeiten per LCD anzeigen*/ } return 0; // Wird niemals erreicht }