数字温度计
文章目录
一、读取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
烧录运行