STM32F103C8T6 RTC to get date and time
-
- Posts: 8
- Joined: Fri Jan 31, 2020 6:13 am
Re: STM32F103C8T6 RTC to get date and time
Thanks. I tried your modified code with bluepill. It works well as you mentioned above and i tried without removing PC14 and PC15 Pins. It is very accurate too. This is accurate only with power supply condition. But incase of 0v main supply, the RTC should work as it is, for precise time and date measurement applications. Can you give me few hits to make the RTC to work even without main power supply?. I read about VBAT pin in datasheet. Does connecting a 3.3v battery to VBAT pin is enough for precise time applications? Also guide me how to configure backup registers and procedure for backup..
Re: STM32F103C8T6 RTC to get date and time
connect a 3v coin cell at vbat. there are plenty supply of coin cell holderssoundaryasundaram wrote: ↑Tue Feb 04, 2020 12:29 pm Thanks. I tried your modified code with bluepill. It works well as you mentioned above and i tried without removing PC14 and PC15 Pins. It is very accurate too. This is accurate only with power supply condition. But incase of 0v main supply, the RTC should work as it is, for precise time and date measurement applications. Can you give me few hits to make the RTC to work even without main power supply?
https://www.aliexpress.com/wholesale?ca ... 032+holder
-
- Posts: 8
- Joined: Fri Jan 31, 2020 6:13 am
Re: STM32F103C8T6 RTC to get date and time
In bluepill, i connected 3.3v supply from another arduinouno microcontroller to VBAT pin of bluepill and i connected both controllers ground. I used Arduinouno instead of coin battery and uploaded the previous code. I set the initial time as 1580903310.
Soon after i disconnected the bluepill's main supply, the RTC should work by getting supply from Arduinouno's 3.3V. But in my case, it did not work. When i reconnect the mainsupply, the RTC restarts from the initial setup time 1580903310. I checked the voltage at Vbat pin using multimeter, it shows 3.26V. Do i need to change anything in coding part to make it work with Vbat?
Soon after i disconnected the bluepill's main supply, the RTC should work by getting supply from Arduinouno's 3.3V. But in my case, it did not work. When i reconnect the mainsupply, the RTC restarts from the initial setup time 1580903310. I checked the voltage at Vbat pin using multimeter, it shows 3.26V. Do i need to change anything in coding part to make it work with Vbat?
Last edited by soundaryasundaram on Wed Feb 05, 2020 6:59 am, edited 1 time in total.
Re: STM32F103C8T6 RTC to get date and time
check that in your code
is called only when you really want to change the clock time. otherwise, it shouldn't be called
it shouldn't be simply a statement in setup(), you'd need to implement a means of calling it only when needed
one way is to comment that line, build and flash the sketch again
Code: Select all
rt.setTime(1580903310);
it shouldn't be simply a statement in setup(), you'd need to implement a means of calling it only when needed
one way is to comment that line, build and flash the sketch again
-
- Posts: 8
- Joined: Fri Jan 31, 2020 6:13 am
Re: STM32F103C8T6 RTC to get date and time
yes,it works. When i referred datasheet, i came across backup registers that works with VBAT supply. May i know the usage of backup registers and its working..? where can i find backup register's configuration, working procedure and explanations, ?.. it may be helpful for me..
In datasheet, i can find few of its details, but only working library examples helps to understand about (STM32backup registers) more clear.
In datasheet, i can find few of its details, but only working library examples helps to understand about (STM32backup registers) more clear.
Re: STM32F103C8T6 RTC to get date and time
backup registers are actually different from the RTC itself, though they are powered from the same VBAT
to use the backup registers call
https://github.com/rogerclarkmelbourne/ ... st.ino#L63
the commands to write backup registers are
e.g.
https://github.com/rogerclarkmelbourne/ ... t.cpp#L144
the command to read backup register is
e.g.
https://github.com/rogerclarkmelbourne/ ... t.cpp#L180
those commands are part of the libmaple core
https://github.com/rogerclarkmelbourne/ ... bkp.h#L156
https://github.com/rogerclarkmelbourne/ ... e/bkp_f1.c
to use the backup registers call
https://github.com/rogerclarkmelbourne/ ... st.ino#L63
Code: Select all
bkp_init();
Code: Select all
uint16_t data = 1234;
uint8_t register = 8;
bkp_enable_writes();
bkp_write(register, data);
bkp_disable_writes();
https://github.com/rogerclarkmelbourne/ ... t.cpp#L144
the command to read backup register is
Code: Select all
uint8_t register = 8;
uint16_t data = bkp_read(register);
https://github.com/rogerclarkmelbourne/ ... t.cpp#L180
those commands are part of the libmaple core
https://github.com/rogerclarkmelbourne/ ... bkp.h#L156
https://github.com/rogerclarkmelbourne/ ... e/bkp_f1.c
-
- Posts: 8
- Joined: Fri Jan 31, 2020 6:13 am
Re: STM32F103C8T6 RTC to get date and time
Ok, i will see all the links soon..
In the previous code, i done modifications.
here is the code
OUTPUT
I got output period as 1001,1003,1004. If i let the controller to run for longer time, the period value changes to 1500. If this continuous, it would definitely show wrong time in few days. What is the reason for this change in period? How could i rectify it?
In the previous code, i done modifications.
here is the code
Code: Select all
#include <RTClock.h>
RTClock rtclock (RTCSEL_LSE); // initialise Low speed External clock for RTCclock
uint32 tt;
tm_t mtt;
uint32 last_ms = 0;
uint32 period = 0;
#define LED_PIN PC13
double count = 0;
const char * months[] = {"Dummy", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
const char * delim = " :";
char s[128]; // for sprintf
char buf[25];
const char * weekdays[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
// This function is called in the attachSecondsInterrpt
void blink ()
{
digitalWrite(LED_PIN, (~ digitalRead(LED_PIN)) & 1);
uint32_t ms = millis();
if (last_ms == 0)
{
last_ms = ms;
}
else
{
period = ms - last_ms;
last_ms = ms;
}
}
uint8_t str2month(const char * d)
{
uint8_t i = 13;
while ( (--i) && strcmp(months[i], d) != 0 );
return i;
}
void ParseBuildTimestamp(tm_t & mt)
{
// Timestamp format: "Dec 8 2017, 22:57:54"
sprintf(s, "Timestamp: %s, %s\n", __DATE__ , __TIME__);
Serial.print(s);
char * token = strtok(s, delim); // get first token
while ( token != NULL )
{
uint8_t m = str2month((const char*)token);
if ( m > 0 )
{
mt.month = m;
Serial.print(" month: "); Serial.println(mt.month);
token = strtok(NULL, delim); // get next token
mt.day = atoi(token);
Serial.print(" day: "); Serial.println(mt.day);
token = strtok(NULL, delim); // get next token
mt.year = atoi(token) - 1970;
Serial.print(" year: "); Serial.println(mt.year);
token = strtok(NULL, delim); // get next token
mt.hour = atoi(token);
Serial.print(" hour: "); Serial.println(mt.hour);
token = strtok(NULL, delim); // get next token
mt.minute = atoi(token);
Serial.print(" minute: "); Serial.println(mt.minute);
token = strtok(NULL, delim); // get next token
mt.second = atoi(token);
Serial.print(" second: "); Serial.println(mt.second);
}
token = strtok(NULL, delim);
}
sprintf(s, "Build: %02d-%02d-%02d %02d:%02d:%02d\n", mt.year + 1970, mt.month, mt.day, mt.hour, mt.minute, mt.second);
Serial.println(s);
}
void setup()
{
delay(5000);
pinMode(LED_PIN, OUTPUT);
ParseBuildTimestamp(mtt); //setting initial time. here, instant compilation time is considered as initial time setup
tt = rtclock.makeTime(mtt) + 8; //since compilation time is 8sec delayed when compared with actual time, so adding 8seconds with the compilation time here.
// Serial.println("make time value 1 is:: "); Serial.println(tt); //printing the adjusted time
rtclock.setTime(tt);
rtclock.attachSecondsInterrupt(blink);// Call blink
}
void loop()
{
if (rtclock.getTime() != tt)
{
tt = rtclock.getTime(); //gets the instatnt time
Serial.print("___________time is: ");
Serial.println(tt);
Serial.print("period : ");
Serial.println(period);
rtclock.breakTime(rtclock.now(), mtt); //gets the instant time in day,month,year,hour,minute,seconds
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.print(s);
}
}
Code: Select all
12:44:13.168 -> Timestamp: Feb 6 2020, 12:44:05
12:44:13.168 -> month: 2
12:44:13.168 -> day: 6
12:44:13.168 -> year: 50
12:44:13.168 -> hour: 12
12:44:13.168 -> minute: 44
12:44:13.168 -> second: 5
12:44:13.168 -> Build: 2020-02-06 12:44:05
12:44:13.168 ->
12:44:14.187 -> ___________time is: 1580993054
12:44:14.187 -> period : 1000
12:44:14.187 -> RTC timestamp: Feb 6 2020, Thu, 12:44:14
12:44:15.175 -> ___________time is: 1580993055
12:44:15.175 -> period : 1000
12:44:15.175 -> RTC timestamp: Feb 6 2020, Thu, 12:44:15
12:44:16.160 -> ___________time is: 1580993056
12:44:16.160 -> period : 1000
12:44:16.160 -> RTC timestamp: Feb 6 2020, Thu, 12:44:16
12:44:17.181 -> ___________time is: 1580993057
12:44:17.181 -> period : 1002
12:44:17.181 -> RTC timestamp: Feb 6 2020, Thu, 12:44:17
12:44:18.166 -> ___________time is: 1580993058
12:44:18.166 -> period : 1000
12:44:18.166 -> RTC timestamp: Feb 6 2020, Thu, 12:44:18
12:44:19.161 -> ___________time is: 1580993059
12:44:19.161 -> period : 1003
12:44:19.161 -> RTC timestamp: Feb 6 2020, Thu, 12:44:19
12:44:20.181 -> ___________time is: 1580993060
12:44:20.181 -> period : 1000
12:44:20.181 -> RTC timestamp: Feb 6 2020, Thu, 12:44:20
12:44:21.169 -> ___________time is: 1580993061
12:44:21.169 -> period : 1003
12:44:21.169 -> RTC timestamp: Feb 6 2020, Thu, 12:44:21
12:44:22.191 -> ___________time is: 1580993062
12:44:22.191 -> period : 1000
12:44:22.191 -> RTC timestamp: Feb 6 2020, Thu, 12:44:22
12:44:23.171 -> ___________time is: 1580993063
12:44:23.171 -> period : 1003
12:44:23.171 -> RTC timestamp: Feb 6 2020, Thu, 12:44:23
12:44:24.191 -> ___________time is: 1580993064
12:44:24.191 -> period : 1000
12:44:24.191 -> RTC timestamp: Feb 6 2020, Thu, 12:44:24
12:44:25.183 -> ___________time is: 1580993065
12:44:25.183 -> period : 1003
12:44:25.183 -> RTC timestamp: Feb 6 2020, Thu, 12:44:25
12:44:26.173 -> ___________time is: 1580993066
12:44:26.173 -> period : 1000
12:44:26.173 -> RTC timestamp: Feb 6 2020, Thu, 12:44:26
12:44:27.195 -> ___________time is: 1580993067
12:44:27.195 -> period : 1002
12:44:27.195 -> RTC timestamp: Feb 6 2020, Thu, 12:44:27
12:44:28.184 -> ___________time is: 1580993068
12:44:28.184 -> period : 1000
12:44:28.184 -> RTC timestamp: Feb 6 2020, Thu, 12:44:28
12:44:29.185 -> ___________time is: 1580993069
12:44:29.185 -> period : 1003
12:44:29.185 -> RTC timestamp: Feb 6 2020, Thu, 12:44:29
12:44:30.178 -> ___________time is: 1580993070
12:44:30.178 -> period : 1000
12:44:30.178 -> RTC timestamp: Feb 6 2020, Thu, 12:44:30
12:44:31.203 -> ___________time is: 1580993071
12:44:31.203 -> period : 1003
12:44:31.203 -> RTC timestamp: Feb 6 2020, Thu, 12:44:31
12:44:32.188 -> ___________time is: 1580993072
12:44:32.188 -> period : 1000
12:44:32.188 -> RTC timestamp: Feb 6 2020, Thu, 12:44:32
Re: STM32F103C8T6 RTC to get date and time
the main issue is that you are setting time in setup() directly from a value read. this will vary with the time you call the time setting routine.
for a command processor, i tend to use codes as such:
there is a catch with this rather naive code, it reads whatever is found from Serial.available() and start processing.
this approach handles single line commands one line at a time, and i use the first char received as the command.
if you want to make it less susceptible to characters arriving between pauses of Serial.available() you would need to code additional logic such as timeout etc. and in addition to check for buffer size not exceeded
setup() runs each time you press reset or power up the board. hence it isn't a most appropriate place to place time setting codes.
it'd be better to implement a command processor in loop() to receive the text string and use that for setting time
setting time would depend on how you account for the delays in the time setting part of the process, from your host/pc etc.
for instance the time between when you read a wall clock time and say hitting return to send the command manually alone could already account
for a random delay.
but for the RTC, the time drift between all subsequent seconds is normally rather small. if you use a lousy crystal, there may be drifts, but that's another issue. i normally ignore the initial random differences when setting time, after all a few seconds off the wall clock doesn't bother me.
for a command processor, i tend to use codes as such:
Code: Select all
#define CMD_SETTIME 'S'
#define BUFSIZE 30
uint8_t buf[BUFSIZE];
void loop() {
if(Serial.available()) {
int i = 0;
memset(buf,0,BUFSIZE);
while(Serial.available()) {
uint8_t c = Serial.read();
if( c == '\n' || c == '\r' )
break;
buf[i++] = c;
}
uint8_t command = buf[0];
switch(command) {
case CMD_SETTIME:
set_time(&buf+1);
break;
case ... :
default:
break;
}
}
this approach handles single line commands one line at a time, and i use the first char received as the command.
if you want to make it less susceptible to characters arriving between pauses of Serial.available() you would need to code additional logic such as timeout etc. and in addition to check for buffer size not exceeded
setup() runs each time you press reset or power up the board. hence it isn't a most appropriate place to place time setting codes.
it'd be better to implement a command processor in loop() to receive the text string and use that for setting time
setting time would depend on how you account for the delays in the time setting part of the process, from your host/pc etc.
for instance the time between when you read a wall clock time and say hitting return to send the command manually alone could already account
for a random delay.
but for the RTC, the time drift between all subsequent seconds is normally rather small. if you use a lousy crystal, there may be drifts, but that's another issue. i normally ignore the initial random differences when setting time, after all a few seconds off the wall clock doesn't bother me.
-
- Posts: 8
- Joined: Fri Jan 31, 2020 6:13 am
Re: STM32F103C8T6 RTC to get date and time
Thanks ag123. Sure, i will implement a code to get time from serial to set time for RTC and discuss about it soon..
Re: STM32F103C8T6 RTC to get date and time
fyi, there is an RTCAdjustment sketch, app in the libmaple core RTC Clock examples
https://github.com/rogerclarkmelbourne/ ... les/RTCAdj
it is pretty much a full fledged RTC app/sketch
you may like to copy that out into a sketch folder and try it out
time setting with that sketch is something like
on the serial terminal, the first character 's' being the command itself
if your core is rather recent you can find it in libraries for F1 within the RTC Clock library in examples
typically i set the time manually comparing against clock time, so you can expect some seconds or at least fraction of a second random differences.
if you want to go the distance you can try to make an app that interact with the serial terminal to send the commands with the time.
that is a bit of work, so i'd guess most people would simply use a common serial terminal app/utility (it can even be the arduino IDE terminal itself)
and type the time/command manually
https://github.com/rogerclarkmelbourne/ ... les/RTCAdj
it is pretty much a full fledged RTC app/sketch
you may like to copy that out into a sketch folder and try it out
time setting with that sketch is something like
Code: Select all
sYYYY-MM-DD HH:MM:SS
if your core is rather recent you can find it in libraries for F1 within the RTC Clock library in examples
typically i set the time manually comparing against clock time, so you can expect some seconds or at least fraction of a second random differences.
if you want to go the distance you can try to make an app that interact with the serial terminal to send the commands with the time.
that is a bit of work, so i'd guess most people would simply use a common serial terminal app/utility (it can even be the arduino IDE terminal itself)
and type the time/command manually