Драйвер для часов реального времени DS1307 на STM8
DS1307 – микросхема часов реального времени RTC(RealTimeClock). Кроме часов, она содержит еще календарь. Связь с микросхемой осуществляется по интерфейсу I2C. Достоинством данной микросхемы является ее низкое энергопотребление. Она может работать как на основном источнике питания, так и на резервном (батарейка 3В, на которой микросхема может работать несколько лет!), тактируется от отдельного кварцевого резонатора 32768Hz. Кроме этого, DS1307 содержит 56 Байт SRAM-памяти, для хранения пользовательских данных.
Полную информацию по DS1307 можно получить из официального даташита DS1307.pdf
В этой статье я не буду рассказывать вам о подробностях работы с DS1307. Это уже избитая тема, о которой много написано в интернете. Тем, кто не работал с DS1307, советую почитать хорошую статью: «Учебный курс AVR. Использования TWI модуля. Работа с DS1307. Дешево и сердито. Ч3»
Я же хочу показать как с помощью написанных ранее драйверов для UART и I2C написать драйвер работы с часами реального времени DS1307 на микроконтроллере STM8S003F. Тем, кто не читал статьи по настройке UARTи I2C, привожу ссылки:
1. Настройка UART на микроконтроллере STM8
2. Настройка I2C на микроконтроллере STM8
Для создания драйвера DS1307 скачиваем:
После создания драйвера DS1307 создадим небольшое приложение, которое будет считывать время из DS1307 и печатать его в виде строки по UART каждую секунду.
Как обычно, сначала нам нужно проиницализировать DS1307. Инициализация достаточно проста: сначала читаем регистр по адресу 0x00, где хранятся секунды и бит CH, который отображает состояние работы часов (1 - остановлены, 0 - запущены). Если часы остановлены, то вызывается функция сброса, которую мы тоже напишем. В ней устанавливаются все значения (секунды, минуты и т.д.) в 0 (или 1, если это месяц или дата), а также сбрасывается бит CH.
//****************************************************************************** //Инициализация часов DS1307 //****************************************************************************** t_ds1307_status ds1307_init(t_ds1307_time_mode time_mode){ //Состояние выполнения операции I2C t_i2c_status status = I2C_SUCCESS; //Переменная для хранения прочитанных данных t_ds1307_date_time data; //Инициализация RTC. Читаем 0-й регистр status = i2c_rd_reg(DS1307_SLAVE_ADDR, DS1307_REG_SEC, (char *)&data, 1); //Проверка состояния выполнении операции по I2C ds1307_check_error(status); //Если работа часов запрещена, то разрешаем сбросом CH=0 if(data.ch){ //Сброс даты и времени return ds1307_reset(time_mode); } return DS1307_SUCCESS; }
t_ds1307_date_time - это структура, которая хранит все значения времени и даты. Ее описание можно будет найти в файле ds1307_drv.h, который будет находиться в архиве, прикрепленном в конце статьи.
//****************************************************************************** //Сброс времени и даты DS1307 //****************************************************************************** t_ds1307_status ds1307_reset(t_ds1307_time_mode time_mode){ //Состояние выполнения операции I2C t_i2c_status status = I2C_SUCCESS; //Структура хранения времени и даты t_ds1307_date_time dt; //Включаем тактирование часов dt.ch = 0; //Сброс времени dt.seconds = 0; dt.minutes = 0; dt.hours = 0; dt.mode = time_mode; //Сброс даты dt.date = 1; dt.month = 1; dt.year = 00; //Запись регистров ds1307 status = i2c_wr_reg(DS1307_SLAVE_ADDR, DS1307_REG_SEC, (char *)&dt, sizeof(t_ds1307_date_time)); //Проверка состояния выполнении операции по I2C ds1307_check_error(status); return DS1307_SUCCESS; }
ds1307_check_error - это макрос, который проверяет состояние операции с I2C и на ее основании возвращает значение операции DS1307. Макрос вы также найдете в прикрепленном архиве.
Осталось описать функции для установки времени и его чтения из RTC.
//****************************************************************************** //Установка времени и даты DS1307 //****************************************************************************** t_ds1307_status ds1307_set(t_ds1307_date_time * dt){ //Состояние выполнения операции I2C t_i2c_status status = I2C_SUCCESS; //Не запрещаем работу часов dt->ch = 0; //Переводим дату и время в BCD-формат dt->seconds = ds1307_dec2bcd(dt->seconds); dt->minutes = ds1307_dec2bcd(dt->minutes); dt->hours = ds1307_dec2bcd(dt->hours); dt->day = ds1307_dec2bcd(dt->day); dt->date = ds1307_dec2bcd(dt->date); dt->month = ds1307_dec2bcd(dt->month); dt->year = ds1307_dec2bcd(dt->year); //Запись регистров ds1307 status = i2c_wr_reg(DS1307_SLAVE_ADDR, DS1307_REG_SEC, (char *)dt, sizeof(t_ds1307_date_time)); //Проверка состояния выполнении операции по I2C ds1307_check_error(status); return DS1307_SUCCESS; } //****************************************************************************** //Чтение времени и даты из регистров DS1307 //****************************************************************************** t_ds1307_status ds1307_get(t_ds1307_date_time * dt){ //Состояние выполнения операции I2C t_i2c_status status = I2C_SUCCESS; t_ds1307_date_time datetime; //Чтение регистров ds1307 status = i2c_rd_reg(DS1307_SLAVE_ADDR, DS1307_REG_SEC, (char *)&datetime, sizeof(t_ds1307_date_time)); //Проверка состояния выполнении операции по I2C ds1307_check_error(status); //Переводим дату и время из BCD-формата в обычный dt->seconds = ds1307_bcd2dec(datetime.seconds); dt->minutes = ds1307_bcd2dec(datetime.minutes); dt->hours = ds1307_bcd2dec(datetime.hours); dt->day = ds1307_bcd2dec(datetime.day); dt->date = ds1307_bcd2dec(datetime.date); dt->month = ds1307_bcd2dec(datetime.month); dt->year = ds1307_bcd2dec(datetime.year); return DS1307_SUCCESS; }
Так как данные в DS1307 хранятся в BCD-коде, то при записи регистров десятичные значения нужно конвертировать в BCD, а при чтении регистров, их значения нужно обратно конвертировать в десятичное представление. Этим занимаются вспомогательные функции ds1307_bcd2dec и ds1307_dec2bcd. Их описание найдете в архиве с проектом.
Вот так может выглядеть код основной программы. Мы инициализируем UART, I2C, затем инициализируем саму DS1307. После этого устанавливаем нужную даты и время. Дальше в бесконечном цикле с паузой около 1 с читаем значения времени и даты и печатаем строку в UART с этой информацией.
int main( void ) { unsigned char temp[2]; //Состояние операции DS1307 t_ds1307_status ds1307_status; //Инициализация UART uart_init(UART_BAUD, F_MASTER_HZ); uart_tx_data("Start RTC\r\n", 11); //Инициализация I2C i2c_master_init(F_MASTER_HZ, F_I2C_HZ); //Инициализация DS1307 ds1307_status = ds1307_init(DS1307_TIME_MODE_24H); if(ds1307_status != DS1307_SUCCESS){ uart_tx_data("DS1307 init error\r\n", 18); while(1); } //Дата ds1307_time.date = 18; ds1307_time.month = 07; ds1307_time.year = 14; //Время ds1307_time.hours = 10; ds1307_time.minutes = 00; ds1307_time.seconds = 00; //Устанавливаем заданное время ds1307_set(&ds1307_time); while(1){ //Читаем текущее время и дату ds1307_get(&ds1307_time); //Выводим на печать время dec2str(ds1307_time.hours, temp, 2, 0); uart_tx_data(temp, 2); uart_tx_data(":", 1); dec2str(ds1307_time.minutes, temp, 2, 0); uart_tx_data(temp, 2); uart_tx_data(":", 1); dec2str(ds1307_time.seconds, temp, 2, 0); uart_tx_data(temp, 2); uart_tx_data(" ", 2); //Выводим на печать дату dec2str(ds1307_time.date, temp, 2, 0); uart_tx_data(temp, 2); uart_tx_data("/", 1); dec2str(ds1307_time.month, temp, 2, 0); uart_tx_data(temp, 2); uart_tx_data("/", 1); dec2str(ds1307_time.year, temp, 2, 0); uart_tx_data(temp, 2); uart_tx_data("\r\n", 2); //Задержка delay_cycles(30000UL); } }
Функция dec2str преобразует десятичное число в строку. Ну вот, пожалуй, и все.
Ссылки для скачивания драйвера и рабочего проекта часов:
- Войдите или зарегистрируйтесь, чтобы отправлять комментарии
Комментарии
!
Добрый день.
Было бы неплохо к каждой статье, выкладывать электрическую схему!