通过传感器能够实现对家居环境中的温度、湿度与光照强度进行采集;当室内温度过高或者湿度过低时,通过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有两个模块,这两个模块用的程序不太一样