数字温度计

阅读资料了解 STM32F103的RTC(实时时钟)原理,使用带SPI或IIC接口的OLED屏显模块实现以下功能:

  1. 读取STM32F103C8T6 内部的时钟(年月日时分秒),日历(星期x),1秒周期,通过串口输出到PC上位机,;
  2. 读取AHT20的温度和湿度,通过OLED,把年月份时分秒、日历和实时温度、湿度显示出来,2秒周期。

一、RTC(实时时钟)

1.RTC介绍

**RTC (Real Time Clock):**实时时钟
RTC是个独立的定时器。RTC模块拥有一个连续计数的计数器,在相应的软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。
在断电情况下 RTC仍可以独立运行 只要芯片的备用电源一直供电,RTC上的时间会一直走。
RTC实质是一个掉电后还继续运行的定时器,从定时器的角度来看,相对于通用定时器TIM外设,它的功能十分简单,只有计时功能(也可以触发中断)。但其高级指出也就在于掉电之后还可以正常运行。
两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒、分钟、小时( 12 或 24
小时制)、星期几、日期、月份和年份。此外,还可提供二进制格式的亚秒值。系统可以自动将月份的天数补偿为 28、29(闰年)、30 和 31
天。
上电复位后,所有RTC寄存器都会受到保护,以防止可能的非正常写访问。
无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC使不会停止工作

2.RTC特征

● 可编程的预分频系数:分频系数高为220。
● 32位的可编程计数器,可用于较长时间段的测量。
● 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟 频率的四分之一以上)

● 可以选择以下三种RTC的时钟源:
● HSE时钟除以128;
● LSE振荡器时钟;
● LSI振荡器时钟

● 2个独立的复位类型:
● APB1接口由系统复位;
● RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位

● 3个专门的可屏蔽中断:
● 1.闹钟中断,用来产生一个软件可编程的闹钟中断。

● 2.秒中断,用来产生一个可编程的周期性中断信号(长可达1秒)。

● 3.溢出中断,指示内部可编程计数器溢出并回转为0的状态。

RTC时钟源:
三种不同的时钟源可被用来驱动系统时钟(SYSCLK):
● HSI振荡器时钟
● HSE振荡器时钟
● PLL时钟

这些设备有以下2种二级时钟源:
● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。 RTC用于从停机/待机模式下自动唤醒系统。
● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。

3.RTC原理图

在这里插入图片描述

4.RTC时钟选择

使用HSE分频时钟或者LSI的时候,在主电源VDD掉电的情况下,这两个时钟来源都会受到影响,因此没法保证RTC正常工作.所以RTC一般都时钟低速外部时钟LSE,频率为实时时钟模块中常用的32.768KHz,因为32768 = 2^15,分频容易实现,所以被广泛应用到RTC模块.(在主电源VDD有效的情况下(待机),RTC还可以配置闹钟事件使STM32退出待机模式).

5.RTC复位过程

除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系统寄存器都由系统复位或电源复位进行异步复位。
RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位。

系统复位后,禁止访问后备寄存器和RCT,防止对后卫区域(BKP)的意外写操作

6.配置RTC寄存器

必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、
RTC_CNT、RTC_ALR寄存器。

另外,对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询
RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是’1’
时,才可以写入RTC寄存器。

7.RTC时钟源

RTC是一个独立的时钟源
在这里插入图片描述

8. RTC寄存器

RTC控制寄存器 (RTC_CRH, RTC_CRL)
RTC预分频装载寄存器 (RTC_PRLH, RTC_PRLL)
RTC预分频余数寄存器 (RTC_DIVH, RTC_DIVL)
RTC计数器寄存器 (RTC_CNTH, RTC_CNTL)
RTC闹钟寄存器 (RTC_ALRH ,RTC_ALRL)

二、时钟串口输出

读取STM32F103C8T6 内部的时钟(年月日时分秒),日历(星期x),1秒周期,通过串口输出到PC上位机。

1.创建工程

1.1 点击File,创建新项目New Project
请添加图片描述
1.2 选择芯片STM32F103C8T6
请添加图片描述
1.3 配置RCC
(设置高速外部时钟,使能外部晶振LSE)
在这里插入图片描述

1.4 配置SYS
请添加图片描述
1.5 配置RTC(激活时钟源(Activate Clock Source)和日历(Activate Calendar))
进入RTC,设置时间为创建时间2023/11/17/ 19:17
请添加图片描述
RTC_OUT: Not RTC_OUT
Tamper: ×
第一个是是否使能 tamper(PC13)引脚上输出校正的秒脉冲时钟,
第二个: RTC入侵检测校验功能
RTC校验功能,使能侵入检测功能。RTC时钟经64分频输出到侵入检测引脚TAMPER上
当 TAMPER引脚上的信号从 0变成1或者从 1变成 0(取决于备份控制寄存器BKP_CR的 TPAL位),会产生一个侵入检测事件。侵入检测事件将所有数据备份寄存器内容清除。
也就是第一个是使能tamper(PC13)引脚作为时钟脉冲输出
第二个是使能tamper(PC13)引脚作为入侵检测功能
下面是两个RTC的中断:
RTC全局中断RTC_IRQHandler()
闹钟中断函数RTCAlarm_IRQHandler()

1.6 使能串口
在这里插入图片描述
1.7 配置USART1
在这里插入图片描述
1.8 配置时钟树
在这里插入图片描述
1.9 创建项目
在这里插入图片描述
在这里插入图片描述

2.keil代码修改

时间日期函数

打开stm32f1xx_hal_rtc.h文件可以看到以下关于时间和日期的函数
请添加图片描述
日期结构体
请添加图片描述
时间结构体
请添加图片描述

main.c函数修改

  • 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;
}

在这里插入图片描述

  • 在main.c中定义时间和日期的结构体用来获取时间和日期
RTC_DateTypeDef GetData;  //获取日期结构体

RTC_TimeTypeDef GetTime;   //获取时间结构体

在这里插入图片描述

  • 在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);

在这里插入图片描述

3.编译并烧录

在这里插入图片描述
在这里插入图片描述

4.实现效果

在这里插入图片描述

三、日期及温湿度表示

读取AHT20的温度和湿度,通过OLED,把年月份时分秒、日历和实时温度、湿度显示出来,2秒周期。

1.建立工程

采用标准库进行编程。参考标准库创建
将AHT20放入工程之中
主函数代码如下:

#include "stm32f10x.h"                 
#include "Delay.h"
#include "OLED.h"
#include "Delay.h"
#include "LED.h"
#include "usart.h"
#include "dht11.h"

extern unsigned int rec_data[4];

int main(void)
{
	OLED_Init();
	OLED_ShowHZ(3,5,0); //温
	OLED_ShowHZ(3,7,2); //度
	OLED_ShowHZ(3,9,4);	//:
	OLED_ShowHZ(3,12,2); //度
	OLED_ShowHZ(4,5,8); //湿
	OLED_ShowHZ(4,7,10); //度
	OLED_ShowHZ(4,9,4); //:
	OLED_ShowChar(4,12,'%');//%
	int year=2023;
	int month=11;
	int day=20;
	int hour=23;
	int min=59;
	int s=55;
	
	while (1)
	{
		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[0]-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);
	}
}



AHT代码如下:

#include "stm32f10x.h"                  // Device header
#include  "dht11.h"
#include  "delay.h"

unsigned int rec_data[4];



void DH11_GPIO_Init_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP; //????
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);

}

void DH11_GPIO_Init_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING; 
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);

}




void DHT11_Start(void)
{
	DH11_GPIO_Init_OUT(); 
	
	dht11_high; 
	Delay_us(30);
	
	dht11_low; //??????18us
	Delay_ms(20);
	
	dht11_high; //????20~40us
	Delay_us(30);
	
	DH11_GPIO_Init_IN(); //????
}


//??????
char DHT11_Rec_Byte(void)
{
	unsigned char i = 0;
	unsigned char data;
	
	for(i=0;i<8;i++) //1?????1???byte,1???byte?8?bit
	{
		while( Read_Data == 0); //?1bit??,???????,???????
		Delay_us(30); //??30us???????0???1,0??26~28us
		
		data <<= 1; //??
		
		if( Read_Data == 1 ) //????30us???????????1
		{
			data |= 1; //??+1
		}
		
		while( Read_Data == 1 ); //???????,???????
	}
	
	return data;
}

//????

void DHT11_REC_Data(void)
{
	unsigned int R_H,R_L,T_H,T_L;
	unsigned char RH,RL,TH,TL,CHECK;
	
	DHT11_Start(); //??????
	dht11_high; //????
	
	if( Read_Data == 0 ) //??DHT11????
	{
		while( Read_Data == 0); //???????,???????
		while( Read_Data == 1); //???????,???????
		
		R_H = DHT11_Rec_Byte();
		R_L = DHT11_Rec_Byte();
		T_H = DHT11_Rec_Byte();
		T_L = DHT11_Rec_Byte();
		CHECK = DHT11_Rec_Byte(); //??5???
		
		dht11_low; //????bit???????,DHT11???? 50us
		Delay_us(55); //????55us
		dht11_high; //??????????????????
		
		if(R_H + R_L + T_H + T_L == CHECK) //??????,??????????????
		{
			RH = R_H;
			RL = R_L;
			TH = T_H;
			TL = T_L;
		}
	}
	rec_data[0] = RH;
	rec_data[1] = RL;
	rec_data[2] = TH;
	rec_data[3] = TL;
}



2.实现效果

在这里插入图片描述

四、总结

在阅读资料并尝试实现STM32F103的RTC(实时时钟)与带SPI或IIC接口的OLED屏显模块的功能过程中,我获得了许多宝贵的经验和心得体会。
首先,我深入了解了STM32F103的RTC模块的工作原理和配置方法。我了解到,RTC模块可以通过外部时钟源或内部时钟源进行驱动,并且可以通过配置不同的寄存器来调整时钟的精度和格式。
其次,我近一步学会了如何使用带SPI接口的OLED屏显模块。OLED屏幕可以提供清晰的图像和文字显示,同时还可以通过SPI或IIC接口与STM32F103进行通信。在实验过程中,我学会了如何通过编写程序来控制OLED屏幕的显示内容和显示方式。
在实现读取STM32F103C8T6内部时钟、日历以及AHT20温度和湿度,并通过OLED屏幕显示和串口输出功能的过程中,我遇到了许多挑战。例如,我需要编写程序来读取STM32F103的内部时钟和日历数据,然后通过串口将数据发送到PC上位机。同时,我还需要编写程序来读取AHT20的温度和湿度数据,并通过OLED屏幕实时显示出来。最后,通过不断地实践和调试,我学会了如何解决实验中遇到的问题。
总之,通过这次实验,我不仅学会了如何正确配置和使用STM32F103的RTC模块和带SPI或IIC接口的OLED屏显模块,还学会了如何将它们结合起来实现复杂的功能。此外,我也获得了许多宝贵的调试经验和解决问题的能力。

  • 23
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值