Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Binäruhr 1.0
- //
- // Copyright (C) 2009 Paul Wilhelm <[email protected]>
- // http://mosfetkiller.de/?s=binaeruhr
- // Includes
- #define F_CPU 1000000UL // 8 MHz / 8 (CKDIV enabled)
- #include <util/delay.h>
- #include <avr/interrupt.h>
- #include <avr/io.h>
- #define FALSE 0
- #define TRUE 1
- // DS1307 address
- #define DS1307_ADDRESS 0b11010000 // Bit 0 = R/W bit
- // Pinbelegungen
- #define I2C_SCL_w_port PORTA
- #define I2C_SCL_r_port PINA
- #define I2C_SCL_dir DDRA
- #define I2C_SCL_bit 0
- #define I2C_SDA_w_port PORTA
- #define I2C_SDA_r_port PINA
- #define I2C_SDA_dir DDRA
- #define I2C_SDA_bit 1
- // Pinbelegungen Schalter nach GND (Hoch und Runter hängen am I2C-Bus...unschön, funktioniert aber)
- #define BUTTON_UP_PORT_OUT PORTA // Hoch
- #define BUTTON_UP_PORT_IN PINA
- #define BUTTON_UP_PIN 0
- #define BUTTON_DOWN_PORT_OUT PORTA // Runter
- #define BUTTON_DOWN_PORT_IN PINA
- #define BUTTON_DOWN_PIN 1
- #define BUTTON_ENTER_PORT_OUT PORTD // Enter
- #define BUTTON_ENTER_PORT_IN PIND
- #define BUTTON_ENTER_PIN 6
- // Makros
- #define set_bit(var, bit) ((var) |= (1 << (bit)))
- #define clear_bit(var, bit) ((var) &= (unsigned)~(1 << (bit)))
- #define set_I2C_SCL_dir set_bit (I2C_SCL_dir, I2C_SCL_bit)
- #define clear_I2C_SCL_dir clear_bit (I2C_SCL_dir, I2C_SCL_bit)
- #define set_I2C_SCL set_bit (I2C_SCL_w_port, I2C_SCL_bit)
- #define clear_I2C_SCL clear_bit (I2C_SCL_w_port, I2C_SCL_bit)
- #define set_I2C_SDA_dir set_bit (I2C_SDA_dir, I2C_SDA_bit)
- #define clear_I2C_SDA_dir clear_bit (I2C_SDA_dir, I2C_SDA_bit)
- #define set_I2C_SDA set_bit (I2C_SDA_w_port, I2C_SDA_bit)
- #define clear_I2C_SDA clear_bit (I2C_SDA_w_port, I2C_SDA_bit)
- #define I2C_Delay_us 100 // Immer schön langsam...wir haben ja Zeit :-)
- // Bei Fehlern in der I2C-Übertragung leuchtet die LED unten links auf
- // und das Programm wird gestoppt.
- // Prototypen
- void init();
- void draw_matrix();
- void i2c_start();
- void i2c_stop();
- void i2c_put_byte(unsigned char byte);
- unsigned char i2c_get_byte(unsigned char ack);
- // LED-Matrix
- volatile unsigned char matrix[8][6];
- // Zeit
- volatile unsigned char time[7];
- // Display
- volatile unsigned char display_dim = 9;
- // Tastenzähler
- volatile unsigned char button_up = 0, button_down = 0, button_enter = 0;
- // Main
- int main(void)
- {
- // Initialisieren
- init();
- // Benutzereingaben entgegennehmen (Uhr stellen)
- set_bit(TIMSK, OCIE0A); // Tastenzähler einschalten
- unsigned char parameter = 0, value = 0, value_old = 0, max = 0;
- unsigned char input = TRUE;
- while (input)
- {
- // Maximalwert festlegen (ja ja, ist unschön :-D)
- switch (parameter)
- {
- case 0:
- case 1: max = 59; break;
- case 2: max = 24; break;
- case 3: max = 7; break;
- case 4: max = 31; break;
- case 5: max = 12; break;
- case 6: max = 100; break;
- }
- // Wert hoch
- if ((button_up >= 10) && (button_down == 0))
- {
- button_up = 0;
- if (value < max) value++; else value = 0;
- }
- // Wert runter
- if ((button_down >= 10) && (button_up == 0))
- {
- button_down = 0;
- if (value > 0) value--; else value = max;
- }
- // Enter (nächster Parameter)
- if (button_enter >= 10)
- {
- button_enter = 0;
- if (parameter < 6) parameter++; else parameter = 0;
- // value auf Parameterwert setzen
- value = time[parameter];
- // Gewählten Parameter blinken lassen
- if (parameter == 0)
- {
- // Die Sekunden brauchen eine Extrawurst
- for (unsigned char k = 1; k < 5; k++)
- {
- for (unsigned char i = 0; i < 6; i++)
- {
- matrix[0][i] = k % 2;
- }
- _delay_ms(50);
- }
- }
- else
- {
- // Alle anderen Parameter
- for (unsigned char k = 1; k < 5; k++)
- {
- for (unsigned char i = 1; i < 8; i++)
- {
- matrix[i][parameter - 1] = k % 2;
- }
- _delay_ms(50);
- }
- }
- // Neu zeichnen
- draw_matrix();
- }
- // Hoch + Runter gleichzeitig gedrückt: Eingabe beendet
- if ((button_down >= 10) && (button_up >= 10))
- {
- // Ganz wichtig! Warten, bis die Taster wieder losgelassen wurden, ansonsten gibt es I2C-Brei...
- while ((button_down > 0) || (button_up > 0));
- // Sicher ist sicher!
- _delay_ms(25);
- input = FALSE;
- }
- if (value != value_old)
- {
- time[parameter] = value;
- value_old = value;
- draw_matrix();
- }
- }
- clear_bit(TIMSK, OCIE0A); // Tastenzähler ausschalten
- // Jetzt gehts los!
- i2c_start(); // Sicherheitshalber :-)
- i2c_stop();
- // Register Address auf 0x07 setzen (Control Register)
- i2c_start();
- i2c_put_byte(DS1307_ADDRESS | 0); // Schreiben
- i2c_put_byte(0x07);
- // Control Register setzen (Output Control = 0; Square Wave Enable = 0; Rate Select = 0)
- i2c_put_byte(0);
- i2c_stop();
- // Register Address auf 0x00 setzen (Register 0)
- i2c_start();
- i2c_put_byte(DS1307_ADDRESS | 0); // Schreiben
- i2c_put_byte(0x00);
- // Zeit setzen
- i2c_put_byte(((time[0] / 10) << 4) | (time[0] - (time[0] / 10) * 10)); // Clock Halt (Bit 7 = 0)
- i2c_put_byte(((time[1] / 10) << 4) | (time[1] - (time[1] / 10) * 10));
- i2c_put_byte(((time[2] / 10) << 4) | (time[2] - (time[2] / 10) * 10)); // 24 Hour Format (Bit 6 = 0)
- i2c_put_byte(time[3]);
- i2c_put_byte(((time[4] / 10) << 4) | (time[4] - (time[4] / 10) * 10));
- i2c_put_byte(((time[5] / 10) << 4) | (time[5] - (time[5] / 10) * 10));
- i2c_put_byte(((time[6] / 10) << 4) | (time[6] - (time[6] / 10) * 10));
- i2c_stop();
- // Hauptschleife
- while (1)
- {
- // Register address auf 0 setzen
- i2c_start();
- i2c_put_byte(DS1307_ADDRESS | 0); // Schreiben
- i2c_put_byte(0x00);
- i2c_stop();
- // Zeit lesen
- i2c_start();
- i2c_put_byte(DS1307_ADDRESS | 1); // Lesen
- for (unsigned char i = 0; i < 7; i++)
- {
- unsigned char temp = i2c_get_byte(!(i == 6)); // 0..5 = TRUE; 6 = FALSE
- if (i == 0)
- {
- time[i] = (temp & 0b00001111) + ((temp & 0b01110000) >> 4) * 10; // Bit 7 (Clock Halt) im Register 0 nicht verwenden!
- }
- else
- {
- // Die Maske darf auch auf die Stunden (Register 2) angewendet werden, da Bit 6 = 0 ist (24h-Format)
- time[i] = (temp & 0b00001111) + ((temp & 0b11110000) >> 4) * 10;
- }
- }
- i2c_stop();
- // --- Schnickschnack ---
- // Das Display von 22:00 Uhr bis 5:59 Uhr dimmen
- if ((time[2] >= 22) || (time[2] < 6)) display_dim = 1; else display_dim = 9;
- // Matrix füllen
- draw_matrix();
- }
- }
- // Initialisieren
- void init()
- {
- // Ports vorbereiten
- DDRA = 0b00; // PA1 = SDA; PA0 = SCAL - beziehungsweise PA1 = Taster "Runter"; PA0 = Taster "Hoch"
- PORTA = 0b11; // PullUp
- DDRB = 0b11111111; // PB0-PB7: Spalten (Anoden)
- PORTB = 0b00000000; // LOW
- DDRD = 0b0111111; // PD6: Taster "Enter"; PD5-PD0: Zeilen (Kathoden)
- PORTD = 0b1111111; // HIGH
- cli();
- // Timer-Interrupt TIMER0 vorbereiten (Tastenzähler)
- set_bit(TCCR0A, WGM01); // CTC
- set_bit(TCCR0B, CS02); // Prescaler 1024
- clear_bit(TCCR0B, CS01);
- set_bit(TCCR0B, CS00);
- // Tastenzähler-Geschwindigkeit
- OCR0A = 10; // Ca. 100 Hz
- // Timer-Interrupt TIMER1 vorbereiten (Display-Multiplexing)
- set_bit(TIMSK, OCIE1A);
- // Multiplexing-Geschwindigkeit (blockweise)
- OCR1AH = 0x00;
- OCR1AL = 0xf0;
- set_bit(TCCR1B, WGM12); // CTC
- clear_bit(TCCR1B, CS12); // Prescaler 64
- set_bit(TCCR1B, CS11);
- set_bit(TCCR1B, CS10);
- sei();
- }
- // LED-Matrix füllen
- void draw_matrix()
- {
- // Sekunden vertikal
- for (unsigned char temp_y = 0; temp_y < 6; temp_y++)
- {
- matrix[0][temp_y] = time[0] & (1 << (5 - temp_y));
- }
- // Restliche Werte horizontal
- for (unsigned char i = 0; i < 6; i++)
- {
- for (unsigned char temp_x = 1; temp_x < 8; temp_x++)
- {
- matrix[temp_x][i] = time[i + 1] & (1 << (temp_x - 1));
- }
- }
- }
- // Interruptvektor von TIMER0 - Tastenzähler
- ISR(TIMER0_COMPA_vect)
- {
- // Hoch
- if (bit_is_clear(BUTTON_UP_PORT_IN, BUTTON_UP_PIN))
- {
- if (button_up < 255) button_up++;
- }
- else
- {
- if (button_up > 0) button_up--;
- }
- // Runter
- if (bit_is_clear(BUTTON_DOWN_PORT_IN, BUTTON_DOWN_PIN))
- {
- if (button_down < 255) button_down++;
- }
- else
- {
- if (button_down > 0) button_down--;
- }
- // Enter
- if (bit_is_clear(BUTTON_ENTER_PORT_IN, BUTTON_ENTER_PIN))
- {
- if (button_enter < 255) button_enter++;
- }
- else
- {
- if (button_enter > 0) button_enter--;
- }
- }
- // Interruptvektor von TIMER1 - LED-Multiplexing
- ISR(TIMER1_COMPA_vect)
- {
- for (unsigned char y = 0; y < 6; y++)
- {
- for (unsigned char x = 0; x < 8; x++)
- {
- if (matrix[x][y] > 0) // LED an
- {
- PORTB = (1 << x); // X (0..7)
- PORTD = 0b1000000 | (~(1 << y)); // Y (0..5)
- }
- for (unsigned long i = 0; i < display_dim; i++) { asm volatile("nop"::); } // Verzögerung
- PORTB = 0b00000000; // LED aus
- PORTD = 0b1111111;
- }
- }
- }
- // Startbedingung
- // SCL HIGH, SDA wechselt auf LOW
- void i2c_start()
- {
- // SCL ist immer noch HIGH
- clear_I2C_SDA; // SDA: LOW
- set_I2C_SDA_dir; // SDA: Schreiben
- _delay_us(I2C_Delay_us);
- clear_I2C_SCL; // SCL: LOW
- set_I2C_SCL_dir; // SCL: Schreiben
- _delay_us(I2C_Delay_us);
- }
- // Stopbedingung
- void i2c_stop()
- {
- // SCL ist immer noch LOW
- clear_I2C_SDA; // SDA: LOW
- set_I2C_SDA_dir; // SDA: Schreiben
- _delay_us(I2C_Delay_us);
- clear_I2C_SCL_dir; // SCL: Lesen
- set_I2C_SCL; // SCL: HIGH (PullUp)
- _delay_us(I2C_Delay_us);
- clear_I2C_SDA_dir; // SDA: Lesen
- set_I2C_SDA; // SDA: HIGH (PullUp)
- }
- void i2c_put_byte(unsigned char byte)
- {
- unsigned char bit;
- for(bit = 0; bit < 8; bit++)
- {
- if (byte & 0b10000000)
- {
- // Bit = 1
- clear_I2C_SDA_dir; // SDA: Lesen
- set_I2C_SDA; // SDA: HIGH (PullUp)
- } else {
- // Bit = 0
- clear_I2C_SDA; // SDA: LOW
- set_I2C_SDA_dir; // SDA: Schreiben
- }
- clear_I2C_SCL_dir; // SCL: Lesen
- set_I2C_SCL; // SCL: HIGH (PullUp)
- _delay_us(I2C_Delay_us);
- clear_I2C_SCL; // SCL: LOW
- set_I2C_SCL_dir; // SCL: Schreiben
- _delay_us(I2C_Delay_us);
- byte <<= 1;
- }
- // SDA Release
- clear_I2C_SDA_dir; // SDA: Lesen
- set_I2C_SDA; // SDA: HIGH (PullUp)
- _delay_us(I2C_Delay_us);
- // SCL wieder auf HIGH setzen
- clear_I2C_SCL_dir; // SCL: Lesen
- set_I2C_SCL; // SCL: HIGH (PullUp)
- _delay_us(I2C_Delay_us);
- // ACK empfangen
- if (bit_is_set(I2C_SDA_r_port, I2C_SDA_bit))
- {
- // Fehler!
- matrix[7][5] = 1; // LED unten links setzen
- while (1); // Endlosschleife
- }
- _delay_us(I2C_Delay_us);
- clear_I2C_SCL; // SCL: LOW
- set_I2C_SCL_dir; // SCL: Schreiben
- _delay_us(I2C_Delay_us);
- }
- unsigned char i2c_get_byte(unsigned char ack)
- {
- unsigned char bit, byte = 0;
- clear_I2C_SDA_dir;
- set_I2C_SDA;
- for(bit = 0; bit < 8; bit++)
- {
- clear_I2C_SCL_dir;
- set_I2C_SCL;
- _delay_us(I2C_Delay_us);
- if (bit_is_set(I2C_SDA_r_port, I2C_SDA_bit))
- {
- byte = (byte << 1) | 0b00000001;
- } else {
- byte = (byte << 1);
- }
- clear_I2C_SCL;
- set_I2C_SCL_dir;
- _delay_us(I2C_Delay_us);
- }
- // ACK ausgeben?
- if (ack == TRUE)
- clear_I2C_SDA; // SDA: LOW
- set_I2C_SDA_dir; // SDA: Schreiben
- _delay_us(I2C_Delay_us);
- clear_I2C_SCL_dir;
- set_I2C_SCL;
- _delay_us(I2C_Delay_us);
- clear_I2C_SCL;
- set_I2C_SCL_dir;
- _delay_us(I2C_Delay_us);
- clear_I2C_SDA_dir;
- set_I2C_SDA;
- return byte;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement