手把手教你做基于stm32的红外、语音、按键智能灯光控制(下)

目录:

    • 4.6. DHT11温湿度传感器模块
    • 4.7. 语音识别模块
    • 4.7. OLED显示屏模块
  • 5. 不同的工作模式
  • 6. 总结

在接着(上)写之前,首先来看一下效果:
链接: link

4.6. DHT11温湿度传感器模块

这个模块主要就是用来监测环境温度的,没有什么其他的作用
.c文件

#include "stm32f10x.h"
#include "dht11.h"
#include "delay.h"

uint8_t dat[5]={0x00,0x00,0x00,0x00,0x00};    //存储读取的温湿度信息
uint32_t sum=0;         //存放校验时的求和

/****************************************
设置PB12端口为输出
*****************************************/
void DHT11_PortOutput(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;
 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//输出50MHz
 GPIO_Init(GPIOB,&GPIO_InitStructure);
}

/****************************************
设置PB12端口为输入
*****************************************/
void DHT11_PortInput(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;
 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//推挽输出
 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//输出50MHz
 GPIO_Init(GPIOB,&GPIO_InitStructure);
}

/****************************************
函数名称:void DHT_Read_Byte()
函数功能:对DHT的数据中的一个字节读取函数
输入参数:无
返回值:无
*****************************************/
uint8_t DHT_Read_Byte(void)
{
  uint8_t temp;      //存放读取到的位数据
	uint8_t ReadDat = 0;
  uint8_t i;
	uint8_t retry = 0;
  for(i=0;i<8;i++)
  {
    while(DHT11 ==0 && retry < 100)     //等待DHT11输出高电平
		{
			delay_us(1);
			retry++;
		}
		retry = 0;
    delay_us(30);          //延时30us,由于‘0’代码高电平时间26~28us,'1'代码高电平时间70us,延时30us可判断出是1,还是0
    temp = 0;             //先将寄存器清零
    if(DHT11 ==1)        //延时30us之后如果还是高电平,证明为1代码
      temp = 1;            //将1存储
    while(DHT11 ==1 && retry < 100)      //等待信号被拉低,跳出
		{
			delay_us(1);
			retry++;			
		}
		retry = 0;
    ReadDat<<=1;           //数据左移1位,存放新得到的数据
    ReadDat|= temp;         //新得到的数据放到最后1位
  }
	return ReadDat;
}

/*********************************************
函数名称:unsigned char DHT_Read()
函数功能:读取DHT11的温湿度
输入参数:无
返回值: flag--数据读取、校验成功标志
*********************************************/
uint8_t DHT_Read(void)
{
  uint8_t i;
	uint8_t retry = 0;
  DHT11_PortOutput();           //端口方向设置为输出
  DHT11_LOW;           //端口数据拉低
  delay_ms(18);          //延时18ms,时序要求
  DHT11_HIGH;           //端口数据拉高
  delay_us(40);          //延时40us,
  DHT11_PortInput();           //方向设置为输入
  delay_us(20);          //延时20us
  if(DHT11 ==0)          //如果读取到低电平,证明DHT11响应
  {
    while(DHT11 ==0 && retry < 100)  //等待变高电平
		{
			delay_us(1);
			retry++;				
		}
		retry = 0;
    while(DHT11 ==1 && retry < 100) //等待变低电平
		{
			delay_us(1);
			retry++;	
		}
		retry = 0;
    for(i=0;i<5;i++)    //循环5次将40位读出
     {
      dat[i] = DHT_Read_Byte();    //读出1个字节
     }
    delay_us(50);         //最后延时等待50us
  }
  sum=dat[0]+dat[1]+dat[2]+dat[3];     //前4个字节数据的和
  if(dat[4]==(u8)(sum))     //前4个数据和的末8位要和第5个数据相等,才算读取正确
    {
      return 1;                  //校验正确,返回1
    }
  else
     return 0;                  //校验错误,返回0
}





.h文件

#ifndef  __DHT11_H__
#define  __DHT11_H__


#define  DHT11  GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)
#define  DHT11_HIGH  GPIO_SetBits(GPIOB,GPIO_Pin_12)
#define  DHT11_LOW  GPIO_ResetBits(GPIOB,GPIO_Pin_12)

void DHT11_PortOutput(void);
void DHT11_PortInput(void);
uint8_t DHT_Read_Byte(void);
uint8_t DHT_Read(void);

#endif

4.7. 语音识别模块

这里要注意,语音识别模块本身也是一个51单片机,所以说这个语音识别模块的代码仅仅是语音模块的51单片机与stm32进行交互的代码,并不是51单片机的代码,但是一般来讲,商家给你发货以后,都会在里面提前烧录上代码,所以我们不用去管51里面的代码。
.c文件

#include "stm32f10x.h"                  // Device header
#include "voice.h"

/*
PB10   :TXD
PB11   : RXD
*/
extern uint32_t flag_led_on_off;
//变量引用
//变量声明
u8 RXBUF[20];       //串口存储数组
u8 RXOVER=0;        //串口接收标志位
u8 RXCOUNT=0;       //串口计数变量  
u8 i;               //清空数组变量

//串口IO初始化函数
void USART3_Init(u32 bound)
{
	GPIO_InitTypeDef GPIO_InitStructure;         //IO端口的初始化
	USART_InitTypeDef USART_InitStructure;			 //串口的初始化
	NVIC_InitTypeDef NVIC_InitStructure;         //使能中断接收
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能IO端口的时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //使能串口的时钟 
	
	//发送
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_10;  //发送引脚
	GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	//接收
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_11;  //接收引脚
	GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);

	USART_InitStructure.USART_BaudRate = bound;    //设置传输的波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;  //设置传输一帧数据的数据位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;       //一位停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;					 //无奇偶校验位
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  //能使接收的发送
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //无硬件流控制
	USART_Init(USART3,&USART_InitStructure);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);          //优先级分组
	NVIC_InitStructure.NVIC_IRQChannel= USART3_IRQn;         //开启串口2的中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0; //抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       //响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	

	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE); //使能串口接收
	USART_Cmd(USART3,ENABLE);               //使能串口2
	
}

/*
函数名:USART3中断服务函数
功能:  接收数据
注意:接收数据长度可调:RXCOUNT
*/
void USART3_IRQHandler(void)
{
	u8 temp;
  if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
  {
		USART_ClearITPendingBit(USART3,USART_IT_RXNE);
		temp = USART_ReceiveData(USART3);
		if(temp == '\n' || RXCOUNT == 20)   //判断是否接收到一个完整字符
		{
			RXCOUNT = 0;
			RXOVER =1;    //接收数据完成标志位置1
			USART_ITConfig(USART3,USART_IT_RXNE,DISABLE);//失能串口接收中断标志	
		}
		else
		{
			RXBUF[RXCOUNT] = temp;   //依次存放到数组中
			RXCOUNT++;		           //字符长度变化
		}
	}
}

//串口处理函数
void USART_Deal(void)
{
		if(RXOVER)
		{
			RXOVER = 0;    //清除接收标志位
			switch(RXBUF[0]-48)
			{
				case   1:
					flag_led_on_off=1;   //点亮小灯
					break;
				
				case   2:
					flag_led_on_off=0; //熄灭小灯
					break;	
				
				default: 
					break;			
			}
			for(i=0;i<20;i++)            //将已接收数据的数组清空:共20个字符长度
			{
				 RXBUF[i] = 0;          	 //重置数据缓存区
			}
			USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//始能串口接收 
		}
}

.h文件

#ifndef    __VOICE_H
#define   __VOICE_H



void USART3_Init(u32 bound);
void USART_Deal(void);



#endif

如果51单片机里面没有代码,就要使用串口工具进行烧录,需要问商家要源码,然后将hex文件烧录到里面。

4.7. OLED显示屏模块

OLED显示模块主要是用来显示和调试用的

OLED显示程序包括字库程序太大,放到以下链接中去下载,下载设置了0积分。
https://download.csdn.net/download/nbbskk/87238933

5. 不同的工作模式

以上第四章节完成了各个模块的驱动程序,那么接下来就要实现手动模式、自动模式和模式切换的代码了。

模式切换:

  1. 当最小系统板上电以后,自动进入模式选择界面,通过按键和红外遥控器可以进行模式的选择,选择的模式可用通过显示屏显示。
  2. 在选择完成相应的模式以后,也可以通过按键或者红外遥控器选择进入手动模式或者自动模式,进入相应模式以后,就可以执行相应的功能。
  3. 当进入相应模式以后,如果想要切换模式,可以通过手动退出,然后继续在模式选择界面进行选择。

.c文件

#include "stm32f10x.h"                  // Device header
#include "oled.h"
#include "mode_option.h"
#include "auto_mode.h"
#include "manu_mode.h"
#include "remote.h"


extern uint32_t flag_auto_manu;
extern uint32_t flag_in_system;
uint32_t flag_break_mode=0;

void mode_option_show(void)//文字显示
{

	OLED_ShowChinese(35,0,0,16,1);//选
	OLED_ShowChinese(51,0,1,16,1);//择
	OLED_ShowChinese(67,0,2,16,1);//模
	OLED_ShowChinese(83,0,3,16,1);//式
	OLED_Refresh();
}


void auto_manu_option(void)//选择自动模式或者手动模式的函数
{
	if(flag_auto_manu==0)
	{
		OLED_ShowChinese(50,30,4,16,1);//手
		OLED_ShowChinese(66,30,5,16,1);//动
		OLED_Refresh();
	}
		
	else
	{
		OLED_ShowChinese(50,30,6,16,1);//自
		OLED_ShowChinese(66,30,5,16,1);//动
		OLED_Refresh();	
	}
		
}


void system_in_auto_manu(void)//选择是否进入系统的函数
{
		if(flag_auto_manu==0&&flag_in_system==1)//如果手自动标志位为0并且进入系统标志位为1,则进入手动模式
		{
			flag_break_mode=0;//退出标志位置为0
			flag_in_system=0;//进入系统标志位置为0
			manu_mode_init();//手动模式初始化
			manu_go();//手动模式运行
		}
		else if(flag_auto_manu==1&&flag_in_system==1)//如果手自动标志位为1并且进入系统标志位为1,则进入自动模式
		{
			flag_break_mode=0;
			flag_in_system=0;
			auto_mode_init();
			auto_go();
		}
}



.h文件

#ifndef   __MODE_OPTION_H
#define  __MODE_OPTION_H

void mode_option_show(void);
void auto_manu_option(void);
void system_in_auto_manu(void);


#endif

手动模式:

  1. 红外控制模式:使用带有红外遥控器的用户可以通过遥控器来对智能灯光进行控制。用户可以通过遥控器上的按键来打开/关闭灯光。
  2. 语音控制模式:使用语音助手的用户可以通过语音命令来控制智能灯光。用户可以说出指令,如“开灯”、“关灯”等,系统会解析语音指令并执行相应的操作。
  3. 按键控制模式:用户可以通过智能灯光控制系统配备的按键来控制灯光。
    .c文件
#include "stm32f10x.h"                  // Device header
#include "manu_mode.h"
#include "LED.h"
#include "remote.h"
#include "dht11.h"
#include "oled.h"
#include "voice.h"

extern uint32_t flag_break_mode;
extern uint32_t flag_led_on_off;
extern uint8_t dat[5];//存放温度数值

void manu_mode_init(void)
{
	LED_Init();//led灯初始化
	USART3_Init(9600);//语音模块初始化
	OLED_Clear();
	
	OLED_ShowChinese(0,0,7,16,1);//灯
	OLED_ShowChinese(16,0,8,16,1);//光
	OLED_ShowChar(32,0,':',16,1);
	OLED_ShowChinese(0,16,9,16,1);//温
	OLED_ShowChinese(16,16,10,16,1);//度
	OLED_ShowChar(32,16,':',16,1);
}


void manu_go(void)
{
	flag_led_on_off=0;//进入模式后,默认关灯
	while(1)
	{
		remote_receive();//循环检测红外遥控
		USART_Deal();//循环检测语音模块
		if(flag_break_mode==1)//判断是否需要退出
		{
			flag_break_mode=0;
			OLED_Clear();
			break;
		}
		if(flag_led_on_off==0)//如果LED灯标志位为0,LED灯关闭
		{
			LED1_off();
			OLED_ShowChinese(40,0,12,16,1);//关
		}
		else//如果LED灯标志位为1,LED灯打开
		{
			LED1_on();
			OLED_ShowChinese(40,0,13,16,1);//开
		}
		if(DHT_Read())//读到DHT11温湿度传感器的数值并显示
		   {
			   OLED_ShowNum(40,16,dat[2],2,16,1);
			   OLED_ShowChar(56,16,'.',16,1);
			   OLED_ShowNum(60,16,dat[3],1,16,1);
			   OLED_ShowChinese(70,16,10,16,1);//度
			   OLED_Refresh();
		   }
	}
}






.h文件

#ifndef  __MANU_MODE_H
#define __MANU_MODE_H


void manu_mode_init(void);
void manu_go(void);



#endif

自动模式:

  1. 当外部环境变暗的时候,光照度传感器会检测到光照度的降低并输出相应的信号,这些信号会传递给单片机进行处理,并且会使得相应的标志位进行标记。
  2. 当红外检测传感器检测到周围有人的时候,也会产生相应的信号传递给单片机,将相应的标志位进行置位。
  3. 当同时满足外部环境变暗并且周围有人的时候,这是系统会自动处理事件,将灯打开;当其中一个事件不满足的时候,灯光就会关闭。
    .c文件
#include "stm32f10x.h"                  // Device header
#include "auto_mode.h"
#include "LED.h"
#include "remote.h"
#include "delay.h"
#include "bh1750.h"
#include "oled.h"
#include "infrared.h"
#include "dht11.h"

extern uint32_t flag_break_mode;
extern uint32_t flag_infrared;
uint16_t light_value=0;
extern uint8_t dat[5];

void auto_mode_init(void)
{
	LED_Init();
	infrared_Init();
	BH1750_Config_Init();     //BH1750的初始化
	bh_data_send(BHPowOn);   //打开模块等待测量命令
    bh_data_send(BHReset);     //重置数据寄存器值在PowerOn模式下有效
    bh_data_send(BHModeL);      //低分辨率 单位4lx  测量时间16ms 

    delay_ms(180);             //等待测量结束延时180ms,保证通讯    
	
	OLED_Clear();
	
	OLED_ShowChinese(0,0,7,16,1);//灯
	OLED_ShowChinese(16,0,8,16,1);//光
	OLED_ShowChar(32,0,':',16,1);
	OLED_ShowChinese(0,16,9,16,1);//温
	OLED_ShowChinese(16,16,10,16,1);//度
	OLED_ShowChar(32,16,':',16,1);
	OLED_ShowChinese(0,32,11,16,1);//亮
	OLED_ShowChinese(16,32,10,16,1);//度
	OLED_ShowChar(32,32,':',16,1);
}


void auto_go(void)
{
	while(1)
	{
		remote_receive();
		if(flag_break_mode==1)
		{
			flag_break_mode=0;
			OLED_Clear();
			break;
		}
		light_value = bh_data_read()*4/1.2;  //光照强度的计算公式 = 寄存器值*分辨率/1.2 
		infrared_read();//检测红外检测模块的值
		OLED_ShowNum(40,32,light_value,4,16,1);//显示亮度值
		OLED_ShowString(72,32,(uint8_t*)"lx",16,1);//显示单位
		if(light_value<1000&&flag_infrared==1)//当亮度小于1000lx,并且红外检测模块标志位置为1,则开灯
		{
			LED1_on();
			OLED_ShowChinese(40,0,13,16,1);//开
		}		
		else//否则关灯
		{
			LED1_off();
			OLED_ShowChinese(40,0,12,16,1);//关
			
		}	
		if(DHT_Read())
		   {
			   OLED_ShowNum(40,16,dat[2],2,16,1);
			   OLED_ShowChar(56,16,'.',16,1);
			   OLED_ShowNum(60,16,dat[3],1,16,1);
			   OLED_ShowChinese(70,16,10,16,1);//度
			   OLED_Refresh();
		   }
	}
}




.h文件

#ifndef   __AUTO_MODE_H
#define  __AUTO_MODE_H

void auto_mode_init(void);
void auto_go(void);



#endif

6. 总结

基于stm32的红外、语音、按键智能灯光控制基本就可以实现了,如果想要完整的源码、原理图、PCB、流程图可以私信我,谢谢大家!!!

你可能感兴趣的:(stm32,嵌入式硬件,单片机)