嵌入式室内环境参数监控系统设计

这篇具有很好参考价值的文章主要介绍了嵌入式室内环境参数监控系统设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、设计要求

本次课设要求学生们掌握四个方面,第一是文献检索及实验研究方法,第二是室内环境监控系统一般组成; 第三是掌握技术方案比选方法;最后是掌握STM32 ADC使用,同时本次课设需要做到以下几个方面:

  1. 了解国内室内环境参数监控系统组成及技术架构;
  2. 设计室内环境参数监控系统,要求至少采集温度及光照,完成环境参数传感器选型;
  3. 基于开发板或其他32位微控制器及所选用的传感器设计一个室内环境参数采集终端,实现至少一路温度、光照强度数据采集;
  4. 设置温度和光照门限,当温度高于门限值时蜂鸣器报警,当光照强度高于及低于门限值时控制LED灯亮度以实现光照调节(也可自行设计亮度调节方式)。
  5. 将采集到的温度和光照强度数据显示到LCD屏上;

二、设计原理

  1. 硬件设计
  1. 采用STM32F103ZET6单片机作为主控芯片,具有较强的处理能力,且具有低功耗、低成本等特点,可以实现室内环境参数监控的多种复杂操作;
  2. 采用DHT11温湿度传感器,可以实时检测室内温度和湿度;
  3. 采用光强传感器,可以检测室内光照强度参数;
  4. 采用LCD显示屏,可以显示室内环境参数的实时数据;
  5. 采用LED灯,可以模拟补光操作;
  6. 采用蜂鸣器,可以实现报警功能。
  1. 软件设计
  1. 采用C语言编写程序,实现对传感器参数的采集、处理以及参数的显示;
  2. 采用报警功能,当室内温度参数超出设定范围时,可以发出警报信号;
  3. 采用室内光照强度实时调节,根据室内光照强度参数实时调节以达到适合工作、学习的平衡状态。

三、设计方案

1硬件设计

1.1硬件系统框图

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

 文章来源地址https://www.toymoban.com/news/detail-801020.html

1.2主控芯片模块(STM32F103ZET6)

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

 

STM32F103ZET6芯片的主要特性如下:

  1. 集成了32位的ARM Cortex-M3内核,最高工作频率可达72MHZ,计算能力    为1.25DMIPS,具有单周期乘法指令和硬件除法器;
  2. 具有512KB片内Flash存储器和64KB片内片内SARM存储器;
  3. 内部集成了8MHZ晶体振荡电路器,可外接416MHZ的时钟源;
  4. 2.0-3.0V单一供电源,具有上电复位功能;
  5. 具有睡眠、停止、待机三种低功耗工作模式;
  6. 144个引脚LQFP封装;
  7. 内部集成了11个定时器:4个16位通用定时器,2个16位定时器可产生的PWM波控制电机的定时器,2个16位的可驱动DAC的定时器,2个加窗口的看门狗定时器和1 个24位的系统节拍定时器;
  8. 2个12位的DAC和3个12位的ADC;
  9. 集成了内部温度传感和实时时钟RTC;
  10. 具有112根高速通用输入输出口,可从其中任选16根作为外部中断输入口,几乎全部GPIO口可承受5V输入(PA0~PA7,PB0~PB1,PC0~PC5,PC13~PC15和PF6~PF10除外);
  11. 集成了13个外部通信接口:2个12C、3个SPI、1个CAN、5个UART、5个UART、1个USB2.0设备和1个并行SDIO;
  12. 具有12通道的DMA控制器,支持定时器、ADC、DAC、SDIO、12S、SPI、12C和UART外设;
  13. 具有96位的全球唯一编号;
  14. 工作温度-40~85℃;  

1.3电源电路模块

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

1.4复位电路模块

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

       可实现上电复位和按键复位,开发板接通电源时,复位持续时间由R2电阻值C10容值乘积决定,一般情况下电阻值取10k电容值取10uf可以满足复位要求,按钮RESET可以实现按键复位,当需要复位时按下RESET按钮,RESET引脚直接接地,CPU进入复位状态。 

1.5时钟电路模块

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

 

从上图可以看出三种不同的时钟源可被用来驱动系统时钟(SYSCLK):

(1)HSI振荡器时钟

(2)HSE振荡器时钟

(3)PLL时钟

这些设备有以下2种二级时钟源:

(1)40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。RTC用于从停机/ 待机模式下自动唤醒系统。

(2)32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。

当不被使用时,任一个时钟源都可被独立地启动或关闭,由此优化系统功耗。

1.6DHT11温湿度传感器模块

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

       DHT11是一款温湿度一体化的数字传感器。该传感器包括一个电容式测湿元件和一个 NTC测温元件,并与一个高性能 8 位单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集本地湿度和温度。DHT11与单片机之间能采用简单的单总线进行通信,仅仅需要一个I/O口。传感器内部湿度和温度数据40Bit的数据一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。DHT11功耗很低,5V 源电压下,工作平均最大电流0.5mA。

1.7光强传感器模块

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

 图中,LSI为光敏二极管,外观看起来与贴片LED类似(位于OLED插座旁边,LSI)R34为其提供反向电压,当环境光线发生变化时,LSI两端的电压也会随之改变,通过ADC3_IN6通道获取LIGHT_SENSOR(PF8)上面的电压,即可得到环境光线的强弱,光线越强,电压越低,光线越弱,电压越高。

1.8TFT_LCD显示模块

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

FTLCD 模块采用 2*17 的 2.54 公排针与外部连接,即图中 TFT_LCD 部分。从图 1.8.1可以看出,正点原子 TFTLCD 模块采用 16 位的并口方式与外部连接。该模块与显示功能的相关信号线如表 1.8.2:

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件 

 1.9LED照明补光模块

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

 1.10蜂鸣器报警模块

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

开发板配置了一个无源蜂鸣器BEEP作为系统报警使用,由PNP三极管Q1控制其导通或关闭,加两个电阻实现当管脚输出3.3V电平时才能发生,且防止由于外部干扰导致的误发声。

  1. 软件设计
    1. DHT11传感器温湿度采集
      1. 程序设计

DHT11实验中使用的是单总线协议,用到的是库函数中 GPIO 相关函数。

DHT11配置步骤 :

(1)使能DHT11数据线对应的GPIO时钟。 本实验中DHT11的数据线引脚是PG11,因此需要先使能 GPIOG 的时钟;

(2)设置对应 GPIO 工作模式(开漏输出),本实验 GPIO 使用开漏输出模式;

(3)参考单总线协议,编写信号代码:

  1. DHT11开始发送数据流程
  2. 在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

主机发送开始信号后,延时等待 20us-40us 后读取 DH11T 的回应信号,读取总线为低电平,说明 DHT11 发送响应信号,DHT11 发送响应信号后,再把总线拉高,准备发送数据,每一 bit 数据都以低电平开始,格式见下面图示。如果读取响应信号为高电平,则 DHT11 没有响应,请检查线路是否连接正常。在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件主机复位信号和DHT11响应信号

(4)编写 DHT11的读函数 ,基于读1bit数据的基础上,编写 DHT11 读1字节函数。

(5)编写DHT11获取温度函数, 参考 DHT11典型温湿度读取过程,编写获取温湿度函数。

2.1.2程序流程图

在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

本实验开机的时候先检测是否有 DHT1 1存在,如果没有,则提示错误。只有在检测到 DHT11之后才开始读取温湿度值并显示在 LCD 上,如果发现了 DHT1 1,则程序每隔 100ms 左右读取一次数据,并把温湿度显示在 LCD 上。 LED0 闪烁用于提示程序正在运行。

2.1.3程序代码

//复位DHT11
void DHT11_Rst(void)	   
{                 
	DHT11_IO_OUT(); 	//SET OUTPUT
    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();//SET INPUT	 
    while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
	{
		retry++;
		delay_us(1);
	};	 
	if(retry>=100)return 1;
	else retry=0;
    while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		delay_us(1);
	};
	if(retry>=100)return 1;	    
	return 0;
}
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void) 			 
{
 	u8 retry=0;
	while(DHT11_DQ_IN&&retry<100)//等待变为低电平
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while(!DHT11_DQ_IN&&retry<100)//等待变高电平
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);//等待40us
	if(DHT11_DQ_IN)return 1;
	else return 0;		   
}
//从DHT11读取一个字节
//返回值:读到的数据
u8 DHT11_Read_Byte(void)    
{        
    u8 i,dat;
    dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°),humi:湿度值(范围:20%~90%)
u8 DHT11_Read_Data(u8 *temp,u8 *humi)    
{        
 	u8 buf[5];
	u8 i;
	DHT11_Rst();
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=buf[0];
			*temp=buf[2];
		}
	}else return 1;
	return 0;	    
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在  	 
u8 DHT11_Init(void)
{	 
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);	 //使能PG端口时钟
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;				 //PG11端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOG, &GPIO_InitStructure);				 //初始化IO口
 	GPIO_SetBits(GPIOG,GPIO_Pin_11);						 //PG11 输出高	    
	DHT11_Rst();  //复位DHT11
	return DHT11_Check();//等待DHT11的回应
}

 

  1. 2光照强度采集
    1. 1程序设计

通过 ADC3_CH6通道读取 LIGHT_SENSOR(PF8)上面的电压,即可得到环境光线的强弱。光线越强,电压越低,光线越暗,电压越高。

  1. 1.2
    1. 程序流程图
    2. 在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

    通过 ADC3 的通道 6(PF8)读取光敏传感器(LS1)的电压值,并转换为 0~100 的光线强度值,显示在 LCD 模块上面。光线越亮,值越大;光线越暗,值越小。大家可以用手指遮挡 LS1和用手电筒照射 LS1,来查看光强变化。 LED0 闪烁用于提示程序正在运行。

  2. .2.3程序代码

    //初始化光敏传感器
    void Lsens_Init(void)
    {
      GPIO_InitTypeDef GPIO_InitStructure;
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);//使能PORTF时钟	
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//PF8 anolog输入
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
    GPIO_Init(GPIOF, &GPIO_InitStructure);	
    	Adc3_Init();
    }
    //读取Light Sens的值
    //0~100:0,最暗;100,最亮 
    u8 Lsens_Get_Val(void)
    {
    	u32 temp_val=0;
    	u8 t;//读取次数
    	for(t=0;t<LSENS_READ_TIMES;t++)
    	{
    		temp_val+=Get_Adc3(LSENS_ADC_CHX);	//读取ADC值
    		delay_ms(5);
    	}
    	temp_val/=LSENS_READ_TIMES;//得到平均值 
    	if(temp_val>4000)temp_val=4000;
    	return (u8)(100-(temp_val/40));
    }

     

  3. ADC模数转换
    1. 程序设计
    2. ADC模块采集的是光敏电阻两端的电压值,电压属于模拟信息需转化为数字信息,只有这样才能的处理数据从而完成光照强度的监控。
  4. 代码
    //初始化ADC3
    //这里我们仅以规则通道为例
    //我们默认仅开启通道6																
    void  Adc3_Init(void)
    {      
    	ADC_InitTypeDef ADC_InitStructure; 
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3	, ENABLE );	  //使能ADC3通道时钟
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,ENABLE);//ADC复位
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,DISABLE);//复位结束	
        
    	ADC_DeInit(ADC3);  //复位ADC3,将外设 ADC3的全部寄存器重设为缺省值
    	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式: 独立模式
    	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//模数转换工作在单通道模式
    	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;	//模数转换工作在单次转换模式
    	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动
    	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐
    	ADC_InitStructure.ADC_NbrOfChannel = 1;	//顺序进行规则转换的ADC通道的数目
    	ADC_Init(ADC3, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器  
    	ADC_Cmd(ADC3, ENABLE);	//使能指定的ADC3
    	ADC_ResetCalibration(ADC3);	//使能复位校准  
    	while(ADC_GetResetCalibrationStatus(ADC3));	//等待复位校准结束
    	ADC_StartCalibration(ADC3);	 //开启AD校准
    	while(ADC_GetCalibrationStatus(ADC3));	 //等待校准结束
    }		 
    //获得ADC3_ch6通道的值
    u16 Get_Adc3(u8 ch)   
    {
      //设置指定ADC的规则组通道,一个序列,采样时间
    	ADC_RegularChannelConfig(ADC3, ch, 1, ADC_SampleTime_239Cycles5 );	//ADC3,ADC通道,采样时间为239.5周期	  			    
    	ADC_SoftwareStartConvCmd(ADC3, ENABLE);		//使能指定的ADC3的软件转换启动功能	
    	while(!ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC ));//等待转换结束
    	return ADC_GetConversionValue(ADC3);	//返回最近一次ADC3规则组的转换结果
    }

    3.TFT_LCD显示代码

    //初始化lcd
    void LCD_Init(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
        FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;
        FSMC_NORSRAMTimingInitTypeDef  readWriteTiming; 
        FSMC_NORSRAMTimingInitTypeDef  writeTiming;
    
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE);   //使能FSMC时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOG,ENABLE); //使能PORTB,D,E,G以及AFIO复用功能时钟
    
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;           //PB0 推挽输出 背光
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
    
        //PORTD复用推挽输出
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_14|GPIO_Pin_15;    //PORTD复用推挽输出
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOD, &GPIO_InitStructure); 
         
        //PORTE复用推挽输出
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; //PORTE复用推挽输出
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOE, &GPIO_InitStructure);
    
        //PORTG12复用推挽输出 P0RTG0-->RS
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_12;   //PORTD复用推挽输出
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOG, &GPIO_InitStructure);
    //LCD开启显示
    void LCD_DisplayOn(void)
    {
        if (lcddev.id == 0X5510)    //5510开启显示指令
        {
            LCD_WR_REG(0X2900);     //开启显示
        }
        else                        //9341/5310/1963/7789 等发送开启显示指令
        {
            LCD_WR_REG(0X29);       //开启显示
        }
    }
    
    //LCD关闭显示
    void LCD_DisplayOff(void)
    {
        if (lcddev.id == 0X5510)    //5510关闭显示指令
        {
            LCD_WR_REG(0X2800);     //关闭显示
        }
        else                        //9341/5310/1963/7789 等发送关闭显示指令
        {
            LCD_WR_REG(0X28);       //关闭显示
        }
    }
    
    //清屏函数
    //color:要清屏的填充色
    void LCD_Clear(u16 color)
    {
        u32 index = 0;
        u32 totalpoint = lcddev.width;
        totalpoint *= lcddev.height;    //得到总点数
        LCD_SetCursor(0x00, 0x0000);    //设置光标位置
        LCD_WriteRAM_Prepare();         //开始写入GRAM
        for (index = 0; index < totalpoint; index++)
        {
            LCD->LCD_RAM=color;
        }
    }
    //在指定区域内填充指定颜色
    //区域大小:(xend-xsta+1)*(yend-ysta+1)
    //xsta
    //color:要填充的颜色
    void LCD_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16 color)
    {
        u16 i, j;
        u16 xlen = 0;
        xlen = ex - sx + 1;
        for (i = sy; i <= ey; i++)
        {
            LCD_SetCursor(sx, i);       //设置光标位置
            LCD_WriteRAM_Prepare();     //开始写入GRAM
            for (j = 0; j < xlen; j++)
            {
                LCD->LCD_RAM=color;     //设置光标位置
            }
        }
    }
    
    //在指定区域内填充指定颜色块
    //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
    //color:要填充的颜色
    void LCD_Color_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16 *color)
    {
        u16 height, width;
        u16 i, j;
        width = ex - sx + 1;            //得到填充的宽度
        height = ey - sy + 1;           //高度
        for (i = 0; i < height; i++)
        {
            LCD_SetCursor(sx, sy + i);  //设置光标位置
            LCD_WriteRAM_Prepare();     //开始写入GRAM
            for (j = 0; j < width; j++)
            {
                LCD->LCD_RAM=color[i * width + j];  //写入数据
            }
        }
    }
    
    //在指定位置显示一个字符
    //x,y:起始坐标
    //num:要显示的字符:" "--->"~"
    //size:字体大小 12/16/24
    //mode:叠加方式(1)还是非叠加方式(0)
    void LCD_ShowChar(u16 x, u16 y, u8 num, u8 size, u8 mode)
    {
        u8 temp, t1, t;
        u16 y0 = y;
        u8 csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);  //得到字体一个字符对应点阵集所占的字节数
        num = num - ' ';    //得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
        for (t = 0; t < csize; t++)
        {
            if (size == 12)temp = asc2_1206[num][t];        //调用1206字体
            else if (size == 16)temp = asc2_1608[num][t];   //调用1608字体
            else if (size == 24)temp = asc2_2412[num][t];   //调用2412字体
            else return;                                    //没有的字库
            for (t1 = 0; t1 < 8; t1++)
            {
                if (temp & 0x80)LCD_Fast_DrawPoint(x, y, POINT_COLOR);
                else if (mode == 0)LCD_Fast_DrawPoint(x, y, BACK_COLOR);
                temp <<= 1;
                y++;
                if (y >= lcddev.height)return;      //超区域了
                if ((y - y0) == size)
                {
                    y = y0;
                    x++;
                    if (x >= lcddev.width)return;   //超区域了
    
                    break;
                }
            }
        }
    }
    
    //m^n函数
    //返回值:m^n次方.
    u32 LCD_Pow(u8 m, u8 n)
    {
        u32 result = 1;
        while (n--)result *= m;
        return result;
    }
    //显示数字,高位为0,则不显示
    //x,y :起点坐标
    //len :数字的位数
    //size:字体大小
    //color:颜色
    //num:数值(0~4294967295);
    void LCD_ShowNum(u16 x, u16 y, u32 num, u8 len, u8 size)
    {
        u8 t, temp;
        u8 enshow = 0;
        for (t = 0; t < len; t++)
        {
            temp = (num / LCD_Pow(10, len - t - 1)) % 10;
            if (enshow == 0 && t < (len - 1))
            {
                if (temp == 0)
                {
                    LCD_ShowChar(x + (size / 2)*t, y, ' ', size, 0);
                    continue;
                }
                else enshow = 1;
            }
            LCD_ShowChar(x + (size / 2)*t, y, temp + '0', size, 0);
        }
    }
    
    //显示数字,高位为0,还是显示
    //x,y:起点坐标
    //num:数值(0~999999999);
    //len:长度(即要显示的位数)
    //size:字体大小
    //mode:
    //[7]:0,不填充;1,填充0.
    //[6:1]:保留
    //[0]:0,非叠加显示;1,叠加显示.
    void LCD_ShowxNum(u16 x, u16 y, u32 num, u8 len, u8 size, u8 mode)
    {
        u8 t, temp;
        u8 enshow = 0;
        for (t = 0; t < len; t++)
        {
            temp = (num / LCD_Pow(10, len - t - 1)) % 10;
            if (enshow == 0 && t < (len - 1))
            {
                if (temp == 0)
                {
                    if (mode & 0X80)LCD_ShowChar(x + (size / 2)*t, y, '0', size, mode & 0X01);
                    else LCD_ShowChar(x + (size / 2)*t, y, ' ', size, mode & 0X01);
                    continue;
                }
                else enshow = 1;
            }
            LCD_ShowChar(x + (size / 2)*t, y, temp + '0', size, mode & 0X01);
        }
    }
    
    //显示字符串
    //x,y:起点坐标
    //width,height:区域大小
    //size:字体大小
    //*p:字符串起始地址
    void LCD_ShowString(u16 x, u16 y, u16 width, u16 height, u8 size, u8 *p)
    {
        u8 x0 = x;
        width += x;
        height += y;
        while ((*p <= '~') && (*p >= ' '))   //判断是不是非法字符!
        {
            if (x >= width)
            {
                x = x0;
                y += size;
            }
            if (y >= height)break; //退出
            LCD_ShowChar(x, y, *p, size, 0);
            x += size / 2;
            p++;
        }
    }
    
    

    2.5蜂鸣器报警代码

    void BEEP_Init(void)//BEEP初始化
    {
    
      GPIO_InitTypeDef  GPIO_InitStructure;
    
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口时钟
    	
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//beep->PB8端口配置
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//端口模式配置
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//端口速率配置
      GPIO_Init(GPIOB,&GPIO_InitStructure);//根据参数初始化GPIOB_Pin8
    
      GPIO_ResetBits(GPIOB,GPIO_Pin_8);//初始时端口配置为低电平
    }
    
    if(temperature>=34)
    {
    BEEP=1;
    }	

    2.6LED照明补光程序代码

    //TIM3 PWM部分初始化 
    //PWM输出初始化
    //arr:自动重装值
    //psc:时钟预分频数
    void TIM3_PWM_Init(u16 arr,u16 psc)
    {  
    	GPIO_InitTypeDef GPIO_InitStructure;
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	TIM_OCInitTypeDef  TIM_OCInitStructure;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIOE外设和AFIO复用功能模块时钟
       //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOA.7
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM_CH2
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
       //初始化TIM3
    	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    	
    	//初始化TIM3 Channel2 PWM模式	 
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
     	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
    	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2
    
    	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
    	TIM_Cmd(TIM3, ENABLE);  //使能TIM3
    }

    三、主程序

    int main(void)
     {
     	u8 adcx;//光照强度
    	u8 t=0;	
    	u8 temperature;//温度
    	u8 humidity;   //湿度
    	u16 led1pwmval; //PWN输出的占空比
    	delay_init();	    	 //延时函数初始化	  
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    	uart_init(115200);	 	//串口初始化为115200
    	LED_Init();		  		 //初始化与LED连接的硬件接口
    	BEEP_Init();        //初始化BEEP
      LCD_Init();				 //初始化LCD
    	Lsens_Init(); 		//初始化光敏传感器
    	TIM3_PWM_Init(899,0);	 //不分频。PWM频率=72000000/900=80Khz
    
    	POINT_COLOR=RED;//设置字体为红色
      	
    	//显示提示信息											      
    	LCD_ShowString(30,50,200,16,16,"Based On STM32");	
    	LCD_ShowString(30,70,200,16,16,"DHT11_LSENS MONITORING");	
    	LCD_ShowString(30,90,200,16,16,"Copyright GROUP1");
    	LCD_ShowString(30,110,200,16,16,"2022/12/25");
    
    	while(DHT11_Init())	//DHT11初始化	
    	{
    		LCD_ShowString(30,130,200,16,16,"DHT11 Error");
    
    		delay_ms(200);
    		LCD_Fill(30,130,239,130+16,WHITE);
     		delay_ms(200);
    	}
    	LCD_ShowString(30,130,200,16,16,"DHT11 OK");
    	POINT_COLOR=BLUE;//设置字体为蓝色
    	LCD_ShowString(30,170,200,16,16,"LSENS_VAL:");
      LCD_ShowString(30,190,200,16,16,"Temp:  C");	 
     	LCD_ShowString(30,210,200,16,16,"Humi:  %");		
    	while(1)
    	{
    		adcx=Lsens_Get_Val();
    		LCD_ShowxNum(30+10*8,170,adcx,3,16,0);//显示ADC的值 
    		if(t%10==0)			//每100ms读取一次
    		{									  
    			DHT11_Read_Data(&temperature,&humidity);	//读取温湿度值					    
    			LCD_ShowNum(30+40,190,temperature,2,16);	//显示温度	   		   
    			LCD_ShowNum(30+40,210,humidity,2,16);		//显示湿度	 	   
    		}				   
    	 	delay_ms(10);
    		t++;
    		if(temperature>=34) 
    		{
    			BEEP=1;
    		}	
    		led1pwmval=(100-adcx)/10;//根据光照强度实时调整LED1的亮度
    		TIM_SetCompare2(TIM3,led1pwmval);}
    }

    四、测试

  5. 在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

          项目文件编译并下载到单片机后上电,LCD屏上可以清晰显示当前测试环境的温度、湿度和光照强度。 

  6. 在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件

    通过上面两图的对比,未外加灯光时光照强度为7,LED1很亮;当外加灯光时,光照强度为93,LED1微亮或者熄灭。

  7. 在正点原子上实现室内环境控制器,单片机,stm32,嵌入式硬件 

    测试时室温为14摄氏度,当设置温度报警上限为10摄氏度时,可以听到蜂鸣器发出声音报警。 

     

到了这里,关于嵌入式室内环境参数监控系统设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【ARM 嵌入式 编译系列 2.1 -- GCC 编译参数学习】

    请阅读 【ARM GCC 编译专栏导读】 上篇文章:ARM 嵌入式 编译系列 2 – GCC 编译过程介绍 下篇文章:ARM 嵌入式 C 入门及渐进 3 – GCC attribute ((weak)) 弱符号使用 上篇文章 ARM 嵌入式 编译系列 2 – GCC 编译过程介绍 已经介绍过了具体的编译流程,本篇文章主要介绍变过程中常见的

    2024年02月13日
    浏览(32)
  • 【ARM 嵌入式 编译系列 3.5 -- gcc 链接参数介绍】

    请阅读 【嵌入式开发学习必备专栏 之 ARM GCC 编译专栏】 上篇文章【ARM 嵌入式 编译系列 3.4 – 查看所依赖库文件的路径 详细介绍】一直在提 链接参数 ,那么链接参数有哪些,它们又有什么作用呢? 如前一篇文章中的的链接参数到底是什么意思呢? -L : 指定了 链接库的路径

    2024年01月17日
    浏览(35)
  • 超详细!旗舰SoC RK3588参数介绍-飞凌嵌入式

    OK3568-C开发板 RK3588是瑞芯微旗下最新的8K旗舰SoC芯片,采用ARM架构,主要用于PC、边缘计算设备、个人移动互联网设备和其他数字多媒体应用。 RK3588集成了四核Cortex-A76和四核Cortex-A55,以及单独的NEON协处理器,支持8K视频编解码。许多功能强大的嵌入式硬件引擎为高端应用提供

    2024年01月25日
    浏览(32)
  • ubuntu20嵌入式开发环境搭建

    安装步骤:省略。 网上有很多教程,不做笔记了。 值得注意的一点:安装时建议选择中文安装,会默认带有中文输入法。 安装Vmware Tools后,可以实现主机跟虚拟机之间的文件拷贝,文本内容的复制粘贴等操作。使用起来更方便。 依次使用下面的命令即可完成安装: sudo ap

    2024年02月19日
    浏览(24)
  • 嵌入式系统——交叉编译概念与环境搭建

      本文属于嵌入式系统的基础知识,主要介绍编译过程和交叉编译。对于基于ARM内核的微处理器移植操作系统,不可避免的需要使用交叉编译。交叉编译指的是不同平台间编译程序代码的操作,不同平台有两方面:(1)不同的操作系统;(2)不同的处理器平台,如ARM和X

    2024年02月10日
    浏览(28)
  • 嵌入式Linux Qt交叉编译环境搭建

    TinkerBoard2主板,BuildRoot根文件系统,package自带的Qt版本为5.14.2,所以安装的版本也是5.14.2 安装的组件看个人需求,我都要了 默认安装路径/opt/Qt5.14.2/ 源码路径/opt/Qt5.14.2/5.14.2/Src/ 安装后选定的打包工具路径/opt/Qt5.14.2/5.14.2/(我的默认有gcc_64和android) 这种方法容易导致version `G

    2024年01月25日
    浏览(31)
  • STM32开发环境搭建&工程创建(嵌入式学习)

    简介 STM32CubeMX是STMicroelectronics公司提供的一款集成开发环境(IDE)工具,用于快速配置和初始化STM32微控制器系列的软件工程。它提供了图形化界面和交互式工具,使开发者能够轻松地生成STM32微控制器的初始化代码和配置文件。 STM32CubeMX具有以下主要功能和特点: 微控制器

    2024年02月11日
    浏览(45)
  • 【ARM 嵌入式 编译系列 2.5 -- GCC 编译参数学习 --specs=nano.specs选项 】

    请阅读 【嵌入式开发学习必备专栏 之 ARM GCC 编译专栏】 ARM 工具链 ( arm-none-eabi- ) 包括了一个叫作 --specs 的编译器和链接器选项,这个选项允许用户指定一个或多个 “specs” 文件,以影响编译或链接阶段的行为。Specs 文件包含一系列的命令行参数,这些参数可以是编译器选项

    2024年01月22日
    浏览(37)
  • 【ARM 嵌入式 编译系列 2.4 -- GCC 编译参数学习 -Wl,--gc-sections 】

    请阅读 【嵌入式开发学习必备专栏 之 ARM GCC 编译专栏】 在使用 GCC (GNU Compiler Collection) 进行编译时,可以通过不同的编译参数(标志)来控制编译行为、优化级别、警告输出等。以下是您列出的一些 GCC 编译参数的介绍: 参数 作用 –all-warnings 与-Wall 相同。 请改用后一个选

    2024年01月22日
    浏览(85)
  • 全志V3S嵌入式驱动开发(开发环境再升级)

    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】         前面我们陆陆续续开发了差不多有10个驱动,涉及到网口、串口、音频和视频等几个方面。但是整个开发的效率还是比较低的。每次开发调试的时候都很麻烦,譬如说,如果是驱动代码

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包