STM32与NBIOT智慧农业

Pursue

整体介绍

1. 主控
  采用搭载STM32L4R5ZI低功耗芯片的ST官方NUCLEO-L4R5ZI开发板,使用stm32cubeMX配置,HAL库开发。
l4r5zi

2. 传感器部分
  使用DHT11采集环境温湿度,BH1750采集光照强度,采用电容式土壤湿度传感器,JW01 CO2,HCHO,TVOC三合一传感器。
3. 按键开关
  使用了一个RGB灯来代表植物生长灯,设有红、蓝、绿、白四种颜色;配备6个按键,分别控制RGB灯、板载LED2、4路继电器。
4. NB-IOT
  采用安信可EC-01F-kit开发板,通过串口与单片机通讯。
nb
5. 阿里云物联网平台
  将采集到的数据通过NB-IOT模组通过MQTT协议发送到阿里云物联网平台,并利用IOT-Studio简单绘制用户端页面。

ali

liuc


配置

1. 时钟,定时器配置
  首先配置RCC,SYS。其次配置定时器TIM1实现微秒级延时,用来读取DHT11温湿度数据,具体可以参考DHT11数据手册。
tim1

2. 引脚配置

GPIO 引脚 对应功能
推挽输出 PB7,PF15 主灯和DHT11温湿度传感器
LPUART PG7(TX),PG8(RX) 与上位机通信串口,通过板载usb连接
USART2 PD5(TX),PD6(RX) JW01二氧化碳传感器
I2C1 PB8(SCL),PB9(SDA) BH1750光照强度传感器
TIM2 PA0,PA1,PA2 RGB植物生长灯
推挽输出 PG10,PG11,PG13,PG15 四路继电器开关
上拉输入(EXTI) PA4,PB0,PC1,PD3,PD12,PG2 按键中断,分别控制主灯,RGB,四个继电器
ADC1_IN1 PC0 土壤湿度传感器

继电器可连接水泵,风扇等,实现控制开关。

示例代码

1. DHT11温湿度传感器
   DHT11.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include "dht11.h"

extern TIM_HandleTypeDef htim1;

static void DATA_OUTPUT(u8 flg);//DATA输出
static u8 DATA_INPUT(void);//DATA输入
static u8 DH11_Read_Byte(void);//DH11读信号

u8 DH11_Read(void);//读取DH11温度和湿度

static void Test(void);//测试程序

DH11_DATA DH11_data;

void Delay_us(uint16_t us)
{ //微秒延时
uint16_t differ = 0xffff-us-5;
__HAL_TIM_SET_COUNTER(&htim1,differ); //设定TIM1计数器起始值
HAL_TIM_Base_Start(&htim1); //启动定时器

while(differ < 0xffff-5){ //判断
differ = __HAL_TIM_GET_COUNTER(&htim1); //查询计数器的计数值
}
HAL_TIM_Base_Stop(&htim1);
}


void DATA_OUTPUT(u8 flg)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};

GPIO_InitStruct.Pin = DATA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DATA_GPIO_Port, &GPIO_InitStruct);

if(flg==0)
{
DATA_RESET();
}
else
{
DATA_SET();
}
}

u8 DATA_INPUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
u8 flg=0;

GPIO_InitStruct.Pin = DATA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(DATA_GPIO_Port, &GPIO_InitStruct);

if(DATA_READ()==GPIO_PIN_RESET)
{
flg=0;
}
else
{
flg=1;
}

return flg;
}

u8 DH11_Read_Byte(void)
{
u8 ReadDat=0;
u8 temp=0;
u8 retry=0;
u8 i=0;

for(i=0;i<8;i++)
{
while(DATA_READ()==0&&retry<100)//等待直到DHT11输出高电平
{
Delay_us(1);
retry++;
}
retry=0;
Delay_us(40);
if(DATA_READ()==1)
{
temp=1;
}
else
{
temp=0;
}
while(DATA_READ()==1&&retry<100)//等待直到DHT11输出低电平,表示退出。本轮1bit信号接收完毕。
{
Delay_us(1);
retry++;
}
retry=0;
ReadDat<<=1;
ReadDat|=temp;
}

return ReadDat;
}

u8 DH11_Read(void)
{
u8 retry=0;
u8 i=0;

DATA_OUTPUT(0);//设置为输出模式MCU向DH11发送信号
HAL_Delay(18);
DATA_SET();
Delay_us(20);

DATA_INPUT();//设置为输入模式DH11向MCU发送信号
Delay_us(20);
if(DATA_READ()==0)
{
while(DATA_READ()==0&&retry<100)
{
Delay_us(1);
retry=0;
}
retry=0;
while(DATA_READ()==1&&retry<100)
{
Delay_us(1);
retry++;
}
retry=0;

for(i=0;i<5;i++)//Data[0]湿度, Data[2]温度。Data[1]和Data[3]分别为0和2的小数位。Data[4]用于校验。
{
DH11_data.Data[i]=DH11_Read_Byte();
}
Delay_us(50);
}
u32 sum=DH11_data.Data[0]+DH11_data.Data[1]+DH11_data.Data[2]+DH11_data.Data[3];//校验
if((sum)==DH11_data.Data[4])
{
DH11_data.humidity=DH11_data.Data[0];//获取湿度
DH11_data.temp=DH11_data.Data[2];//获取温度
return 1;
}
else
{
return 0;
}
}

void Test(void)
{
if(DH11_Read())
{
DH11_data.index++;
if(DH11_data.index>=128)
{
DH11_data.index=0;
}
}

}


void DH11_Task(void)
{
Test();
}


DHT11.H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef _DH11_H_
#define _DH11_H_

#include"main.h"

#define u8 unsigned char
#define u16 unsigned short
#define u32 unsigned int

//DATA IO的定义
#define DATA_SET() HAL_GPIO_WritePin(DATA_GPIO_Port, DATA_Pin, GPIO_PIN_SET)
#define DATA_RESET() HAL_GPIO_WritePin(DATA_GPIO_Port, DATA_Pin, GPIO_PIN_RESET)

#define DATA_READ() HAL_GPIO_ReadPin(DATA_GPIO_Port,DATA_Pin)

typedef struct
{
u8 Data[5];//数据存放数组
u8 index;
u8 temp;//温度
u8 humidity;//湿度

}DH11_DATA;

extern DH11_DATA DH11_data;//DH11属性封装

void DH11_Task(void);//后台轮询调用

#define DATA_Pin GPIO_PIN_15
#define DATA_GPIO_Port GPIOF


#endif

实现

1
2
3
4
5
6
7
8
int main(void)
{
HAL_TIM_Base_Start(&htim1);
while(1)
{
DH11_Task();
}
}
2. BH1750光照强度传感器
   BH1750.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include "bh1750.h"
#include "i2c.h"


/*i2c句柄*/
#define bh1750_i2c hi2c1

/*内部函数声明区*/
static uint8_t BH1750_Send_Cmd(BH1750_MODE cmd);
static uint8_t BH1750_Read_Dat(uint8_t* dat);
static uint16_t BH1750_Dat_To_Lux(uint8_t* dat);



/**
* @brief 向BH1750发送一条指令
* @param cmd —— BH1750工作模式指令(在BH1750_MODE中枚举定义)
* @retval 成功返回HAL_OK
*/
static uint8_t BH1750_Send_Cmd(BH1750_MODE cmd)
{
return HAL_I2C_Master_Transmit(&bh1750_i2c, BH1750_ADDR_WRITE, (uint8_t*)&cmd, 1, 0xFFFF);
}


/**
* @brief 从BH1750接收一次光强数据
* @param dat —— 存储光照强度的地址(两个字节数组)
* @retval 成功 —— 返回HAL_OK
*/
static uint8_t BH1750_Read_Dat(uint8_t* dat)
{
return HAL_I2C_Master_Receive(&bh1750_i2c, BH1750_ADDR_READ, dat, 2, 0XFFFF);
}


/**
* @brief 将BH1750的两个字节数据转换为光照强度值(0-65535)
* @param dat —— 存储光照强度的地址(两个字节数组)
* @retval 成功 —— 返回光照强度值
*/
static uint16_t BH1750_Dat_To_Lux(uint8_t* dat)
{
uint16_t lux = 0;
lux = dat[0];
lux <<= 8;
lux |= dat[1];
lux = (int)(lux / 1.2);

return lux;
}


/**
* @brief 返回光照强度值
* @param 无
* @retval 成功 —— 返回光照强度值
*/
uint16_t Get_BH1750_Value(void)
{
uint8_t dat[2] = {0}; //dat[0]是高字节,dat[1]是低字节
uint16_t lux;

if(HAL_OK != BH1750_Send_Cmd(ONCE_H_MODE))
{
return 0;
}
HAL_Delay(120);
if(HAL_OK != BH1750_Read_Dat(dat))
{
return 0;
}

lux = BH1750_Dat_To_Lux(dat);
return lux;
}

BH1750.H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#ifndef __BH1750_H_
#define __BH1750_H_

#include "stdint.h"

/*外部函数区*/
/*通过指针获取光照强度值*/
uint16_t Get_BH1750_Value(void);


/* //用法

uint16_t bh1750_lux;
bh1750_lux = Get_BH1750_Value();
printf("current: %5d lux\r\n", bh1750_lux);

*/


/*bh1750地址*/
#define BH1750_ADDR_WRITE 0x46 //01000110
#define BH1750_ADDR_READ 0x47 //01000111


typedef enum
{
POWER_OFF_CMD = 0x00, //断电:无激活状态
POWER_ON_CMD = 0x01, //通电:等待测量指令
RESET_REGISTER = 0x07, //重置数字寄存器(在断电状态下不起作用)
CONT_H_MODE = 0x10, //连续H分辨率模式:在11x分辨率下开始测量,测量时间120ms
CONT_H_MODE2 = 0x11, //连续H分辨率模式2:在0.51x分辨率下开始测量,测量时间120ms
CONT_L_MODE = 0x13, //连续L分辨率模式:在411分辨率下开始测量,测量时间16ms
ONCE_H_MODE = 0x20, //一次高分辨率模式:在11x分辨率下开始测量,测量时间120ms,测量后自动设置为断电模式
ONCE_H_MODE2 = 0x21, //一次高分辨率模式2:在0.51x分辨率下开始测量,测量时间120ms,测量后自动设置为断电模式
ONCE_L_MODE = 0x23 //一次低分辨率模式:在411x分辨率下开始测量,测量时间16ms,测量后自动设置为断电模式
} BH1750_MODE;




#endif /*__BH1750_H_*/

实现

1
2
int lux;
lux = Get_BH1750_Value();
3. JW01二氧化碳传感器
   采用串口中断与DMA接收数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//串口中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uint8_t sum = 0;
if(huart -> Instance == USART3)
{
if(rx_buf[0] == 44){

tvoc = (rx_buf[2]*256+rx_buf[3]) * 0.001;
ch2o = (rx_buf[4]*256+rx_buf[5]) * 0.001;
co2 = (rx_buf[6]*256+rx_buf[7]);

HAL_UART_Receive_DMA((UART_HandleTypeDef *)&huart3, (uint8_t *)rx_buf, 9);
}
else {
HAL_UART_DMAStop((UART_HandleTypeDef *)&huart3);
HAL_Delay(10);
HAL_UART_Receive_DMA((UART_HandleTypeDef *)&huart3, (uint8_t *)rx_buf, 9);
}
}
}
评论
目录
STM32与NBIOT智慧农业