#include #include #include #include #include #include #include #include #include #define F_CPU 4000000 #define UART_BAUD_RATE 9600 #define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*16l)-1) #define CLOCK_IO 1 #define CLOCK_CLK 2 #define CLOCK_ENABLE 0 typedef unsigned char u08; typedef char s08; typedef unsigned short u16; typedef short s16; static volatile u08 *uart_data_ptr; static volatile u08 uart_counter; static volatile u08 led; static volatile u08 g_hour; static volatile u08 g_minute; static volatile u08 g_alarmHour; static volatile u08 g_alarmMinute; static volatile u08 g_alarmSet; static volatile u08 g_commandStart; static volatile u08 g_command[30]; static volatile u08 g_commandCount; static volatile char output[6]; SIGNAL(SIG_UART_TRANS) { uart_data_ptr++; if (--uart_counter) UDR = *uart_data_ptr; } SIGNAL(SIG_UART_RECV) { register char inByte; inByte = UDR; if (inByte == 'Z') { g_command[g_commandCount] = '\0'; g_commandCount = 0; g_commandStart = 0; return; } if ((inByte == 'S') && (!g_commandStart)) { g_commandStart = 1; memset(g_command, ' ', 8); } else { g_command[g_commandCount] = inByte; g_commandCount++; if (g_commandCount > 29) { g_commandCount = 7; } } } void clearOutput() { output[0] = '\0'; output[1] = '\0'; output[2] = '\0'; output[3] = '\0'; output[4] = '\0'; output[5] = '\0'; } void uart_send(u08 *buf, u08 size) { if (!uart_counter) { uart_data_ptr = buf; uart_counter = size; UDR = *buf; } while (uart_counter != 0) { } } void uart_init(void) /* initialize uart */ { /* enable RxD/TxD and ints */ UCSRB = (1<> 4; for (i=0; i<4; i++) { number = number >> 1; if (swap & mask) { number |= 0x08; } mask = mask >> 1; } retVal = number; // process low byte (1's) number = 0; swap = bcd; mask = 0x08; for (i=0; i<4; i++) { number = number >> 1; if (swap & mask) { number |= 0x08; } mask = mask >> 1; } retVal += (number * 10); return retVal; } uint8_t iToBcd(uint8_t inNumber) { int newByte; newByte = 0; while (inNumber > 10) { inNumber -= 10; newByte++; } newByte = newByte << 4; newByte = (newByte | inNumber); return newByte; } // Set data on rising edge - note .RST must be asserted void setBitClock(uint8_t bit) { cbi(PORTB, CLOCK_CLK); delay(10); if (bit) { sbi(PORTB, CLOCK_IO); } else { cbi(PORTB, CLOCK_IO); } delay(5); sbi(PORTB, CLOCK_CLK); delay(10); cbi(PORTB, CLOCK_CLK); } // Read data on falling edge - note .RST must be asserted uint8_t getBitClock(void) { uint8_t retVal = 0; delay(10); if (bit_is_set(PINB, CLOCK_IO)) { retVal = 1; } else { retVal = 0; } cbi(PORTB, CLOCK_CLK); delay(10); sbi(PORTB, CLOCK_CLK); delay(10); cbi(PORTB, CLOCK_CLK); delay(5); delay(10); return retVal; } void sendClockByte(uint8_t inByte) { uint8_t i; uint8_t bit; uint8_t mask = 1; // Set PIND6 for output sbi(DDRB, CLOCK_IO); for (i=0; i<8; i++) { bit = inByte & mask; if (bit) setBitClock(1); else setBitClock(0); mask <<= 1; } } uint8_t receiveClockByte() { uint8_t returnVal = 0; uint8_t i; // Set PIND6 for input cbi(DDRB, CLOCK_IO); for (i=0; i<8; i++) { returnVal = returnVal << 1; returnVal = returnVal | getBitClock(); } return returnVal; } void startTransfer() { cbi(PORTB, CLOCK_IO); sbi(PORTB, CLOCK_ENABLE); } void endTransfer() { cbi(PORTB, CLOCK_ENABLE); } // Events are triggered on the hour uint8_t getTime() { uint8_t commandByte; // Minute - get minute register delay(5000); startTransfer(); commandByte = 0x83; sendClockByte(commandByte); g_minute = receiveClockByte(); g_minute = bcdToI(g_minute); endTransfer(); // Hour - get hour register delay(5000); startTransfer(); commandByte = 0x85; sendClockByte(commandByte); g_hour = receiveClockByte(); g_hour = bcdToI(g_hour); endTransfer(); return 0; } uint8_t setTime() { uint8_t commandByte; // Second - set second register delay(5000); startTransfer(); commandByte = 0x80; sendClockByte(commandByte); sendClockByte(0); endTransfer(); // Minute - set minute register delay(5000); startTransfer(); commandByte = 0x82; sendClockByte(commandByte); sendClockByte(iToBcd(g_minute)); endTransfer(); // Hour - set hour register delay(5000); startTransfer(); commandByte = 0x84; sendClockByte(commandByte); sendClockByte(iToBcd(g_hour)); endTransfer(); return 0; } void clockOn() { uint8_t i; uint8_t inByte; /* make sure the clock is running / reset */ for (i=0; i<2; i++) { // read value in seconds register to not cause time shifting delay(1000); startTransfer(); delay(100); sendClockByte(0x81); inByte = receiveClockByte(); endTransfer(); delay(1000); // write value in seconds register startTransfer(); delay(100); sendClockByte(0x8e); sendClockByte((inByte | 0x80)); endTransfer(); delay(1000); // write control bit (make sure clock isn't stopped) startTransfer(); delay(100); sendClockByte(0x8e); sendClockByte(0x00); endTransfer(); delay(1000); // turn on the trickle charger startTransfer(); delay(1000); sendClockByte(0x90); sendClockByte(0xa5); endTransfer(); delay(1000); } } // end clock functions ////////////////////////////////////////////// void commandProcess() { u08 i; if (g_command[0] == 'T') { clearOutput(); if (g_command[1] == 0) { output[0] = g_command[2]; } else { output[0] = g_command[1]; output[1] = g_command[2]; } g_hour = atoi(output); clearOutput(); if (g_command[3] == 0) { output[0] = g_command[4]; } else { output[0] = g_command[3]; output[1] = g_command[4]; } g_minute = atoi(output); setTime(); uart_send("ZZ\n\r", 4); } if (g_command[0] == 'D') { getTime(); uart_send("S", 1); clearOutput(); itoa(g_hour, output, 10); if (g_hour < 10) { output[1] = output[0]; output[0] = '0'; } uart_send(output, 2); uart_send(":", 1); clearOutput(); itoa(g_minute, output, 10); if (g_minute < 10) { output[1] = output[0]; output[0] = '0'; } uart_send(output, 2); uart_send("Z", 1); uart_send("\n\r", 2); } if (g_command[0] == 'A') { clearOutput(); if (g_command[1] == 0) { output[0] = g_command[2]; } else { output[0] = g_command[1]; output[1] = g_command[2]; } g_alarmHour = atoi(output); clearOutput(); if (g_command[3] == 0) { output[0] = g_command[4]; } else { output[0] = g_command[3]; output[1] = g_command[4]; } g_alarmMinute = atoi(output); g_alarmSet = 1; uart_send("ZZ\n\r", 4); } if (g_command[0] == 'P') { uart_send("S", 1); clearOutput(); itoa(g_alarmHour, output, 10); if (g_alarmHour < 10) { output[1] = output[0]; output[0] = '0'; } uart_send(output, 2); uart_send(":", 1); clearOutput(); itoa(g_alarmMinute, output, 10); if (g_alarmMinute < 10) { output[1] = output[0]; output[0] = '0'; } uart_send(output, 2); uart_send("Z", 1); uart_send("\n\r", 2); } for (i=0; i<8; i++) { g_command[i] = '\0'; } } int main(void) { volatile char temps[10] = "\0\0\0\0\0\0\0\0\0\0"; uint16_t totalMinutes; uint16_t alarmMinutes; DDRB = 0xff; DDRD = 0xff; PORTD = 0; uart_init(); sei(); delay(50000); delay(50000); delay(50000); delay(50000); led = 0; g_alarmHour = 0; g_alarmMinute = 0; g_alarmSet = 0; uart_send("DS1302 RTC alarm test!\n\r", 24); clockOn(); getTime(); while(1) { if (g_alarmSet) { totalMinutes = g_hour * 60; totalMinutes += g_minute; alarmMinutes = g_alarmHour * 60; alarmMinutes += g_alarmMinute; if (totalMinutes >= alarmMinutes) { uart_send("ALARM\n\r", 7); sbi(PORTD, 7); g_alarmSet = 0; } } if (!g_commandStart) { commandProcess(); } } }