基于STM32温湿度和超声波距离仿真

目录

一、项目功能概述

二、仿真

三、程序

资料下载地址:基于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);
	
}



基于单片机的温度监测仿真#include <reg52.h> /////////////头文件 //////////////////////////////////////////////////////////////////////////// void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str); void ConfigTimer0(unsigned int ms); unsigned char IntToString(unsigned char *str, int dat); extern bit Start18B20(); extern bit Get18B20Temp(int *temp); extern void InitLcd1602(); bit DHT_Start(); void aj (void); bit DHT_ByteRead(unsigned char *dat); ///////////////////////////////////////////////////////////////////// sbit K1=P1^4; ///引脚声明 sbit K2=P1^5; sbit K3=P1^6; sbit K4=P1^7; sbit M1=P1^0; sbit M2=P1^1; sbit M3=P1^2; sbit M4=P1^3; sbit D1=P2^7; sbit D2=P2^6; sbit KD1=P2^3; sbit KD2=P2^4; ///////////////// ///////////////////////////// 数组命名 int SD,WD,x,xx,SDC,WDC,PWM1,PWM2; int KK1,KK2; int wdg=40,wdd=20,sdg=80,sdd=60; bit SZ,JB; bit flag1s = 0; //1s定时标志 unsigned char T0RH = 0; //T0重载值的高字节 unsigned char T0RL = 0; //T0重载值的低字节 ///////////////////////////////// 延时子程序 void delay () { x=99999; while(x--); } ///////////////////////////////// void main() ////////////////主程序 { bit tmp; unsigned char str[12]; unsigned char DHT[5]; ////初始化/////////////////////// EA = 1; //开总中断 ConfigTimer0(10); //T0定时10ms InitLcd1602(); //初始化液晶 M1=0; M1=0;M2=0;M3=0;D1=0;D2=0; //////////////////////////////////// DHT_Start(); delay(); delay(); delay(); delay(); while (1) { LcdShowStr(0, 0, "WD"); //显示到液晶屏上 LcdShowStr(0, 1, "SD"); //显示到液晶屏上 LcdShowStr(5, 0, "H"); //显示到液晶屏上 LcdShowStr(5, 1, "H"); //显示到液晶屏上 LcdShowStr(9, 0, "L"); //显示到液晶屏上 LcdShowStr(9, 1, "L"); //显示到液晶屏上 if (flag1s) //每秒更新一次温度 { str[0] = (wdg/10) + '0'; //十位转为ASCII码 str[1] = (wdg) + '0'; //个位转为ASCII str[2] = '\0'; LcdShowStr(6, 0, str); str[0] = (wdd/10) + '0'; //十位转为ASCII码 str[1] = (wdd) + '0'; //个位转为ASCII str[2] = '\0'; LcdShowStr(10,0, str); str[0] = (sdg/10) + '0'; //十位转为ASCII码 str[1] = (sdg) + '0'; //个位转为ASCII str[2] = '\0'; LcdShowStr(6, 1, str); str[0] = (sdd/10) + '0'; //十位转为ASCII码 str[1] = (sdd) + '0'; //个位转为ASCII str[2] = '\0'; LcdShowStr(10, 1, str); DHT_Start(); tmp=DHT_ByteRead(&DHT;); if(tmp==1) { str[0] = (DHT[0]/10) + '0'; //十位转为ASCII码 str[1] = (DHT[0]) + '0'; //个位转为ASCII LcdShowStr(2, 1, str); str[0] = (DHT[2]/10) + '0'; //十位转为ASCII码 str[1] = (DHT[2]) + '0'; //个位转为ASCII str[2] = '\0'; LcdShowStr(2,0, str); WD= DHT[2]; SD=DHT[0]; } } ////////////////////超热警报 if(wdg<=WD) { WDC=WD-wdg+2; M1=1; } else M1=0; if(wdd>=WD) { WDC=wdd-WD+2; M2=1; } else M2=0; if(sdg<=SD) { SDC=SD-sdg+2; M3=1; } else M3=0; if(sdd>=SD) { SDC=sdd-SD+2; M4=1; } else M4=0; if(wdg<=WD||wdd>=WD) { PWM1++; if(PWM1<WDC) D1=1; if(PWM1>=WDC) D1=0; if(PWM1==10) PWM1=0; } if(wdg>WD&&wdd;<WD&&KK1;==0) D1=0; if(sdg<=SD||sdd>=SD) { PWM2++; if(PWM2<SDC) D2=1; if(PWM2>=SDC) D2=0; if(PWM2==10) PWM2=0; } if(sdg>SD&&sdd;<SD&&KK2;==0) D2=0; /////////////////////////////按键设置 aj(); ////////////////////////////////////////////// } } void aj (void) { if(KD1==0) { delay(); KK1++; if(KK1==1) D1=1; if(KK1>=2) { D1=0; KK1=0; } } if(KD2==0) { delay(); KK2++; if(KK2==1) D2=1; if(KK2>=2) { D2=0; KK2=0; } } if(K1==0) { xx++; delay(); if(xx==1) LcdShowStr(12, 0, "WDH"); //显示到液晶屏上 if(xx==2) LcdShowStr(12, 0, "WDL"); //显示到液晶屏上 if(xx==3) LcdShowStr(12, 0, "SDH"); //显示到液晶屏上 if(xx==4) LcdShowStr(12, 0, "SDL"); //显示到液晶屏上 if(xx>=5) xx=0; } if(K2==0) { if(xx==1) { LcdShowStr(12, 1, "WD+"); //显示到液晶屏上 wdg++; } if(xx==2) { LcdShowStr(12, 1, "WD+"); //显示到液晶屏上 wdd++; } if(xx==3) { LcdShowStr(12, 1, "SD+"); //显示到液晶屏上 sdg++; } if(xx==4) { LcdShowStr(12, 1, "SD+"); //显示到液晶屏上 sdd++; } delay(); } if(K3==0) { if(xx==1) { LcdShowStr(12, 1, "WD-"); //显示到液晶屏上 wdg--; } if(xx==2) { LcdShowStr(12, 1, "WD-"); //显示到液晶屏上 wdd--; } if(xx==3) { LcdShowStr(12, 1, "SD-"); //显示到液晶屏上 sdg--; } if(xx==4) { LcdShowStr(12, 1, "SD-"); //显示到液晶屏上 sdd--; } delay(); } if(K4==0) { delay(); xx=0; InitLcd1602(); //初始化液晶 } } /* 整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度 */ unsigned char IntToString(unsigned char *str, int dat) { signed char i = 0; unsigned char len = 0; unsigned char buf[6]; if (dat < 0) //如果为负数,首先取绝对值,并在指针上添加负号 { dat = -dat; *str++ = '-'; len++; } do { //先转换为低位在前的十进制数组 buf[i++] = dat % 10; dat /= 10; } while (dat > 0); len += i; //i最后的值就是有效字符的个数 while (i-- > 0) //将数组值转换为ASCII码反向拷贝到接收指针上 { *str++ = buf[i] + '0'; } *str = '\0'; //添加字符串结束符 …………………… …………限于本文篇幅 余下代码请从51黑下载附件…………
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

森旺电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值