STM32日历读取与温湿度显示

一、RTC实时时钟原理

1、RTC简介

STM32的 RTC 外设(Real Time Clock),实质是一个掉电后还继续运行的定时器。
掉电:

掉电是指主电源 VDD断开的情况,为了 RTC外设掉电继续运行,必须接
上锂电池给 STM32 的 RTC、备份发卡通过 VBAT引脚供电。当主电源 VDD有效时,由 VDD
给 RTC 外设供电;而当 VDD掉电后,由 VBAT给 RTC 外设供电。但无论由什么电源供电,
RTC 中的数据都保存在属于 RTC 的备份域中,若主电源 VDD 和 VBAT 都掉电,那么备份域
中保存的所有数据将丢失。备份域除了 RTC 模块的寄存器,还有 42 个 16 位的寄存器可以
在 VDD 掉电的情况下保存用户程序的数据,系统复位或电源复位时,这些数据也不会被复
位。

2、RTC架构图

在这里插入图片描述

二、读取STM32内部时钟到PC

2.1 任务要求

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

2.2 程序设计要点

1、初始化 RTC 外设;
2、设置时间以及添加配置标志;
3、获取当前时间;

2.3 代码实现

1、定义时间结构体,包含 年月日/时分秒

//时间结构体
typedef struct 
{
  vu8 hour;
  vu8 min;
  vu8 sec;			
  //公历日月年周
  vu16 w_year;
  vu8  w_month;
  vu8  w_date;
  vu8  week;		 
}_calendar_obj;	
extern _calendar_obj calendar;	//日历结构体

2、对RTC进行初始化,配置实时时钟
设置初始时间为2023/11/27/16:48:00
初始时间在初始化函数那里更改

//实时时钟配置
//初始化RTC时钟,同时检测时钟是否工作正常
//BKP->DR1用于保存是否第一次配置的设置
//返回0:正常
//其他:错误代码

u8 RTC_Init(void)
{
	//检查是不是第一次配置时钟
	u8 temp=0;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟   
	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问  
	//if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)		//从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
		//{	 			
		BKP_DeInit();	//复位备份区域 	
		RCC_LSEConfig(RCC_LSE_ON);	//设置外部低速晶振(LSE),使用外设低速晶振
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)	//检查指定的RCC标志位设置与否,等待低速晶振就绪
			{
			temp++;
			Delay_ms(10);
			}
		if(temp>=250)return 1;//初始化时钟失败,晶振有问题	    
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
		RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟  
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_WaitForSynchro();		//等待RTC寄存器同步  
		RTC_ITConfig(RTC_IT_SEC, ENABLE);		//使能RTC秒中断
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_EnterConfigMode();/// 允许配置	
		RTC_SetPrescaler(32767); //设置RTC预分频的值
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_Set(2023,11,27,16,48,00);  //设置时间	2023/11/27/16:48
		RTC_ExitConfigMode(); //退出配置模式  
		BKP_WriteBackupRegister(BKP_DR1, 0X5050);	//向指定的后备寄存器中写入用户程序数据
		RTC_NVIC_Config();//RCT中断分组设置		    				     
		RTC_Get();//更新时间	
		return 0; //ok
}

3、中断服务函数

//RTC时钟中断
//每秒触发一次  
//extern u16 tcnt; 
void RTC_IRQHandler(void)
{		 
  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
  {							
  	RTC_Get();//更新时间   
  }
  if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断
  {
  	RTC_ClearITPendingBit(RTC_IT_ALR);		//清闹钟中断	  	
    RTC_Get();				//更新时间   
	printf("Alarm Time:%d-%d-%d %d:%d:%d\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间	
  	
	} 				  								 
  RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);		//清闹钟中断
  RTC_WaitForLastTask();	  	    						 	   	 
}

4、主函数main.c

#include "sys.h"
#include "usart.h"
#include "rtc.h"
#include "stm32f10x.h"
#include "delay.h"
#include "gui.h"
#include "bmp.h"
#include "oled.h"

int main(void) {
    u8 t;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);               /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
    //delay_init();                                                   /* 延时函数初始化 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);      /* 关闭jtag,使能SWD,可以用SWD模式调试 */
    Delay_ms(500);                                                /* 等待稳定 */
    uart_init(115200);//以115200的波特率初始化串口
    //IIC_Init();
    RTC_Init();                //RTC初始化
    while (1) {
        if (t != calendar.sec) {
            t = calendar.sec;
            printf("%d-%02d-%02d %02d:%02d:%02d\r\n", calendar.w_year, calendar.w_month, calendar.w_date,
                   calendar.hour, calendar.min, calendar.sec);
            switch (calendar.week) {
                case 0:
                    printf("Sunday   \r\n");
                    break;
                case 1:
                    printf("Monday   \r\n");
                    break;
                case 2:
                    printf("Tuesday  \r\n");
                    break;
                case 3:
                    printf("Wednesday\r\n");
                    break;
                case 4:
                    printf("Thursday \r\n");
                    break;
                case 5:
                    printf("Friday   \r\n");
                    break;
                case 6:
                    printf("Saturday \r\n");
                    break;
            }
        }
        Delay_ms(10);
    }
}

2.4 硬件实现

1、烧录
在这里插入图片描述
2、物理连接

在这里插入图片描述
3、实现效果
在这里插入图片描述

三、OLED显示年月份时分秒和实时温湿度

3.1 任务要求

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

3.2 代码实现

1、在oledfont.h文件中的cfont16[]函数中添加需要用得到字模

const typFNT_GB16 cfont16[] = 
{
  
/*--  文字:  温  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"温",0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00,

/*--  文字:  湿  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"湿",0x00,0x00,0x27,0xF8,0x14,0x08,0x14,0x08,0x87,0xF8,0x44,0x08,0x44,0x08,0x17,0xF8,0x11,0x20,0x21,0x20,0xE9,0x24,0x25,0x28,0x23,0x30,0x21,0x20,0x2F,0xFE,0x00,0x00,

/*--  文字:  度  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"度",0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E,

/*--  文字:  显  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"显",0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,0x04,0x40,0x44,0x44,0x24,0x44,0x14,0x48,0x14,0x50,0x04,0x40,0xFF,0xFE,0x00,0x00,

/*--  文字:  示  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"示",0x00,0x00,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFE,0x01,0x00,0x01,0x00,0x11,0x10,0x11,0x08,0x21,0x04,0x41,0x02,0x81,0x02,0x05,0x00,0x02,0x00,
  
/*--  文字:  星  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"星",0x00,0x00,0x1F,0xF0,0x10,0x10,0x1F,0xF0,0x10,0x10,0x1F,0xF0,0x01,0x00,0x11,0x00,0x1F,0xF8,0x21,0x00,0x41,0x00,0x1F,0xF0,0x01,0x00,0x01,0x00,0x7F,0xFC,0x00,0x00,

/*--  文字:  期  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"期",0x22,0x00,0x22,0x7C,0x7F,0x44,0x22,0x44,0x22,0x44,0x3E,0x7C,0x22,0x44,0x22,0x44,0x3E,0x44,0x22,0x7C,0x22,0x44,0xFF,0x44,0x04,0x84,0x22,0x84,0x41,0x14,0x82,0x08,

/*--  文字:  时  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"时",0x00,0x08,0x00,0x08,0x7C,0x08,0x44,0x08,0x45,0xFE,0x44,0x08,0x44,0x08,0x7C,0x08,0x44,0x88,0x44,0x48,0x44,0x48,0x44,0x08,0x7C,0x08,0x44,0x08,0x00,0x28,0x00,0x10,

/*--  文字:  分  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"分",0x00,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,0x20,0x08,0x40,0x04,0x9F,0xE2,0x04,0x20,0x04,0x20,0x04,0x20,0x08,0x20,0x08,0x20,0x10,0x20,0x21,0x40,0x40,0x80,

/*--  文字:  秒  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
"秒",0x08,0x20,0x1C,0x20,0xF0,0x20,0x10,0xA8,0x10,0xA4,0xFC,0xA2,0x11,0x22,0x31,0x20,0x3A,0x24,0x54,0x24,0x54,0x28,0x90,0x08,0x10,0x10,0x10,0x20,0x10,0xC0,0x13,0x00,

//以及文字:一二三四五六年月日
};

2、修改main.c

#include "sys.h"
#include "usart.h"
#include "rtc.h"
#include "stm32f10x.h"
#include "delay.h"
#include "gui.h"
#include "bmp.h"
#include "oled.h"
int main(void) {
  u8 t;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);               /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
  //delay_init();                                                   /* 延时函数初始化 */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);      /* 关闭jtag,使能SWD,可以用SWD模式调试 */
  Delay_ms(500);                                                /* 等待稳定 */
  uart_init(115200);
  IIC_Init();
  RTC_Init();                //RTC初始化
  OLED_Init();			         //初始化OLED  
  OLED_Clear(0);             //清屏(全黑)
	while (1) {
		
		read_AHT20_once();
		OLED_Clear(0);
        
		if (t != calendar.sec) {
            t = calendar.sec;
			GUI_ShowNum(00,00,calendar.w_year,4,16,1);
			GUI_ShowCHinese(32,00,16,"年",1);
			GUI_ShowNum(48,00,calendar.w_month,2,16,1);
			GUI_ShowCHinese(64,00,16,"月",1);
			GUI_ShowNum(80,00,calendar.w_date,2,16,1);
			GUI_ShowCHinese(96,00,16,"日",1);
			GUI_ShowNum(00,20,calendar.hour,2,16,1);
			GUI_ShowCHinese(16,20,16,"时",1);
			GUI_ShowNum(32,20,calendar.min,2,16,1);
			GUI_ShowCHinese(48,20,16,"分",1);
			GUI_ShowNum(64,20,calendar.sec,2,16,1);
			GUI_ShowCHinese(80,20,16,"秒",1);
            
            switch (calendar.week) {
                case 0:
					GUI_ShowCHinese(00,40,16,"星期日",1);
					//GUI_ShowString(0,100,"Sunday",16,1);
                    //printf("Sunday   \r\n");
                    break;
                case 1:
					GUI_ShowCHinese(00,40,16,"星期一",1);
                    //GUI_ShowString(0,100,"Monday",16,1);
				    //printf("Monday   \r\n");
                    break;
                case 2:
					GUI_ShowCHinese(00,40,16,"星期二",1);
					//GUI_ShowString(0,100,"Tuesday",16,1);
                    //printf("Tuesday  \r\n");
                    break;
                case 3:
					GUI_ShowCHinese(00,40,16,"星期三",1);
                    //GUI_ShowString(0,100,"Wednesday",16,1);
				    //printf("Wednesday\r\n");
                    break;
                case 4:
					GUI_ShowCHinese(00,40,16,"星期四",1);
					//GUI_ShowString(0,100,"Thursday",16,1);
                    //printf("Thursday \r\n");
                    break;
                case 5:
					GUI_ShowCHinese(00,40,16,"星期五",1);
					//GUI_ShowString(0,100,"Friday",16,1);
                    //printf("Friday   \r\n");
                    break;
                case 6:
					GUI_ShowCHinese(00,40,16,"星期六",1);
					//GUI_ShowString(0,100,"Saturday",16,1);
                    //printf("Saturday \r\n");
                    break;
            }
        }			
		Delay_ms(1500);
        Delay_ms(1500);
		OLED_Clear(0);
    }
}

3.3 硬件实现

1、硬件连接
OLED屏连线说明(7脚)

1.GND 电源地
2.VCC 电源正(3~5.5V)
3.D0(SCL) SCK管脚
4.D1(SDA) MOSI管脚
5.RES(RST) 用来复位(低电平复位)
6.DC(D/C) 数据和命令控制管脚 1表示数据 0表示命令
7.CS(NSS) 片选管脚

在这里插入图片描述

AHT20
在这里插入图片描述
2、FlyMCU烧录
在这里插入图片描述
3、实验效果请添加图片描述

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用STM32读取DHT11温湿度传感器的数据,需要先了解DHT11传感器的通信协议。DHT11使用单总线协议进行通信,数据传输分为40位,其中前8位为起始位,接下来32位为数据位,最后8位为校验位。 以下是使用STM32读取DHT11温湿度传感器的步骤: 1. 设置STM32的GPIO口为输出模式,然后将输出电平置为高电平,等待至少18毫秒(建议等待20毫秒)。 2. 将GPIO口设置为输入模式,等待DHT11的响应信号。DHT11会在上电后主动拉低总线,保持至少80毫秒,然后再拉高总线,等待20至40毫秒供STM32响应。 3. 接收DHT11发送的数据。DHT11发送的数据总共40位,每个数据位的高电平持续时间分别为50微秒(0)和70微秒(1),STM32通过计算每个数据位高电平的持续时间来得到数据。 4. 将接收到的数据解析为温度和湿度值,并进行校验。 下面是一个简单的示例代码,使用STM32F103C8T6读取DHT11传感器的温湿度值: ```c #include "stm32f10x.h" #define DHT11_GPIO GPIOA #define DHT11_PIN GPIO_Pin_0 void delay_us(uint32_t us) // 延时函数,单位us { uint32_t i; while (us--) { i = 10; // 自己设置 while (i--); } } void DHT11_Start(void) // 启动信号 { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_GPIO, &GPIO_InitStructure); GPIO_SetBits(DHT11_GPIO, DHT11_PIN); delay_us(20000); GPIO_ResetBits(DHT11_GPIO, DHT11_PIN); delay_us(20000); GPIO_SetBits(DHT11_GPIO, DHT11_PIN); delay_us(40); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(DHT11_GPIO, &GPIO_InitStructure); } uint8_t DHT11_Read_Byte(void) // 读取一个字节 { uint8_t i, data = 0; for (i = 0; i < 8; i++) { while (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == RESET); delay_us(40); if (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == SET) { data |= 1 << (7 - i); } while (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == SET); } return data; } uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi) // 读取温湿度值 { uint8_t i, buf[5], check_sum; DHT11_Start(); if (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == RESET) { while (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == RESET); while (GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN) == SET); for (i = 0; i < 5; i++) { buf[i] = DHT11_Read_Byte(); } check_sum = buf[0] + buf[1] + buf[2] + buf[3]; if (check_sum == buf[4]) { *humi = buf[0]; *temp = buf[2]; return 1; } } return 0; } int main() // 主函数 { uint8_t temp, humi; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); while (1) { if (DHT11_Read_Data(&temp, &humi)) { // 解析数据,进行相关操作 } delay_us(500000); // 间隔一段时间再次读取 } } ``` 注意,本示例代码中的延时函数需要根据实际情况进行修改。此外,该示例代码只是一个简单的读取温湿度值的例子,实际应用中还需要根据具体需求进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值