zoukankan      html  css  js  c++  java
  • 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 "
    #define  CMD_CWMODE    "AT+CWMODE=3 "
    #define  CMD_RST         "AT+RST "
    #define  CMD_CIFSR        "AT+CIFSR "
    #define  CMD_CWJAP       "AT+CWJAP=" XXXX "," XXXX " "
    #define  CMD_CIPSTART     "AT+CIPSTART="TCP","183.230.40.39",876 "
    #define  CMD_CIPMODE     "AT+CIPMODE=1 "
    #define  CMD_CIPSEND      "AT+CIPSEND "
    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);释放内存。

  • 相关阅读:
    spring+mybatis多数据源切换
    【linux环境下】RabbitMq的安装和监控插件安装
    Slurm远程登录Jupyter Notebook
    Google Colab 使用
    关于conda和jupyter使用
    关于给C盘扩容以及动态磁盘
    关于使用实验室服务器的GPU以及跑上TensorFlow代码
    一些更改的后端接口和代码
    MarkDown to PDF
    蜗牛慢慢爬 LeetCode 25. Reverse Nodes in k-Group [Difficulty: Hard]
  • 原文地址:https://www.cnblogs.com/neverguveip/p/9457246.html
Copyright © 2011-2022 走看看