STM32F4+Wi-Fi+EDP 向 OneNet 上传数据

源地址:https://www.arduino.cn/thread-19000-1-1.html
    利用STM32F4+WIFI+EDP向OneNet平台上传数据,虽然非常简单,但是在个人调试过程中的仍有一些细节需要注意,下面将调试过程总结如下,希望能和大家一起交流,共同进步。 实验过程主要分为以下四个步骤:

1.调试STM32F4的串口发送功能。
2.利用STM32F4串口向WIFI模块发送平台连接的TCP连接指令。
3.利用STM32F4串口向WIFI模块发送EDP设备连接请求报文。
4.利用STM32F4串口向WIFI模块发送EDP数据报文。
步骤1:串口发送功能的调试,STM32F4有一套编写好的库函数,我们只需要简单调用其中的某些函数,即可以实现STM32F4的串口发送功能。 串口初始化函数代码如下:
[C++] 纯文本查看 复制代码
?
代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
void usart1_init(u32 bound)
{
     //GPIO端口初始化
     GPIO_InitTypeDef GPIO_InitStructure;
     USART_InitTypeDef USART_InitStructure;
     NVIC_InitTypeDef NVIC_InitStructure;
     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //使能USART1时钟
     //串口1对应引脚复用映射
     GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
     GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
     //USART1端口配置
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
     GPIO_Init(GPIOA,&GPIO_InitStructure);
     //USART1串口初始化配置
     USART_InitStructure.USART_BaudRate = bound;
     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
     USART_InitStructure.USART_StopBits = USART_StopBits_1;
     USART_InitStructure.USART_Parity = USART_Parity_No;
     USART_InitStructure.USART_HardwareFlowControl =                     USART_HardwareFlowControl_None;
     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   
     USART_Init(USART1, &USART_InitStructure);
 
     USART_Cmd(USART1, ENABLE); //使能串口1
     //开启串口接收中断
     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
     //USART1 NVIC配置
     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;   
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   
     NVIC_Init(&NVIC_InitStructure);   
}

串口发送函数代码如下:

[C++] 纯文本查看 复制代码
?
代码
001
002
003
004
005
006
007
008
009
010
011
void usart1_write(USART_TypeDef* USARTx, uint8_t *Data,uint8_t len)
{
     uint8_t  i;
     USART_ClearFlag(USART1,USART_FLAG_TC);
     //USART_GetFlagStatus(USART1, USART_FLAG_TC);
     for (i=0; i<len; i++)
     {                                        
         USART_SendData(USARTx, *Data++);
         while ( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
     }
}

这里主要是注意USART_ClearFlag(USART1,USART_FLAG_TC);调试过程中发现发送功能函数发送的字符串缺少第一个字符,刚开始以为是串口波特率定义为115200过快,造成第一个字节没法显示,查看查阅stm32f10x参考手册,找到问题原因: TC:发送完成 当包含有数据的一帧发送完成后,由硬件将该位置位。如果USART_CR1中的TCIE为1,则产生中断。由软件序列清除该位(先读USART_SR,然后写入USART_DR)。TC位也可以通过写入0来清除,只有在多缓存通讯中才推荐这种清除程序。 0:发送还未完成;1:发送完成。而软件清除该位(先读USART_SR,然后写入USART_DR)。也就是说,要先read USART_SR,然后write USART_DR,才能完成TC状态位的清除。而在硬件复位后,串口发送的首个数据之前没有read SR的操作,是直接write DR,也就是说,TC没有被清除掉。那么在发送字符串之前加上一句清除发送位TC标记或者读取USART_SR值的代码都可以解决问题。

[C++] 纯文本查看 复制代码
?
代码
001
002
USART_GetFlagStatus(USART1, USART_FLAG_TC); //得到串口状态标记函数
USART_SR USART_ClearFlag(USART2,USART_FLAG_TC); //清除TC位


步骤2:通过串口指令配置WIFI模块,和OneNet平台建立TCP连接。参考WIFI模块命令手册,依次发送如下几个命令到WIFI模块:

AT
AT+CWMODE=3
AT+RST
AT+CIFSR
AT+CWJAP="your ssid","password"
AT+CIPSTART="TCP","183.230.40.33",80  //和服务器建立TCP连接
AT+CIPMODE=1    //进入透明传输模式
AT+CIPSEND  //开始传输
对应程序代码如下:(对应的四个XXXX字符串换成你自己的设备ID,设备ID关联的APIKEY以及你的WIFI网络名和连接密码)

[C++] 纯文本查看 复制代码
?
代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
#define  CMD_AT          "AT\r\n"
#define  CMD_CWMODE    "AT+CWMODE=3\r\n"
#define  CMD_RST         "AT+RST\r\n"
#define  CMD_CIFSR        "AT+CIFSR\r\n"
#define  CMD_CWJAP       "AT+CWJAP=\" XXXX \",\" XXXX \"\r\n"
#define  CMD_CIPSTART     "AT+CIPSTART=\"TCP\",\"183.230.40.39\",876\r\n"
#define  CMD_CIPMODE     "AT+CIPMODE=1\r\n"
#define  CMD_CIPSEND      "AT+CIPSEND\r\n"
void create_tcp_link( void )
{
     usart1_write(USART1, CMD_AT, strlen (CMD_AT));
     delay();
     usart1_write(USART1, CMD_CWMODE, strlen (CMD_CWMODE));
     delay();
     usart1_write(USART1, CMD_RST, strlen (CMD_RST));
     delay();
     usart1_write(USART1, CMD_CIFSR, strlen (CMD_CIFSR));
     delay();
     usart1_write(USART1, CMD_CWJAP, strlen (CMD_CWJAP));
     delay();
     usart1_write(USART1, CMD_CIPSTART, strlen (CMD_CIPSTART));
     delay();
     usart1_write(USART1, CMD_CIPMODE, strlen (CMD_CIPMODE));
     delay();
     usart1_write(USART1, CMD_CIPSEND, strlen (CMD_CIPSEND));
     delay();
}

这里有两个问题,指令发送出去之后WIFI模块是否得到正确的响应我们并不知道,另外发送指令后的delay函数,到底延时多久,如果延时太短,指令发送太快,WIFI模块可能无法接收到我们发送的指令,我们需要对代码进一步优化.

[C++] 纯文本查看 复制代码
?
代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
void  wait_cmd_echo( char * cmd_buf)
{
     usart1_write(USART1,cmd_buf, strlen (cmd_buf)); //发送WIFI指令
     while (1)
     {
         if (usart1_rcv_flag==1) //接收WIFI模块回复信息完成
         {
             if ( strstr (usart1_rcv_buf, "OK" )!=NULL) //如果WIFI模块回复成功信息
             {
                 memset (usart1_rcv_buf,0,usart1_rcv_len);
                 usart1_rcv_len=0;
                 usart1_rcv_flag=0;
                 break ; //跳出循环进行下一条指令发送
             }
             else if ( strstr (usart1_rcv_buf, "ERROR" )!=NULL) //如果WIFI模块回复失败信息
             {
                 memset (usart1_rcv_buf,0,usart1_rcv_len);
                 usart1_rcv_len=0;
                 usart1_rcv_flag=0;
                 usart1_write(USART1,cmd_buf, strlen (cmd_buf)); //重发指令
             }
         }
         If(wait_cmd_timeout==1) //等待WIFI模块回复超时
         {
             usart1_write(USART1,cmd_buf, strlen (cmd_buf)); //重发指令
         }
     }
}
void create_tcp_link( void )
{
wait_cmd_echo(CMD_AT);
wait_cmd_echo(CMD_CWMODE);
wait_cmd_echo(CMD_RST);
wait_cmd_echo(CMD_CIFSR);
wait_cmd_echo(CMD_CWJAP);
wait_cmd_echo(CMD_CIPSTART);
wait_cmd_echo(CMD_CIPMODE);
usart1_write(USART1, CMD_CIPSEND, strlen (CMD_CIPSEND));
}

步骤3:通过串口向WIFI模块发送设备连接请求报文,这里我们利用平台提供的SDK。

[C++] 纯文本查看 复制代码
?
代码
001
002
003
004
005
006
#define  DEVICEID "634631"
#define  APIKEY   "BlkPaCqLFHrGVfFRacsXVEwVv80="
EdpPacket* send_pkg;
send_pkg = PacketConnect1(DEVICEID, APIKEY);  //设备连接请求包生成函数
usart1_write(USART1,send_pkg->_data,send_pkg->_write_pos); //发送设备连接请求报文   
DeleteBuffer(&send_pkg); //释放内存

一定要记得DeleteBuffer(&send_pkg);不然程序运行一段时间后,可能由于内存耗尽而崩溃。

步骤4:通过串口向WIFI模块发送设备连接请求报文

[C++] 纯文本查看 复制代码
?
代码
001
002
003
004
005
006
007
008
009
010
011
012
013
char text[25] = {0};
char send_buf[512];
//生成数据报文的JSON格式
strcat (send_buf, "{\"datastreams\": [{" );
strcat (send_buf, "\"id\": \"systime\"," );
strcat (send_buf, "\"datapoints\": [" );
strcat (send_buf, "{" );
sprintf (text, "\"value\":\"%d\"" ,40);
strcat (send_buf, text);
strcat (send_buf, "}]}]}" );   
send_pkg = PacketSaveJson(DEVICEID, send_buf); //生成EDP数据报文
usart1_write(USART1,send_pkg->_data,send_pkg->_write_pos); //发送EDP数据报文       
DeleteBuffer(&send_pkg); //释放内存

同样,要注意DeleteBuffer(&send_pkg);释放内存。

猜你喜欢

转载自blog.csdn.net/wcx1293296315/article/details/80555075