ToB企服应用市场:ToB评测及商务社交产业平台

标题: 基于STM32和oneNET云平台的数据收罗体系(MQTT协议) [打印本页]

作者: 曹旭辉    时间: 2024-6-23 14:12
标题: 基于STM32和oneNET云平台的数据收罗体系(MQTT协议)

前言

该篇为基于stm32+esp8266通过mqtt协议毗连onenet物联网云平台,单片机部分将收罗到的数据(温湿度、光照强度、压强等等)上传至云平台服务器,云平台可下发指令操控单片机,实现远程通讯。
一、onenet云平台产品创建

1. 第一步,注册账号后点击右上角 控制台

2. 第二步,看左上角 选择切换旧版本

3. 第三步,左上角,全部产品中选择多协议接入

4. 点击添加产品,填好产品信息(红框重点)

5. 选择添加设备

6. 至此,完成产品创建,示比方下:

二、硬件选择


三、计划理念

综上,共消费两个串口,三个定时器。
云端及时检测与远程操控:


四、实战编程

1. 传感器部分

(1)DHT11
  1. /*-------------------------------------------------*/
  2. /*函数名:复位DHT11                                */
  3. /*参  数:无                                       */
  4. /*返回值:无                                       */
  5. /*-------------------------------------------------*/  
  6. void DHT11_Rst(void)          
  7. {                 
  8.   DHT11_IO_OUT();         //设置IO输出模式
  9.   DHT11_OUT(0);         //拉低IO
  10.   DelayMs(30);      //拉低至少18ms,我们拉低30
  11.   DHT11_OUT(1);         //拉高IO
  12.   DelayUs(30);      //主机拉高20~40us,我们拉高30us
  13. }
  14. /*-------------------------------------------------*/
  15. /*函数名:等待DHT11的回应                           */
  16. /*参  数:无                                       */
  17. /*返回值:1错误 0正确                               */
  18. /*-------------------------------------------------*/
  19. char DHT11_Check(void)           
  20. {   
  21.         char timeout;                            //定义一个变量用于超时判断  
  22.        
  23.         timeout = 0;                             //超时变量清零   
  24.         DHT11_IO_IN();                           //IO设置输入模式
  25.     while((DHT11_DQ_IN == 1) && (timeout < 70))//DHT11会拉低40~50us,我们等待70us超时时间       
  26.         {         
  27.                 timeout++;                           //超时变量+1
  28.                 DelayUs(1);                                //延时1us
  29.         }
  30.         if(timeout >= 70)return 1;               //如果timeout>=70,说明是因为超时退出的while循环,返回1表示错误
  31.         else timeout = 0;                        //反之,说明是因为等到了DHT11拉低IO,退出的while循环,正确并清零timeout
  32.     while((DHT11_DQ_IN == 0) && (timeout < 70))//DHT11拉低后会再次拉高40~50us,,我们等待70us超时时间       
  33.         {                
  34.                 timeout++;                           //超时变量+1
  35.                 DelayUs(1);                          //延时1us
  36.         }
  37.         if(timeout >= 70)return 2;               //如果timeout>=70,说明是因为超时退出的while循环,返回2表示错误  
  38.         return 0;                                //反之正确,返回0
  39. }
  40. /*-------------------------------------------------*/
  41. /*函数名:读取一个位                                */
  42. /*参  数:无                                       */
  43. /*返回值:1或0                                     */
  44. /*-------------------------------------------------*/
  45. char DHT11_Read_Bit(void)                          
  46. {
  47.         char timeout;                                     //定义一个变量用于超时判断  
  48.        
  49.         timeout = 0;                               //清零timeout       
  50.         while((DHT11_DQ_IN == 1) && (timeout < 40))//每一位数据开始,是12~14us的低电平,我们等40us
  51.         {   
  52.                 timeout++;                             //超时变量+1
  53.                 DelayUs(1);                            //延时1us
  54.         }
  55.         timeout = 0;                               //清零timeout       
  56.         while((DHT11_DQ_IN == 0) && (timeout < 60))//接下来,DHT11会拉高IO,根据拉高的时间判断是0或1,我们等60us
  57.         {  
  58.                 timeout++;                             //超时变量+1
  59.                 DelayUs(1);                            //延时1us
  60.         }
  61.         DelayUs(35);                               //延时35us
  62.         if(DHT11_DQ_IN)return 1;                   //如果延时后,是高电平,那么本位接收的是1,返回1
  63.         else return 0;                                       //反之延时后,是低电平,那么本位接收的是0,返回0
  64. }
  65. /*-------------------------------------------------*/
  66. /*函数名:读取一个字节                              */
  67. /*参  数:无                                       */
  68. /*返回值:数据                                      */
  69. /*-------------------------------------------------*/
  70. char DHT11_Read_Byte(void)   
  71. {        
  72.     char i;                                                       //定义一个变量用于for循环  
  73.         char dat;                                              //定义一个变量用于保存数据
  74.         dat = 0;                                                //清除保存数据的变量
  75.         for (i = 0; i < 8; i++){                              //一个字节8位,循环8次       
  76.                    dat <<= 1;                                            //左移一位,腾出空位   
  77.             dat |= DHT11_Read_Bit();                              //读取一位数据
  78.     }                                                    
  79.     return dat;                                                   //返回一个字节的数据
  80. }
  81. /*-------------------------------------------------*/
  82. /*函数名:读取一次数据温湿度                         */
  83. /*参  数:temp:温度值                               */
  84. /*参  数:humi:湿度值                               */
  85. /*返回值:1错误 0正确                               */
  86. /*-------------------------------------------------*/
  87. char DHT11_Read_Data(char *temp, char *humi)   
  88. {        
  89.         char buf[5];                                         //一次完整的数据有5个字节,定义一个缓冲区
  90.        
  91.         char i;                                              //定义一个变量用于for循环  
  92.         DHT11_Rst();                                         //复位DHT11       
  93.         if(DHT11_Check() == 0)                                                             //判断DHT11回复状态=0的话,表示正确,进入if
  94.         {
  95.                 for(i = 0; i < 5; i++){                          //一次完整的数据有5个字节,循环5次               
  96.                         buf[i] = DHT11_Read_Byte();                  //每次读取一个字节
  97.                 }
  98.                 if((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])//判断数据校验,前4个字节相加应该等于第5个字节,正确的话,进入if       
  99.                 {     
  100.                         //u1_printf("%d\r\n",buf[0]);         //温度数据
  101.                         //u1_printf("%d\r\n",buf[1]);
  102.                         //u1_printf("%d\r\n",buf[2]);        //湿度数据
  103.                         //u1_printf("%d\r\n",buf[3]);
  104.                         //u1_printf("%d\r\n",buf[4]);
  105.                         *humi = buf[0];                              //湿度数据,保存在humi指针指向的地址变量中
  106.                         *temp = buf[2];                                                             //温度数据,保存在temp指针指向的地址变量中
  107.                 }else return 1;                                  //反之,数据校验错误,直接返回1
  108.         }else return 2;                                      //反之,如果DHT11回复状态=1的话,表示错误,进入else,直接返回2
  109.        
  110.         return 0;                                                 //读取正确返回0   
  111. }  
  112. /*-------------------------------------------------*/
  113. /*函数名:初始化DHT11                              */
  114. /*参  数:无                                       */
  115. /*返回值:1错误 0正确                              */
  116. /*-------------------------------------------------*/             
  117. char DHT11_Init(void)
  118. {
  119.         GPIO_InitTypeDef GPIO_InitStructure;                  //定义一个IO端口参数结构体
  120.        
  121.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟
  122.        
  123.         GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6;            //准备设置PA8
  124.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //速率50Mhz
  125.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;             //推免输出方式
  126.         GPIO_Init(GPIOA, &GPIO_InitStructure);                      //设置PA8       
  127.         DHT11_Rst();                                          //复位DHT11
  128.         return DHT11_Check();                                 //返回DHT11的回复状态
  129. }
复制代码
(2)MQ-2
  1. void Adc_Init(void)
  2. {
  3.     ADC_InitTypeDef ADC_InitStructure;
  4.         GPIO_InitTypeDef GPIO_InitStructure;
  5.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟
  6.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
  7.         //PA1 作为模拟通道输入引脚                        
  8.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
  10.         GPIO_Init(GPIOA, &GPIO_InitStructure);       
  11.         ADC_DeInit(ADC1);  //复位ADC1
  12.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
  13.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式
  14.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
  15.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
  16.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
  17.         ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目
  18.         ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   
  19.   
  20.         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
  21.        
  22.         ADC_ResetCalibration(ADC1);        //使能复位校准  
  23.          
  24.         while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
  25.        
  26.         ADC_StartCalibration(ADC1);         //开启AD校准
  27.         while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束
  28. //        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能
  29. }
  30. /**************************** ADC转换值获取函数 ****************************
  31. 功  能:获取ADC模块转换后的数值
  32. 参  数:无
  33. 返回值:存放ADC转换值
  34. ***************************************************************************/
  35. u16 Get_adcvalue(void)
  36. {
  37.         //设置指定ADC的规则组通道,一个序列,采样时间
  38.         ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      
  39.   
  40.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能       
  41.          
  42.         while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
  43.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
  44. }
  45. u16 Get_Adc_Average(u8 times)
  46. {
  47.         u32 temp_val=0;
  48.         u8 t;
  49.         for(t=0;t<times;t++)
  50.         {
  51.                 temp_val+=Get_adcvalue();
  52.                 DelayMs(5);
  53.         }
  54.         return temp_val/times;
  55. }
复制代码
(3)LED
  1. /*-------------------------------------------------*/
  2. /*函数名:初始化LED函数                                   */
  3. /*参  数:无                                       */
  4. /*返回值:无                                       */
  5. /*-------------------------------------------------*/
  6. void LED_Init(void)
  7. {             
  8.         GPIO_InitTypeDef GPIO_InitStr;
  9.        
  10.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);     //使能时钟
  11.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE ,ENABLE);
  12.        
  13.             
  14.        
  15.         GPIO_InitStr.GPIO_Mode=GPIO_Mode_Out_PP;    //结构体变量赋值
  16.         GPIO_InitStr.GPIO_Pin=GPIO_Pin_5;
  17.         GPIO_InitStr.GPIO_Speed=GPIO_Speed_50MHz;
  18.        
  19.         GPIO_Init(GPIOB,&GPIO_InitStr);       //初始化GPIOB
  20.         GPIO_SetBits(GPIOB,GPIO_Pin_5);       //赋予 GPIO_Pin_5 初始为高电平
  21.        
  22.        
  23.         GPIO_InitStr.GPIO_Mode=GPIO_Mode_Out_PP;  
  24.         GPIO_InitStr.GPIO_Pin=GPIO_Pin_5;
  25.         GPIO_InitStr.GPIO_Speed=GPIO_Speed_50MHz;
  26.        
  27.         GPIO_Init(GPIOE,&GPIO_InitStr);
  28.         GPIO_SetBits(GPIOE,GPIO_Pin_5);
  29. }
  30. /*-------------------------------------------------*/
  31. /*函数名:LED开启                                  */
  32. /*参  数:无                                       */
  33. /*返回值:无                                       */
  34. /*-------------------------------------------------*/
  35. void LED_On(void)
  36. {                       
  37.         GPIO_ResetBits(GPIOB, GPIO_Pin_5);                                                  //PD2 输出低
  38. }
  39. /*-------------------------------------------------*/
  40. /*函数名:LED关闭                                  */
  41. /*参  数:无                                       */
  42. /*返回值:无                                       */
  43. /*-------------------------------------------------*/
  44. void LED_Off(void)
  45. {               
  46.         GPIO_SetBits(GPIOB, GPIO_Pin_5);                                                  //PD2 输出高
  47. }
复制代码
2. ESP8266

  1. /*-------------------------------------------------*/
  2. /*函数名:初始化WiFi的复位IO                       */
  3. /*参  数:无                                       */
  4. /*返回值:无                                       */
  5. /*-------------------------------------------------*/
  6. void WiFi_ResetIO_Init(void)
  7. {
  8.         GPIO_InitTypeDef GPIO_InitStructure;                    //定义一个设置IO端口参数的结构体
  9.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE); //使能PA端口时钟
  10.        
  11.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;               //准备设置PA4
  12.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //速率50Mhz
  13.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;               //推免输出方式
  14.         GPIO_Init(GPIOA, &GPIO_InitStructure);                        //设置PA4
  15.         RESET_IO(1);                                            //复位IO拉高电平
  16. }
  17. /*-------------------------------------------------*/
  18. /*函数名:WiFi发送设置指令                          */
  19. /*参  数:cmd:指令                                */
  20. /*参  数:timeout:超时时间(100ms的倍数)          */
  21. /*返回值:0:正确   其他:错误                      */
  22. /*-------------------------------------------------*/
  23. char WiFi_SendCmd(char *cmd, int timeout)
  24. {
  25.         WiFi_RxCounter = 0;                                                   //WiFi接收数据量变量清零                        
  26.         memset(WiFi_RX_BUF, 0, WiFi_RXBUFF_SIZE);                             //清空WiFi接收缓冲区
  27.         WiFi_printf("%s\r\n", cmd);                                          //发送指令
  28.         while(timeout--)                                                                                //等待超时时间到0
  29.         {                                                  
  30.                 DelayMs(100);                                                 //延时100ms
  31.                 if(strstr(WiFi_RX_BUF, "OK"))                                      //如果接收到OK表示指令成功
  32.                         break;                                                                               //主动跳出while循环
  33.                 u1_printf("%d ", timeout);                                         //串口输出现在的超时时间
  34.         }                       
  35.         u1_printf("\r\n");                                                  //串口输出信息
  36.         if(timeout <= 0)return 1;                                                    //如果timeout<=0,说明超时时间到了,也没能收到OK,返回1
  37.         else return 0;                                                                                 //反之,表示正确,说明收到OK,通过break主动跳出while
  38. }
  39. /*-------------------------------------------------*/
  40. /*函数名:WiFi复位                                 */
  41. /*参  数:timeout:超时时间(100ms的倍数)          */
  42. /*返回值:0:正确   其他:错误                      */
  43. /*-------------------------------------------------*/
  44. char WiFi_Reset(int timeout)
  45. {
  46.         RESET_IO(0);                                              //复位IO拉低电平
  47.         DelayMs(500);                                                    //延时500ms
  48.         RESET_IO(1);                                                     //复位IO拉高电平       
  49.         while(timeout--)                                                                          //等待超时时间到0
  50.         {                                                
  51.                 DelayMs(100);                                           //延时100ms
  52.                 if(strstr(WiFi_RX_BUF, "ready"))                         //如果接收到ready表示复位成功
  53.                         break;                                                                            //主动跳出while循环
  54.                 u1_printf("%d ", timeout);                               //串口输出现在的超时时间
  55.         }
  56.         u1_printf("\r\n");                                        //串口输出信息
  57.         if(timeout <= 0)return 1;                                          //如果timeout<=0,说明超时时间到了,也没能收到ready,返回1
  58.         else return 0;                                                                              //反之,表示正确,说明收到ready,通过break主动跳出while
  59. }
  60. /*-------------------------------------------------*/
  61. /*函数名:WiFi加入路由器指令                       */
  62. /*参  数:timeout:超时时间(1s的倍数)            */
  63. /*返回值:0:正确   其他:错误                     */
  64. /*-------------------------------------------------*/
  65. char WiFi_JoinAP(int timeout)
  66. {               
  67.         WiFi_RxCounter = 0;                                    //WiFi接收数据量变量清零                        
  68.         memset(WiFi_RX_BUF, 0, WiFi_RXBUFF_SIZE);              //清空WiFi接收缓冲区
  69.         WiFi_printf("AT+CWJAP="%s","%s"\r\n", SSID, PASS); //发送指令       
  70.         while(timeout--)                                                                           //等待超时时间到0
  71.         {                                   
  72.                 DelayMs(1000);                                                //延时1s
  73.                 if(strstr(WiFi_RX_BUF, "OK"))   //如果接收到WIFI GOT IP表示成功
  74.                         break;                                                                  //主动跳出while循环
  75.                 u1_printf("%d ", timeout);                         //串口输出现在的超时时间
  76.         }
  77.         u1_printf("\r\n%s\r\n", WiFi_RX_BUF);
  78.         u1_printf("\r\n");                                            //串口输出信息
  79.         if(timeout <= 0)return 1;                              //如果timeout<=0,说明超时时间到了,也没能收到WIFI GOT IP,返回1
  80.         return 0;                                              //正确,返回0
  81. }
  82. /*-------------------------------------------------*/
  83. /*函数名:连接TCP服务器,并进入透传模式            */
  84. /*参  数:timeout: 超时时间(100ms的倍数)        */
  85. /*返回值:0:正确  其他:错误                      */
  86. /*-------------------------------------------------*/
  87. char WiFi_Connect_Server(int timeout)
  88. {       
  89.         WiFi_RxCounter=0;                                      //WiFi接收数据量变量清零                        
  90.         memset(WiFi_RX_BUF,0,WiFi_RXBUFF_SIZE);         //清空WiFi接收缓冲区   
  91.         WiFi_printf("AT+CIPSTART="TCP","%s",%d\r\n", ServerIP, ServerPort);//发送连接服务器指令
  92.         while(timeout--)                                                                //等待超时与否
  93.         {                           
  94.                 DelayMs(100);                                     //延时100ms       
  95.                 if(strstr(WiFi_RX_BUF, "CONNECT"))          //如果接受到CONNECT表示连接成功
  96.                         break;                                  //跳出while循环
  97.                 if(strstr(WiFi_RX_BUF, "CLOSED"))           //如果接受到CLOSED表示服务器未开启
  98.                         return 1;                               //服务器未开启返回1
  99.                 if(strstr(WiFi_RX_BUF, "ALREADY CONNECTED"))//如果接受到ALREADY CONNECTED已经建立连接
  100.                         return 2;                               //已经建立连接返回2
  101.                 u1_printf("%d ", timeout);                   //串口输出现在的超时时间  
  102.         }
  103.         u1_printf("\r\n");                              //串口输出信息
  104.         if(timeout <= 0)return 3;                       //超时错误,返回3
  105.         else                                            //连接成功,准备进入透传
  106.         {
  107.                 u1_printf("连接服务器成功,准备进入透传\r\n"); //串口显示信息
  108.                 WiFi_RxCounter = 0;                          //WiFi接收数据量变量清零                        
  109.                 memset(WiFi_RX_BUF, 0, WiFi_RXBUFF_SIZE);    //清空WiFi接收缓冲区     
  110.                 WiFi_printf("AT+CIPSEND\r\n");               //发送进入透传指令
  111.                 while(timeout--)                                                         //等待超时与否
  112.                 {                           
  113.                         DelayMs(100);                            //延时100ms       
  114.                         if(strstr(WiFi_RX_BUF, "\r\nOK\r\n\r\n>"))//如果成立表示进入透传成功
  115.                                 break;                                   //跳出while循环
  116.                         u1_printf("%d ", timeout);                //串口输出现在的超时时间  
  117.                 }
  118.                 if(timeout <= 0)return 4;                      //透传超时错误,返回4       
  119.         }
  120.         return 0;                                             //成功返回0       
  121. }
  122. /*-------------------------------------------------*/
  123. /*函数名:WiFi_Smartconfig                         */
  124. /*参  数:timeout:超时时间(1s的倍数)            */
  125. /*返回值:0:正确   其他:错误                     */
  126. /*-------------------------------------------------*/
  127. char WiFi_Smartconfig(int timeout)
  128. {
  129.        
  130.         WiFi_RxCounter=0;                                           //WiFi接收数据量变量清零                        
  131.         memset(WiFi_RX_BUF,0,WiFi_RXBUFF_SIZE);                     //清空WiFi接收缓冲区     
  132.         while(timeout--)                                                                        //等待超时时间到0
  133.         {                                          
  134.                 DelayMs(1000);                                                         //延时1s
  135.                 if(strstr(WiFi_RX_BUF, "connected"))                               //如果串口接受到connected表示成功
  136.                         break;                                                  //跳出while循环  
  137.                 u1_printf("%d ", timeout);                                 //串口输出现在的超时时间  
  138.         }       
  139.         u1_printf("\r\n");                                          //串口输出信息
  140.         if(timeout <= 0)return 1;                                     //超时错误,返回1
  141.         return 0;                                                   //正确返回0
  142. }
  143. /*-------------------------------------------------*/
  144. /*函数名:等待加入路由器                           */
  145. /*参  数:timeout:超时时间(1s的倍数)            */
  146. /*返回值:0:正确   其他:错误                     */
  147. /*-------------------------------------------------*/
  148. char WiFi_WaitAP(int timeout)
  149. {               
  150.         while(timeout--){                               //等待超时时间到0
  151.                 DelayMs(1000);                                             //延时1s
  152.                 if(strstr(WiFi_RX_BUF, "WIFI GOT IP"))         //如果接收到WIFI GOT IP表示成功
  153.                         break;                                                                                                                            //主动跳出while循环
  154.                 u1_printf("%d ", timeout);                     //串口输出现在的超时时间
  155.         }
  156.         u1_printf("\r\n");                              //串口输出信息
  157.         if(timeout <= 0)return 1;                         //如果timeout<=0,说明超时时间到了,也没能收到WIFI GOT IP,返回1
  158.         return 0;                                       //正确,返回0
  159. }
  160. /*-------------------------------------------------*/
  161. /*函数名:WiFi连接服务器                           */
  162. /*参  数:无                                       */
  163. /*返回值:0:正确   其他:错误                     */
  164. /*-------------------------------------------------*/
  165. char WiFi_Connect_IoTServer(void)
  166. {       
  167.         u1_printf("准备复位模块\r\n");                   //串口提示数据
  168.         if(WiFi_Reset(50))                                                                //复位,100ms超时单位,总计5s超时时间
  169.         {                             
  170.                 u1_printf("复位失败,准备重启\r\n");              //返回非0值,进入if,串口提示数据
  171.                 return 1;                                   //返回1
  172.         }else u1_printf("复位成功\r\n");                 //串口提示数据
  173.        
  174.         u1_printf("准备设置STA模式\r\n");                //串口提示数据
  175.         if(WiFi_SendCmd("AT+CWMODE=1",50))//设置STA模式,100ms超时单位,总计5s超时时间
  176.         {            
  177.                 u1_printf("设置STA模式失败,准备重启\r\n");   //返回非0值,进入if,串口提示数据
  178.                 return 2;                                   //返回2
  179.         }else u1_printf("设置STA模式成功\r\n");          //串口提示数据
  180.        
  181.         if(wifi_mode==0) //如果联网模式=0:SSID和密码写在程序里
  182.         {                              
  183.                 u1_printf("准备取消自动连接\r\n");            //串口提示数据
  184.                 if(WiFi_SendCmd("AT+CWAUTOCONN=0",50))                 //取消自动连接,100ms超时单位,总计5s超时时间
  185.                 {      
  186.                         u1_printf("取消自动连接失败,准备重启\r\n"); //返回非0值,进入if,串口提示数据
  187.                         return 3;                                  //返回3
  188.                 }else u1_printf("取消自动连接成功\r\n");        //串口提示数据
  189.                                
  190.                 u1_printf("准备连接路由器\r\n");                //串口提示数据       
  191.                 if(WiFi_JoinAP(30))//连接路由器,1s超时单位,总计30s超时时间
  192.                 {                          
  193.                         u1_printf("连接路由器失败,准备重启\r\n");  //返回非0值,进入if,串口提示数据
  194.                         return 4;                                 //返回4       
  195.                 }else u1_printf("连接路由器成功\r\n");         //串口提示数据                       
  196.         }
  197.        
  198.         u1_printf("准备设置透传\r\n");                    //串口提示数据
  199.         if(WiFi_SendCmd("AT+CIPMODE=1",50))                          //设置透传,100ms超时单位,总计5s超时时间
  200.         {           
  201.                 u1_printf("设置透传失败,准备重启\r\n");       //返回非0值,进入if,串口提示数据
  202.                 return 8;                                    //返回8
  203.         }else u1_printf("设置透传成功\r\n");              //串口提示数据
  204.        
  205.         u1_printf("准备关闭多路连接\r\n");                //串口提示数据
  206.         if(WiFi_SendCmd("AT+CIPMUX=0",50))                                  //关闭多路连接,100ms超时单位,总计5s超时时间
  207.         {            
  208.                 u1_printf("关闭多路连接失败,准备重启\r\n");   //返回非0值,进入if,串口提示数据
  209.                 return 9;                                    //返回9
  210.         }else u1_printf("关闭多路连接成功\r\n");          //串口提示数据
  211.          
  212.         u1_printf("准备连接服务器\r\n");                  //串口提示数据
  213.         if(WiFi_Connect_Server(100))                                       //连接服务器,100ms超时单位,总计10s超时时间
  214.         {            
  215.                 u1_printf("连接服务器失败,准备重启\r\n");     //返回非0值,进入if,串口提示数据
  216.                 return 10;                                   //返回10
  217.         }else u1_printf("连接服务器成功\r\n");            //串口提示数据       
  218.         return 0;                                        //正确返回0
  219. }
  220.        
复制代码
3. 定时器

(1)初始化
  1. /*-------------------------------------------------*/
  2. /*函数名:定时器2使能10s定时                        */
  3. /*参  数:无                                       */
  4. /*返回值:无                                       */
  5. /*-------------------------------------------------*/
  6. void TIM2_ENABLE_10S(void)
  7. {
  8.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;             //定义一个设置定时器的变量
  9.         NVIC_InitTypeDef NVIC_InitStructure;                           //定义一个设置中断的变量       
  10.        
  11.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                //设置中断向量分组:第2组 抢先优先级:0 1 2 3 子优先级:0 1 2 3               
  12.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);            //使能TIM2时钟       
  13.         TIM_DeInit(TIM2);                                              //定时器2寄存器恢复默认值       
  14.         TIM_TimeBaseInitStructure.TIM_Period = 20000-1;                    //设置自动重装载值
  15.         TIM_TimeBaseInitStructure.TIM_Prescaler = 36000-1;             //设置定时器预分频数
  16.         TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
  17.         TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;    //1分频
  18.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);            //设置TIM2
  19.        
  20.         TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                    //清除溢出中断标志位
  21.         TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                     //使能TIM2溢出中断   
  22.         TIM_Cmd(TIM2, ENABLE);                                         //开TIM2                          
  23.        
  24.         NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;                //设置TIM2中断
  25.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;      //抢占优先级2
  26.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;             //子优先级1
  27.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //中断通道使能
  28.         NVIC_Init(&NVIC_InitStructure);                                //设置中断
  29. }
  30. /*-------------------------------------------------*/
  31. /*函数名:定时器3使能30s定时                       */
  32. /*参  数:无                                       */
  33. /*返回值:无                                       */
  34. /*-------------------------------------------------*/
  35. void TIM3_ENABLE_30S(void)
  36. {
  37.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;             //定义一个设置定时器的变量
  38.         NVIC_InitTypeDef NVIC_InitStructure;                           //定义一个设置中断的变量
  39.        
  40.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                //设置中断向量分组:第2组 抢先优先级:0 1 2 3 子优先级:0 1 2 3               
  41.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);           //使能TIM3时钟       
  42.         TIM_DeInit(TIM3);                                              //定时器3寄存器恢复默认值       
  43.         TIM_TimeBaseInitStructure.TIM_Period = 60000-1;                    //设置自动重装载值
  44.         TIM_TimeBaseInitStructure.TIM_Prescaler = 36000-1;             //设置定时器预分频数
  45.         TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
  46.         TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;    //1分频
  47.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);            //设置TIM3
  48.        
  49.         TIM_ClearITPendingBit(TIM3, TIM_IT_Update);                    //清除溢出中断标志位
  50.         TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);                     //使能TIM3溢出中断   
  51.         TIM_Cmd(TIM3, ENABLE);                                         //开TIM3                          
  52.        
  53.         NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;                //设置TIM3中断
  54.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;      //抢占优先级2
  55.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;             //子优先级0
  56.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //中断通道使能
  57.         NVIC_Init(&NVIC_InitStructure);                                //设置中断
  58. }
  59. /*-------------------------------------------------*/
  60. /*函数名:定时器3使能2s定时                        */
  61. /*参  数:无                                       */
  62. /*返回值:无                                       */
  63. /*-------------------------------------------------*/
  64. void TIM3_ENABLE_2S(void)
  65. {
  66.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;             //定义一个设置定时器的变量
  67.         NVIC_InitTypeDef NVIC_InitStructure;                           //定义一个设置中断的变量
  68.        
  69.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                //设置中断向量分组:第2组 抢先优先级:0 1 2 3 子优先级:0 1 2 3               
  70.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);           //使能TIM3时钟
  71.         TIM_DeInit(TIM3);                                              //定时器3寄存器恢复默认值       
  72.         TIM_TimeBaseInitStructure.TIM_Period = 20000-1;                    //设置自动重装载值
  73.         TIM_TimeBaseInitStructure.TIM_Prescaler = 7200-1;              //设置定时器预分频数
  74.         TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
  75.         TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;    //1分频
  76.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);            //设置TIM3
  77.        
  78.         TIM_ClearITPendingBit(TIM3, TIM_IT_Update);                    //清除溢出中断标志位
  79.         TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);                     //使能TIM3溢出中断   
  80.         TIM_Cmd(TIM3, ENABLE);                                         //开TIM3                          
  81.        
  82.         NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;                //设置TIM3中断
  83.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;      //抢占优先级1
  84.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;             //子优先级0
  85.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //中断通道使能
  86.         NVIC_Init(&NVIC_InitStructure);                                //设置中断
  87. }
  88. /*-------------------------------------------------*/
  89. /*函数名:定时器4初始化                            */
  90. /*参  数:arr:自动重装值   0~65535                */
  91. /*参  数:psc:时钟预分频数 0~65535                */
  92. /*返回值:无                                       */
  93. /*说  明:定时时间:arr*psc*1000/72000000  单位ms  */
  94. /*-------------------------------------------------*/
  95. void TIM4_Init(unsigned short int arr, unsigned short int psc)
  96. {
  97.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;              //定义一个设置定时器的变量
  98.         NVIC_InitTypeDef NVIC_InitStructure;                            //定义一个设置中断的变量
  99.        
  100.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                 //设置中断向量分组:第2组 抢先优先级:0 1 2 3 子优先级:0 1 2 3               
  101.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);            //使能TIM4时钟       
  102.     TIM_TimeBaseInitStructure.TIM_Period = arr;                         //设置自动重装载值
  103.         TIM_TimeBaseInitStructure.TIM_Prescaler = psc;                  //设置定时器预分频数
  104.         TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
  105.         TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //1分频
  106.         TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);             //设置TIM4
  107.        
  108.         TIM_ClearITPendingBit(TIM4, TIM_IT_Update);                     //清除溢出中断标志位
  109.         TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);                      //使能TIM4溢出中断   
  110.         TIM_Cmd(TIM4, DISABLE);                                         //先关闭TIM4                          
  111.        
  112.         NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;                 //设置TIM4中断
  113.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;       //抢占优先级1
  114.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              //子优先级0
  115.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //中断通道使能
  116.         NVIC_Init(&NVIC_InitStructure);                                 //设置中断
  117. }
复制代码
(2)中断
  1. /*-------------------------------------------------*/
  2. /*函数名:定时器4中断服务函数。处理MQTT数据          */
  3. /*参  数:无                                       */
  4. /*返回值:无                                       */
  5. /*-------------------------------------------------*/
  6. void TIM4_IRQHandler(void)
  7. {
  8.         if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)//如果TIM_IT_Update置位,表示TIM4溢出中断,进入if       
  9.         {                       
  10.                 memcpy(&MQTT_RxDataInPtr[2], Usart2_RxBuff, Usart2_RxCounter);  //拷贝数据到接收缓冲区
  11.                 MQTT_RxDataInPtr[0] = Usart2_RxCounter/256;                          //记录数据长度高字节
  12.                 MQTT_RxDataInPtr[1] = Usart2_RxCounter%256;                                                 //记录数据长度低字节
  13.                 MQTT_RxDataInPtr += RBUFF_UNIT;                                        //指针下移
  14.                 if(MQTT_RxDataInPtr == MQTT_RxDataEndPtr)                             //如果指针到缓冲区尾部了
  15.                         MQTT_RxDataInPtr = MQTT_RxDataBuf[0];                            //指针归位到缓冲区开头
  16.                 Usart2_RxCounter = 0;                                                //串口2接收数据量变量清零
  17.                 TIM_SetCounter(TIM3, 0);                                             //清零定时器3计数器,重新计时ping包发送时间
  18.                 TIM_Cmd(TIM4, DISABLE);                                                                 //关闭TIM4定时器
  19.                 TIM_SetCounter(TIM4, 0);                                                         //清零定时器4计数器
  20.                 TIM_ClearITPendingBit(TIM4, TIM_IT_Update);                                      //清除TIM4溢出中断标志        
  21.         }
  22. }
  23. /*-------------------------------------------------*/
  24. /*函数名:定时器3中断服务函数                      */
  25. /*参  数:无                                       */
  26. /*返回值:无                                       */
  27. /*-------------------------------------------------*/
  28. void TIM3_IRQHandler(void)
  29. {
  30.         if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)//如果TIM_IT_Update置位,表示TIM3溢出中断,进入if       
  31.                 {  
  32.                 switch(pingFlag)                                         //判断pingFlag的状态
  33.                 {                              
  34.                         case 0:                                                        //如果pingFlag等于0,表示正常状态,发送Ping报文  
  35.                                         MQTT_PingREQ();                 //添加Ping报文到发送缓冲区  
  36.                                         break;
  37.                         case 1:                                                        //如果pingFlag等于1,说明上一次发送到的ping报文,没有收到服务器回复,所以1没有被清除为0,可能是连接异常,我们要启动快速ping模式
  38.                                         TIM3_ENABLE_2S();             //我们将定时器6设置为2s定时,快速发送Ping报文
  39.                                         MQTT_PingREQ();                        //添加Ping报文到发送缓冲区  
  40.                                         break;
  41.                         case 2:                                                        //如果pingFlag等于2,说明还没有收到服务器回复
  42.                         case 3:                                            //如果pingFlag等于3,说明还没有收到服务器回复
  43.                         case 4:                                            //如果pingFlag等于4,说明还没有收到服务器回复       
  44.                                         MQTT_PingREQ();                  //添加Ping报文到发送缓冲区
  45.                                         break;
  46.                         case 5:                                                        //如果pingFlag等于5,说明我们发送了多次ping,均无回复,应该是连接有问题,我们重启连接
  47.                                         connectFlag = 0;        //连接状态置0,表示断开,没连上服务器
  48.                                         TIM_Cmd(TIM3, DISABLE); //关TIM3                                
  49.                                         break;                       
  50.                 }
  51.                 pingFlag++;                                              //pingFlag自增1,表示又发送了一次ping,期待服务器的回复
  52.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIM3溢出中断标志        
  53.         }
  54. }
  55. /*-------------------------------------------------*/
  56. /*函数名:定时器2中断服务函数                      */
  57. /*参  数:无                                       */
  58. /*返回值:无                                       */
  59. /*-------------------------------------------------*/
  60.         extern u16 ADC_Val;
  61. void TIM2_IRQHandler(void)
  62. {
  63.         char humidity;                                //定义一个变量,保存湿度值
  64.         char temperature;                        //定义一个变量,保存温度值       
  65.                                
  66.         char head1[3];
  67.         char temp[50];                                //定义一个临时缓冲区1,不包括报头
  68.         char tempAll[100];                        //定义一个临时缓冲区2,包括所有数据
  69.        
  70.         int        dataLen = 0;                        //报文长度
  71.         ADC_Val_Disp(10,20);    //气敏检测
  72.         if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)       
  73.         {
  74.                 DHT11_Read_Data(&temperature,&humidity);//读取温湿度值
  75.                 memset(temp,    0, 50);                                    //清空缓冲区1
  76.                 memset(tempAll, 0, 100);                                //清空缓冲区2
  77.                 memset(head1,   0, 3);                                        //清空MQTT头
  78.                 sprintf(temp,"{"MQ":"%d","TM":"%d","HM":"%d"}",
  79.                                                   (ADC_Val/100), temperature, humidity);//构建报文
  80.                 head1[0] = 0x03;                                                 //固定报头
  81.                 head1[1] = 0x00;                                                 //固定报头
  82.                 head1[2] = strlen(temp);                                  //剩余长度       
  83.                 sprintf(tempAll, "%c%c%c%s", head1[0], head1[1], head1[2], temp);
  84.                
  85.                 u1_printf("\r\n"); //串口显示相关数据
  86.                 u1_printf("%s\r\n", tempAll + 3);
  87.                
  88.                 dataLen = strlen(temp) + 3;
  89.                 MQTT_PublishQs0(Data_TOPIC_NAME,tempAll, dataLen);//添加数据,发布给服务器
  90.                
  91.                 TIM_ClearITPendingBit(TIM2, TIM_IT_Update);          
  92.         }
  93. }
复制代码
4. 串口

(1)初始化
  1. /*-------------------------------------------------*/
  2. /*函数名:初始化串口1发送功能                      */
  3. /*参  数:bound:波特率                            */
  4. /*返回值:无                                       */
  5. /*-------------------------------------------------*/
  6. void Usart1_Init(unsigned int bound)
  7. {                  
  8.     GPIO_InitTypeDef GPIO_InitStructure;     //定义一个设置GPIO功能的变量
  9.         USART_InitTypeDef USART_InitStructure;   //定义一个设置串口功能的变量
  10.    
  11.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能串口1时钟
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA时钟
  13.        
  14.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;              //准备设置PA9
  15.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //IO速率50M
  16.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;               //复用推挽输出,用于串口1的发送
  17.     GPIO_Init(GPIOA, &GPIO_InitStructure);                 //设置PA9
  18.    
  19.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;             //准备设置PA10
  20.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入,用于串口1的接收
  21.     GPIO_Init(GPIOA, &GPIO_InitStructure);                 //设置PA10
  22.        
  23.         USART_InitStructure.USART_BaudRate = bound;                                    //波特率设置
  24.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;                    //8个数据位
  25.         USART_InitStructure.USART_StopBits = USART_StopBits_1;                         //1个停止位
  26.         USART_InitStructure.USART_Parity = USART_Parity_No;                            //无奇偶校验位
  27.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  28.                                                                                    //如果不使能接收模式
  29.         USART_InitStructure.USART_Mode = USART_Mode_Tx ;                                   //只发模式        
  30.     USART_Init(USART1, &USART_InitStructure);                                      //设置串口1       
  31.         USART_Cmd(USART1, ENABLE);                                                                               //使能串口1
  32. }
  33. /*-------------------------------------------------*/
  34. /*函数名:串口1 printf函数                         */
  35. /*参  数:char* fmt,...  格式化输出字符串和参数     */
  36. /*返回值:无                                       */
  37. /*-------------------------------------------------*/
  38. __align(8) char Usart1_TxBuff[USART1_TXBUFF_SIZE];  
  39. void u1_printf(char * fmt, ...)
  40. {  
  41.         unsigned int i, length;
  42.        
  43.         va_list ap;
  44.         va_start(ap, fmt);
  45.         vsprintf(Usart1_TxBuff, fmt, ap);
  46.         va_end(ap);       
  47.        
  48.         length = strlen((const char*)Usart1_TxBuff);               
  49.         while((USART1->SR&0X40) == 0);
  50.         for(i = 0; i < length; i++)
  51.         {                       
  52.                 USART1->DR = Usart1_TxBuff[i];
  53.                 while((USART1->SR&0X40) == 0);       
  54.         }       
  55. }
  56. /*-------------------------------------------------*/
  57. /*函数名:初始化串口2发送功能                        */
  58. /*参  数:bound:波特率                             */
  59. /*返回值:无                                        */
  60. /*-------------------------------------------------*/
  61. void Usart2_Init(unsigned int bound)
  62. {                  
  63.     GPIO_InitTypeDef GPIO_InitStructure;     //定义一个设置GPIO功能的变量
  64.         USART_InitTypeDef USART_InitStructure;   //定义一个设置串口功能的变量
  65.         NVIC_InitTypeDef NVIC_InitStructure;     //如果使能接收功能,定义一个设置中断的变量
  66.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //设置中断向量分组:第2组 抢先优先级:0 1 2 3 子优先级:0 1 2 3       
  67.       
  68.        
  69.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //使能串口2时钟
  70.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA时钟
  71.         USART_DeInit(USART2);                                  //串口2寄存器重新设置为默认值
  72.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;              //准备设置PA2
  73.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //IO速率50M
  74.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;               //复用推挽输出,用于串口2的发送
  75.     GPIO_Init(GPIOA, &GPIO_InitStructure);                 //设置PA2
  76.    
  77.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;              //准备设置PA3
  78.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入,用于串口2的接收
  79.     GPIO_Init(GPIOA, &GPIO_InitStructure);                 //设置PA3
  80.        
  81.         USART_InitStructure.USART_BaudRate = bound;                                    //波特率设置
  82.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;                    //8个数据位
  83.         USART_InitStructure.USART_StopBits = USART_StopBits_1;                         //1个停止位
  84.         USART_InitStructure.USART_Parity = USART_Parity_No;                            //无奇偶校验位
  85.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  86.         USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;                       //收发模式
  87.       
  88.     USART_Init(USART2, &USART_InitStructure);                                      //设置串口2       
  89.         USART_ClearFlag(USART2, USART_FLAG_RXNE);                      //清除接收标志位
  90.         USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);            //开启接收中断
  91.     NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;         //设置串口2中断
  92.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
  93.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                  //子优先级0
  94.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                          //中断通道使能
  95.         NVIC_Init(&NVIC_InitStructure);                                  //设置串口2中断
  96.         USART_Cmd(USART2, ENABLE);                                //使能串口2
  97. }
  98. /*-------------------------------------------------*/
  99. /*函数名:串口2 printf函数                          */
  100. /*参  数:char* fmt,...  格式化输出字符串和参数      */
  101. /*返回值:无                                        */
  102. /*-------------------------------------------------*/
  103. __align(8) char USART2_TxBuff[USART2_TXBUFF_SIZE];  
  104. void u2_printf(char* fmt, ...)
  105. {  
  106.         unsigned int i, length;
  107.        
  108.         va_list ap;
  109.         va_start(ap, fmt);
  110.         vsprintf(USART2_TxBuff, fmt, ap);
  111.         va_end(ap);       
  112.        
  113.         length=strlen((const char*)USART2_TxBuff);               
  114.         while((USART2->SR&0X40) == 0);
  115.         for(i = 0; i < length; i++)
  116.         {                       
  117.                 USART2->DR = USART2_TxBuff[i];
  118.                 while((USART2->SR&0X40) == 0);       
  119.         }       
  120. }
  121. /*-------------------------------------------------*/
  122. /*函数名:串口2发送缓冲区中的数据                    */
  123. /*参  数:data:数据                                */
  124. /*返回值:无                                        */
  125. /*-------------------------------------------------*/
  126. void u2_TxData(unsigned char *data)
  127. {
  128.         int        i;       
  129.         while((USART2->SR&0X40) == 0);
  130.         for(i = 1; i <= (data[0] * 256 + data[1]); i++)
  131.         {                       
  132.                 USART2->DR = data[i+1];
  133.                 while((USART2->SR&0X40) == 0);       
  134.         }
  135. }
复制代码
(2)中断
  1. /*-------------------------------------------------*/
  2. /*函数名:串口2接收中断函数(最高优先级,处理接收数据)*/
  3. /*参  数:无                                       */
  4. /*返回值:无                                       */
  5. /*-------------------------------------------------*/
  6. void USART2_IRQHandler(void)   
  7. {                     
  8.         if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)    //如果USART_IT_RXNE标志置位,表示有数据到了,进入if分支
  9.         {  
  10.                 if(connectFlag == 0)                                                              //如果connectFlag等于0,当前还没有连接服务器,处于指令配置状态
  11.                 {                                    
  12.                         if(USART2->DR)
  13.                         {                                                              //处于指令配置状态时,非零值才保存到缓冲区       
  14.                                 Usart2_RxBuff[Usart2_RxCounter] = USART2->DR;//保存到缓冲区       
  15.                                 Usart2_RxCounter++;                                                  //每接收1个字节的数据,Usart2_RxCounter加1,表示接收的数据总量+1
  16.                         }                                       
  17.                 }
  18.                 else
  19.                 {                                                                    //反之connectFlag等于1,连接上服务器了       
  20.                         Usart2_RxBuff[Usart2_RxCounter] = USART2->DR;    //把接收到的数据保存到Usart2_RxBuff中                               
  21.                         if(Usart2_RxCounter == 0)
  22.                         {                                                                                                                                                                         //如果Usart2_RxCounter等于0,表示是接收的第1个数据,进入if分支                               
  23.                                 TIM_Cmd(TIM4, ENABLE);
  24.                         }
  25.                         else                                                                                                                                                                                 //else分支,表示果Usart2_RxCounter不等于0,不是接收的第一个数据
  26.                         {                                                                                                    
  27.                                 TIM_SetCounter(TIM4, 0);  
  28.                         }       
  29.                         Usart2_RxCounter++;                                              //每接收1个字节的数据,Usart2_RxCounter加1,表示接收的数据总量+1
  30.                 }
  31.         }
  32. }
复制代码
5. MQTT

  1. /*----------------------------------------------------------*/
  2. /*函数名:初始化接收,发送,命令数据的 缓冲区 以及各状态参数  */
  3. /*参  数:无                                                */
  4. /*返回值:无                                                */
  5. /*----------------------------------------------------------*/
  6. void MQTT_Buff_Init(void)
  7. {       
  8.         MQTT_RxDataInPtr=MQTT_RxDataBuf[0];                                  //指向发送缓冲区存放数据的指针归位
  9.         MQTT_RxDataOutPtr=MQTT_RxDataInPtr;                                  //指向发送缓冲区读取数据的指针归位
  10.         MQTT_RxDataEndPtr=MQTT_RxDataBuf[R_NUM-1];                     //指向发送缓冲区结束的指针归位
  11.        
  12.         MQTT_TxDataInPtr=MQTT_TxDataBuf[0];                                         //指向发送缓冲区存放数据的指针归位
  13.         MQTT_TxDataOutPtr=MQTT_TxDataInPtr;                                     //指向发送缓冲区读取数据的指针归位
  14.         MQTT_TxDataEndPtr=MQTT_TxDataBuf[T_NUM-1];           //指向发送缓冲区结束的指针归位
  15.        
  16.         MQTT_CMDInPtr=MQTT_CMDBuf[0];                        //指向命令缓冲区存放数据的指针归位
  17.         MQTT_CMDOutPtr=MQTT_CMDInPtr;                        //指向命令缓冲区读取数据的指针归位
  18.         MQTT_CMDEndPtr=MQTT_CMDBuf[C_NUM-1];                       //指向命令缓冲区结束的指针归位
  19.         MQTT_ConectPack();                                         //发送缓冲区添加连接报文
  20.         MQTT_Subscribe(S_TOPIC_NAME,0);                                  //发送缓冲区添加订阅topic,等级0       
  21.        
  22.         pingFlag = connectPackFlag = subcribePackFlag = 0;   //各个参数清零
  23. }
  24. /*----------------------------------------------------------*/
  25. /*函数名:云初始化参数,得到客户端ID,用户名和密码          */
  26. /*参  数:无                                                */
  27. /*返回值:无                                                */
  28. /*----------------------------------------------------------*/
  29. void IoT_Parameter_Init(void)
  30. {       
  31.         memset(ClientID,0,128);                              //客户端ID的缓冲区全部清零
  32.         sprintf(ClientID,"%s",DEVICEID);                     //构建客户端ID,并存入缓冲区
  33.         ClientID_len = strlen(ClientID);                     //计算客户端ID的长度
  34.        
  35.         memset(Username,0,128);                              //用户名的缓冲区全部清零
  36.         sprintf(Username,"%s",PRODUCTID);                    //构建用户名,并存入缓冲区
  37.         Username_len = strlen(Username);                     //计算用户名的长度
  38.        
  39.         memset(Passward,0,128);                              //用户名的缓冲区全部清零
  40.         sprintf(Passward,"%s",AUTHENTICATION);               //构建密码,并存入缓冲区
  41.         Passward_len = strlen(Passward);                     //计算密码的长度
  42.        
  43.         memset(ServerIP,0,128);  
  44.         sprintf(ServerIP,"%s","183.230.40.39");              //构建服务器域名
  45.         ServerPort = 6002;                                   //服务器端口号6002
  46.        
  47.         u1_printf("服 务 器:%s:%d\r\n",ServerIP,ServerPort); //串口输出调试信息
  48.         u1_printf("客户端ID:%s\r\n",ClientID);               //串口输出调试信息
  49.         u1_printf("用 户 名:%s\r\n",Username);               //串口输出调试信息
  50.         u1_printf("密    码:%s\r\n",Passward);               //串口输出调试信息
  51. }
  52. /*----------------------------------------------------------*/
  53. /*函数名:连接服务器报文                                    */
  54. /*参  数:无                                                */
  55. /*返回值:无                                                */
  56. /*----------------------------------------------------------*/
  57. void MQTT_ConectPack(void)
  58. {       
  59.         int temp,Remaining_len;
  60.        
  61.         Fixed_len = 1;                                                        //连接报文中,固定报头长度暂时先=1
  62.         Variable_len = 10;                                                    //连接报文中,可变报头长度=10
  63.         Payload_len = 2 + ClientID_len + 2 + Username_len + 2 + Passward_len; //连接报文中,负载长度      
  64.         Remaining_len = Variable_len + Payload_len;                           //剩余长度=可变报头长度+负载长度
  65.        
  66.         temp_buff[0]=0x10;                         //固定报头第1个字节 :固定0x01               
  67.         do{                                        //循环处理固定报头中的剩余长度字节,字节量根据剩余字节的真实长度变化
  68.                 temp = Remaining_len%128;              //剩余长度取余128
  69.                 Remaining_len = Remaining_len/128;     //剩余长度取整128
  70.                 if(Remaining_len>0)                      
  71.                         temp |= 0x80;                      //按协议要求位7置位         
  72.                 temp_buff[Fixed_len] = temp;           //剩余长度字节记录一个数据
  73.                 Fixed_len++;                               //固定报头总长度+1   
  74.         }while(Remaining_len > 0);                 //如果Remaining_len>0的话,再次进入循环
  75.        
  76.         temp_buff[Fixed_len + 0] = 0x00;     //可变报头第1个字节 :固定0x00                   
  77.         temp_buff[Fixed_len + 1] = 0x04;     //可变报头第2个字节 :固定0x04
  78.         temp_buff[Fixed_len + 2] = 0x4D;         //可变报头第3个字节 :固定0x4D
  79.         temp_buff[Fixed_len + 3] = 0x51;         //可变报头第4个字节 :固定0x51
  80.         temp_buff[Fixed_len + 4] = 0x54;         //可变报头第5个字节 :固定0x54
  81.         temp_buff[Fixed_len + 5] = 0x54;     //可变报头第6个字节 :固定0x54
  82.         temp_buff[Fixed_len + 6] = 0x04;         //可变报头第7个字节 :固定0x04
  83.         temp_buff[Fixed_len + 7] = 0xC2;         //可变报头第8个字节 :使能用户名和密码校验,不使用遗嘱,不保留会话
  84.         temp_buff[Fixed_len + 8] = 0x00;          //可变报头第9个字节 :保活时间高字节 0x00
  85.         temp_buff[Fixed_len + 9] = 0x64;         //可变报头第10个字节:保活时间高字节 0x64   100s
  86.        
  87.         /*     CLIENT_ID      */
  88.         temp_buff[Fixed_len+10] = ClientID_len/256;                                                  //客户端ID长度高字节
  89.         temp_buff[Fixed_len+11] = ClientID_len%256;                                                 //客户端ID长度低字节
  90.         memcpy(&temp_buff[Fixed_len+12],ClientID,ClientID_len);                 //复制过来客户端ID字串       
  91.         /*     用户名        */
  92.         temp_buff[Fixed_len+12+ClientID_len] = Username_len/256;                                 //用户名长度高字节
  93.         temp_buff[Fixed_len+13+ClientID_len] = Username_len%256;                                 //用户名长度低字节
  94.         memcpy(&temp_buff[Fixed_len+14+ClientID_len],Username,Username_len);    //复制过来用户名字串       
  95.         /*      密码        */
  96.         temp_buff[Fixed_len+14+ClientID_len+Username_len] = Passward_len/256;        //密码长度高字节
  97.         temp_buff[Fixed_len+15+ClientID_len+Username_len] = Passward_len%256;        //密码长度低字节
  98.         memcpy(&temp_buff[Fixed_len+16+ClientID_len+Username_len],Passward,Passward_len); //复制过来密码字串
  99.         TxDataBuf_Deal(temp_buff, Fixed_len + Variable_len + Payload_len);      //加入发送数据缓冲区
  100. }
  101. /*----------------------------------------------------------*/
  102. /*函数名:SUBSCRIBE订阅topic报文                            */
  103. /*参  数:QoS:订阅等级                                     */
  104. /*参  数:topic_name:订阅topic报文名称                     */
  105. /*返回值:无                                                */
  106. /*----------------------------------------------------------*/
  107. void MQTT_Subscribe(char *topic_name, int QoS)
  108. {       
  109.         Fixed_len = 2;                                                 //SUBSCRIBE报文中,固定报头长度=2
  110.         Variable_len = 2;                                                     //SUBSCRIBE报文中,可变报头长度=2       
  111.         Payload_len = 2 + strlen(topic_name) + 1;                      //计算有效负荷长度 = 2字节(topic_name长度)+ topic_name字符串的长度 + 1字节服务等级
  112.        
  113.         temp_buff[0] = 0x82;                                   //第1个字节 :固定0x82                     
  114.         temp_buff[1] = Variable_len + Payload_len;             //第2个字节 :可变报头+有效负荷的长度       
  115.         temp_buff[2] = 0x00;                                   //第3个字节 :报文标识符高字节,固定使用0x00
  116.         temp_buff[3] = 0x01;                                           //第4个字节 :报文标识符低字节,固定使用0x01
  117.         temp_buff[4] = strlen(topic_name)/256;                 //第5个字节 :topic_name长度高字节
  118.         temp_buff[5] = strlen(topic_name)%256;                           //第6个字节 :topic_name长度低字节
  119.         memcpy(&temp_buff[6], topic_name, strlen(topic_name)); //第7个字节开始 :复制过来topic_name字串               
  120.         temp_buff[6 + strlen(topic_name)] = QoS;               //最后1个字节:订阅等级
  121.        
  122.         TxDataBuf_Deal(temp_buff, Fixed_len + Variable_len + Payload_len);  //加入发送数据缓冲区
  123. }
  124. /*----------------------------------------------------------*/
  125. /*函数名:PING报文,心跳包                                   */
  126. /*参  数:无                                                */
  127. /*返回值:无                                                */
  128. /*----------------------------------------------------------*/
  129. void MQTT_PingREQ(void)
  130. {
  131.         temp_buff[0] = 0xC0;              //第1个字节 :固定0xC0                     
  132.         temp_buff[1] = 0x00;              //第2个字节 :固定0x00
  133.         TxDataBuf_Deal(temp_buff, 2);     //加入数据到缓冲区
  134. }
  135. /*----------------------------------------------------------*/
  136. /*函数名:等级0 发布消息报文                                  */
  137. /*参  数:topic_name:topic名称                              */
  138. /*参  数:data:数据                                         */
  139. /*参  数:data_len:数据长度                                 */
  140. /*返回值:无                                                 */
  141. /*----------------------------------------------------------*/
  142. void MQTT_PublishQs0(char *topic, char *data, int data_len)
  143. {       
  144.         int temp,Remaining_len;
  145.        
  146.         Fixed_len = 1;                              //固定报头长度暂时先等于:1字节
  147.         Variable_len = 2 + strlen(topic);           //可变报头长度:2字节(topic长度)+ topic字符串的长度
  148.         Payload_len = data_len;                     //有效负荷长度:就是data_len
  149.         Remaining_len = Variable_len + Payload_len; //剩余长度=可变报头长度+负载长度
  150.        
  151.         temp_buff[0] = 0x30;                              //固定报头第1个字节 :固定0x30          
  152.         do{                                         //循环处理固定报头中的剩余长度字节,字节量根据剩余字节的真实长度变化
  153.                 temp = Remaining_len%128;                   //剩余长度取余128
  154.                 Remaining_len = Remaining_len/128;      //剩余长度取整128
  155.                 if(Remaining_len>0)                      
  156.                         temp |= 0x80;                            //按协议要求位7置位         
  157.                 temp_buff[Fixed_len] = temp;            //剩余长度字节记录一个数据
  158.                 Fixed_len++;                                     //固定报头总长度+1   
  159.         }while(Remaining_len>0);                    //如果Remaining_len>0的话,再次进入循环
  160.                              
  161.         temp_buff[Fixed_len+0] = strlen(topic)/256;                       //可变报头第1个字节     :topic长度高字节
  162.         temp_buff[Fixed_len+1] = strlen(topic)%256;                                  //可变报头第2个字节     :topic长度低字节
  163.         memcpy(&temp_buff[Fixed_len+2], topic,strlen(topic));             //可变报头第3个字节开始 :拷贝topic字符串       
  164.         memcpy(&temp_buff[Fixed_len + 2 + strlen(topic)], data, data_len);//有效负荷:拷贝data数据
  165.        
  166.         TxDataBuf_Deal(temp_buff, Fixed_len + Variable_len + Payload_len);//加入发送数据缓冲区       
  167. }
  168. /*----------------------------------------------------------*/
  169. /*函数名:处理服务器发来的等级0的推送                          */
  170. /*参  数:redata:接收的数据                                 */
  171. /*返回值:无                                                 */
  172. /*----------------------------------------------------------*/
  173. void MQTT_DealPushdata_Qs0(unsigned char *redata)
  174. {
  175.         int  re_len;                                  //定义一个变量,存放接收的数据总长度
  176.         int  pack_num;                         //定义一个变量,当多个推送一起过来时,保存推送的个数
  177.     int  temp,temp_len;                    //定义一个变量,暂存数据
  178.     int  totle_len;                        //定义一个变量,存放已经统计的推送的总数据量
  179.         int  topic_len;                             //定义一个变量,存放推送中主题的长度
  180.         int  cmd_len;                          //定义一个变量,存放推送中包含的命令数据的长度
  181.         int  cmd_loca;                         //定义一个变量,存放推送中包含的命令的起始位置
  182.         int  i;                                //定义一个变量,用于for循环
  183.         int  local,multiplier;
  184.         unsigned char tempbuff[RBUFF_UNIT];           //临时缓冲区
  185.         unsigned char *data;                   //redata过来的时候,第一个字节是数据总量,data用于指向redata的第2个字节,真正的数据开始的地方
  186.                
  187.         re_len = redata[0]*256+redata[1];                     //获取接收的数据总长度               
  188.         data = &redata[2];                                    //data指向redata的第2个字节,真正的数据开始的
  189.         pack_num = temp_len = totle_len = temp = 0;           //各个变量清零
  190.         local = 1;
  191.         multiplier = 1;
  192.         do{
  193.                 pack_num++;                                       //开始循环统计推送的个数,每次循环推送的个数+1       
  194.                 do{
  195.                         temp = data[totle_len + local];   
  196.                         temp_len += (temp & 127) * multiplier;
  197.                         multiplier *= 128;
  198.                         local++;
  199.                 }while ((temp & 128) != 0);
  200.                 totle_len += (temp_len + local);                  //累计统计的总的推送的数据长度
  201.                 re_len -= (temp_len + local) ;                    //接收的数据总长度 减去 本次统计的推送的总长度      
  202.                 local = 1;
  203.                 multiplier = 1;
  204.                 temp_len = 0;
  205.         }while(re_len!=0);                                    //如果接收的数据总长度等于0了,说明统计完毕了
  206.         u1_printf("本次接收了%d个推送数据\r\n",pack_num);                //串口输出信息
  207.         temp_len = totle_len = 0;                                      //各个变量清零
  208.         local = 1;
  209.         multiplier = 1;
  210.         for(i = 0; i < pack_num; i++)                        //已经统计到了接收的推送个数,开始for循环,取出每个推送的数据
  211.         {                                               
  212.                 do{
  213.                         temp = data[totle_len + local];   
  214.                         temp_len += (temp & 127) * multiplier;
  215.                         multiplier *= 128;
  216.                         local++;
  217.                 }while ((temp & 128) != 0);                               
  218.                 topic_len = data[local + totle_len]*256 + data[local + 1 + totle_len] + 2; //计算本次推送数据中主题占用的数据量
  219.                 cmd_len = temp_len - topic_len;                                                         //计算本次推送数据中命令数据占用的数据量
  220.                 cmd_loca = totle_len + local +  topic_len;                                             //计算本次推送数据中命令数据开始的位置
  221.                 memcpy(tempbuff, &data[cmd_loca], cmd_len);                                              //命令数据拷贝出来                                 
  222.                 CMDBuf_Deal(tempbuff, cmd_len);                                                        //加入命令到缓冲区
  223.                 totle_len += (temp_len + local);                                                         //累计已经统计的推送的数据长度
  224.                 local = 1;
  225.                 multiplier = 1;
  226.                 temp_len = 0;
  227.         }       
  228. }
  229. /*----------------------------------------------------------*/
  230. /*函数名:处理发送缓冲区                                      */
  231. /*参  数:data:数据                                         */
  232. /*参  数:size:数据长度                                                                                      */
  233. /*返回值:无                                                 */
  234. /*----------------------------------------------------------*/
  235. void TxDataBuf_Deal(unsigned char *data, int size)
  236. {
  237.         memcpy(&MQTT_TxDataInPtr[2], data, size);     //拷贝数据到发送缓冲区       
  238.         MQTT_TxDataInPtr[0] = size/256;               //记录数据长度
  239.         MQTT_TxDataInPtr[1] = size%256;               //记录数据长度
  240.         MQTT_TxDataInPtr += TBUFF_UNIT;               //指针下移
  241.         if(MQTT_TxDataInPtr == MQTT_TxDataEndPtr)     //如果指针到缓冲区尾部了
  242.                 MQTT_TxDataInPtr = MQTT_TxDataBuf[0];     //指针归位到缓冲区开头
  243. }
  244. /*----------------------------------------------------------*/
  245. /*函数名:处理命令缓冲区                                                                         */
  246. /*参  数:data:数据                                        */
  247. /*参  数:size:数据长度                                    */
  248. /*返回值:无                                                */
  249. /*----------------------------------------------------------*/
  250. void CMDBuf_Deal(unsigned char *data, int size)
  251. {
  252.         memcpy(&MQTT_CMDInPtr[2], data,size);         //拷贝数据到命令缓冲区
  253.         MQTT_CMDInPtr[0] = size/256;                        //记录数据长度
  254.         MQTT_CMDInPtr[1] = size%256;                  //记录数据长度
  255.         MQTT_CMDInPtr[size+2] = '\0';                 //加入字符串结束符
  256.         MQTT_CMDInPtr += CBUFF_UNIT;                         //指针下移
  257.         if(MQTT_CMDInPtr == MQTT_CMDEndPtr)           //如果指针到缓冲区尾部了
  258.                 MQTT_CMDInPtr = MQTT_CMDBuf[0];                  //指针归位到缓冲区开头
  259. }
复制代码
五、进阶练习

在以上底子上可尝试以下功能:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4