数字温度计

数字温度计


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

一.了解时钟RTC
RTC (Real Time Clock):实时时钟

RTC是个独立的定时器。RTC模块拥有一个连续计数的计数器,在相应的软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。
在这里插入图片描述

在断电情况下 RTC仍可以独立运行 只要芯片的备用电源一直供电,RTC上的时间会一直走。

RTC实质是一个掉电后还继续运行的定时器,从定时器的角度来看,相对于通用定时器TIM外设,它的功能十分简单,只有计时功能(也可以触发中断)。但其高级指出也就在于掉电之后还可以正常运行。

两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒、分钟、小时( 12 或 24 小时制)、星期几、日期、月份和年份。此外,还可提供二进制格式的亚秒值。系统可以自动将月份的天数补偿为 28、29(闰年)、30 和 31 天。

上电复位后,所有RTC寄存器都会受到保护,以防止可能的非正常写访问。

无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC使不会停止工作。

RCT特征:
● 可编程的预分频系数:分频系数高为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)。

RTC原理框图
在这里插入图片描述

RTC时钟的框图还是比较简单的,这里我们把他分成 两个部分:

APB1 接口:用来和 APB1 总线相连。 此单元还包含一组 16 位寄存器,可通过 APB1 总线对其进行读写操作。APB1 接口由 APB1 总 线时钟驱动,用来与 APB1 总线连接。

通过APB1接口可以访问RTC的相关寄存器(预分频值,计数器值,闹钟值)。

RTC 核心接口:由一组可编程计数器组成,分成 两个主要模块 。
在这里插入图片描述

第一个模块是 RTC 的 预分频模块,它可编程产生 1 秒的 RTC 时间基准 TR_CLK。RTC 的预分频模块包含了一个 20 位的可编程分频器(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每个 TR_CLK 周期中 RTC 产生一个中断(秒中断)。
在这里插入图片描述

第二个模块是一个 32 位的可编程计数器 (RTC_CNT),可被初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算,可以记 录 4294967296 秒,约合 136 年左右,作为一般应用,这已经是足够了的。

RTC具体流程:
RTCCLK经过RTC_DIV预分频,RTC_PRL设置预分频系数,然后得到TR_CLK时钟信号,我们一般设置其周期为1s,RTC_CNT计数器计数,假如1970设置为时间起点为0s,通过当前时间的秒数计算得到当前的时间。RTC_ALR是设置闹钟时间,RTC_CNT计数到RTC_ALR就会产生计数中断,

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

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

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

RTC中断
秒中断:
这里时钟自带一个秒中断,每当计数加一的时候就会触发一次秒中断,。注意,这里所说的秒中断并非一定是一秒的时间,它是由RTC时钟源和分频值决定的“秒”的时间,当然也是可以做到1秒钟中断一次。我们通过往秒中断里写更新时间的函数来达到时间同步的效果

闹钟中断:
闹钟中断就是设置一个预设定的值,计数每自加多少次触发一次闹钟中断

二.创建CubeMX工程
创建STM32F103C8工程
配置rcc
在这里插入图片描述
配置RTC
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

配置sys
在这里插入图片描述
使能串口
在这里插入图片描述
时钟树配置
在这里插入图片描述
设置项目
在这里插入图片描述
在这里插入图片描述
生成代码用Keil打开
打开stm32f1xx_hal_rtc.h文件可以看到以下函数

/* RTC Time and Date functions ************************************************/
/** @addtogroup RTC_Exported_Functions_Group2
  * @{
  */
HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);/*设置系统时间*/
HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);/*读取系统时间*/
HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);/*设置系统日期*/
HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);/*读取系统日期*/
/**
  * @}
  */

/* RTC Alarm functions ********************************************************/
/** @addtogroup RTC_Exported_Functions_Group3
  * @{
  */
HAL_StatusTypeDef HAL_RTC_SetAlarm(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format);/*启动报警功能*/
HAL_StatusTypeDef HAL_RTC_SetAlarm_IT(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format);/*设置报警中断*/
HAL_StatusTypeDef HAL_RTC_DeactivateAlarm(RTC_HandleTypeDef *hrtc, uint32_t Alarm);/*报警时间回调函数*/
HAL_StatusTypeDef HAL_RTC_GetAlarm(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Alarm, uint32_t Format);
void              HAL_RTC_AlarmIRQHandler(RTC_HandleTypeDef *hrtc);
HAL_StatusTypeDef HAL_RTC_PollForAlarmAEvent(RTC_HandleTypeDef *hrtc, uint32_t Timeout);
void              HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc);

/*时间结构体*/
typedef struct
{
  uint8_t Hours;            /*!< Specifies the RTC Time Hour.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 23 */

  uint8_t Minutes;          /*!< Specifies the RTC Time Minutes.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

  uint8_t Seconds;          /*!< Specifies the RTC Time Seconds.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

} RTC_TimeTypeDef;

/*日期结构体*/
typedef struct
{
  uint8_t WeekDay;  /*!< Specifies the RTC Date WeekDay (not necessary for HAL_RTC_SetDate).
                         This parameter can be a value of @ref RTC_WeekDay_Definitions */

  uint8_t Month;    /*!< Specifies the RTC Date Month (in BCD format).
                         This parameter can be a value of @ref RTC_Month_Date_Definitions */

  uint8_t Date;     /*!< Specifies the RTC Date.
                         This parameter must be a number between Min_Data = 1 and Max_Data = 31 */

  uint8_t Year;     /*!< Specifies the RTC Date Year.
                         This parameter must be a number between Min_Data = 0 and Max_Data = 99 */

} RTC_DateTypeDef;

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

编译运行,效果如下:
在这里插入图片描述

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

配置好标准库后
在oled.h文件中加入下列代码

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

void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowChinese(uint8_t Line,uint8_t Column,uint8_t num);
void OLED_ShowChinese1(uint8_t Line,uint8_t Column,uint8_t num);
#endif


在oled.c文件中加入下列代码

#include "stm32f10x.h"
#include "OLED_Font.h"


/*Òý½ÅÅäÖÃ*/
#define OLED_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
#define OLED_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))

/*Òý½Å³õʼ»¯*/
void OLED_I2C_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//¿ªÂ©Êä³ö
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
  * @brief  I2C¿ªÊ¼
  * @param  ÎÞ
  * @retval ÎÞ
  */
void OLED_I2C_Start(void)
{
	OLED_W_SDA(1);
	OLED_W_SCL(1);
	OLED_W_SDA(0);
	OLED_W_SCL(0);
}

/**
  * @brief  I2CÍ£Ö¹
  * @param  ÎÞ
  * @retval ÎÞ
  */
void OLED_I2C_Stop(void)
{
	OLED_W_SDA(0);
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
  * @brief  I2C·¢ËÍÒ»¸ö×Ö½Ú
  * @param  Byte Òª·¢Ë͵ÄÒ»¸ö×Ö½Ú
  * @retval ÎÞ
  */
void OLED_I2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		OLED_W_SDA(Byte & (0x80 >> i));
		OLED_W_SCL(1);
		OLED_W_SCL(0);
	}
	OLED_W_SCL(1);	//¶îÍâµÄÒ»¸öʱÖÓ£¬²»´¦ÀíÓ¦´ðÐźÅ
	OLED_W_SCL(0);
}

/**
  * @brief  OLEDдÃüÁî
  * @param  Command ҪдÈëµÄÃüÁî
  * @retval ÎÞ
  */
void OLED_WriteCommand(uint8_t Command)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//´Ó»úµØÖ·
	OLED_I2C_SendByte(0x00);		//дÃüÁî
	OLED_I2C_SendByte(Command); 
	OLED_I2C_Stop();
}

/**
  * @brief  OLEDдÊý¾Ý
  * @param  Data ҪдÈëµÄÊý¾Ý
  * @retval ÎÞ
  */
void OLED_WriteData(uint8_t Data)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//´Ó»úµØÖ·
	OLED_I2C_SendByte(0x40);		//дÊý¾Ý
	OLED_I2C_SendByte(Data);
	OLED_I2C_Stop();
}

/**
  * @brief  OLEDÉèÖùâ±êλÖÃ
  * @param  Y ÒÔ×óÉϽÇΪԭµã£¬ÏòÏ·½ÏòµÄ×ø±ê£¬·¶Î§£º0~7
  * @param  X ÒÔ×óÉϽÇΪԭµã£¬ÏòÓÒ·½ÏòµÄ×ø±ê£¬·¶Î§£º0~127
  * @retval ÎÞ
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
	OLED_WriteCommand(0xB0 | Y);					//ÉèÖÃYλÖÃ
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//ÉèÖÃXλÖõÍ4λ
	OLED_WriteCommand(0x00 | (X & 0x0F));			//ÉèÖÃXλÖøß4λ
}

/**
  * @brief  OLEDÇåÆÁ
  * @param  ÎÞ
  * @retval ÎÞ
  */
void OLED_Clear(void)
{  
	uint8_t i, j;
	for (j = 0; j < 8; j++)
	{
		OLED_SetCursor(j, 0);
		for(i = 0; i < 128; i++)
		{
			OLED_WriteData(0x00);
		}
	}
}

/**
  * @brief  OLEDÏÔʾһ¸ö×Ö·û
  * @param  Line ÐÐλÖ㬷¶Î§£º1~4
  * @param  Column ÁÐλÖ㬷¶Î§£º1~16
  * @param  Char ÒªÏÔʾµÄÒ»¸ö×Ö·û£¬·¶Î§£ºASCII¿É¼û×Ö·û
  * @retval ÎÞ
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//ÉèÖùâ±êλÖÃÔÚÉϰ벿·Ö
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//ÏÔʾÉϰ벿·ÖÄÚÈÝ
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//ÉèÖùâ±êλÖÃÔÚÏ°벿·Ö
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//ÏÔʾÏ°벿·ÖÄÚÈÝ
	}
}

/**
  * @brief  OLEDÏÔʾ×Ö·û´®
  * @param  Line ÆðʼÐÐλÖ㬷¶Î§£º1~4
  * @param  Column ÆðʼÁÐλÖ㬷¶Î§£º1~16
  * @param  String ÒªÏÔʾµÄ×Ö·û´®£¬·¶Î§£ºASCII¿É¼û×Ö·û
  * @retval ÎÞ
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

/**
  * @brief  OLED´Î·½º¯Êý
  * @retval ·µ»ØÖµµÈÓÚXµÄY´Î·½
  */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result *= X;
	}
	return Result;
}

/**
  * @brief  OLEDÏÔʾÊý×Ö£¨Ê®½øÖÆ£¬ÕýÊý£©
  * @param  Line ÆðʼÐÐλÖ㬷¶Î§£º1~4
  * @param  Column ÆðʼÁÐλÖ㬷¶Î§£º1~16
  * @param  Number ÒªÏÔʾµÄÊý×Ö£¬·¶Î§£º0~4294967295
  * @param  Length ÒªÏÔʾÊý×ֵij¤¶È£¬·¶Î§£º1~10
  * @retval ÎÞ
  */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLEDÏÔʾÊý×Ö£¨Ê®½øÖÆ£¬´ø·ûºÅÊý£©
  * @param  Line ÆðʼÐÐλÖ㬷¶Î§£º1~4
  * @param  Column ÆðʼÁÐλÖ㬷¶Î§£º1~16
  * @param  Number ÒªÏÔʾµÄÊý×Ö£¬·¶Î§£º-2147483648~2147483647
  * @param  Length ÒªÏÔʾÊý×ֵij¤¶È£¬·¶Î§£º1~10
  * @retval ÎÞ
  */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
	uint8_t i;
	uint32_t Number1;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLEDÏÔʾÊý×Ö£¨Ê®Áù½øÖÆ£¬ÕýÊý£©
  * @param  Line ÆðʼÐÐλÖ㬷¶Î§£º1~4
  * @param  Column ÆðʼÁÐλÖ㬷¶Î§£º1~16
  * @param  Number ÒªÏÔʾµÄÊý×Ö£¬·¶Î§£º0~0xFFFFFFFF
  * @param  Length ÒªÏÔʾÊý×ֵij¤¶È£¬·¶Î§£º1~8
  * @retval ÎÞ
  */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i, SingleNumber;
	for (i = 0; i < Length; i++)							
	{
		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
		if (SingleNumber < 10)
		{
			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
		}
		else
		{
			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
		}
	}
}

/**
  * @brief  OLEDÏÔʾÊý×Ö£¨¶þ½øÖÆ£¬ÕýÊý£©
  * @param  Line ÆðʼÐÐλÖ㬷¶Î§£º1~4
  * @param  Column ÆðʼÁÐλÖ㬷¶Î§£º1~16
  * @param  Number ÒªÏÔʾµÄÊý×Ö£¬·¶Î§£º0~1111 1111 1111 1111
  * @param  Length ÒªÏÔʾÊý×ֵij¤¶È£¬·¶Î§£º1~16
  * @retval ÎÞ
  */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
	}
}

/**********************************
ÏÔʾһ¸öÎÄ×Ö
ÊäÈëÊý¾Ý£º 
x----ÐÐ
y----ÁÐ
no----×Ö¿âÊý×éÎÄ×Ö¶ÔÓ¦µÄλÖÃ
**********************************/
 void OLED_ShowChinese(uint8_t Line,uint8_t Column,uint8_t num)
 {
	 uint8_t i;
	 OLED_SetCursor((Line-1)*2,(Column-1)*16);
	 for(i=0;i<16;i++)
	 {
		 OLED_WriteData(Font_Chinese[2*num][i]);
		 
	 }
	 
 	 OLED_SetCursor((Line-1)*2+1,(Column-1)*16);
	 for(i=0;i<16;i++)
	 {
		 OLED_WriteData(Font_Chinese[2*num+1][i]);
	 }
	 
 }
 
 void OLED_ShowChinese1(uint8_t Line,uint8_t Column,uint8_t num)
 {
	 uint8_t i;
	 OLED_SetCursor((Line-1)*2,(Column-1)*16);
	 for(i=0;i<16;i++)
	 {
		 OLED_WriteData(Font_Chinese1[2*num][i]);
		 
	 }
	 
 	 OLED_SetCursor((Line-1)*2+1,(Column-1)*16);
	 for(i=0;i<16;i++)
	 {
		 OLED_WriteData(Font_Chinese1[2*num+1][i]);
	 }
	 
 }


/**
  * @brief  OLED³õʼ»¯
  * @param  ÎÞ
  * @retval ÎÞ
  */
void OLED_Init(void)
{
	uint32_t i, j;
	
	for (i = 0; i < 1000; i++)			//ÉϵçÑÓʱ
	{
		for (j = 0; j < 1000; j++);
	}
	
	OLED_I2C_Init();			//¶Ë¿Ú³õʼ»¯
	
	OLED_WriteCommand(0xAE);	//¹Ø±ÕÏÔʾ
	
	OLED_WriteCommand(0xD5);	//ÉèÖÃÏÔʾʱÖÓ·ÖƵ±È/Õñµ´Æ÷ƵÂÊ
	OLED_WriteCommand(0x80);
	
	OLED_WriteCommand(0xA8);	//ÉèÖöà·¸´ÓÃÂÊ
	OLED_WriteCommand(0x3F);
	
	OLED_WriteCommand(0xD3);	//ÉèÖÃÏÔʾƫÒÆ
	OLED_WriteCommand(0x00);
	
	OLED_WriteCommand(0x40);	//ÉèÖÃÏÔʾ¿ªÊ¼ÐÐ
	
	OLED_WriteCommand(0xA1);	//ÉèÖÃ×óÓÒ·½Ïò£¬0xA1Õý³£ 0xA0×óÓÒ·´ÖÃ
	
	OLED_WriteCommand(0xC8);	//ÉèÖÃÉÏÏ·½Ïò£¬0xC8Õý³£ 0xC0ÉÏÏ·´ÖÃ

	OLED_WriteCommand(0xDA);	//ÉèÖÃCOMÒý½ÅÓ²¼þÅäÖÃ
	OLED_WriteCommand(0x12);
	
	OLED_WriteCommand(0x81);	//ÉèÖöԱȶȿØÖÆ
	OLED_WriteCommand(0xCF);

	OLED_WriteCommand(0xD9);	//ÉèÖÃÔ¤³äµçÖÜÆÚ
	OLED_WriteCommand(0xF1);

	OLED_WriteCommand(0xDB);	//ÉèÖÃVCOMHÈ¡ÏûÑ¡Ôñ¼¶±ð
	OLED_WriteCommand(0x30);

	OLED_WriteCommand(0xA4);	//ÉèÖÃÕû¸öÏÔʾ´ò¿ª/¹Ø±Õ

	OLED_WriteCommand(0xA6);	//ÉèÖÃÕý³£/µ¹×ªÏÔʾ

	OLED_WriteCommand(0x8D);	//ÉèÖóäµç±Ã
	OLED_WriteCommand(0x14);

	OLED_WriteCommand(0xAF);	//¿ªÆôÏÔʾ
		
	OLED_Clear();				//OLEDÇåÆÁ
}


在main.c中添加如下程序

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include  "dht11.h"
#include  "usart.h"
#include "rtc.h"
//PB12
extern unsigned int rec_data[4];
extern u8 rmon,rday,rhour,rmin,rsec,rweek; //2λÔÂÈÕʱ·ÖÃëÖÜ
extern u16 ryear; //4λÄê
int main()
{
	Delay_ms(100);

  OLED_Init();
	uart_init(9600);
	OLED_Clear();
  RCC_Configuration();
	RTC_Config();
  OLED_ShowChinese(3, 1,0);						//ÎÂ
	OLED_ShowChinese(3, 2, 1); 	          //¶È
	OLED_ShowString(3,5,":");						//:
  OLED_ShowString(3,9,".");	
	OLED_ShowChinese1(4, 1,0);						//ʪ	
	OLED_ShowChinese1(4, 2, 1); 	          //¶È
  OLED_ShowString(4,5,":");	
	OLED_ShowString(4,9,".");	
	RTC_Set(2023,11,25,12,27,00);
	while(1)
	{
		Delay_ms(1000);
	  if(RTC_Get()==0)
		{
			OLED_ShowNum(1,1,ryear/1000,1);
			OLED_ShowNum(1,2,ryear%1000/100,1);
			OLED_ShowNum(1,3,ryear%100/10,1);
			OLED_ShowNum(1,4,ryear%10,1);
			OLED_ShowString(1,5,"-");
			
			OLED_ShowNum(1,6,rmon%100/10,1);
			OLED_ShowNum(1,7,rmon%10,1);
			OLED_ShowString(1,8,"-");
			
			OLED_ShowNum(1,9,rday%100/10,1);
			OLED_ShowNum(1,10,rday%10,1);
			
			OLED_ShowNum(2,1,rhour%100/10,1);
			OLED_ShowNum(2,2,rday%10,1);
			OLED_ShowString(2,3,":");
			OLED_ShowNum(2,4,rmin%100/10,1);
			OLED_ShowNum(2,5,rmin%10,1);
			OLED_ShowString(2,6,":");
			
			OLED_ShowNum(2,7,rsec%100/10,1);
			OLED_ShowNum(2,8,rsec%10,1);
		}
		DHT11_REC_Data(); //½ÓÊÕζȺÍʪ¶ÈµÄÊý¾Ý
		
	  OLED_ShowNum(3,7,rec_data[2],2);
		OLED_ShowNum(3,10,rec_data[3],1);
		OLED_ShowNum(4,7,rec_data[0],2);
		OLED_ShowNum(4,10,rec_data[1],2);

	}
}

DHT11.c文件

#include "stm32f10x.h"                  // Device header
#include  "dht11.h"
#include  "Delay.h"
//Êý¾Ý
unsigned int rec_data[4];


//¶ÔÓÚstm32À´Ëµ£¬ÊÇÊä³ö
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);

}

//¶ÔÓÚstm32À´Ëµ£¬ÊÇÊäÈë
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;
}


DHT11.h文件

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



#define dht11_high GPIO_SetBits(GPIOB, GPIO_Pin_12)
#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


烧录运行
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值