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

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9001|回复: 0

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

[复制链接]
发表于 2016-1-20 16:36 | 显示全部楼层 |阅读模式
    利用STM32F4+WIFI+EDP向OneNet平台上传数据,虽然非常简单,但是在个人调试过程中的仍有一些细节需要注意,下面将调试过程总结如下,希望能和大家一起交流,共同进步。 实验过程主要分为以下四个步骤:

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

[mw_shl_code=cpp,true]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 );
    }
}[/mw_shl_code]
这里主要是注意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值的代码都可以解决问题。

[mw_shl_code=cpp,true]USART_GetFlagStatus(USART1, USART_FLAG_TC); //得到串口状态标记函数
USART_SR USART_ClearFlag(USART2,USART_FLAG_TC); //清除TC位[/mw_shl_code]

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

[mw_shl_code=cpp,true]#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();
}[/mw_shl_code]
这里有两个问题,指令发送出去之后WIFI模块是否得到正确的响应我们并不知道,另外发送指令后的delay函数,到底延时多久,如果延时太短,指令发送太快,WIFI模块可能无法接收到我们发送的指令,我们需要对代码进一步优化.

[mw_shl_code=cpp,true]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));
}
[/mw_shl_code]
步骤3:通过串口向WIFI模块发送设备连接请求报文,这里我们利用平台提供的SDK。

[mw_shl_code=cpp,true]#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);//释放内存[/mw_shl_code]
一定要记得DeleteBuffer(&send_pkg);不然程序运行一段时间后,可能由于内存耗尽而崩溃。

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

[mw_shl_code=cpp,true]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); //释放内存[/mw_shl_code]
同样,要注意DeleteBuffer(&send_pkg);释放内存。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-9-20 12:12 , Processed in 0.067363 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表