这是我的物联网开发系列文章,将介绍如何从嵌入式开发、云平台开发、Android端开发来实现一个简单的物联网应用开发,体验物联网全栈开发的过程,积累开发的经验。
本篇文章为系列文章第三篇,主要介绍如何通过STM32来获取传感器(DHT11和光敏电阻传感器)的相关数据,开发工具是Keil MDK5和STM32CubeMX。
系列文章第一篇:物联网介绍和系统初步设计
系列文章第二篇:配置阿里云物联网平台及设备端连接测试
预警:本文内容比较长,有点罗嗦,包含较多图片,熟悉操作的小伙伴根据需要看。
本文目录
一、生成初始化工程代码
1.主要配置内容
STM32CubeMX是一个非常好用的STM32配置初始化代码的工具。我们可以使用它来对芯片的时钟、引脚和外设进行初始化配置,然后再去Keil里面进行更深入的开发。
由于STM32F103C8T6的外设和引脚比较少,而我们使用的硬件又比较多,所以必须先对引脚的使用做好安排。根据我们的设计需要,我们的STM32F103C8T6需要配置的引脚如下表。表格里有些引脚和外设是在后续的文章中使用的,在这里也一并配置好。
GPIO口 | 功能 | 备注 |
---|---|---|
PA9 | USART1_TX | CH340的RX,连接串口调试助手 |
PA10 | USART1_RX | CH340的TX,连接串口调试助手 |
PB10 | USART3_TX | ESP-12S的RX |
PB11 | USART3_RX | ESP-12S的TX |
PC13 | GPIO | STM32板上的LED |
PA0 | GPIO | STM32板上的按键S2 |
PA1 | GPIO | 蜂鸣器 |
PA2 | GPIO | 风扇电机 |
PB0 | ADC1_IN8 | 光敏电阻传感器 |
PA8 | OLED_RES | OLED |
PB15 | SPI2_MOSI | OLED |
PB14 | OLED_CS | OLED |
PB13 | SPI2_SCK | OLED |
PB12 | OLED_DC | OLED |
PA13 | SYS_JTMS-SWDIO | ST-Link |
PA14 | SYS_JTCK-SWCLK | ST-Link |
PB9 | GPIO | DHT11温湿度传感器 |
除了上述的引脚要配置之外,还要配置TIM时钟、NVIC中断、RCC的外部晶振和时钟树。
2.配置步骤【多图预警】
注意:STM32CubeMX在使用之前,需要安装好Java环境和STM32的MCU芯片包。具体的可以查看这篇博客:链接。
2.1选取芯片创建工程
打开STM32CubeMX,然后选择从MCU新建一个工程。在左侧选择 STM32F1,然后在右边找到STM32F103C8选中,点击 Start Project。
2.2配置引脚
注意:我在配置的时候并不是按照下文中的顺序,所以截图内容并不是按照我实际顺序来的。以下的外设(除了NVIC)都有配置就行,不用过分在意顺序。
- 配置RCC和外部晶振。点击左边的 RCC ,然把高速时钟和低速时钟都设置为外部晶振。如下图。
- 配置DEBUG模式。点击左边的 SYS ,在Debug选项中选择SW模式(Serial Wire),下面的选项选择Systick。如果是使用JTAG调试的小伙伴就在Debug这里自行更改。
- 配置USART串口。点击左边的USART1,在Mode选项中选择异步模式(Asynchronous),下面的参数保持默认就好。同样,USART3也是如此配置。
- 配置TIM。点击左边的TIM2,在Clock Source选项选择内部时钟(Internal Clock),在下面的参数中,将PSC设置为7200-1,将ARR设置为1000-1,然后点击NVIC Settings页面,在enable那里打勾,开启TIM的中断,如下图。这个TIM2是用于串口USART3的通信接收的计时。
- 配置SPI。点击左边的SPI2,在Mode选项选择Transmit Only Master,下面的参数保持默认。这个SPI是用于OLED的。
- 配置ADC。点击左边的ADC1,在Mode页面里将IN8打勾,开启ADC1的通道8,下面的参数保持默认。
- 配置GPIO。在右边的芯片图那里,找到引脚PA8并点击,在选项中选择GPIO_Output模式,如下图。PB14、PB12、PA1、PA2、PC13也是如此设置为GPIO_Output模式。PA0、PB9引脚则设置为GPIO_Input模式。
然后点击左边的GPIO进入GPIO页面,点击PC13,将其的输出电平设置为高电平,并添加标签(User Label),标签的填写可以参照下图。使用标签的话,自动生成的代码会为该引脚添加标签的宏定义,方便我们后期使用。
- 配置NVIC。点击左边的NVIC,将TIM2、USART1、USART3的中断打勾,然后设置中断优先级分别为1、3、2。
最终配置完引脚的芯片图如下。
2.3配置时钟树
按照下图所示的5个地方,对应修改时钟树。
2.4生成代码
来到Project Manager,填写好工程名称和文件位置,选择IDE为MDK-ARM,选择最低版本为V5.27或者5.0都行。
点击左侧的Code Generator,将下图所示的两个选项选上。第一个选项表示只将我们用到的库函数代码保存到工程,可以节省工程的空间;第二个选项是表示生成代码时将各种外设的代码按照头文件和源文件的方式分开放,如果这个没勾的话,代码全都挤在main文件里面。
最后,点击右上角的GENERATE CODE就可以生成初始化的代码了。生成代码成功之后就可以在文件位置找到我们的工程了。
二、在Keil中进行初始配置
1.添加启动文件和DHT11的驱动程序
在STM32CubeMX生成的工程,我们需要自己将启动文件添加进工程,如下图添加到MDK-ARM分组。另外顺便将DHT11的相关驱动程序(dht11.c、dht11.h、delay.c、delay.h的代码详见本文后面的《DHT11驱动程序》一节)放到工程的文件夹中,同样也要将dht11.c和delay.c添加到工程的分组之中。
提醒:如果驱动程序放置的位置不在工程的头文件路径中,需要将放置驱动程序的位置添加到工程的头文件路径中。
2.配置调试串口(USART1)
由于我们需要使用串口将传感器数据输出打印到电脑,所以在这里先对用于调试的串口(USART1)进行简单配置。
- usart.c
首先我们要在usart.c中定义一个用于串口发送的缓存数组USART1_TX_BUF[USART1_MAX_SEND_LEN]
,然后添加一个用于串口输出的函数u1_printf(char* fmt,...)
,其中需要使用到头文件"string.h"
、"stdio.h"
和"stdarg.h"
,记得要include。
uint8_t USART1_TX_BUF[USART1_MAX_SEND_LEN];
void u1_printf(char* fmt,...)
{
uint8_t i,j;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART1_TX_BUF,fmt,ap);
va_end(ap);
i=strlen((const char*)USART1_TX_BUF);//此次发送数据的长度
for(j=0;j<i;j++)//循环发送数据
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR=USART1_TX_BUF[j];
}
}
注意:
1.使用STM32CubeMX生成的工程代码有严格的格式,很多的注释,我们自己在Keil上添加的代码一定要放在带有USER CODE BEGIN
和USER CODE END
的注释之间的位置。没放在这些位置的代码,下次使用STM32CubeMX对本工程修改时会被清除掉。
2.在.c文件中添加的函数,如果是其他的文件也需要使用到的函数,比如上面说的u1_printf(char* fmt,...)
,需要在对应的头文件中添加函数的声明。
以上两点后面不再赘述。
- usart.h
在头文件中,要添加一个宏定义USART1_MAX_SEND_LEN
,这个是表示缓存数组的长度的。另外,要将上面定义的缓存数组USART1_TX_BUF[USART1_MAX_SEND_LEN]
给extern,方便别的文件可能会使用到。
#define USART1_MAX_SEND_LEN 256
extern uint8_t USART1_TX_BUF[USART1_MAX_SEND_LEN];
三、获取温湿度数据
1.DHT11的介绍
1.1概述
DHT11是一款有已校准数字信号输出的温湿度传感器。 其精度湿度±5%RH, 温度±2℃,量程湿度20-90%RH, 温度0~50℃。
DHT11应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,使其成为该类应用中,在苛刻应用场合的最佳选择。产品为4针单排引脚封装,连接方便。1
1.2引脚信息
引脚 | 注释 |
---|---|
VDD | 供电 3-5.5VDC |
DATA | 串行数据,单总线 |
NC | 空脚,请悬空 |
GND | 接地,电源负极 |
注:我这里使用的DHT11是经过再次封装的,在板子上已经将NC悬空,所以只有三个引脚(VDD、DATA、GND)。
1.3数据与通信
DATA引脚用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右。数据分小数部分和整数部分,具体格式如下:
- 一次完整的数据传输为40bit,高位先出。
- 数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和
- 数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。
DATA引脚的单总线通信需要使用到微秒级延时,基本过程如下图。后面的驱动程序也是要按照通信的过程原理进行拉高或者拉低,从而读取数据。
2.DHT11驱动程序
DHT11的驱动程序以及使用的延时程序来自于正点原子的程序,并修改了一些内容。
- dht11.c
#include "dht11.h"
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F103开发板
//DHT11驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2019/9/19
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//
//复位DHT11
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //设置为输出
DHT11_DQ_OUT=0; //拉低DQ
delay_ms(20); //拉低至少18ms
DHT11_DQ_OUT=1; //DQ=1
delay_us(30); //主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_Check(void)
{
u8 retry=0;
DHT11_IO_IN()