Наконец то и в мои руки попала микросхема часов реального времени DS1307. Это маленькая микросхема, требующая минимум обвязки, с которой очень просто работать. Ниже я покажу на примере как сделать часы на основе этой микросхемы, микроконтроллера Atmega16 и среды программирования CodeVisionAVR. Сначала немного о самой микросхеме часов: Назначение выводов: X1,X2 - Входы для подключения часового кварца (32,768кГц) VBat - подключения "+" батарейки 3В (например CR2032) GND - общий SDA - линия данных I2C SCL - тактовая линия I2C SQW/OUT - выход для тактирования внешних устройств Vcc - +5В
Схема часов приведена ниже:
Мозгом часов является микроконтроллер atmega16, к которому подключена микросхема часов, дисплей с контроллером HD44780, и три кнопки для настройки часов.
Теперь надо заставить все это работать. Для того чтобы наша atmega смогла работать с микросхемой часов, нам нужно настроить шину I2C, для этого в генераторе кода нужно перейти на вкладку I2C, выбрать порт к которому будем подключать часы,в моем варианте это PORTB, указать на какие пины будут подключены линии SDA и SCL, и выбрать микросхему часов, для этого перейти на внутреннюю вкладку DS1307 и поставить галочку Enable:
В CodeVisionAVR есть готовая библиотека для работы с часами DS1307, что сильно упрощает жизнь. И так что мы можем:
void rtc_write(unsigned char address,unsigned char data); - запись данных в микросхему часов, например выбрать 12 или 24 часовой формат времени, выбрать частоту импульсов на выходе OUT и т.д.;
void rtc_init(unsigned char rs,unsigned char sqwe,unsigned char out); - инициализация микросхемы часов;
void rtc_get_time(unsigned char *hour,unsigned char *min,unsigned char *sec); - получение времени от микросхемы часов;
void rtc_set_time(unsigned char hour,unsigned char min,unsigned char sec); - установка значения времени в часы;
void rtc_get_date(unsigned char *date,unsigned char *month,unsigned char *year); - получение даты;
void rtc_set_date(unsigned char date,unsigned char month,unsigned char year); - настройка даты.
Этих функций нам вполне хватит для того чтобы наши часики заработали. Чтобы несколько раз не писать одно и тоже, привожу исходный код с подробными комментариями:
#include <mega16.h> #include <stdio.h> #include <delay.h> // I2C Bus functions #asm .equ __i2c_port=0x18 ;PORTB .equ __sda_bit=1 .equ __scl_bit=0 #endasm #include <i2c.h>
// DS1307 Real Time Clock functions #include <ds1307.h> #define pause delay_ms(200)
#asm .equ __lcd_port=0x1B ;PORTA #endasm #include <lcd.h> unsigned char hour, min, sec; unsigned char set; unsigned char lcd_buffer[33]; void main(void) { PORTA=0x00; DDRA=0x00; PORTB=0x00; DDRB=0x00; PORTC=0xFF; DDRC=0xFF; PORTD=0x00; DDRD=0x00; TCCR0=0x00; TCNT0=0x00; OCR0=0x00; TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; MCUCR=0x00; MCUCSR=0x00; TIMSK=0x00; ACSR=0x80; SFIOR=0x00;
i2c_init(); //Инициализация шины I2C rtc_init(3,1,0); //Инициализация микросхемы часов rtc_write(0,0); //Запуск часов lcd_init(16); //Инициализация экрана lcd_clear(); //Очистка экрана while (1) //Основный цикл программы { set=0; //Обнуление переменной, необходимой для работы с кнопками if(PINC.0==0) // Если нажата кнопка "Set" переходим к настройке часов { set=1; while(set==1) { pause; switch (PINC) { // Отслеживаем нажатие кнопок case 0xFD: hour++; if (hour>23){hour=0;}; break; //Если нажата кнопка ">" то увеличиваем колчество часов на 1 case 0xFB: hour--; if (hour==255){hour=23;}; break; //Если нажата кнопка "<" то уменьшаем колчество часов на 1 case 0xFE: set=2; break; //Если нажата кнопка "Set", переходим к настройкам минут }; lcd_clear(); // Очистка экрана sprintf(lcd_buffer,"Hour: %u%u",hour/10,hour%10); //Запись в буфер значения параметра час lcd_puts(lcd_buffer); // Вывод на экран текущее значение параметра час }; while(set==2) { pause; switch (PINC) { // Отслеживаем нажатие кнопок case 0xFD: min++; if (min>59){min=0;}; break; //Если нажата кнопка ">" то увеличиваем колчество минут на 1 case 0xFB: min--; if (min==255){min=59;}; break; //Если нажата кнопка "<" то уменьшаем колчество минут на 1 case 0xFE: set=0;rtc_set_time(hour,min,sec); break; //Если нажата кнопка "Set", отправляем в микросхему часов новые значения времени }; lcd_clear(); // Очистка экрана sprintf(lcd_buffer,"Min: %u%u",min/10,min%10); //Запись в буфер значение минут lcd_puts(lcd_buffer); // Вывод на экран текущее количество минут }; }; rtc_get_time(&hour,&min,&sec); //считать время sprintf(lcd_buffer,"Time: %u%u:%u%u:%u%u",hour/10,hour%10,min/10,min%10,sec/10,sec%10); // Запись в буфер значение времени lcd_clear(); //очистка экрана lcd_puts(lcd_buffer); Выводим на экран текущее время pause; }; }
Свои часы я собрал на плате переходнике soic8-DIP. Меленькая компактная плата, на которой спокойно размещаются все детали:
|