Драйвер для часов реального времени DS1307 на STM8

Сайт: 

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

Схема подключения DS1307 к контроллеру

Полную информацию по DS1307 можно получить из официального даташита DS1307.pdf

В этой статье я не буду рассказывать вам о подробностях работы с DS1307. Это уже избитая тема, о которой много написано в интернете. Тем, кто не работал с DS1307, советую почитать хорошую статью: «Учебный курс AVR. Использования TWI модуля. Работа с DS1307. Дешево и сердито. Ч3»

Я же хочу показать как с помощью написанных ранее драйверов для UART и I2C написать драйвер работы с часами реального времени DS1307 на микроконтроллере STM8S003F. Тем, кто не читал статьи по настройке UARTи I2C, привожу ссылки:

1.      Настройка UART на микроконтроллере STM8

2.      Настройка I2C на микроконтроллере STM8

Для создания драйвера DS1307 скачиваем:

1.      Драйвер UART STM8

2.      Драйвер I2C STM8

После создания драйвера 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 преобразует десятичное число в строку. Ну вот, пожалуй, и все. 

Ссылки для скачивания драйвера и рабочего проекта часов:

  1. Драйвер DS1307 для STM8
  2. Проект часов реального времени DS1307 на STM8 в среде IAR