Часы реального времени на STM32F103C8T6 (Arduino)

В микроконтроллере STM32 есть встроенные часы реального времени которые могут работать от внутреннего низкоскоростного RC-резонатора (LSI), внешнего низкоскоростного кварцевого резонатора (LSE) или внешнего высокоскоростного резонатора с делителем (HSE/128). Внешний низкоскоростной кварцевый резонатор, с частотой 32768 Гц, использовать предпочтительнее, так как он обеспечивает большую точность хода часов и уже установлен на отладочной плате STM32.

Часы реального времени могут работать независимо от основного питания, для этого на вход vbat нужно подать питание напряжением 3 В (батарейка).

Ниже показан скетч позволяющий установить текущее время и вывести время в монитор порта. Работа часов реального времени управляется библиотекой RTClock, устанавливать библиотеку не нужно она входит в состав набора библиотек Arduino_STM32-master который устанавливаются при установке поддержки платы STM32F103C8T6 (как установить поддержку платы в Arduino IDE — http://rcl-radio.ru/?p=68376).

#include <RTClock.h>
 
RTClock rtclock (RTCSEL_LSE, 32768); // внешний кварц 32768 Гц
time_t tt, tt1;
tm_t mtt;
const char * delim = " :";
char s[128]; 
const char * weekdays[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
const char * months[] = {"Dummy", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
byte sec_time;
 
 
void setup(){
  Serial.begin(9600);
  ParseBuildTimestamp(mtt);  //  Unix время, отсчет от 00:00:00 1 января 1970
  tt = rtclock.makeTime(mtt) + 25; // +25 сек ко времени, для коррекции времени загрузки скетча
 // rtclock.setTime(tt); 
  tt1 = tt;
}
 
void loop(){
    tt1 = tt;
    rtclock.breakTime(rtclock.now(), mtt);
    if(mtt.second!=sec_time){   
    sprintf(s, "RTC timestamp: %s %u %u, %s, %02u:%02u:%02u\n",months[mtt.month], mtt.day, mtt.year+1970, weekdays[mtt.weekday], mtt.hour, mtt.minute, mtt.second);
    Serial.println(s);
    sec_time = mtt.second;
  }
}
 
uint8_t str2month(const char * d){uint8_t i = 13;while ( (--i) && strcmp(months[i], d)!=0 );return i;}
 
void ParseBuildTimestamp(tm_t & mt){
    sprintf(s, "Timestamp: %s, %s\n", __DATE__, __TIME__);// Формат времени: "Dec  8 2017, 22:57:54"
    Serial.print(s);
    char * token = strtok(s, delim); // get first token
    // walk through tokens
    while( token != NULL ) {
        uint8_t m = str2month((const char*)token);
        if ( m>0 ) {
            mt.month = m;
            token = strtok(NULL, delim); // get next token
            mt.day = atoi(token);
            token = strtok(NULL, delim); // get next token
            mt.year = atoi(token) - 1970;
            token = strtok(NULL, delim); // get next token
            mt.hour = atoi(token);
            token = strtok(NULL, delim); // get next token
            mt.minute = atoi(token);
            token = strtok(NULL, delim); // get next token
            mt.second = atoi(token);
        }
        token = strtok(NULL, delim);
    }
}

После прошивки микроконтроллера в мониторе порта Вы увидите примерно следующее:

Для установки текущего времени раскомментируйте строку:

rtclock.setTime(tt);

После заливки скетча, закомментируйте эту строчку и по новой залейте скетч:

// rtclock.setTime(tt);

Для примера можно собрать простые часы, дата и время будет выводится на LCD1602  с модулем I2C.

Подключение LCD1602 при использовании шины I2C к плате STM32 мало чем отличается от подключения к Arduino Nano, только вместо A4 A5 для Nano, в STM32 используются выводы B6 (SCL) B7 (SDA). При подключении платы STM32 к USB порту LCD1602 с I2C модулем питается от выхода 5V. При наличии внешнего источника питания 5 В, это напряжение необходимо подавать на VCC I2C модуля и на вход 5V платы STM32.

#include <RTClock.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h> // http://rcl-radio.ru/wp-content/uploads/2019/12/liquidcrystali2c-9.zip
LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей
 
RTClock rtclock (RTCSEL_LSE, 32765); // внешний кварц 32768 Гц (коррекция погрешности кварца)
time_t tt, tt1;
tm_t mtt;
const char * delim = " :";
char s[128]; 
const char * weekdays[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
const char * months[] = {"Dummy", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
byte sec_time;
 
 
void setup(){
  Serial.begin(9600);
  lcd.init();                     
  lcd.backlight();// Включаем подсветку дисплея
  ParseBuildTimestamp(mtt);  //  Unix время, отсчет от 00:00:00 1 января 1970
  tt = rtclock.makeTime(mtt) + 25; // +25 сек ко времени, для коррекции времени загрузки скетча
 // rtclock.setTime(tt); 
  tt1 = tt;
}
 
void loop(){
    tt1 = tt;
    rtclock.breakTime(rtclock.now(), mtt);
    if(mtt.second!=sec_time){   
    sprintf(s, "RTC timestamp: %s %u %u, %s, %02u:%02u:%02u\n",months[mtt.month], mtt.day, mtt.year+1970, weekdays[mtt.weekday], mtt.hour, mtt.minute, mtt.second);
    Serial.println(s);
    sec_time = mtt.second;
    lcd.setCursor(4, 0);
    lcd.print(mtt.hour/10);lcd.print(mtt.hour%10);lcd.print(":");lcd.print(mtt.minute/10);lcd.print(mtt.minute%10);lcd.print(":");lcd.print(mtt.second/10);lcd.print(mtt.second%10);
    lcd.setCursor(0, 1);
    if(mtt.day<10){lcd.print(" ");}lcd.print(mtt.day);lcd.print(" ");lcd.print(months[mtt.month]);lcd.print(" ");lcd.print(mtt.year+1970);lcd.print(" ");lcd.print(weekdays[mtt.weekday]);
  }
}
 
uint8_t str2month(const char * d){uint8_t i = 13;while ( (--i) && strcmp(months[i], d)!=0 );return i;}
 
void ParseBuildTimestamp(tm_t & mt){
    sprintf(s, "Timestamp: %s, %s\n", __DATE__, __TIME__);// Формат времени: "Dec  8 2017, 22:57:54"
    Serial.print(s);
    char * token = strtok(s, delim); // get first token
    // walk through tokens
    while( token != NULL ) {
        uint8_t m = str2month((const char*)token);
        if ( m>0 ) {
            mt.month = m;
            token = strtok(NULL, delim); // get next token
            mt.day = atoi(token);
            token = strtok(NULL, delim); // get next token
            mt.year = atoi(token) - 1970;
            token = strtok(NULL, delim); // get next token
            mt.hour = atoi(token);
            token = strtok(NULL, delim); // get next token
            mt.minute = atoi(token);
            token = strtok(NULL, delim); // get next token
            mt.second = atoi(token);
        }
        token = strtok(NULL, delim);
    }
}

Форум — http://forum.rcl-radio.ru/viewtopic.php?pid=5416#p5416

Добавить комментарий

Войти с помощью: