stm32数字温度计

本文详细描述了一个实验,使用STM32F103C8T6的RTC读取时间、日历,通过SPI或IIC接口驱动OLED屏幕显示,同时获取AHT20传感器的温度和湿度数据,并每2秒更新显示。实验涉及RTC工作原理、数据通信与实时数据处理。
摘要由CSDN通过智能技术生成

实验目的

该实验旨在通过使用带SPI或IIC接口的OLED屏幕模块,结合STM32F103的RTC实现以下功能:

读取STM32F103C8T6内部的时钟(年月日时分秒)、日历(星期),并以1秒周期将这些数据通过串口输出到PC上位机。

读取AHT20的温度和湿度,将年月日时分秒、日历以及实时温度和湿度以2秒周期显示在OLED屏幕上。

通过这个实验,可实现对RTC和OLED屏幕的应用,以及了解如何读取STM32F103C8T6内部时钟数据和AHT20传感器的温度和湿度数据,并将它们展示在OLED屏幕上。

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

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

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

实验相关知识
RTC介绍与应用
RTC基本概念
RTC(Real Time Clock)实时时钟是一种独立的定时器,它为系统提供了基本的时钟和日历功能。RTC位于系统的后备区域,这意味着在系统复位时,其数据不会清零。此外,即使在电源VDD(2.0-3.6V)断开的情况下,RTC仍可以通过备份电源VBAT(1.8~3.6V)供电,继续运行。

RTC的核心是一个32位的可编程计数器,它可以对应到Unix时间戳的秒计数器。此外,还有一个20位的可编程预分频器,可以适配不同频率的输入时钟。

关于RTC的时钟源选择,它可以选择三种不同的源:HSE时钟除以128(通常为8MHz/128),LSE振荡器时钟(通常为32.768KHz),以及LSI振荡器时钟(40KHz)。
在这里插入图片描述

在这里插入图片描述

RTC结构
RTC主要由两个内部低速时钟和一个外部高速时钟构成。基本结构如下:

硬件电路如下

在这里插入图片描述

在这里插入图片描述

实验内容

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

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

基于HAL库利用RTC读取日期时间并输出到串口
接下来利用HAL库读取RTC实时时钟并输出到串口

3.1 配置CubeMX
新建工程

在这里插入图片描述

选择C8T6芯片
在这里插入图片描述

首先进行RCC配置,打开RCC的高速与低速时钟

在这里插入图片描述

随后在“Timers”中找到RTC,并进行配置

在这里插入图片描述

下方栏中可设置日期星期和时间,这里我设置的是2023年11月18日19点55分

在这里插入图片描述

随后打开USART1,设置串口通信,设置为异步通信,同时开启中断

在这里插入图片描述

打开时钟树,选择LSI低速内部时钟模式

在这里插入图片描述

生成工程

在这里插入图片描述

3.2 代码撰写
生成的工程中只需要修改主函数代码就可以了。
首先我们需要重定向printf函数,使其能够打印文字和数据到串口。同时定义年月日结构体以及时分秒结构体。我们在主函数头文件下进行如下修改

#include "main.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"

#include "stdio.h"
int fputc(int ch,FILE *f){
 uint8_t temp[1]={ch};
 HAL_UART_Transmit(&huart1,temp,1,2);
 return ch;
}
RTC_DateTypeDef GetData;  //获取日期结构体

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





随后在主函数while循环内进行读取数据与显示
while (1)
  {
/* 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 */
		/* 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");
		}

      printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);

      printf("\r\n");

      HAL_Delay(1000);

  }

完整主函数如下

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"

#include "stdio.h"
int fputc(int ch,FILE *f){
 uint8_t temp[1]={ch};
 HAL_UART_Transmit(&huart1,temp,1,2);
 return ch;
}
RTC_DateTypeDef GetData;  //获取日期结构体

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

void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
 
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();


  MX_GPIO_Init();
  MX_RTC_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
/* 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 */
		/* 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");
		}

      printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);

      printf("\r\n");

      HAL_Delay(1000);

  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the CPU, AHB and APB busses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

3.3 烧录与结果显示
硬件电路与普通串口通信连接一致。
打开串口助手后记得调设置

在这里插入图片描述

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

四、读取日期温湿度传感输出到显示屏
由于HAL库与OLED的配置之间存在很强的不兼容性,故本次实验我们采用标准库进行编程。
将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;
}

烧录结果如下:

在这里插入图片描述

在这里插入图片描述

实验总结心得体会

通过阅读资料和实践操作,我深入了解了STM32F103C8T6内部时钟模块的工作原理和基本概念。RTC作为一种独立的定时器,为系统提供基本的时钟和日历功能,并且位于后备区域,在系统复位时不会清零。我学习到RTC核心是一个32位可编程计数器,它可以对应到Unix时间戳的秒计数器,并且具有多种时钟源选择,如HSE时钟、LSE振荡器时钟和LSI振荡器时钟。这些知识使我对嵌入式系统中实时时钟的应用有了更加全面的了解。

其次,我成功实现了从STM32F103C8T6内部时钟模块读取年、月、日、时、分、秒以及星期的功能,并将这些数据以1秒周期通过串口输出到PC上位机。这让我对串口通信的配置和数据传输有了更深入的了解,也提升了我在嵌入式系统开发中处理实时数据的能力。

另外,我也学习并实践了使用AHT20传感器读取温度和湿度数据,并在OLED屏幕上以2秒周期显示年月日时分秒、星期、实时温度和湿度。这个过程让我对I2C接口的使用有了更深刻的认识,同时也理解了如何与传感器进行数据交互和在OLED屏幕上实现实时数据的展示。增加了对RTC、串口通信、传感器数据读取和OLED显示的实际操作经验,还进一步提升了对嵌入式系统开发中实时数据处理的掌握能力。这种实践经验对于我的专业技能提升至关重要,也增强了我在嵌入式系统领域的信心。我相信这些所学所得将在未来的项目中发挥重要作用,让我能够更加熟练地应对各种实际挑战。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值