DS1307 – микросхема часов реального времени RTC(RealTimeClock). Кроме часов, она содержит еще календарь. Связь с микросхемой осуществляется по интерфейсу I2C. Достоинством данной микросхемы является ее низкое энергопотребление. Она может работать как на основном источнике питания, так и на резервном (батарейка 3В, на которой микросхема может работать несколько лет!), тактируется от отдельного кварцевого резонатора 32768Hz. Кроме этого, DS1307 содержит 56 Байт SRAM-памяти, для хранения пользовательских данных.

Полную информацию по DS1307 можно получить из официального даташита на DS1307
В этой статье я не буду рассказывать вам о подробностях работы с 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
", 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
", 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("
", 2);
//Задержка
delay_cycles(30000UL);
}
}
Функция dec2str преобразует десятичное число в строку. Ну вот, пожалуй, и все.
Ссылки для скачивания драйвера и рабочего проекта часов:
