基于stm32的数字温度计

目录:
一、RTC原理
二、cubeMX建立项目
三、代码修改
四、烧录
五、总结

一、RTC原理:
(1)STM32F103芯片的RTC(Real Time Clock)原理是利用一个独立的定时器来实时记录当前系统的时间和日期。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。此外,如果想要使用RTC实时记录系统时间,芯片需要接入额外备用电源,通常为纽扣电池,这样在芯片掉电后,RTC可以由电池供电继续运行。
(2)特征:
可编程的预分频系数:分频系数高为220。

32位的可编程计数器,可用于较长时间段的测量。

2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟 频率的四分之一以上)。

可以选择以下三种RTC的时钟源:
HSE时钟除以128;
LSE振荡器时钟;
SI振荡器时钟
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模块和时钟配置系统
RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。RTC核心由一组可编程计数器组成,分为两个主要模块。第一个是RTC预分频模块,它可以编程产生最长1秒的RTC时间基TR_CLK。如果设置了秒中断允许位,可以产生秒中断。第二个是32位的可编程计数器,可被初始化为当前时间。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比,当匹配时候如果设置了闹钟中断允许位,可以产生闹钟中断。
(4)原理框图:
在这里插入图片描述
(5)RTC配置
在配置RTC寄存器之前,必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器。
(6)时钟选择
使用HSE分频时钟或者LSI的时候,在主电源VDD掉电的情况下,这两个时钟来源都会受到影响,因此没法保证RTC正常工作.所以RTC一般都时钟低速外部时钟LSE,频率为实时时钟模块中常用的32.768KHz,因为32768 = 2^15,分频容易实现,所以被广泛应用到RTC模块.(在主电源VDD有效的情况下(待机),RTC还可以配置闹钟事件使STM32退出待机模式).
(7)RTC复位
除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系统寄存器都由系统复位或电源复位进行异步复位。
RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位。
(8)时钟源
在这里插入图片描述
(9)RTC中断
秒中断:
这里时钟自带一个秒中断,每当计数加一的时候就会触发一次秒中断。注意,这里所说的秒中断并非一定是一秒的时间,它是由RTC时钟源和分频值决定的“秒”的时间,当然也是可以做到1秒钟中断一次。我们通过往秒中断里写更新时间的函数来达到时间同步的效果。
闹钟中断:
闹钟中断就是设置一个预设定的值,计数每自加多少次触发一次闹钟中断。
(10)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)

二、cubeMX建立工程
通过创建工程来读取stm32F103C8T6内部时钟并通过串口发送到电脑。

1.打开cubeMX新建项目,
选择stm32F103C8T6芯片:
在这里插入图片描述

选择好之后开始工程:
在这里插入图片描述

2.配置RCC
在这里插入图片描述
配置SYS:
在这里插入图片描述
激活RTC:
在这里插入图片描述
时间为创建时间2023/11/21 21:51
在这里插入图片描述

配置使能串口:
在这里插入图片描述

3.配置时钟树:
在这里插入图片描述
4.设置项目;
在这里插入图片描述
在这里插入图片描述
5.以上工程创建完成,点击GENERNTE CODE:
在这里插入图片描述
然后点击Open Project:
在这里插入图片描述
之后跳转到keil 5。

三、代码
1.时间日期函数:
打开stm32f1xx_hal_rtc.h文件,
可以看到以下关于时间和日期的函数:
在这里插入图片描述
日期结构体:
在这里插入图片描述
时间结构体:
在这里插入图片描述
2.重写main函数:
在main函数中重写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;
}

这个地方如果重写了printf函数,需要将下面的地方进行勾选,否则会导致失败:
在这里插入图片描述

在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);
      /* 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");
		}

然后进行如下配置;
在这里插入图片描述
然后编译,没有报错,生成.hex文件:
在这里插入图片描述
四、烧录

将生成的.hex文件,烧录到STM32F103C8T6中:
在这里插入图片描述
五、读取AHT20的温度和湿度并通过OLED显示
本实验基于之前做过的通过串口上显示温湿度以及通过OLED屏显示温湿度数据等,所以这里只做数据修改。

1.打开创建的keil工程:
dht11.c代码:

#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; 
	Delay_ms(20);
	
	dht11_high; 
	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++) 
	{
		while( Read_Data == 0); 
		Delay_us(30); 
		
		data <<= 1; 
		
		if( Read_Data == 1 ) 
		{
			data |= 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 )
	{
		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(); 
		
		dht11_low; 
		Delay_us(55); 
		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;
}

dht11.h代码:

#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"                  // Device header



#define dht11_high GPIO_SetBits(GPIOB, GPIO_Pin_12)     //GPIOB,GPIO_PIN_13
#define dht11_low GPIO_ResetBits(GPIOB, GPIO_Pin_12)
#define Read_Data GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)

void DHT11_GPIO_Init_OUT(void);
void DHT11_GPIO_Init_IN(void);
void DHT11_Start(void);
unsigned char DHT11_REC_Byte(void);
void DHT11_REC_Data(void);



#endif

main.c函数:

#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=15;
	int min=40;
	int s=0;
	
	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[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);
	}
}

编译通过:
在这里插入图片描述
烧录:
将编译生成的.hex文件烧录到连接好的电路中去。
运行结果如下:
在这里插入图片描述
六、总结
通过这次试验,让我了解了STM32F103的RTC原理,以及通过这些原理来对它进行使用,即通过串口在电脑端读取stm32的时间,以及在OLED屏显上显示出来。这次试验让我收获颇多,也对我后续的学习有了更大的帮助。

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真的是aaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值