技能梳理16@stm32+lora+oled+dht11+bh1750+红外

167 阅读3分钟

通过传感器能够实现对家居环境中的温度、湿度与光照强度进行采集;当室内温度过高或者湿度过低时,通过LED灯与蜂鸣器进行声光报警;从机作为数据采集部分,将采集的数据通过LoRa协议发送给主机,主机显示;在防盗功能开启后,通过红外传感器检测室内是否有人,如果有人判断为有人入室偷盗,则进行声光报警;采集终端负责采集温湿度,光照强度,还有红外的数据;如果温湿度,光照强度超出设定值,或者红外监测到有人,则进行报警。这些数据通过lora显示到主机上

1、项目简介

在这里插入图片描述

2、实现逻辑

#从机检测温湿度、光照强度、红外状态
#从机将数据显示到oled及发送到主机,主机也显示到oled上
#从机判读是否数据超标,超标就进行报警
#从机有一个引脚是控制防盗功能的开启关闭,如果引脚拉高,红外检测到人,进行声光报警,然后发送给主机端,oled显示

3、应用场景

#远程环境参数检测
#远程防盗

4、核心代码梳理

//主从机代码一体
uint8_t rx_ok, rx_order, led_sta = 0,  alarm_sta = 0, beep_sta = 0, people_sta = 0, gate_sta = 0 ,gate = 0, gate_last = 0, gate_num = 1;
float temp, hump, alarm, watch;
int   intT, decT, intH, decH;
uint16_t temperature;
uint16_t humidity;
unsigned short light_temp;
uint32_t light;

uint8_t tx_oled[14] = {0}, BUF[5];

#define DHT11_DQ_OUT_LOW HAL_GPIO_WritePin(GPIOA, DHT11_Pin, GPIO_PIN_RESET)
#define DHT11_DQ_OUT_HIGH HAL_GPIO_WritePin(GPIOA, DHT11_Pin, GPIO_PIN_SET)
#define DHT11_DQ_IN HAL_GPIO_ReadPin(GPIOA, DHT11_Pin)



#define SET_SCK_0()         HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin, GPIO_PIN_RESET)
#define SET_SCK_1()         HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin, GPIO_PIN_SET)
#define SET_DTA_0()         HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin, GPIO_PIN_RESET)
#define SET_DTA_1()         HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin, GPIO_PIN_SET)
#define GET_DTA()           HAL_GPIO_ReadPin(GPIOB, BH1750_SDA_Pin)
#define GET_SCK()           HAL_GPIO_ReadPin(GPIOB, BH1750_SCL_Pin)

#define BH1750_DELAY        40   //us
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
void delay_us(uint32_t delay);
unsigned short GetLight(void);
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//temp hump
void DHT11_IO_IN(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = DHT11_Pin;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void DHT11_IO_OUT(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = DHT11_Pin;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void DHT11_Rst(void) {
    DHT11_IO_OUT(); 	//
    DHT11_DQ_OUT_LOW; 	//
    HAL_Delay(20);    	//
    DHT11_DQ_OUT_HIGH; 	//
    delay_us(30);     	//
}

uint8_t DHT11_Check(void) {
    uint8_t retry=0;
    DHT11_IO_IN();
    while (DHT11_DQ_IN && retry<100) {
        retry++;
        delay_us(1);
    };
    if(retry>=100)return 1;
    else retry=0;
    while (!DHT11_DQ_IN&&retry<100) {
        retry++;
        delay_us(1);
    };
    if(retry>=100)return 1;
    return 0;	//DHT11
}

uint8_t DHT11_Read_Bit(void) {
    uint8_t 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);
    if(DHT11_DQ_IN)return 1;
    else return 0;
}

uint8_t DHT11_Read_Byte(void) {
    uint8_t i,dat;
    dat=0;
    for (i=0; i<8; i++) {
        dat<<=1;
        dat|=DHT11_Read_Bit();
    }
    return dat;
}

uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi) {
    uint8_t buf[5];
    uint8_t i;
    DHT11_Rst();
    if(DHT11_Check()==0) {
        for(i=0; i<5; i++) {
            buf[i]=DHT11_Read_Byte();
        }
        if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]) {
            *humi=(buf[0]<<8) + buf[1];
            *temp=(buf[2]<<8) + buf[3];
        }
    } else return 1;
    return 0;
}

uint8_t DHT11_Init(void) {
    DHT11_Rst();
    return DHT11_Check();
}




bh1750****************//
/***开始信号***/
void BH1750_Start()
{
    HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin,GPIO_PIN_SET);                    //拉高数据线
    HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_SET);                   //拉高时钟线
    delay_us(5);                 //延时
    HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin,GPIO_PIN_RESET);                    //产生下降沿
    delay_us(5);                 //延时
    HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_RESET);                    //拉低时钟线
}

/*****停止信号******/
void BH1750_Stop()
{
    HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin,GPIO_PIN_RESET);                   //拉低数据线
    HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_SET);                      //拉高时钟线
    delay_us(5);                 //延时
    HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin,GPIO_PIN_SET);                    //产生上升沿
    delay_us(5);                 //延时
}
/**************************************
发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void BH1750_SendACK(int ack)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


    if(ack == 1)   //写应答信号
        HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin,GPIO_PIN_SET);
    else if(ack == 0)
        HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin,GPIO_PIN_RESET);
    else
        return;

    HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_SET);      //拉高时钟线
    delay_us(5);                //延时
    HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_RESET);      //拉低时钟线
    delay_us(5);                 //延时
}
/**************************************
接收应答信号
**************************************/
int BH1750_RecvACK()
{
    int mcy;
    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;  /*这里一定要设成输入上拉,否则不能读出数据*/
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Pin = BH1750_SDA_Pin;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_SET);            //拉高时钟线
    delay_us(5);                 //延时

    if(HAL_GPIO_ReadPin( GPIOB, BH1750_SDA_Pin ) == 1 )//读应答信号
        mcy = 1 ;
    else
        mcy = 0 ;

    HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_RESET);                    //拉低时钟线
    delay_us(5);                 //延时

    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init( GPIOB, &GPIO_InitStruct );

    return mcy;
}

/**************************************
向IIC总线发送一个字节数据
**************************************/
void BH1750_SendByte(uint8_t dat)
{
    uint8_t i;

    HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_RESET);                //拉低时钟线
    delay_us(2);             //延时
    for (i=0; i<8; i++)         //8位计数器
    {
        if( 0X80 & dat )
            HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin,GPIO_PIN_SET);
        else
            HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin,GPIO_PIN_RESET);

        dat <<= 1;
        HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_SET);               //拉高时钟线
        delay_us(2);             //延时
        HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_RESET);                //拉低时钟线
        delay_us(2);             //延时
    }
    //BH1750_RecvACK();
}

/**************************************
从IIC总线读取一个字节数据
**************************************/
uint8_t BH1750_RecvByte()
{
    uint8_t i;
    uint8_t dat = 0;
    uint8_t bit;

    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;   /*这里一定要设成输入上拉,否则不能读出数据*/
    GPIO_InitStruct.Pin = BH1750_SDA_Pin;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init( GPIOB, &GPIO_InitStruct );

    //HAL_GPIO_WritePin(GPIOB, BH1750_SDA_Pin,GPIO_PIN_SET);          //使能内部上拉,准备读取数据,

    for (i=0; i<8; i++)         //8位计数器
    {
        //dat <<= 1;
        HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_RESET);               //拉高时钟线
        delay_us(2);             //延时
        HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_SET);
        dat <<= 1;
        HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_SET);
        if( SET == HAL_GPIO_ReadPin( GPIOB, BH1750_SDA_Pin ) )
            dat |= 0X01;

        //拉低时钟线
        delay_us(1);             //延时
    }
    HAL_GPIO_WritePin(GPIOB, BH1750_SCL_Pin,GPIO_PIN_RESET);
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init( GPIOB, &GPIO_InitStruct );
    return dat;
}

void Init_BH1750()
{
    BH1750_Start();
    BH1750_SendByte(0x46);
    BH1750_SendByte(0x01);
    BH1750_Stop();
}


void Single_Write_BH1750(u8 REG_Address)
{
    BH1750_Start();//起始信号
    BH1750_SendByte(0x46);//发送设备地址+写信号
    BH1750_RecvACK();
    BH1750_SendByte(REG_Address);//内部寄存器地址,请参考中文pdf22页
    BH1750_RecvACK();
    BH1750_Stop();//发送停止信号
}


/*********************************************************
连续读出BH1750内部数据
*********************************************************/
void Multiple_Read_BH1750()
{
    BH1750_Start();//起始信号
    BH1750_SendByte(0x47);//发送设备地址+读信号
    BH1750_RecvACK();
    BUF[0] = BH1750_RecvByte();//BUF[0]存储0x32地址中的数据
    BH1750_SendACK(0);
    BUF[1] = BH1750_RecvByte();//BUF[0]存储0x32地址中的数据
    BH1750_SendACK(1);
    BH1750_Stop();//停止信号
    HAL_Delay(5);
}

//连续读出BH1750内部数据
void mread(void)
{
    u8 i=0;
    Single_Write_BH1750(0x01);// power on
    Single_Write_BH1750(0x10);// H- resolution mode
    HAL_Delay(18);//延时18ms

    Multiple_Read_BH1750();//连续读出数据,存储在BUF中
}

/* 向oled平台发数据函数
 * return 1 ok; 0 fail
 */
uint8_t send_oled(void)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)tx_oled, 14, 0xFFFF); //发送

 //   HAL_Delay(1000);
    return 1;
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
    uint32_t clk;
    tx_oled[0] = 0xff;
    tx_oled[1] = 0x74;
    tx_oled[13] = 0xff;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_ADC1_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
	
	HAL_GPIO_WritePin(GPIOA, beep_rx_Pin|beep_tx_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOA, alarm_led_Pin, GPIO_PIN_RESET);
#if  RX_OLED
    OLED_Init();
    OLED_ColorTurn(0);//
    OLED_DisplayTurn(0);//
    OLED_Refresh();
    OLED_Clear();
    OLED_ShowString(0,0,"TEMP:    .    C",16);
    OLED_ShowString(0,14,"HUMP:    .    %",16);
    OLED_ShowString(0,28,"LIGHT:      LUX",16);
	OLED_ShowString(0,42,"PEO:   ALM:   ",16);
    OLED_Refresh();
		
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);//open uart1 RXNE
#endif

#if  TX_SENSOR
    /****dht11*****/
    uint8_t int_num = 3;
    while(int_num--) {
        HAL_Delay(500);
        DHT11_Init();
    }
#endif
		
    //Init_BH1750();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while (1)
    {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

#if  TX_SENSOR
        DHT11_Read_Data(&temperature,&humidity);
        tx_oled[5] = temperature>>8;
        tx_oled[6] = temperature&0xff;
        tx_oled[7] = humidity>>8;
        tx_oled[8] = humidity&0xff;


        mread();
        light_temp = BUF[0];
        light_temp=(light_temp<<8)+BUF[1];//合成数据
        light=light_temp/1.2;
        tx_oled[9] = (light>>8)&0xff;
        tx_oled[10] = light&0xff;

				if(!HAL_GPIO_ReadPin(infr_people_GPIO_Port, infr_people_Pin))//红外检测人
				{
					tx_oled[11] = 1;
				}
				else tx_oled[11] = 0;
				
				
				if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9)) //门锁
					gate = 1;
				else gate = 0;
				if((gate_last) && (!gate) )
					gate_num++;
				
				gate_last = gate;
					
				if(gate_num%2)
					gate_sta = 0;
				else gate_sta = 1;
				
				HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, !gate_sta);
				
				if((gate_sta && tx_oled[11]) || (tx_oled[5] >= 40) || (tx_oled[7] <= 20))
				{
					tx_oled[12] = 1; //alarm
					HAL_GPIO_WritePin(GPIOA, beep_tx_Pin, GPIO_PIN_RESET);
				}
				else 
				{
					tx_oled[12] = 0;
					HAL_GPIO_WritePin(GPIOA, beep_tx_Pin, GPIO_PIN_SET);
				}
				
        if(clk % 10 == 0) //
            send_oled();

        HAL_Delay(100);
        clk++;
#endif

#if RX_OLED
	alarm_sta = tx_oled[12];
	OLED_ShowNum(87,42,alarm_sta,1,16);
	if(alarm_sta)
	{
		HAL_GPIO_WritePin(GPIOA, beep_rx_Pin, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOA, alarm_led_Pin, GPIO_PIN_SET);
	}
	else
	{
		HAL_GPIO_WritePin(GPIOA, beep_rx_Pin, GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOA, alarm_led_Pin, GPIO_PIN_RESET);
	}
	
	people_sta = tx_oled[11];
	OLED_ShowNum(33,42,people_sta,1,16);
	
	light_temp=(tx_oled[9]<<8) + tx_oled[10];//合成数据
  light=light_temp/1.2;
	OLED_ShowNum(53,28,light,5,16);//LIGHT
	
	
	OLED_ShowNum(53,0,tx_oled[5],2,16); //temp
	OLED_ShowNum(77,0,tx_oled[6],2,16);
	OLED_ShowNum(53,14,tx_oled[7],2,16);//hump
	OLED_ShowNum(77,14,tx_oled[8],2,16);
	
	
	OLED_Refresh();

#endif
    }
  /* USER CODE END 3 */
}

5、部分参考资料

#硬件原理图 pcb(比较简单的直插)见资料包
在这里插入图片描述
在这里插入图片描述

6、注意事项

#主从机的硬件是一样的,代码用的一个,通过宏定义区分选择固件 #define TX_SENSOR 0
#define RX_OLED 1
#这个lora用到现成模块,直接可以串口透传
#硬件比较简单,按着原理图用洞洞板也可以搭建
#淘宝上销量比较高的bh1750有两个模块,这两个模块用的程序不太一样

完整可运行项目地址