对BEEP模块感兴趣的读者朋友可以试试用PWM调节去控制BEEP模块,感受一下BEPP放出的另类音乐。
四、OLED模块
关于OLED的使用与原理不熟悉的笔者欢迎去笔者另一篇文章学习。【强烈推荐】基于stm32的OLED各种显示实现(含动态图)_混分巨兽龙某某的博客-CSDN博客_stm32使用oled显示屏手把手教你彻底搞懂基于stm32的OLED的使用,教程中包含各种API函数的使用。满足几乎所有OLED显示的需要。文章末尾附带源码,强烈推荐!!!https://blog.csdn.net/black_sneak/article/details/125418537?spm=1001.2014.3001.5501
五、CubexMX配置
1、RCC配置外部高速晶振(精度更高)——HSE;
2、SYS配置:Debug设置成Serial Wire(否则可能导致芯片自锁);
3.1、GPIO配置:PB1设置为普通输出(DHT11的DATA接线引脚);
3.2、GPIO配置:PA5接到了HC-SR04的TRIG触发引脚,默认输出低电平
3.3、GPIO配置:PB8板子上默认接通BEEP的引脚,默认低电平;
4、 TIM1配置:由上面可知HC-SR04和DTH11的使用都需要us级的延迟函数,HAL库自带只有ms的,所以需要自己设计一个定时器;
5、TIM2配置:设置定时器TIM2每1us向上计数一次,通道1为上升沿捕获并连接到超声波模块的ECHO引脚,记得开启定时器中断(涉及到捕获中断+定时器溢出中断)。
6、I2C2配置:作为OLED的通讯方式;
7、时钟树配置:
8**、工程配置**
六、代码
6.1、超声波HC-SR04模块代码
其实,超声波HC-SR04的驱动就是基于GPIO口的调用。同时,由于超声波测距模块是基于超声波的物理性质,去进行距离测量,故此其精度受到很多因素影响(这里我们考虑温度堆砌影响)。
HC-SR04.h:
#ifndef HCSR04_H_
#define HCSR04_H_
#include "main.h"
typedef struct
{
uint8_t edge_state;
uint16_t tim_overflow_counter;
uint32_t prescaler;
uint32_t period;
uint32_t t1; // 上升沿时间
uint32_t t2; // 下降沿时间
uint32_t high_level_us; // 高电平持续时间
float distance;
TIM_TypeDef* instance;
uint32_t ic_tim_ch;
HAL_TIM_ActiveChannel active_channel;
}Hcsr04InfoTypeDef;
extern Hcsr04InfoTypeDef Hcsr04Info;
/**
* @description: 超声波模块的输入捕获定时器通道初始化
* @param {TIM_HandleTypeDef} *htim
* @param {uint32_t} Channel
* @return {*}
*/
void Hcsr04Init(TIM_HandleTypeDef *htim, uint32_t Channel);
/**
* @description: HC-SR04触发
* @param {*}
* @return {*}
*/
void Hcsr04Start();
/**
* @description: 定时器计数溢出中断处理函数
* @param {*} main.c中重定义void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
* @return {*}
*/
void Hcsr04TimOverflowIsr(TIM_HandleTypeDef *htim);
/**
* @description: 输入捕获计算高电平时间->距离
* @param {*} main.c中重定义void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
* @return {*}
*/
void Hcsr04TimIcIsr(TIM_HandleTypeDef* htim);
/**
* @description: 读取距离
* @param {*}
* @return {*}
*/
float Hcsr04Read();
#endif /* HCSR04_H_ */
HC-SR04.c:
#include "hc-sr04.h"
#include "tim.h"
Hcsr04InfoTypeDef Hcsr04Info;
/**
* @description: 超声波模块的输入捕获定时器通道初始化
* @param {TIM_HandleTypeDef} *htim
* @param {uint32_t} Channel
* @return {*}
*/
void Hcsr04Init(TIM_HandleTypeDef *htim, uint32_t Channel)
{
/*--------[ Configure The HCSR04 IC Timer Channel ] */
// MX_TIM2_Init(); // cubemx中配置
Hcsr04Info.prescaler = htim->Init.Prescaler; // 72-1
Hcsr04Info.period = htim->Init.Period; // 65535
Hcsr04Info.instance = htim->Instance; // TIM2
Hcsr04Info.ic_tim_ch = Channel;
if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_1)
{
Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_1; // TIM_CHANNEL_4
}
else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_2)
{
Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_2; // TIM_CHANNEL_4
}
else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_3)
{
Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_3; // TIM_CHANNEL_4
}
else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_4)
{
Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_4; // TIM_CHANNEL_4
}
else if(Hcsr04Info.ic_tim_ch == TIM_CHANNEL_4)
{
Hcsr04Info.active_channel = HAL_TIM_ACTIVE_CHANNEL_4; // TIM_CHANNEL_4
}
/*--------[ Start The ICU Channel ]-------*/
HAL_TIM_Base_Start_IT(htim);
HAL_TIM_IC_Start_IT(htim, Channel);
}
/**
* @description: HC-SR04触发
* @param {*}
* @return {*}
*/
void Hcsr04Start()
{
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
Tims_delay_us(10); // 10us以上
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}
/**
* @description: 定时器计数溢出中断处理函数
* @param {*} main.c中重定义void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
* @return {*}
*/
void Hcsr04TimOverflowIsr(TIM_HandleTypeDef *htim)
{
if(htim->Instance == Hcsr04Info.instance) // TIM2
{
Hcsr04Info.tim_overflow_counter++;
}
}
/**
* @description: 输入捕获计算高电平时间->距离
* @param {*} main.c中重定义void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
* @return {*}
*/
void Hcsr04TimIcIsr(TIM_HandleTypeDef* htim)
{
if((htim->Instance == Hcsr04Info.instance) && (htim->Channel == Hcsr04Info.active_channel))
{
if(Hcsr04Info.edge_state == 0) // 捕获上升沿
{
// 得到上升沿开始时间T1,并更改输入捕获为下降沿
Hcsr04Info.t1 = HAL_TIM_ReadCapturedValue(htim, Hcsr04Info.ic_tim_ch);
__HAL_TIM_SET_CAPTUREPOLARITY(htim, Hcsr04Info.ic_tim_ch, TIM_INPUTCHANNELPOLARITY_FALLING);
Hcsr04Info.tim_overflow_counter = 0; // 定时器溢出计数器清零
Hcsr04Info.edge_state = 1; // 上升沿、下降沿捕获标志位
}
else if(Hcsr04Info.edge_state == 1) // 捕获下降沿
{
// 捕获下降沿时间T2,并计算高电平时间
Hcsr04Info.t2 = HAL_TIM_ReadCapturedValue(htim, Hcsr04Info.ic_tim_ch);
Hcsr04Info.t2 += Hcsr04Info.tim_overflow_counter * Hcsr04Info.period; // 需要考虑定时器溢出中断
Hcsr04Info.high_level_us = Hcsr04Info.t2 - Hcsr04Info.t1; // 高电平持续时间 = 下降沿时间点 - 上升沿时间点
// 计算距离
Hcsr04Info.distance = (Hcsr04Info.high_level_us / 1000000.0) * 340.0 / 2.0 * 100.0;
// 重新开启上升沿捕获
Hcsr04Info.edge_state = 0; // 一次采集完毕,清零
__HAL_TIM_SET_CAPTUREPOLARITY(htim, Hcsr04Info.ic_tim_ch, TIM_INPUTCHANNELPOLARITY_RISING);
}
}
}
/**
* @description: 读取距离
* @param {*}
* @return {*}
*/
float Hcsr04Read()
{
// 测距结果限幅
if(Hcsr04Info.distance >= 500)
{
Hcsr04Info.distance = 500; //元器件资料说是600cm最高距离,这里保守一点
}
return Hcsr04Info.distance;
}
由于利用中断去读取定时测算的脉冲距离,所以这里需要重写定时器的中断服务函数。(这部分放在main.c最后即可)
/* USER CODE BEGIN 4 */
/**
* @description: 定时器输出捕获中断
* @param {TIM_HandleTypeDef} *htim
* @return {*}
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) //捕获回调函数
{
Hcsr04TimIcIsr(htim);
}
/**
* @description: 定时器溢出中断
* @param {*}
* @return {*}
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) //在中断回调函数中添加用户代码
{
Hcsr04TimOverflowIsr(htim);
}
/* USER CODE END 4 */
6.2、温湿度DTH11模块代码
DTH11.H代码:
#ifndef __DHT11_H__
#define __DHT11_H__
/* Private includes ----------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "stdio.h"
#include "tim.h"
#include "stm32f1xx.h"
/* Private define ------------------------------------------------------------*/
#define DHT11_PIN_SET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET) // ??GPIO??
#define DHT11_PIN_RESET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET) // ??GPIO??
#define DHT11_READ_IO HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_9) // DHT11 GPIO??
#define DLY_TIM_Handle (&htim2) // ?????
/* Private variables ---------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void DHT11(void);
void DHT11_START(void);
unsigned char DHT11_READ_BIT(void);
unsigned char DHT11_READ_BYTE(void);
unsigned char DHT11_READ_DATA(void);
unsigned char DHT11_Check(void);
static void DHT11_GPIO_MODE_SET(uint8_t mode);
void delay_us(uint16_t nus);
float data_compensate(); //★补偿函数
#endif
DTH11.C代码:
#include "dht11.h"
#include "oled.h"
#include "hc-sr04.h"
/**
* @brief DHT11Çý¶¯º¯Êý
* @param void
* @retval None
*/
void DHT11(void)
{
DHT11_READ_DATA();
HAL_Delay(50); // ãÐÉèÑÓ³Ù
}
/**
* @brief ????????????
* @param void
* @retval None
*/
void DHT11_START(void)
{
DHT11_GPIO_MODE_SET(0); // ?????????
DHT11_PIN_RESET; // ??????
HAL_Delay(20); // ???? 18 < ms > 30
DHT11_GPIO_MODE_SET(1); // ?????????,??DHT11??
} // ?????????,GPIO -> 1
/**
* @brief ?????? 1bit
* @param void
* @retval 0/1
*/
unsigned char DHT11_READ_BIT(void)
{
while(!DHT11_READ_IO); // ????????
Tims_delay_us(40); // ????????
if(DHT11_READ_IO) // ????????????? 1
{
while(DHT11_READ_IO); // ????????
return 1;
}
else // ??????? 0
{
return 0;
}
}
/**
* @brief ???????? 1byte / 8bit
* @param void
* @retval temp
*/
unsigned char DHT11_READ_BYTE(void)
{
uint8_t i,temp = 0; // ??????
for(i=0; i<8 ;i++)
{
temp <<= 1;
if(DHT11_READ_BIT()) // 1byte -> 8bit
{
temp |= 1; // 0000 0001
}
}
return temp;
}
/**
* @brief ?????????? 5byte / 40bit
* @param void
* @retval 0/1/2
*/
float DHT11_READ_DATA(void)
{
uint8_t i;
uint8_t data[5] = {0};
DHT11_START(); // ????????
if(DHT11_Check()) // ??DHT11??
{
while(!DHT11_READ_IO); // ??DHT11????????
while(DHT11_READ_IO); // ??DHT11????????
for(i=0; i<5; i++)
{
data[i] = DHT11_READ_BYTE(); // ?? 5byte
}
if(data[0] + data[1] + data[2] + data[3] == data[4])
{
//温度显示
OLED_ShowCN_STR(0,2,5,2);
OLED_ShowStr(32,2,":",2);
OLED_ShowNum(40,2,data[2],2,16);
OLED_ShowCN_STR(59,2,7,1);
OLED_ShowCN_STR(0,6,11,3);
OLED_ShowStr(48,6,":",2);
OLED_Showdecimal(55,6,data_compensate(data[2]),3,2,16);
OLED_ShowStr(100,6,"cm",2);
// //ʪ¶ÈÏÔʾ
// OLED_ShowCN_STR(0,6,2,2);
// OLED_ShowStr(32,6,":",2);
// OLED_ShowNum(40,6,data[0],2,16);
// OLED_ShowStr(59,6,"HR",2);
return data_compensate(data[2]); // ??????
}
else
{
return 0; // ??????
}
}
else // ??DHT11???
{
return 2;
}
}
/**
* @brief ????????????(??DHT11?????)
* @param void
* @retval 0/1
*/
unsigned char DHT11_Check(void)
{
Tims_delay_us(40);
if(DHT11_READ_IO == 0) // ???DHT11??
{
return 1;
}
else // ???DHT11???
{
return 0;
}
}
/**
* @brief ??????
* @param mode: 0->out, 1->in
* @retval None
*/
static void DHT11_GPIO_MODE_SET(uint8_t mode)
{
if(mode)
{
/* ?? */
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_1; // 9???
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // ????
GPIO_InitStruct.Pull = GPIO_PULLUP; // ????
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
else
{
/* ?? */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_1; // 9???
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; // Push Pull ??????
GPIO_InitStructure.Pull = GPIO_PULLUP; // ????
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; // ??
HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);
}
}
float data_compensate(int data)
{
float newspeed = 331.45+0.607*data;
Hcsr04Info.distance = (Hcsr04Info.high_level_us / 1000000.0) * newspeed / 2.0 * 100.0;
return Hcsr04Info.distance;
}
///**
// * @brief ?????us,Prescaler -> 72-1
// * @param us: <= 65535
// * @retval None
// */
//void Tims_delay_us(uint16_t nus)
//{
// __HAL_TIM_SET_COUNTER(DLY_TIM_Handle, 0);
// __HAL_TIM_ENABLE(DLY_TIM_Handle);
// while (__HAL_TIM_GET_COUNTER(DLY_TIM_Handle) < nus)
// {
// }
// __HAL_TIM_DISABLE(DLY_TIM_Handle);
//}
/**
* @brief ???? us , ??? 72M ?????
* @param us: <= 4294967295
* @retval None
*/
void Coarse_delay_us(uint32_t us)
{
uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
while (delay--)
{
;
}
}
6.3、BEEP报警显示模块代码
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!
希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-rqWWS3nu-1715685796834)]
[外链图片转存中…(img-JjmTNknt-1715685796834)]
[外链图片转存中…(img-18gmGyvl-1715685796835)]
[外链图片转存中…(img-lk25dccJ-1715685796835)]
[外链图片转存中…(img-NQHAx9zx-1715685796836)]
[外链图片转存中…(img-eKvGd0C9-1715685796836)]
[外链图片转存中…(img-c2yNaNnv-1715685796837)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!