STM32F103的RTC原理
1.RTC原理
RTC(实时时钟)是STM32F103中的一个独立定时器,用于提供实时计数和时钟日历功能237。它由一组连续计数的计数器组成,可以记录时间和日期,并提供闹钟功能。
RTC的工作原理如下:
时钟来源:RTC的时钟来源有三种,分别是高速外部时钟(HSE)、低速外部时钟(LSE)和低速内部时钟(LSI)。HSE和LSE是RTC的备选方案,HSE用于提供32位系统时钟,而LSE用于提供IWDG(独立看门狗)的时钟。LSI则专门为RTC提供时钟。
寄存器和时钟配置:RTC的寄存器和时钟配置位于后备区域,与BKP寄存器一起工作。这些寄存器和配置在断电后不会被清除,需要通过VBAT电源供电来保持数据的保存。如果主电源和VBAT电源都没有供电,RTC将停止工作。
计数器和分频:RTC包含一个32位的可编程计数器(RTC_CNT),用于记录时间和日期。计数器的值可以通过修改来重新设置系统的当前时间和日期。RTC还可以通过预分频模块产生最长1秒的时间基准信号(TR_CLK),用于秒中断和闹钟中断。
RTC_Alarm:RTC还提供了闹钟功能,可以设置一个闹钟时间(RTC_Alarm),当计数器的值与闹钟时间相等时,会触发中断,执行相应的操作。
RTC的配置和使用需要通过相应的寄存器进行操作,具体的配置步骤可以参考相关的文档和资料。通过合理配置和使用RTC,可以实现精确的时间记录和闹钟功能。
2.RTC特征
RTC(实时时钟)是STM32F103中的一个独立定时器,具有以下特征:
独立性:RTC是一个独立的定时器,与其他外设模块相互独立,可以在系统复位或从待机模式唤醒后保持设置和时间的稳定。
连续计数器:RTC模块拥有一组连续计数的计数器,可以提供时钟日历的功能。通过修改计数器的值,可以重新设置系统当前的时间和日期。
时钟来源:RTC的时钟来源有三种,分别是高速外部时钟(HSE)、低速外部时钟(LSE)和低速内部时钟(LSI)。可以根据具体需求选择合适的时钟源。
RTC核心:RTC核心由一组可编程计数器组成。其中,预分频模块可以产生最长1秒的RTC时间基准时钟(TR_CLK),并可产生秒中断。另外,32位的可编程计数器可以被初始化为当前时间,并按照TR_CLK周期累加。当计数器的值与闹钟寄存器中的值匹配时,可以产生闹钟中断。
后备区域:RTC模块和时钟配置系统(RCC_BDCR寄存器)位于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间保持不变。系统复位后,对后备寄存器和RTC的访问被禁止,以防止对后备区域的意外写操作。需要执行特定操作才能使能对后备寄存器和RTC的访问。
以上是STM32F103中RTC的特征概述。RTC作为一个独立的定时器,可以提供精确的时间和日期功能,适用于需要实时时钟的应用场景。
STM32日历读取,设置和输出
CubeMX建立项目
1.芯片选择STM32F103C8T6,创建工程
2.配置SYS
3.配置RCC,(设置高速外部时钟,使能外部晶振LSE)
4.配置RTC(激活时钟源(Activate Clock Source)和日历(Activate Calendar))
5.时间为创建时间2023/11/15 19:51
5.使能串口
6.时钟树配置
7.项目命名创建
8.用keil打开文件
Keil调试代码
1.main.c文件中重写fputc函数,完成printf函数的重定向
//添加头文件#include "stdio.h"
int fputc(int ch,FILE *f){
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,2);
return ch;
}
2.main函数中定义时间和日期的结构体用来获取时间和日期
RTC_DateTypeDef GetData; //获取日期结构体
RTC_TimeTypeDef GetTime; //获取时间结构体
3.main函数的while循环中添加以下代码
/* Get the RTC current Time */
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
/* Get the RTC current Date */
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
/* Display date Format : yy/mm/dd */
printf("%02d/%02d/%02d\r\n",2000 + GetData.Year, GetData.Month, GetData.Date);
/* Display time Format : hh:mm:ss */
printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
printf("\r\n");
HAL_Delay(1000);
/* Display date Format : weekday */
if(GetData.WeekDay==1){
printf("星期一\r\n");
}else if(GetData.WeekDay==2){
printf("星期二\r\n");
}else if(GetData.WeekDay==3){
printf("星期三\r\n");
}else if(GetData.WeekDay==4){
printf("星期四\r\n");
}else if(GetData.WeekDay==5){
printf("星期五\r\n");
}else if(GetData.WeekDay==6){
printf("星期六\r\n");
}else if(GetData.WeekDay==7){
printf("星期日\r\n");
}
4.调试成功,0错误,0警告
烧录结果
OLED显示时间+温度和湿度
代码实现
AHT20的代码
/*******************************************/
/*@????:?????????? */
/*@??:????????? */
/*@??:V1.2 */
/*******************************************/
//#include "main.h"
#include "AHT20.h"
#include "gpio.h"
#include "i2c.h"
void Delay_N10us(uint32_t t)//????
{
uint32_t k;
while(t--)
{
for (k = 0; k < 2; k++);//110
}
}
void SensorDelay_us(uint32_t t)//????
{
for(t = t-2; t>0; t--)
{
Delay_N10us(1);
}
}
void Delay_4us(void) //????
{
Delay_N10us(1);
Delay_N10us(1);
Delay_N10us(1);
Delay_N10us(1);
}
void Delay_5us(void) //????
{
Delay_N10us(1);
Delay_N10us(1);
Delay_N10us(1);
Delay_N10us(1);
Delay_N10us(1);
}
void Delay_1ms(uint32_t t) //????
{
while(t--)
{
SensorDelay_us(1000);//??1ms
}
}
//void AHT20_Clock_Init(void) //????
//{
// RCC_APB2PeriphClockCmd(CC_APB2Periph_GPIOB,ENABLE);
//}
void SDA_Pin_Output_High(void) //?PB7????? , ???????, PB7??I2C?SDA
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//????
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,& GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);
}
void SDA_Pin_Output_Low(void) //?P7????? ???????
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//????
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,& GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_RESET);
}
void SDA_Pin_IN_FLOATING(void) //SDA???????
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;//??
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init( GPIOB,&GPIO_InitStruct);
}
void SCL_Pin_Output_High(void) //SCL?????,P14??I2C?SCL
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
}
void SCL_Pin_Output_Low(void) //SCL?????
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
}
void Init_I2C_Sensor_Port(void) //???I2C??,??????
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//????
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,& GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//????
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,& GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);
}
void I2C_Start(void) //I2C????START??
{
SDA_Pin_Output_High();
SensorDelay_us(8);
SCL_Pin_Output_High();
SensorDelay_us(8);
SDA_Pin_Output_Low();
SensorDelay_us(8);
SCL_Pin_Output_Low();
SensorDelay_us(8);
}
void AHT20_WR_Byte(uint8_t Byte) //?AHT20?????
{
uint8_t Data,N,i;
Data=Byte;
i = 0x80;
for(N=0;N<8;N++)
{
SCL_Pin_Output_Low();
Delay_4us();
if(i&Data)
{
SDA_Pin_Output_High();
}
else
{
SDA_Pin_Output_Low();
}
SCL_Pin_Output_High();
Delay_4us();
Data <<= 1;
}
SCL_Pin_Output_Low();
SensorDelay_us(8);
SDA_Pin_IN_FLOATING();
SensorDelay_us(8);
}
uint8_t AHT20_RD_Byte(void)//?AHT20??????
{
uint8_t Byte,i,a;
Byte = 0;
SCL_Pin_Output_Low();
SDA_Pin_IN_FLOATING();
SensorDelay_us(8);
for(i=0;i<8;i++)
{
SCL_Pin_Output_High();
Delay_5us();
a=0;
//if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)) a=1;
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)) a=1;
Byte = (Byte<<1)|a;
//SCL_Pin_Output_Low();
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
Delay_5us();
}
SDA_Pin_IN_FLOATING();
SensorDelay_us(8);
return Byte;
}
uint8_t Receive_ACK(void) //?AHT20?????ACK
{
uint16_t CNT;
CNT = 0;
SCL_Pin_Output_Low();
SDA_Pin_IN_FLOATING();
SensorDelay_us(8);
SCL_Pin_Output_High();
SensorDelay_us(8);
while((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)) && CNT < 100)
CNT++;
if(CNT == 100)
{
return 0;
}
SCL_Pin_Output_Low();
SensorDelay_us(8);
return 1;
}
void Send_ACK(void) //????ACK??
{
SCL_Pin_Output_Low();
SensorDelay_us(8);
SDA_Pin_Output_Low();
SensorDelay_us(8);
SCL_Pin_Output_High();
SensorDelay_us(8);
SCL_Pin_Output_Low();
SensorDelay_us(8);
SDA_Pin_IN_FLOATING();
SensorDelay_us(8);
}
void Send_NOT_ACK(void) //?????ACK
{
SCL_Pin_Output_Low();
SensorDelay_us(8);
SDA_Pin_Output_High();
SensorDelay_us(8);
SCL_Pin_Output_High();
SensorDelay_us(8);
SCL_Pin_Output_Low();
SensorDelay_us(8);
SDA_Pin_Output_Low();
SensorDelay_us(8);
}
void Stop_I2C(void) //??????
{
SDA_Pin_Output_Low();
SensorDelay_us(8);
SCL_Pin_Output_High();
SensorDelay_us(8);
SDA_Pin_Output_High();
SensorDelay_us(8);
}
uint8_t AHT20_Read_Status(void)//??AHT20??????
{
uint8_t Byte_first;
I2C_Start();
AHT20_WR_Byte(0x71);
Receive_ACK();
Byte_first = AHT20_RD_Byte();
Send_NOT_ACK();
Stop_I2C();
return Byte_first;
}
uint8_t AHT20_Read_Cal_Enable(void) //??cal enable??????
{
uint8_t val = 0;//ret = 0,
val = AHT20_Read_Status();
if((val & 0x68)==0x08)
return 1;
else return 0;
}
void AHT20_SendAC(void) //?AHT20??AC??
{
I2C_Start();
AHT20_WR_Byte(0x70);
Receive_ACK();
AHT20_WR_Byte(0xac);//0xAC????
Receive_ACK();
AHT20_WR_Byte(0x33);
Receive_ACK();
AHT20_WR_Byte(0x00);
Receive_ACK();
Stop_I2C();
}
//CRC????:CRC8/MAXIM
//???:X8+X5+X4+1
//Poly:0011 0001 0x31
//????????? 1000 1100 0x8c
//C????:
uint8_t Calc_CRC8(uint8_t *message,uint8_t Num)
{
uint8_t i;
uint8_t byte;
uint8_t crc=0xFF;
for(byte=0; byte<Num; byte++)
{
crc^=(message[byte]);
for(i=8;i>0;--i)
{
if(crc&0x80) crc=(crc<<1)^0x31;
else crc=(crc<<1);
}
}
return crc;
}
void AHT20_Read_CTdata(uint32_t *ct) //??CRC??,????AHT20????????
{
volatile uint8_t Byte_1th=0;
volatile uint8_t Byte_2th=0;
volatile uint8_t Byte_3th=0;
volatile uint8_t Byte_4th=0;
volatile uint8_t Byte_5th=0;
volatile uint8_t Byte_6th=0;
uint32_t RetuData = 0;
uint16_t cnt = 0;
AHT20_SendAC();//?AHT10??AC??
Delay_1ms(80);//??80ms??
cnt = 0;
while(((AHT20_Read_Status()&0x80)==0x80))//????bit[7]?0,???????,??1,?????
{
SensorDelay_us(1508);
if(cnt++>=100)
{
break;
}
}
I2C_Start();
AHT20_WR_Byte(0x71);
Receive_ACK();
Byte_1th = AHT20_RD_Byte();//???,??????0x98,??????,bit[7]?1;???0x1C,??0x0C,??0x08???????,bit[7]?0
Send_ACK();
Byte_2th = AHT20_RD_Byte();//??
Send_ACK();
Byte_3th = AHT20_RD_Byte();//??
Send_ACK();
Byte_4th = AHT20_RD_Byte();//??/??
Send_ACK();
Byte_5th = AHT20_RD_Byte();//??
Send_ACK();
Byte_6th = AHT20_RD_Byte();//??
Send_NOT_ACK();
Stop_I2C();
RetuData = (RetuData|Byte_2th)<<8;
RetuData = (RetuData|Byte_3th)<<8;
RetuData = (RetuData|Byte_4th);
RetuData =RetuData >>4;
ct[0] = RetuData;//??
RetuData = 0;
RetuData = (RetuData|Byte_4th)<<8;
RetuData = (RetuData|Byte_5th)<<8;
RetuData = (RetuData|Byte_6th);
RetuData = RetuData&0xfffff;
ct[1] =RetuData; //??
}
void AHT20_Read_CTdata_crc(uint32_t *ct) //CRC???,??AHT20????????
{
volatile uint8_t Byte_1th=0;
volatile uint8_t Byte_2th=0;
volatile uint8_t Byte_3th=0;
volatile uint8_t Byte_4th=0;
volatile uint8_t Byte_5th=0;
volatile uint8_t Byte_6th=0;
volatile uint8_t Byte_7th=0;
uint32_t RetuData = 0;
uint16_t cnt = 0;
// uint8_t CRCDATA=0;
uint8_t CTDATA[6]={0};//??CRC????
AHT20_SendAC();//?AHT10??AC??
Delay_1ms(80);//??80ms??
cnt = 0;
while(((AHT20_Read_Status()&0x80)==0x80))//????bit[7]?0,???????,??1,?????
{
SensorDelay_us(1508);
if(cnt++>=100)
{
break;
}
}
I2C_Start();
AHT20_WR_Byte(0x71);
Receive_ACK();
CTDATA[0]=Byte_1th = AHT20_RD_Byte();//???,??????0x98,??????,bit[7]?1;???0x1C,??0x0C,??0x08???????,bit[7]?0
Send_ACK();
CTDATA[1]=Byte_2th = AHT20_RD_Byte();//??
Send_ACK();
CTDATA[2]=Byte_3th = AHT20_RD_Byte();//??
Send_ACK();
CTDATA[3]=Byte_4th = AHT20_RD_Byte();//??/??
Send_ACK();
CTDATA[4]=Byte_5th = AHT20_RD_Byte();//??
Send_ACK();
CTDATA[5]=Byte_6th = AHT20_RD_Byte();//??
Send_ACK();
Byte_7th = AHT20_RD_Byte();//CRC??
Send_NOT_ACK(); //??: ?????NAK
Stop_I2C();
if(Calc_CRC8(CTDATA,6)==Byte_7th)
{
RetuData = (RetuData|Byte_2th)<<8;
RetuData = (RetuData|Byte_3th)<<8;
RetuData = (RetuData|Byte_4th);
RetuData =RetuData >>4;
ct[0] = RetuData;//??
RetuData = 0;
RetuData = (RetuData|Byte_4th)<<8;
RetuData = (RetuData|Byte_5th)<<8;
RetuData = (RetuData|Byte_6th);
RetuData = RetuData&0xfffff;
ct[1] =RetuData; //??
}
else
{
ct[0]=0x00;
ct[1]=0x00;//???????,????????????
}//CRC??
}
void AHT20_Init(void) //???AHT20
{
Init_I2C_Sensor_Port();
I2C_Start();
AHT20_WR_Byte(0x70);
Receive_ACK();
AHT20_WR_Byte(0xa8);//0xA8??NOR????
Receive_ACK();
AHT20_WR_Byte(0x00);
Receive_ACK();
AHT20_WR_Byte(0x00);
Receive_ACK();
Stop_I2C();
Delay_1ms(10);//??10ms??
I2C_Start();
AHT20_WR_Byte(0x70);
Receive_ACK();
AHT20_WR_Byte(0xbe);//0xBE?????,AHT20???????0xBE, AHT10???????0xE1
Receive_ACK();
AHT20_WR_Byte(0x08);//?????bit[3]?1,?????
Receive_ACK();
AHT20_WR_Byte(0x00);
Receive_ACK();
Stop_I2C();
Delay_1ms(10);//??10ms??
}
void JH_Reset_REG(uint8_t addr)
{
uint8_t Byte_first,Byte_second,Byte_third;
I2C_Start();
AHT20_WR_Byte(0x70);//???0x70
Receive_ACK();
AHT20_WR_Byte(addr);
Receive_ACK();
AHT20_WR_Byte(0x00);
Receive_ACK();
AHT20_WR_Byte(0x00);
Receive_ACK();
Stop_I2C();
Delay_1ms(5);//??5ms??
I2C_Start();
AHT20_WR_Byte(0x71);//
Receive_ACK();
Byte_first = AHT20_RD_Byte();
Send_ACK();
Byte_second = AHT20_RD_Byte();
Send_ACK();
Byte_third = AHT20_RD_Byte();
Send_NOT_ACK();
Stop_I2C();
Delay_1ms(10);//??10ms??
I2C_Start();
AHT20_WR_Byte(0x70);///
Receive_ACK();
AHT20_WR_Byte(0xB0|addr);//?????
Receive_ACK();
AHT20_WR_Byte(Byte_second);
Receive_ACK();
AHT20_WR_Byte(Byte_third);
Receive_ACK();
Stop_I2C();
Byte_second=0x00;
Byte_third =0x00;
}
void AHT20_Start_Init(void)
{
JH_Reset_REG(0x1b);
JH_Reset_REG(0x1c);
JH_Reset_REG(0x1e);
}
OLED的代码
通过汉字取模软件,将所需要的汉字取模出来:
OLED_ShowHZ(1,2,18);//ÈÕ
OLED_ShowHZ(1,4,20);//ÆÚ
OLED_ShowNum(1,7,year,4);//2023
OLED_ShowHZ(1,11,22);//Äê
OLED_ShowNum(1,13,month,2);//11
OLED_ShowHZ(1,15,24);//ÔÂ
OLED_ShowNum(2,1,day,2);//20
OLED_ShowHZ(2,3,26);//ÈÕ
OLED_ShowNum(2,5,hour,2);//15
OLED_ShowHZ(2,7,30);//ʱ
OLED_ShowNum(2,9,min,2);//40
OLED_ShowHZ(2,11,32);//·Ö
OLED_ShowNum(2,13,s,2);//s
OLED_ShowHZ(2,15,28);//Ãë
//OLED_ShowString(2,17,"Mon");
DHT11_REC_Data(); //½ÓÊÕdht11Êý¾Ý
OLED_ShowNum(3,10,rec_data[2]-5,2);
OLED_ShowNum(4,10,rec_data[0]-13,2);
s+=1;
if(s>=60)
{
s=0;
min++;
}
if(min>=60)
{
min=0;
hour++;
}
if(hour>=24)
{
hour=0;
day++;
}
if(day>=31)
{
month++;
day=1;
}
if(month>12)
{
year++;
month=1;
}
Delay_s(1);