1.知识百科
智慧灌溉是运用物联网、云计算、大数据等新一代信息技术,结合农业生产的实际需求,通过传感器采集土壤温湿度、光照强度等信息,利用无线传感网络传输到中央控制系统进行智能控制。智慧灌溉系统由传感器(水位传感器)、无线通信模块(GPRS/CDMA/WLAN/蓝牙)和计算机组成;在农业生产中,通过自动感知环境信息(温度、湿度),实时监控作物生长状况并做出判断和决策。
智慧灌溉
2.开发环境
本次智慧灌溉平台包含有硬件和软件两部分。其中硬件部分有 基于STM32的主控制器,USB接口水泵、稻田模型、水位监测传感器,硬件配置如下所所示:
- 主控制器
- 稻田模型
稻田模型中添加了水位监测传感器设备。
- 水泵
- 应用APP
3.硬件设计
4.软件设计
本次硬件主控MCU选择的是ST公司的基于Cortex-M3架构的STM32F103C8T6,供电部分是12V转5V,采用MP2359实现,5V转3.3V则采用AMS1117-3.3实现。软件设计通过HAL库+KEIL软件。
主控MCU: STM32F103C8T6
通信设备: ESP8266WIFI
传感器设备: 水位检测传感器
水泵: USB接口3W水泵
其他: RGB工作状态指示、串口调试接口、ST_Link下载口
4.1 ESP8266WIFI驱动
ESP8266系列无线模块是一个经济高效的WIFI SOC模块,支持标准IEEE802.11b/g/n协议,内置完整的TCP/IP协议栈。 用户可以使用此系列模块向现有设备添加网络功能,也可以构建独立的网络控制器。
- 支持STA、AP、STA+AP动作模式;
- 体积非常小的802.11b/g/n WiFi SOC模块
- 内置10bit高精度ADC采用低功率32位CPU,兼作应用程序处理器
- 支持USART、GPIO、IIC、PWM、ADC、SPI等接口时钟频率最大为160MHz
- 支持smart config、AirKiss一键网络支持多个休眠模式,深休眠电流低到20uA
- 嵌入式LWIP协议栈
- 支持SDK二次开发
- 通用AT指令可以快速使用支持串行本地升级和远程固件升级( FOTA )
本次采用通用AT指令开发,串口通信,波特率为115200,配置模式为AP+TCP服务器。
/*****************ESP8266初始化*****************
**形参:u8 *wifi_name -- 热点名称
** u8 *wifi_password -- 密码
** u16 port -- 端口号
**
**返回:0--成功,其他值 -- 失败
const char *AP_TCPSERVER[]=
{
"AT\r\n",//测试指令
"ATE0\r\n",//关闭回显
"AT+CWMODE=2\r\n",//--设置为AP(热点)模式
"AT+RST\r\n",//模块重启
"ATE0\r\n",//关闭回显
"AT+CWSAP=\"EPS8266_123\",\"01234567\",1,4\r\n", //--设置wifi信息
"AT+CIPMUX=1\r\n",//设置多连接
"AT+CIPSERVER=1,10\r\n", //--设置TCP服务器模式,端口号(0~65535)
"AT+CIFSR\r\n"//查询IP地址
};
************************************************/
u8 Esp8266_AP_TcpServer_Init(u8 *wifi_name,u8 *wifi_password,u16 port)
{
char buff[100];
char *p=NULL;
u8 i=0;
printf("1.发送测试指令\r\n");
if(Esp8266_SendCmdCheckStat("AT\r\n","OK\r\n"))return 1;
printf("2.关回显\r\n");
if(Esp8266_SendCmdCheckStat("ATE0\r\n","OK\r\n"))return 2;
printf("3.设置模式\r\n");
if(Esp8266_SendCmdCheckStat("AT+CWMODE=2\r\n","OK\r\n"))return 3;
printf("4.模块复位\r\n");
if(Esp8266_SendCmdCheckStat("AT+RST\r\n","OK\r\n"))return 4;
Delay_Ms(1000);
Delay_Ms(1000);
printf("5.关回显\r\n");
if(Esp8266_SendCmdCheckStat("ATE0\r\n","OK\r\n"))return 5;
//字符串拼接
snprintf(buff,sizeof(buff),"AT+CWSAP=\"%s\",\"%s\",1,4\r\n",wifi_name,wifi_password);
printf("buff:%s",buff);
printf("6.设置热点信息\r\n");
if(Esp8266_SendCmdCheckStat(buff,"OK\r\n"))return 6;
printf("7.设置多连接\r\n");
if(Esp8266_SendCmdCheckStat("AT+CIPMUX=1\r\n","OK\r\n"))return 7;
printf("8.设置端口号\r\n");
snprintf(buff,sizeof(buff),"AT+CIPSERVER=1,%d\r\n",port);
if(Esp8266_SendCmdCheckStat(buff,"OK\r\n"))return 8;
printf("9.查询IP地址\r\n");
if(Esp8266_SendCmdCheckStat("AT+CIFSR\r\n","OK\r\n"))return 9;
/*****提取IP地址信息*/
/*usart3:+CIFSR:APIP,"192.168.4.1"
+CIFSR:APMAC,"86:f3:eb:a6:be:f9"
OK
*/
p=strstr((char *)usart3_rx_buff,"APIP");
if(p!=NULL)
{
p+=6;
while((*p!='"') && (*p!='\0'))
{
buff[i]=*p;
p++;
i++;
}
}
buff[i]='\0';
printf("buff:%s\r\n",buff);
strcpy((char *)esp8266_info.esp8266_ip,buff);//IP地址
strcpy((char *)esp8266_info.esp8266_name,(char *)wifi_name);//wifi名称
strcpy((char *)esp8266_info.esp8266_key,(char *)wifi_password);//wifi密码
esp8266_info.esp8266_prot=port;
return 0;
}
4.2 水位监测传感器
本模块工作电压为5V,采用ADC方式采集液位值,原理为印刷电路板侵入水中,阻值会改变,通过测量阻值的变化来测量水位。
- 获取水位值示例
u16 Get_Regular_Channelx(u16 ch)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel=ch;//通道号
sConfig.SamplingTime=ADC_SAMPLETIME_239CYCLES_5;//采样周期
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)//ADC通道初始化
{
Error_Handler();
}
HAL_ADC_Start(&hadc1);//开启ADC
HAL_ADC_PollForConversion(&hadc1,20);//等待规则通道转换完成
return HAL_ADC_GetValue(&hadc1);
}
//采集AD值,多次测量求平均值
int Get_WeatherVal()
{
u16 buffer[10];
u32 count=0;
int i=0,j=0;
u16 temp;
for(i=0;i<10;i++)
{
buffer[i]=Get_Regular_Channelx(ADC_CHANNEL_8);//100ms采集一次水位值
Delay_Ms(2);
}
for(i=0;i<10-1;i++)
{
for(j=0;j<10-1-i;j++)
{
if(buffer[j]>buffer[j+1])
{
temp=buffer[j];
buffer[j]=buffer[j+1];
buffer[j+1]=temp;
}
}
}
for(j=2;j<8;j++)
{
count+=buffer[j];
}
return (count/6);
}
4.3 水泵驱动
本次水泵选择的是3W USB接口抽水电机,通过继电器控制水泵启动和关闭,配合上位机软件和水位传感器实时监测水位值实现电机自动启动和停止工作。低电平启动水泵工作,高电平停止水泵工作。
#define moto_ctl_start() HAL_GPIO_WritePin(moto_clt_GPIO_Port,moto_clt_Pin,GPIO_PIN_RESET)
#define moto_ctl_stop() HAL_GPIO_WritePin(moto_clt_GPIO_Port,moto_clt_Pin,GPIO_PIN_SET)
4.4 核心控制功能
设备上电初始化WIFI,等待app连接。水位传感器实时检测当前水位状态,通过APP启动水泵抽水,当前水位值超过设定是阈值,则水泵自动停止工作。
板载RGB状态指示灯。硬件电源检测正常位红色,WIFI工作工作则红灯闪烁,APP连接成功则白灯闪烁,电机工作则绿灯闪烁。通过RGB灯光状态即可得知当前设备工作状态。
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(usart1_flag)
{
usart1_rx_buff[usart1_cnt]='\0';
printf("rx1=%s,%d\r\n",usart1_rx_buff,usart1_cnt);
usart1_cnt=0;
usart1_flag=0;
}
if(usart3_flag)
{
usart3_rx_buff[usart3_cnt]='\0';
printf("rx3=%s,%d\r\n",usart3_rx_buff,usart3_cnt);
if(strstr((char *)usart3_rx_buff,"0,CONNECT"))
{
wifi_stat=1;//连接成功
time=0;
stat=0;
RGB_Ctl(0,0,0);
snprintf(buff,sizeof(buff),"#%d,%d,%d",0,0,threshold_val%101);
Esp8266_SendData(0,(u8*)buff);//发松数据到客户端
}
else if(strstr((char *)usart3_rx_buff,"0,CLOSED"))
{
wifi_stat=0;//断开连接
time=0;
stat=0;
RGB_Ctl(0,0,0);
moto_ctl_stop();
}
else if(strstr((char *)usart3_rx_buff,"motor:1"))
{
wifi_stat=2;//启动工作
time=0;
stat=0;
RGB_Ctl(0,0,0);
moto_ctl_start();
motor_stat=1;
}
else if(strstr((char *)usart3_rx_buff,"motor:0"))
{
wifi_stat=1;//停止工作
time=0;
stat=0;
RGB_Ctl(0,0,0);
moto_ctl_stop();
motor_stat=0;
}
else if(strstr((char *)usart3_rx_buff,"max:"))//水位阈值
{
//+IPD,0,6:max:97,17
p=strstr((char *)usart3_rx_buff,"max:");
p+=strlen("max:");
threshold_val=atoi(p);
//printf("threshold_val=%d\r\n",threshold_val);
}
usart3_cnt=0;
usart3_flag=0;
}
time++;
time2++;
time3++;
Delay_Ms(1);
if(wifi_stat==0 && time>=500)//应用app未连接(红灯闪烁)
{
time=0;
stat=!stat;
if(stat)
RGB_Ctl(200,0,0);
else
RGB_Ctl(0,0,0);
}
if(wifi_stat==1 && time>=500)//应用app连接成功(白灯闪烁)
{
time=0;
stat=!stat;
if(stat)
RGB_Ctl(255,253,85);
else
RGB_Ctl(0,0,0);
}
else if(wifi_stat==2 && time>=500)//电机工作(绿灯闪烁)
{
time=0;
stat=!stat;
if(stat)
RGB_Ctl(0,255,0);
else
RGB_Ctl(0,0,0);
}
if(time3>=100)
{
time3=0;
data=Get_WeatherVal();
temp=data/3900.00*100;
//printf("data=%.2f.%d\r\n",temp,data);
if((temp)>=threshold_val)//当前水位值超过设定阈值,则停止电机工作
{
if(motor_stat==1)
{
time=0;
stat=0;
RGB_Ctl(0,0,0);
moto_ctl_stop();
motor_stat=0;//关闭电机
wifi_stat=1;
snprintf(buff,sizeof(buff),"#%d,%d,%d",motor_stat,threshold_val,threshold_val);
Esp8266_SendData(0,(u8*)buff);//发松数据到客户端
time2=0;
}
}
}
if(time2>=1000 && motor_stat==1 && wifi_stat>=1)//1s上报一次当前水位状态,且需要再电机工作时进行上报
{
time2=0;
snprintf(buff,sizeof(buff),"#%d,%d,%d",motor_stat,((int)temp)%101,threshold_val%101);
//printf("buff=%s\r\n",buff);
Esp8266_SendData(0,(u8*)buff);//发松数据到客户端
}
}
/* USER CODE END 3 */
}