目录
资料下载地址:基于STM32温湿度和超声波测距
一、项目功能概述
1、采用DHT11实时测量温度并显示
2、采用C-SR04超声波测距并显示
3、LCD液晶屏显示相应数据
4、参数超限相关LED灯亮
二、仿真
三、程序
SR04.C
#include "sr04.h"
//超声波的初始化
void sr04_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
//1.打开时钟 GPIOB GPIOE
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOE, ENABLE);
//2.配置GPIO结构体 GPIOB
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIO
}
//获取距离
uint32_t get_distance()
{
uint32_t i=0;
//1.TRIG引脚 输出高电平 至少10us
GPIO_SetBits(GPIOB,GPIO_Pin_6);//输出高电平
delay_us(15);
GPIO_ResetBits(GPIOB,GPIO_Pin_6);//输出低电平
//2.等待ECHO引脚出现高电平
while( GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6) ==0 );
//3.如果ECHO出现高电平,记录高电平的持续时间 记录有多少个8us
while( GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6) ==1 )
{
i++;
delay_us(8);
}
//4.计算距离 距离 = 时间/2 * 3mm /10 单位是cm
i = i/2;
return i*3/10;//单位是cm
}
DHT11.C
#include "dht11.h"
//DHT11引脚输入模式
void dht_inputmode(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//1.打开时钟 GPIOE
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
//2.配置GPIO结构体 GPIOE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIO
}
//DHT11引脚输出模式
void dht_outputmode(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//1.打开时钟 GPIOE
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
//2.配置GPIO结构体 GPIOE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIO
}
//DHT11通信的开始
void dht_start(void)
{
//1.引脚设置为输出模式
dht_outputmode();
//2.把总线电平拉低 至少18ms 建议25ms左右
DHT_RESET;
delay_ms(25);
//3.把总线拉高 20~40us 建议40us
DHT_SET;
delay_us(40);
}
//DHT11响应信号检测
uint8_t dht_check(void)
{
uint8_t i=0;
//1.引脚设置为输入模式
dht_inputmode();
//2.判断引脚是否出现低电平
while( DHT_READ == 1 && i < 100 )
{
delay_us(1);
i++;
}
if(i>100)
{
return 1; //1 代表没响应 0代表响应
}
else
i=0;
//3.判断引脚低电平持续时间是否够80us
while( DHT_READ == 0 && i < 100 )
{
delay_us(1);
i++;
}
if(i>100)
{
return 1; //1 代表没响应 0代表响应
}
else
{
return 0;//代表响应
}
}
//读取DHT11的一位数据
uint8_t dht_read_bit(void)
{
uint8_t i=0;
//1.判断引脚是否出现低电平
while( DHT_READ == 1 && i < 100 )
{
delay_us(1);
i++;
}
i=0;
//2.判断引脚是否出现高电平
while( DHT_READ == 0 && i < 100 )
{
delay_us(1);
i++;
}
delay_us(40);
//3.读取引脚电平状态
if(DHT_READ == 1)
return 1; //代表数字1
else
return 0; //代表数字0
}
//读取DHT一个字节
uint8_t dht_read_byte(void)
{
u8 i,data;//i为了循环 data为了存储数据
data=0;
for(i=0;i<8;i++)
{
data <<= 1;
data |= dht_read_bit();
}
return data;
}
//读取DHT整个数据
uint32_t dht_read_data(u8 *pbuf)
{
u8 i=0;
//1.通信的开始
dht_start();
//2.检测响应信号
if( dht_check() == 0 )
{
for(i=0;i<5;i++)
{
pbuf[i] = dht_read_byte();
}
if(pbuf[0]+pbuf[1]+pbuf[2]+pbuf[3] != pbuf[4])//进行校验
{
return 1;//代表通信失败
}
}
else
{
return 1;//代表通信失败
}
return 0;//代表通信成功
}
//DHT11的初始化
void dht_init(void)
{
dht_start();
dht_check();
}
LCD.C
#include "lcd.h"
//设置D7引脚为输出模式
void lcd_D7_outputmode(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//1.打开时钟 GPIOF
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
//2.配置GPIO结构体
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
//3.初始化GPIO
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
//设置D7引脚为输入模式
void lcd_D7_inputmode(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//1.打开时钟 GPIOF
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
//2.配置GPIO结构体
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
//3.初始化GPIO
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
//检测忙状态 BF(D7)为忙标志位,高电平表示忙,此时模块不能接收命令或数据,如果为低电平则表示不忙
unsigned char busy_check(void)
{
u16 status=0;//为了接收整个端口的电平状态
//当RS=0,RW=1,以及E=1的时候,BF输出到PD7
lcd_D7_inputmode();//设置D7引脚为输入模式,才能检测引脚的电平状态
LCD_RS_L;
LCD_RW_H;
do
{
LCD_E_H;
delay_ms(5);
status = GPIO_ReadInputData(GPIOD);//读取GPIOD整个端口的电平状态
LCD_E_L;
}while( status & 0x0080 ); // 低电平 不忙 高电平 忙
return 0;
}
//写命令
void lcd_write_cmd(uint16_t cmd)
{
//1.检测忙状态 如果忙状态 则等待
busy_check();
//2.当RS和R/W共同为低电平时可以写入指令
lcd_D7_outputmode();
LCD_RS_L;
LCD_RW_L;
GPIO_Write(GPIOD,cmd);//把指令写入指令寄存器
//3.当E端由高电平跳变为低电平时,液晶模块执行命令
LCD_E_H;
LCD_E_L;
}
//写数据
void lcd_write_data(uint16_t data)
{
//1.检测忙状态 如果忙状态 则等待
busy_check();
//2.当RS为高电平,R/W为低电平时,可以写入数据
lcd_D7_outputmode();
LCD_RS_H;
LCD_RW_L;
GPIO_Write(GPIOD,data);//把指令写入指令寄存器
//3.当E端由高电平跳变为低电平时,液晶模块执行命令
LCD_E_H;
LCD_E_L;
}
//设置坐标
void lcd_set_cursor(uint8_t x,uint8_t y)
{
//一共就4行 不能超过
if(y<1)
y=1;
if(y>4)
y=4;
x &= 0x0F;// x 保证在 0~15
switch(y)
{
case 1: x|=0x80;break; //字符地址 = 基地址 + 偏移地址
case 2: x|=0xC0;break;
case 3: x|=0x90;break;
case 4: x|=0xD0;break;
}
//设置显示地址
lcd_write_cmd(x);
}
//显示字符串
void lcd_show_string(uint8_t x,uint8_t y,char *str)
{
//1.设置坐标
lcd_set_cursor(x,y);
while(*str!= '\0')
{
lcd_write_data(*str++);// *str 代表解引用 得到地址下面的数据 ++ 地址才会偏移
}
}
void lcd_show_char(uint8_t x,uint8_t y,u16 dat)
{
//1.设置坐标
lcd_set_cursor(x,y);
delay_ms(50);
lcd_write_data(dat);
}
//显示数字
void lcd_num(uint8_t x,uint8_t y,uint8_t num)
{
u8 buf[6];
u8 *p;
lcd_set_cursor(x,y);
p = &buf[5];
*p = '\0';
do{
*(--p) = num % 10 + '0';
num /= 10;
}while(num);
while(*p)
{
lcd_write_data(*p++);
}
}
//LCD的初始化
void lcd_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//1.打开时钟 GPIOF
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOD, ENABLE);
//2.配置GPIO结构体 PB0 1 2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
//3.初始化GPIO
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_Write(GPIOD,0);//把D0-D7清0
delay_ms(10);
//显示方式 8位数据总线 5x7点阵 两行显示
lcd_write_cmd(0x38);
delay_ms(10);
//开启显示
lcd_write_cmd(0x0C);
delay_ms(10);
//文字不动,地址自动+1
lcd_write_cmd(0x06);
delay_ms(10);
//清屏
lcd_write_cmd(0x01);
delay_ms(10);
lcd_write_cmd(0x80);
delay_ms(10);
}