STM32之精准RTC时间设计

来源:本站
导读:目前正在解读《STM32之精准RTC时间设计》的相关信息,《STM32之精准RTC时间设计》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《STM32之精准RTC时间设计》的详细说明。
简介:本文主要讲了一下关于STM32之精准RTC时间设计,希望对你的学习有所帮助。

一年前开始做STM32的RTC,到现在才开始整理,战线拖得有点长啦。

先说说为啥要做RTC吧,公司有个产品要定时启动语音提示,本来是想使用STM32内部RTC的,后来发现STM32内部RTC时间有些快,产品上的时间,一个月快了3分钟多,一年那就是半个小时还多。在网上查了资料说,可以软件校准STM32的RTC,这个兴奋啊!

原文:

实现RTC 校准的核心之一是库文件Stm321f0x_bkp.c中的void BKP_SetRTCCalibrationValue (uint8_t CalibrationValue) 函数。谈到RTC校准的相关参考文档包括AN2604.pdf,AN2821.pdf和AN2821.zip。这三个文档都可以从STM32官方网站下载。按照AN2604.pdf描述的原理,RTC 的校准值应在0-127之间。可实现的校准误差对应为0-121ppm。相当于每30天跑快的秒数为0-314s。

这个方法,我也不知道有没有人做过,不过我真的把这些资料认真研读,并且做了实验,不过可惜的是,这个方法是让RTC跑慢了下来,但是效果还是不理想,一个月大概快105S的样子(因为这个时间是推算出来的,两天快7,实验做了5天),所以不得不换方法。

后来,有网友建议使用DS1337,这次我也做了实验,还好这次实验比前面的效果好很多,4天快7S的样子,一个月也有一分钟的误差,这个误差说大不大,说小也不小,可能是有强迫症,然后有重新找方法,看了好多关于DS3231的资料,这次直接买了一个DS3231的模块,实验比较了一下,三天的时间没什么误差,后来买了芯片搞起来。效果真的不错,一个月的误差在2S的范围内,这次果断用了。具体的做法是,使用STM32模拟IIC与DS3231进行通信,读取和设置相关参数;然后再通过模拟IIC与OLED进行通信,将实时时间数据显示在OLED上。以下是实验代码:

OLED.h

#ifndef __OLED_H

#define __OLED_H

#include "sys.h"

#include "stdlib.h"

#ifdef __cplusplus

extern "C" {

#endif

/*************Pin Define***************/

#define SCL_HIGH GPIO_SetBits(GPIOB, GPIO_Pin_3) //LED1点亮//P1OUT|=BIT0 //SCL P1.0

#define SCL_LOW GPIO_ResetBits(GPIOB, GPIO_Pin_3) //P1OUT&=~BIT0

#define SDA_HIGH GPIO_SetBits(GPIOB, GPIO_Pin_4) //P1OUT|=BIT1 //SDA P1.1

#define SDA_LOW GPIO_ResetBits(GPIOB, GPIO_Pin_4) //P1OUT&=~BIT1

/****************************************************/

void OLED_Initial(void);

void IIC_Start(void);

void IIC_Stop(void);

void Write_IIC_Command(unsigned char IIC_Command);

void Write_IIC_Data(unsigned char IIC_Data);

void Write_IIC_Byte(unsigned char IIC_Byte);

void LCD_Set_Pos(unsigned char x, unsigned char y);

void LCD_CLS(void);

void LCD_P8x16Str(unsigned char x,unsigned char y,unsigned char ch[]);

void LCD_P16x16Ch(unsigned char x,unsigned char y,unsigned char N);

void LCD_P6x8Str(unsigned char x,unsigned char y,unsigned char ch[]);

void Draw_BMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);

#ifdef __cplusplus

}

#endif

#endif

OLED.c

#include "stm32f10x_i2c.h"

#include "oled.h"

#include "delay.h"

#include "sys.h"

#define XLevelL 0x00

#define XLevelH 0x10

#define XLevel ((XLevelH&0x0F)*16+XLevelL)

#define Max_Column 128

#define Max_Row 64

#define Brightness 0xCF

#define X_WIDTH 128

#define Y_WIDTH 64

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void OLED_Initial()

{

GPIO_InitTypeDef GPIO_InitStructure;

// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

/* PB8,9 SCL and SDA */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOB, &GPIO_InitStructure);

delay_ms(100); //延时

Write_IIC_Command(0xAE); //display off

Write_IIC_Command(0x20); //Set Memory Addressing Mode

Write_IIC_Command(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid

Write_IIC_Command(0xb0); //Set Page Start Address for Page Addressing Mode,0-7

Write_IIC_Command(0xc8); //Set COM Output Scan Direction

Write_IIC_Command(0x00);//---set low column address

Write_IIC_Command(0x10);//---set high column address

Write_IIC_Command(0x40);//--set start line address

Write_IIC_Command(0x81);//--set contrast control register

Write_IIC_Command(0x7f);

Write_IIC_Command(0xa1);//--set segment re-map 0 to 127

Write_IIC_Command(0xa6);//--set normal display

Write_IIC_Command(0xa8);//--set multiplex ratio(1 to 64)

Write_IIC_Command(0x3F);//

Write_IIC_Command(0xa4);//0xa4,Output follows RAM content;0xa5,Output ignores RAM content

Write_IIC_Command(0xd3);//-set display offset

Write_IIC_Command(0x00);//-not offset

Write_IIC_Command(0xd5);//--set display clock pide ratio/oscillator frequency

Write_IIC_Command(0xf0);//--set pide ratio

Write_IIC_Command(0xd9);//--set pre-charge period

Write_IIC_Command(0x22); //

Write_IIC_Command(0xda);//--set com pins hardware configuration

Write_IIC_Command(0x12);

Write_IIC_Command(0xdb);//--set vcomh

Write_IIC_Command(0x20);//0x20,0.77xVcc

Write_IIC_Command(0x8d);//--set DC-DC enable

Write_IIC_Command(0x14);//

Write_IIC_Command(0xaf);//--turn on oled panel

LCD_CLS();

LCD_Set_Pos(0,0);

}

/**********************************************

//IIC Start

**********************************************/

void IIC_Start()

{

SCL_HIGH;

SDA_HIGH;

SDA_LOW;

SCL_LOW;

}

/**********************************************

//IIC Stop

**********************************************/

void IIC_Stop()

{

SCL_LOW;

SDA_LOW;

SCL_HIGH;

SDA_HIGH;

}

/**********************************************

// IIC Write byte

**********************************************/

void Write_IIC_Byte(unsigned char IIC_Byte)

{

unsigned char i;

for(i=0;i<8;i++)

{

if(IIC_Byte&0x80) //1?0?

SDA_HIGH;

else

SDA_LOW;

SCL_HIGH;

SCL_LOW;

IIC_Byte<<=1; //loop

}

SDA_HIGH;

SCL_HIGH;

SCL_LOW;

}

/**********************************************

// IIC Write Command

**********************************************/

void Write_IIC_Command(unsigned char IIC_Command)

{

IIC_Start();

Write_IIC_Byte(0x78); //Slave address,SA0=0

Write_IIC_Byte(0x00); //write command

Write_IIC_Byte(IIC_Command);

IIC_Stop();

}

/**********************************************

// IIC Write Data

**********************************************/

void Write_IIC_Data(unsigned char IIC_Data)

{

IIC_Start();

Write_IIC_Byte(0x78);

Write_IIC_Byte(0x40); //write data

Write_IIC_Byte(IIC_Data);

IIC_Stop();

}

/*********************LCD 设置坐标************************************/

void LCD_Set_Pos(unsigned char x, unsigned char y)

{

Write_IIC_Command(0xb0+y);

Write_IIC_Command(((x&0xf0)>>4)|0x10);

Write_IIC_Command((x&0x0f)|0x01);

}

/*********************LCD复位************************************/

void LCD_CLS(void)

{

unsigned char y,x;

for(y=0;y<8;y++)

{

Write_IIC_Command(0xb0+y);

Write_IIC_Command(0x01);

Write_IIC_Command(0x10);

for(x=0;x<X_WIDTH;x++)

Write_IIC_Data(0);

}

}

/***************功能描述:显示6*8一组标准ASCII字符串 显示的坐标(x,y),y为页范围0~7****************/

void LCD_P6x8Str(unsigned char x,unsigned char y,unsigned char ch[])

{

unsigned char c=0,i=0,j=0;

while (ch[j]!='')

{

c =ch[j]-32;

if(x>126){x=0;y++;}

LCD_Set_Pos(x,y);

for(i=0;i<6;i++)

Write_IIC_Data(F6x8[c][i]);

x+=6;

j++;

}

}

/*******************功能描述:显示8*16一组标准ASCII字符串 显示的坐标(x,y),y为页范围0~7****************/

void LCD_P8x16Str(unsigned char x,unsigned char y,unsigned char ch[])

{

unsigned char c=0,i=0,j=0;

while (ch[j]!='')

{

c =ch[j]-32;

if(x>120){x=0;y++;}

LCD_Set_Pos(x,y);

for(i=0;i<8;i++)

Write_IIC_Data(F8X16[c*16+i]);

LCD_Set_Pos(x,y+1);

for(i=0;i<8;i++)

Write_IIC_Data(F8X16[c*16+i+8]);

x+=8;

j++;

}

}

/*****************功能描述:显示16*16点阵 显示的坐标(x,y),y为页范围0~7****************************/

void LCD_P16x16Ch(unsigned char x,unsigned char y,unsigned char N)

{

unsigned char wm=0;

unsigned int adder=32*N; //

LCD_Set_Pos(x , y);

for(wm = 0;wm < 16;wm++) //

{

Write_IIC_Data(F16x16[adder]);

adder += 1;

}

LCD_Set_Pos(x,y + 1);

for(wm = 0;wm < 16;wm++) //

{

Write_IIC_Data(F16x16[adder]);

adder += 1;

}

}

/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/

void Draw_BMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])

{

unsigned int j=0;

unsigned char x,y;

if(y1%8==0) y=y1/8;

else y=y1/8+1;

for(y=y0;y<y1;y++)

{

LCD_Set_Pos(x0,y);

for(x=x0;x<x1;x++)

{

Write_IIC_Data(BMP[j++]);

}

}

}

IIC.h

#ifndef __DSIIC_H

#define __DSIIC_H

#include

#include "stm32f10x_i2c.h"

#include "delay.h"

#include "public.h"

/***************************************IO方向设置**********************************************/

#define DS_SDA_IN() {GPIOA->CRH&=0XFFFFFF0F;GPIOA->CRH|=8<<4;} //PA9

#define DS_SDA_OUT() {GPIOA->CRH&=0XFFFFFF0F;GPIOA->CRH|=2<<4;} //1 - 10MHZ 2 - 2MHZ 3- 50MHZ

/***************************************IO操作函数**********************************************/

#define DS_IIC_SCL PAout(10) //SCL

#define DS_IIC_SDA PAout(9) //SDA

#define DS_READ_SDA PAin(9) //输入SDA

#define DS_Write_ADD 0xD0 //DS3231地址+写操作

#define DS_Read_ADD 0xD1 //DS3231地址+读操作

extern unsigned char set_rtc_date[7];

extern unsigned char read_rtc_date[7];

/*************************************IIC所有操作函数*******************************************/

void DS_IIC_Init_Func(void);

void setsda(void);

void clrsda(void);

u8 BCD2HEX(u8 val);

u8 B_BCD(u8 val);

void delay(u16 us);

void Start(void);

void Stop(void);

void SendByte(u8 Dat);

u8 ReceiveByte(u8 b);

void I2cByteWrite(u8 device,u8 addr,u8 bytedata);

u8 I2cByteRead(u8 device,u8 addr);

void Readtime(void);

void ModifyTime(u8 yea,u8 mon,u8 da,u8 hou,u8 min,u8 sec);

void get_show_time(void);

#define SCL_H PAout(10) = 1

#define SCL_L PAout(10) = 0

#define SDA_H PAout(9) = 1

#define SDA_L PAout(9) = 0

#define SDA (GPIOA->IDR & 1<<9)

extern u8 year,month,date,hour,minute,second;

#endif

IIC.c

#include "DS_IIC.h"

void DS_IIC_Init_Func(void)

{

GPIOA->CRH&=0xfffff00f;

GPIOA->CRH|=0x00000220; //0x22000000; //SCK SDA

delay_ms(100);

// I2cByteWrite(0xD0,0x07,0x80); //为DS3231芯片闹钟1设置,通过SQW输出1HZ信号

// I2cByteWrite(0xD0,0x08,0x80);

// I2cByteWrite(0xD0,0x09,0x80);

// I2cByteWrite(0xD0,0x0a,0x80);

// I2cByteWrite(0xD0,0x0e,0x05);

I2cByteWrite(0xD0,0x0e,0);

I2cByteWrite(0xD0,0x0f,0);

//ModifyTime(15,0x03,20,15,32,20);

}

/***********************************************************************************************

** 函数名称:setsda

** 输入参数:无

** 输出参数:无

** 功能描述:SDA输出

***********************************************************************************************/

void setsda(void) //DS_SDA_OUT

{

GPIOA->CRH&=0XFFFFFF0F;

GPIOA->CRH|=2<<4;

}

/***********************************************************************************************

** 函数名称:clrsda

** 输入参数:无

** 输出参数:无

** 功能描述:SDA输入

***********************************************************************************************/

void clrsda(void)//DS_SDA_IN

{

GPIOA->CRH&= 0XFFFFFF0F;

GPIOA->CRH|= 8<<4;

}

/***********************************************************************************************

** 函数名称:BCD2HEX

** 输入参数:val:BCD码数据

** 输出参数:十六进制数据

** 功能描述:将BCD码数据转换成十六进制数据

***********************************************************************************************/

u8 BCD2HEX(u8 val)

{

u8 i;

i= val&0x0f;

val >>= 4;

val &= 0x0f;

val *= 10;

i += val;

return i;

}

/***********************************************************************************************

** 函数名称:B_BCD

** 输入参数:val:十进制数据

** 输出参数:BCD码数据

** 功能描述:将十进制数据转换成BCD码数据

***********************************************************************************************/

u8 B_BCD(u8 val)

{

u8 i,j,k;

i=val/10;

j=val%10;

k=j+(i<<4);

return k;

}

/***********************************************************************************************

** 函数名称:delay

** 输入参数:us:延时us时间

** 输出参数:无

** 功能描述:延时设定的时间

***********************************************************************************************/

void delay(u16 us)

{

delay_us(us*7);

}

/***********************************************************************************************

** 函数名称:Start

** 输入参数:无

** 输出参数:无

** 功能描述:IIC开始条件

***********************************************************************************************/

void Start(void)

{

SDA_H;

delay(5);

SCL_H;

delay(5);

SDA_L;

delay(5);

}

/***********************************************************************************************

** 函数名称:Stop

** 输入参数:无

** 输出参数:无

** 功能描述:IIC结束条件

***********************************************************************************************/

void Stop(void)

{

SDA_L;

delay(5);

SCL_H;

delay(5);

SDA_H;

delay(5);

}

/***********************************************************************************************

** 函数名称:SendByte

** 输入参数:Dat:需发送的数据

** 输出参数:无

** 功能描述:发送一字节数据

***********************************************************************************************/

void SendByte(u8 Dat)

{

u8 i=0;

u8 T_Data=0;

DS_SDA_OUT();

SCL_L;

delay(10);

T_Data=Dat;

for(i=0;i<8;i++)

{

if(T_Data&0x80)

SDA_H;

else

SDA_L;

delay(5);

SCL_L;

delay(5);

SCL_H;

delay(5);

T_Data=T_Data<<1;

SCL_L;

delay(5);

}

SDA_H;

delay(5);

SCL_L;

delay(5);

SCL_H;

delay(5);

SCL_L;

}

/***********************************************************************************************

** 函数名称:ReceiveByte

** 输入参数:b:是否产生应答 0-产生应答 1-不产生应答

** 输出参数:无

** 功能描述:接收一字节数据,并根据b决定是否发送应答信息。

***********************************************************************************************/

u8 ReceiveByte(u8 b)

{

u8 i;

u8 temp;

u8 Dat=0;

DS_SDA_IN();

for(i=0;i<8;i++)

{

SCL_H;

delay(5);

Dat=Dat<<1;

delay(5);

if(SDA)

{

temp=1;

}

else

{

temp=0;

}

if(temp)

Dat|=0x01;

else

Dat|=0x00;

delay(5);

SCL_L;

delay(5);

}

DS_SDA_OUT();

if(b)

SDA_H;

else

SDA_L;

delay(5);

SCL_H;

delay(5);

SCL_L;

delay(5);

SDA_H;

delay(100);

return Dat;

}

/***********************************************************************************************

** 函数名称:I2cByteWrite

** 输入参数:device:设备地址,0xd0; addr:寄存器地址 bytedata:寄存器地址中数据

** 输出参数:无

** 功能描述:向DS3231相关寄存器中写入设定数据

***********************************************************************************************/

void I2cByteWrite(u8 device,u8 addr,u8 bytedata)

{

Start();

delay(5);

SendByte(device);

delay(5);

SendByte(addr);

delay(5);

SendByte(bytedata);

delay(5);

Stop();

}

/***********************************************************************************************

** 函数名称:I2cByteRead

** 输入参数:device:设备地址,0xd1; addr:寄存器地址

** 输出参数:无

** 功能描述:从DS3231相关寄存器中读取数据

***********************************************************************************************/

u8 I2cByteRead(u8 device,u8 addr)

{

u8 Dat=0;

Start();

SendByte(device);

delay(5);

SendByte(addr);

delay(5);

Start();//Restart

SendByte(0xd1);

delay(5);

Dat=ReceiveByte(1);

Stop();

return Dat;

}

/***********************************************************************************************

** 函数名称:Readtime

** 输入参数:无

** 输出参数:无

** 功能描述:从DS3231相关寄存器中读取时间数据

***********************************************************************************************/

void Readtime(void)

{

year=I2cByteRead(0xd0,0x06); //年

month=I2cByteRead(0xd0,0x05); //月

date=I2cByteRead(0xd0,0x04); //日

hour=I2cByteRead(0xd0,0x02); //时

minute=I2cByteRead(0xd0,0x01);//分

second=I2cByteRead(0xd0,0x00);//秒

}

/***********************************************************************************************

** 函数名称:ModifyTime

** 输入参数:yea,mon,da,hou,min,sec分别代表:年,月,日,时,分,秒

** 输出参数:无

** 功能描述:修改DS3231相关寄存器中时间数据

***********************************************************************************************/

void ModifyTime(u8 yea,u8 mon,u8 da,u8 hou,u8 min,u8 sec)

{

u8 temp=0;

temp=B_BCD(yea);

I2cByteWrite(0xD0,0x06,temp);

temp=B_BCD(mon);

I2cByteWrite(0xD0,0x05,temp);

temp=B_BCD(da);

I2cByteWrite(0xD0,0x04,temp);

temp=B_BCD(hou);

I2cByteWrite(0xD0,0x02,temp);

temp=B_BCD(min);

I2cByteWrite(0xD0,0x01,temp);

temp=B_BCD(sec);

I2cByteWrite(0xD0,0x00,temp);

}

/***********************************************************************************************

** 函数名称:get_show_time

** 输入参数:无

** 输出参数:无

** 功能描述:读取DS3231相关寄存器中时间数据

***********************************************************************************************/

void get_show_time(void)

{

year=I2cByteRead(0xd0,0x06);

year=BCD2HEX(year);

month=I2cByteRead(0xd0,0x05);

month=BCD2HEX(month);

date=I2cByteRead(0xd0,0x04);

date=BCD2HEX(date);

hour=I2cByteRead(0xd0,0x02);

hour&=0x3f;

hour=BCD2HEX(hour);

minute=I2cByteRead(0xd0,0x01);

minute=BCD2HEX(minute);

second=I2cByteRead(0xd0,0x00);

second=BCD2HEX(second);

}

main.c

int main(void)

{

delay_init(24); //延时初始化函数

RCC_Configuration();

SPI2_GPIO_Config();

Alarm_GPIO_Config();

NVIC_Configuration();

OLED_Initial();

DS_IIC_Init_Func();

KEY_EXTI();

while(1)

{

if(G_un8TestFlag)

{

LED_1 = 1;

LED_2 = 1;

get_show_time();

G_un32WandRNum = date;

itoafunc(G_un32WandRNum);

LCD_P8x16Str(80,3,&NumStr[1]);

LCD_P8x16Str(68,3,":");

G_un32WandRNum = month;

itoafunc(G_un32WandRNum);

LCD_P8x16Str(52,3,&NumStr[1]);

LCD_P8x16Str(44,3,":");

G_un32WandRNum = year;

itoafunc(G_un32WandRNum);

LCD_P8x16Str(24,3,&NumStr[1]);

G_un32WandRNum = second;

itoafunc(G_un32WandRNum);

LCD_P8x16Str(80,6,&NumStr[1]);

LCD_P8x16Str(68,6,":");

G_un32WandRNum = minute;

itoafunc(G_un32WandRNum);

LCD_P8x16Str(52,6,&NumStr[1]);

LCD_P8x16Str(44,6,":");

G_un32WandRNum = hour;

itoafunc(G_un32WandRNum);

LCD_P8x16Str(24,6,&NumStr[1]);

}

else

{

LED_1 = 0;

LED_2 = 0;

if(G_un32DelayTime == 100)

OLED_Initial();

G_un32DelayTime++;

LCD_P8x16Str(4,0,"RTC Testing...");

}

sleep(1);

}

}

STM32之精准RTC时间设计STM32之精准RTC时间设计

提醒:《STM32之精准RTC时间设计》最后刷新时间 2024-03-14 00:55:12,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《STM32之精准RTC时间设计》该内容的真实性请自行鉴别。