Урок 19
Собираем часы на микросхеме DS1307 и LCD 1602
Сегодня, набравшись уже опыта по программирования шины I2С, а также изучив микросхему реального времени DS1307, мы сможем приступить к программированию простейших часов и выводить их показания уже не в компьютер, а в жидкокристаллический дисплей. Я думаю, это будет намного наглядней и красивее, чем просматривать это в терминальной программе на ПК.
С дисплеем 16х2 мы работать также умеем, поэтому мы практически в данном занятии соединим два прошлых занятия, а также лишний раз повторим пройденный материал.
Будем считать, что модуль с микросхемой у нас уже присоединён к отладочной плате с контроллером Atmega8A, Присоединим к ней также модуль дисплея. Вот упрощённая схема из протеуса (нажмите на картинку для увеличения изображения)
Ясное дело, что ещё здесь будет батарейка для сохранения хода часов при отключении питания, также вообще питание, контрастрость на дисплей. Но, я думаю, это понятно.
А вот так всё будет выглядеть на деле (нажмите на картинку для увеличения изображения)
Дисплей подключен у нас будет подключин также в 4-битном режиме и к тем же ножкам портов, как и в уроке 12.
Проект был создан с именем MyClock1307LCD. Все файлы, кроме главного скопированы туда и впоследствии подключены из проекта урока 17 MyClock1307.
Также к проекту подключены файлы для работы с дисплеем lcd.c и lcd.h. из проекта Test12, где мы работали с шиной USART.
Перейдём в главный модуль MyClock1307LCD.c. Код у нас здесь пока стандартный
#include «main.h»
//—————————————-
int main(void)
{
while(1)
{
}
}
Зайдём в файл lcd.c и исправим там функцию sendchar в sencharlcd во избежания совпадения имен с другими модулями
//—————————————-
void sendcharlcd(unsigned char c)
Также добавим для неё прототип и ещё прототип для функции очистки дисплея в файл lcd.h
void str_lcd (char str1[]);
void clearlcd(void);
void sendcharlcd(unsigned char c);
Теперь можно начать писать код в главном модуле. Причём почти весь его можно скопировать с предыдущих проектов.
Функцию инициализации порта возьмём из урока по дисплею
#include «main.h»
//—————————————-
void port_ini(void)
{
PORTD=0x00;
DDRD=0xFF;
}
//—————————————-
Оттуда же возьмём в main() код инициализации порта и дисплея, а заодно его сразу и очистим
int main(void)
{
port_ini(); //Инициализируем порты
LCD_ini(); //Инициализируем дисплей
clearlcd(); //Очистим дисплей
Из главного модуля проекта из урока по часовой микросхемы возьмём инициализацию I2C
port_ini(); //Инициализируем порты
I2C_Init(); //Инициализируем шину I2C
LCD_ini(); //Инициализируем дисплей
Оттуда же возьмём глобальные переменные для хранения показаний регистров
#include «main.h»
//—————————————-
unsigned char sec,min,hour,day,date,month,year;
//—————————————-
Вполне нам может также пригодиться закомментированный код установки времени, вдруг придется устанавливать, так как кнопки мы пока не заводим
clearlcd(); //Очистим дисплей
//Устанавливаем время
// I2C_StartCondition();
// I2C_SendByte(0b11010000);
// I2C_SendByte(0);//Переходим на 0x00
// I2C_SendByte(RTC_ConvertFromBinDec(0)); //секунды
// I2C_SendByte(RTC_ConvertFromBinDec(31)); //минуты
// I2C_SendByte(RTC_ConvertFromBinDec(20)); //часы
// I2C_SendByte(RTC_ConvertFromBinDec(5)); //день недели
// I2C_SendByte(RTC_ConvertFromBinDec(29)); //дата
// I2C_SendByte(RTC_ConvertFromBinDec(1)); //месяц
// I2C_SendByte(RTC_ConvertFromBinDec(16)); //год
// I2C_StopCondition();
while(1)
Также возьмём пока всё полностью и из бесконечного цикла
while(1)
{
//Читаем время
I2C_SendByteByADDR(0,0b11010000); //переходим на адрес 0
_delay_ms(300);
I2C_StartCondition(); //Отправим условие START
I2C_SendByte(0b11010001); //отправим в устройство бит чтения
sec = I2C_ReadByte();
min = I2C_ReadByte();
hour = I2C_ReadByte();
day = I2C_ReadByte();
date = I2C_ReadByte();
month = I2C_ReadByte();
year = I2C_ReadLastByte();
I2C_StopCondition(); //Отправим условие STOP
sec = RTC_ConvertFromDec(sec); //Преобразуем в десятичный формат
min = RTC_ConvertFromDec(min); //Преобразуем в десятичный формат
hour = RTC_ConvertFromDec(hour); //Преобразуем в десятичный формат
day = RTC_ConvertFromDec(day); //Преобразуем в десятичный формат
year = RTC_ConvertFromDec(year); //Преобразуем в десятичный формат
month = RTC_ConvertFromDec(month); //Преобразуем в десятичный формат
date = RTC_ConvertFromDec(date); //Преобразуем в десятичный формат
USART_Transmit(date/10+0x30);//Преобразуем число в код числа
USART_Transmit(date%10+0x30);//Преобразуем число в код числа
USART_Transmit('.');
USART_Transmit(month/10+0x30);//Преобразуем число в код числа
USART_Transmit(month%10+0x30);//Преобразуем число в код числа
USART_Transmit('.');
USART_Transmit(year/10+0x30);//Преобразуем число в код числа
USART_Transmit(year%10+0x30);//Преобразуем число в код числа
USART_Transmit(' ');
USART_Transmit('-');
USART_Transmit(day+0x30);//Преобразуем число в код числа
USART_Transmit('-');
USART_Transmit(' ');
USART_Transmit(' ');
USART_Transmit(hour/10+0x30);//Преобразуем число в код числа
USART_Transmit(hour%10+0x30);//Преобразуем число в код числа
USART_Transmit(':');
USART_Transmit(min/10+0x30);//Преобразуем число в код числа
USART_Transmit(min%10+0x30);//Преобразуем число в код числа
USART_Transmit(':');
USART_Transmit(sec/10+0x30);//Преобразуем число в код числа
USART_Transmit(sec%10+0x30);//Преобразуем число в код числа
USART_Transmit(0x0d);//переход в начало строки
USART_Transmit(0x0a);//перевод каретки
}
После преобразований данных в бесконечном цикле добавим функцию установки курсора дисплея в начальное положение
date = RTC_ConvertFromDec(date); //Преобразуем в десятичный формат
setpos(0,0); //Ставим курсор на начало координат
Заменим в коде USART_Transmit на sendcharlcd пока там, где работаем с датой ,не со временем, а также перед показаниями года добавим «20», чтобы год смотрелся посолидней
setpos(0,0); //Ставим курсор на начало координат
sendcharlcd(date/10+0x30);//Преобразуем число в код числа
sendcharlcd(date%10+0x30);//Преобразуем число в код числа
sendcharlcd('.');
sendcharlcd(month/10+0x30);//Преобразуем число в код числа
sendcharlcd(month%10+0x30);//Преобразуем число в код числа
sendcharlcd('.');
sendcharlcd('2');
sendcharlcd('0');
sendcharlcd(year/10+0x30);//Преобразуем число в код числа
sendcharlcd(year%10+0x30);//Преобразуем число в код числа
sendcharlcd(' ');
sendcharlcd('-');
sendcharlcd(day+0x30);//Преобразуем число в код числа
sendcharlcd('-');
Так как мы с показаниями времени не влезем на 1 строку, поэтому переведём перед этим строку, а затем также исправим везде вызов функции на sendcharlcd, также уберём перевод строки и возврат каретки.
setpos(0,1); //Ставим курсор на начало координат
sendcharlcd(hour/10+0x30);//Преобразуем число в код числа
sendcharlcd(hour%10+0x30);//Преобразуем число в код числа
sendcharlcd(':');
sendcharlcd(min/10+0x30);//Преобразуем число в код числа
sendcharlcd(min%10+0x30);//Преобразуем число в код числа
sendcharlcd(':');
sendcharlcd(sec/10+0x30);//Преобразуем число в код числа
sendcharlcd(sec%10+0x30);//Преобразуем число в код числа
Попробуем собрать код и прошить контроллер.
Наши часы отлично ходят!
Предыдущий урок Программирование МК AVR Следующий урок
Программатор, модуль RTC DS1307 с микросхемой памяти и дисплей можно приобрести здесь:
Программатор (продавец надёжный) USBASP USBISP 2.0
Модуль RTC DS1307 с микросхемой памяти
Смотреть ВИДЕОУРОК (нажмите на картинку)
Привіт. Зараз багато хто використовує ds3231. Ви з нею працювали? Не хотіли би зробити урок для AVR по цій мікросхемі? Дякую.
Так а там, по-моему, всё также как и у ds1307. В уроке по DS3231 в разделе STM32 это видно. Пробовал под STM32F407. У себя на макетке менял местами DS3231 и DS1307 — всё работало!
У меня вышло на DS3231.А на DS1307 не выходит.Там 7 бит программно нужно устанавливать?Как у вас получилось?
Вы так много дали, что я нашел скучным использовать параллельный интерфейс для вывода даты и времени на LCD. Сразу все зарядил через TWI. Единственное что нашел неудобным — день недели — цифрой. У некоторых неделя начинается с Воскресенья. Вывел сокращения функцией send_string. Все работает! Спасибо!!!