1、主要功能
①环境检测:监测养殖场内外的环境
②环境控制:环境变化时,启动相关设备进行调节
③养殖控制:研究家畜饮食规律,设计合理的食水投喂策略
④家畜检测:监测家畜的生理数据
2、原理图
3、主函数
#include "stm32f10x.h"
#include "main.h"
#include "delay.h"
#include "usart1.h"
#include "usart2.h"
#include "usart3.h"
#include "timer2.h"
#include "timer3.h"
#include "timer4.h"
#include "wifi.h"
#include "led.h"
#include "mqtt.h"
#include "iic.h"
#include "adc.h"
#include "iwdg.h"
#include "oled.h"
#include "key.h"
#include "dht11.h"
#include "ds18b20.h"
char temperature,FLOG1,FLOG2,FLOG3; //定义一个不变量,保存温度值
char humidity; //定义一个不变量,保存湿度值
unsigned int SystemTimer = 0; //用于全局计时的变量 单位秒
unsigned int TEHUTimer = 0; //用于温湿度采集的计时的变量 单位秒
unsigned int ADCTimer = 0; //用于ADC采集的计时的变量 单位秒
short turangtemp;
u8 temp1;
u8 temp2;
char *CMD1 = "switch1:1"; //开关1,开控制命令
char *CMD2 = "switch1:0"; //开关1,关控制命令
char *CMD3 = "switch2:1"; //开关2,开控制命令
char *CMD4 = "switch2:0"; //开关2,关控制命令
char *CMD5 = "switch3:1"; //开关2,开控制命令
char *CMD6 = "switch3:0"; //开关2,关控制命令
float adcdata[3],light_data,tuhum_data,ph_data; //用于保存3个ADC通道的数据
u8 usart_buf[6];
float adcdata2,adcdata0,adcdata1;
int adcdata11,adcdata00,adcdata22;
int main(void)
{
char key_num,NUM; //定义一个变量,保存按键扫描函数的返回值
char data1[64],data2[64]; //缓冲区
IWDG_Init(6,625); //独立看门狗 时间4s
Delay_Init(); //延时功能初始化
IIC_Init(); //初始化IIC接口
LED_Init(); //LED初始化
Adc_Init(); //ADC初始化
DS18B20_Init();
Usart1_Init(9600); //串口1功能初始化,波特率9600
Usart3_Init(9600);
DHT11_Init(); //初始化DHT11传感器
KEY_Init();
WiFi_ResetIO_Init(); //初始化WiFi的复位IO
IoT_Parameter_Init(); //初始化连接云IoT平台MQTT服务器的参数
OLED_Init();
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);
OLED_ShowChinese(0,0,18,16,1); //16*16 空温
OLED_ShowChinese(16,0,19,16,1); //16*16
OLED_ShowChinese(32,0,20,16,1); //16*16 空湿
OLED_ShowChinese(48,0,21,16,1); //16*16
OLED_ShowChinese(64,0,22,16,1); //16*16 光照
OLED_ShowChinese(80,0,23,16,1); //16*16
OLED_ShowChinese(96,0,24,16,1); //16*16 光照
OLED_ShowChinese(112,0,25,16,1); //16*16
OLED_ShowChinese(0,16,0,16,1); //16*16 空温
OLED_ShowChinese(16,16,1,16,1); //16*16
OLED_ShowChinese(0,32,2,16,1); //16*16 空湿
OLED_ShowChinese(16,32,3,16,1); //16*16
OLED_ShowChinese(64,16,4,16,1); //16*16 光照
OLED_ShowChinese(80,16,5,16,1); //16*16
OLED_ShowChinese(64,32,12,16,1); //16*16 烟雾
OLED_ShowChinese(80,32,13,16,1); //16*16
OLED_ShowChinese(0,48,26,16,1); //16*16 人体
OLED_ShowChinese(16,48,27,16,1); //16*16
OLED_ShowChinese(48,48,30,16,1); //16*16
OLED_ShowChinese(64,48,28,16,1); //16*16 人体
OLED_ShowChinese(80,48,29,16,1); //16*16
OLED_ShowChinese(112,48,30,16,1); //16*16
OLED_Refresh();
while(1) //主循环
{
turangtemp=DS18B20_Get_Temp();
if(turangtemp<0)
{
turangtemp=-turangtemp;
}
temp1 = (u8)(turangtemp/10);
temp2 = (u8)(turangtemp%10);
DHT11_Read_Data(&temperature,&humidity); //读取温湿度值
usart_buf[0] = 0xEF;
usart_buf[1] = (uint8_t)(temperature);
usart_buf[2] = (uint8_t)(humidity );
temp1 = usart_buf[4];
//tempdata = usart_buf[1];
//humidata = usart_buf[2];
sprintf(data1,"%d",usart_buf[1]);
sprintf(data2,"%d",usart_buf[2]);
OLED_ShowString(32,16,(u8*)data1,16,1);
OLED_ShowString(32,32,(u8*)data2,16,1);
adcdata0 = (float)(Get_Adc_Average(5,20))*(3.3/4096); //光照
adcdata1 = (float)(Get_Adc_Average(6,20))*(3.3/4096);
adcdata2 = (float)(Get_Adc_Average(7,20))*(3.3/4096);
adcdata00= 100-adcdata0/(5-1.7)*100;//光照
adcdata11= adcdata1/(5-1.7)*100;//烟雾
adcdata22= adcdata2/(5-1.7)*100;//气体
OLED_ShowNum(96,16,adcdata00,2,16,1);
OLED_ShowNum(96,32,adcdata11,2,16,1);
OLED_ShowNum(32,48,temp1,2,16,1);
key_num = KEY_Scan();
if(key_num){
OLED_ShowChinese(96,16,14,16,1); //16*16 人体
OLED_ShowChinese(112,16,15,16,1); //16*16 ;//否则就报警
usart_buf[3] = 1;
}else{
OLED_ShowChinese(96,16,16,16,1); //16*16 人体
OLED_ShowChinese(112,16,17,16,1); //16*16
usart_buf[3] = 0;
}
OLED_ShowNum(96,0,ic,3,16,1);
OLED_Showdecimal(32,32,usart_buf[5],2,2,16);
OLED_Showdecimal(96,16,usart_buf[3],2,2,16);
NUM++;
if(NUM==20){
FLOG2=0;
FLOG1=0;
NUM=0;
}
if(adcdata00<=40) LED2_ON;
else if(adcdata00>40&&FLOG2==0) LED2_OFF;
if(temp1>=30 |usart_buf[1]>=30)LED1_ON;
else if(temp1<30 &&usart_buf[1]<30&&FLOG1==0)LED1_OFF;
OLED_Refresh();
/*--------------------------------------------------------------------*/
/* Connect_flag=1同服务器建立了连接,我们可以发布数据和接收推送了 */
/*--------------------------------------------------------------------*/
if(Connect_flag==1){
/*-------------------------------------------------------------*/
/* 处理发送缓冲区数据 */
/*-------------------------------------------------------------*/
if(MQTT_TxDataOutPtr != MQTT_TxDataInPtr){ //if成立的话,说明发送缓冲区有数据了
//3种情况可进入if
//第1种:0x10 连接报文
//第2种:0x82 订阅报文,且ConnectPack_flag置位,表示连接报文成功
//第3种:SubcribePack_flag=4,说明连接和4个订阅均成功,其他报文可发
if((DMA_flag==0)&&((MQTT_TxDataOutPtr[2]==0x10)||((MQTT_TxDataOutPtr[2]==0x82)&&(ConnectPack_flag==1))||(SubcribePack_flag==4))){
u1_printf("发送数据:0x%x\r\n",MQTT_TxDataOutPtr[2]); //串口提示信息
MQTT_TxData(MQTT_TxDataOutPtr); //发送数据
MQTT_TxDataOutPtr += TBUFF_UNIT; //指针下移
if(MQTT_TxDataOutPtr==MQTT_TxDataEndPtr) //如果指针到缓冲区尾部了
MQTT_TxDataOutPtr = MQTT_TxDataBuf[0]; //指针归位到缓冲区开头
}
}//处理发送缓冲区数据的else if分支结尾
/*-------------------------------------------------------------*/
/* 处理接收缓冲区数据 */
/*-------------------------------------------------------------*/
if(MQTT_RxDataOutPtr != MQTT_RxDataInPtr){ //if成立的话,说明接收缓冲区有数据了
u1_printf("接收到数据:"); //串口提示信息
/*-----------------------------------------------------*/
/* 处理CONNACK报文 */
/*-----------------------------------------------------*/
//if判断,如果第一个字节是0x20,表示收到的是CONNACK报文
//接着我们要判断第4个字节,看看CONNECT报文是否成功
if(MQTT_RxDataOutPtr[2]==0x20){
switch(MQTT_RxDataOutPtr[5]){
case 0x00 : u1_printf("CONNECT报文成功\r\n"); //串口输出信息
ConnectPack_flag = 1; //CONNECT报文成功
MQTT_Subscribe(S1_TOPIC_NAME,0); //发送缓冲区添加订阅topic,等级0
break; //跳出分支case 0x00
case 0x01 : u1_printf("连接已拒绝,不支持的协议版本,准备重启\r\n"); //串口输出信息
Connect_flag = 0; //Connect_flag置零,重启连接
break; //跳出分支case 0x01
case 0x02 : u1_printf("连接已拒绝,不合格的客户端标识符,准备重启\r\n"); //串口输出信息
Connect_flag = 0; //Connect_flag置零,重启连接
break; //跳出分支case 0x02
case 0x03 : u1_printf("连接已拒绝,服务端不可用,准备重启\r\n"); //串口输出信息
Connect_flag = 0; //Connect_flag置零,重启连接
break; //跳出分支case 0x03
case 0x04 : u1_printf("连接已拒绝,无效的用户名或密码,准备重启\r\n"); //串口输出信息
Connect_flag = 0; //Connect_flag置零,重启连接
break; //跳出分支case 0x04
case 0x05 : u1_printf("连接已拒绝,未授权,准备重启\r\n"); //串口输出信息
Connect_flag = 0; //Connect_flag置零,重启连接
break; //跳出分支case 0x05
default : u1_printf("连接已拒绝,未知状态,准备重启\r\n"); //串口输出信息
Connect_flag = 0; //Connect_flag置零,重启连接
break; //跳出分支case default
}
}
/*-----------------------------------------------------*/
/* 处理SUBACK报文 */
/*-----------------------------------------------------*/
//if判断,第一个字节是0x90,表示收到的是SUBACK报文
//接着我们要判断订阅回复,看看是不是成功
else if(MQTT_RxDataOutPtr[2]==0x90){
switch(MQTT_RxDataOutPtr[6]){
case 0x00 :
case 0x01 : u1_printf("订阅成功\r\n"); //串口输出信息
SubcribePack_flag++; //SubcribePack_flag+1,表示订阅报文成功,我们一共订阅4个
switch(SubcribePack_flag){
case 1: MQTT_Subscribe(S2_TOPIC_NAME,0);break; //发送缓冲区添加订阅topic,等级0.
case 2: MQTT_Subscribe(S3_TOPIC_NAME,0);break; //发送缓冲区添加订阅topic,等级0
case 3: MQTT_Subscribe(S4_TOPIC_NAME,0);break; //发送缓冲区添加订阅topic,等级0
case 4: LED1_State(); //判断开关1的初始状态,加入缓冲区,并发布给服务器
TIM3_ENABLE_30S(); //启动定时器3 30s的PING保活定时器
TIM2_ENABLE_1S(); //启动定时器2 1s的定时器
break;
}
break; //跳出分支
default : u1_printf("订阅失败,准备重启\r\n"); //串口输出信息
Connect_flag = 0; //Connect_flag置零,重启连接
break; //跳出分支
}
}
/*-----------------------------------------------------*/
/* 处理PINGRESP报文 */
/*-----------------------------------------------------*/
//if判断,第一个字节是0xD0,表示收到的是PINGRESP报文
else if(MQTT_RxDataOutPtr[2]==0xD0){
u1_printf("PING报文回复\r\n"); //串口输出信息
if(Ping_flag==1){ //如果Ping_flag=1,表示第一次发送
Ping_flag = 0; //要清除Ping_flag标志
}else if(Ping_flag>1){ //如果Ping_flag>1,表示是多次发送了,而且是2s间隔的快速发送
Ping_flag = 0; //要清除Ping_flag标志
TIM3_ENABLE_30S(); //PING定时器重回30s的时间
}
}
/*-----------------------------------------------------*/
/* 处理数据推送报文 */
/*-----------------------------------------------------*/
//if判断,如果第一个字节是0x30,表示收到的是服务器发来的推送数据
//我们要提取控制命令
else if((MQTT_RxDataOutPtr[2]==0x30)){
u1_printf("服务器等级0推送\r\n"); //串口输出信息
MQTT_DealPushdata_Qs0(MQTT_RxDataOutPtr); //处理等级0推送数据
}
MQTT_RxDataOutPtr +=RBUFF_UNIT; //接收指针下移
if(MQTT_RxDataOutPtr==MQTT_RxDataEndPtr) //如果接收指针到接收缓冲区尾部了
MQTT_RxDataOutPtr = MQTT_RxDataBuf[0]; //接收指针归位到接收缓冲区开头
}
/*-------------------------------------------------------------*/
/* 处理命令缓冲区数据 */
/*-------------------------------------------------------------*/
if(MQTT_CMDOutPtr != MQTT_CMDInPtr){ //if成立的话,说明命令缓冲区有数据了
u1_printf("命令:%s\r\n",&MQTT_CMDOutPtr[2]); //串口输出信息
if(!memcmp(&MQTT_CMDOutPtr[2],CMD1,strlen(CMD1))){ //判断指令,如果是CMD1,开开关1
// if(LED1_IN_STA){ //如果现在IO是高电平,表示开关1是关闭状态
LED1_ON;
FLOG1 =1; //开开关1
// LED1_State(); //上报开关1状态
// }
}else if(!memcmp(&MQTT_CMDOutPtr[2],CMD2,strlen(CMD2))){ //判断指令,如果是CMD2,关开关1
// if(!LED1_IN_STA){ //如果现在IO是低电平,表示开关1是打开状态
LED1_OFF; //关开关1
FLOG1 =0; //开开关1
// LED1_State(); //上报开关1状态
// }
}
else if(!memcmp(&MQTT_CMDOutPtr[2],CMD3,strlen(CMD3))){ //判断指令,如果是CMD3,开开关2
// if(LED2_IN_STA){ //如果现在IO是高电平,表示开关2是关闭状态
LED2_ON; //开开关2
FLOG2 =1; //开开关1
//上报开关2状态
// }
}else if(!memcmp(&MQTT_CMDOutPtr[2],CMD4,strlen(CMD4))){ //判断指令,如果是CMD4,关开关2
// if(!LED2_IN_STA){ //如果现在IO是低电平,表示开关2是打开状态
LED2_OFF; //关开
FLOG2 =0; //开开关1 //上报开关2状态
// }
}
else if(!memcmp(&MQTT_CMDOutPtr[2],CMD5,strlen(CMD3))){ //判断指令,如果是CMD3,开开关2
// if(LED2_IN_STA){ //如果现在IO是高电平,表示开关2是关闭状态
LED3_ON; //开开关2
FLOG3 =1; //开开关1
//上报开关2状态
// }
}else if(!memcmp(&MQTT_CMDOutPtr[2],CMD6,strlen(CMD4))){ //判断指令,如果是CMD4,关开关2
// if(!LED2_IN_STA){ //如果现在IO是低电平,表示开关2是打开状态
LED3_OFF; //关开
FLOG3 =0; //开开关1 //上报开关2状态
// }
}
MQTT_CMDOutPtr += CBUFF_UNIT; //指针下移
if(MQTT_CMDOutPtr==MQTT_CMDEndPtr) //如果指针到缓冲区尾部了
MQTT_CMDOutPtr = MQTT_CMDBuf[0]; //指针归位到缓冲区开头
}//处理命令缓冲区数据的else if分支结尾
/*-------------------------------------------------------------*/
/* 处理定时上传任务 */
/*-------------------------------------------------------------*/
Data_State(); //定时上传各种数据的任务
Delay_Ms(1); //延时,必须有,里面有喂狗,不然看门狗会溢出,造成复位
}
/*--------------------------------------------------------------------*/
/* Connect_flag=0同服务器断开了连接,我们要连接服务器 */
/*--------------------------------------------------------------------*/
else{
u1_printf("准备连接服务器\r\n"); //串口输出信息
Usart2_Init(115200); //串口2功能初始化,波特率115200
TIM_Cmd(TIM4,DISABLE); //关闭TIM4
TIM_Cmd(TIM3,DISABLE); //关闭TIM3
TIM_Cmd(TIM2,DISABLE); //关闭TIM2
WiFi_RxCounter=0; //WiFi接收数据量变量清零
memset(WiFi_RX_BUF,0,WiFi_RXBUFF_SIZE); //清空WiFi接收缓冲区
if(WiFi_Connect_IoTServer()==0){ //如果WiFi连接云服务器函数返回0,表示正确,进入if
u1_printf("连接服务器成功\r\n"); //串口输出信息
Usart2_IDELInit(115200); //串口2 开启DMA 和 空闲中断
Connect_flag = 1; //Connect_flag置1,表示连接成功
SystemTimer = 0; //全局计时时间变量清0
TEHUTimer = 0; //温湿度计时时间变量清0
ADCTimer = 0; //ADC计时时间变量清0
WiFi_RxCounter=0; //WiFi接收数据量变量清零
memset(WiFi_RX_BUF,0,WiFi_RXBUFF_SIZE); //清空WiFi接收缓冲区
MQTT_Buff_Init(); //初始化发送接收命令缓冲区
}
}
}
}