【分享】STM32F4+Wi-Fi+EDP 向 OneNet 上传数据-Arduino中文社区 - Powered by Discuz! Archiver

OneNET 发表于 2016-1-20 16:36

【分享】STM32F4+Wi-Fi+EDP 向 OneNet 上传数据

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

1.调试STM32F4的串口发送功能。
2.利用STM32F4串口向WIFI模块发送平台连接的TCP连接指令。
3.利用STM32F4串口向WIFI模块发送EDP设备连接请求报文。
4.利用STM32F4串口向WIFI模块发送EDP数据报文。
步骤1:串口发送功能的调试,STM32F4有一套编写好的库函数,我们只需要简单调用其中的某些函数,即可以实现STM32F4的串口发送功能。 串口初始化函数代码如下:

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);   
}
串口发送函数代码如下:

void usart1_write(USART_TypeDef* USARTx, uint8_t *Data,uint8_t len)
{
    uint8_ti;
    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值的代码都可以解决问题。

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网络名和连接密码)

#defineCMD_AT          "AT\r\n"
#defineCMD_CWMODE    "AT+CWMODE=3\r\n"
#defineCMD_RST         "AT+RST\r\n"
#defineCMD_CIFSR      "AT+CIFSR\r\n"
#defineCMD_CWJAP       "AT+CWJAP=\" XXXX \",\" XXXX \"\r\n"
#defineCMD_CIPSTART   "AT+CIPSTART=\"TCP\",\"183.230.40.39\",876\r\n"
#defineCMD_CIPMODE   "AT+CIPMODE=1\r\n"
#defineCMD_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模块可能无法接收到我们发送的指令,我们需要对代码进一步优化.

voidwait_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。

#defineDEVICEID "634631"
#defineAPIKEY   "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模块发送设备连接请求报文

char text = {0};
char send_buf;
//生成数据报文的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);释放内存。
页: [1]
查看完整版本: 【分享】STM32F4+Wi-Fi+EDP 向 OneNet 上传数据