[技术干货] 如何使用STM32F103+Wifi连接OceanConnect平台

硬件环境:秉火STM32F103

官方例程:Huawei LiteOS + (NB-IoT / WIFI / 2G ) + OceanConnect平台的端云Demo

基础例程:https://download.csdn.net/download/sinat_27066063/10809185

                之前移植好的可以在stm32f103运行的Huawei_LiteOS,OS移植过程可参考Huawei_LiteOS——STM32F103移植

移植代码分享:https://download.csdn.net/download/sinat_27066063/10938714


0  备注

11.png

  • 对接OC平台使用的是lwm2m协议,可进行上传数据,也可下发命令。lwm2m对接的过程可参考论坛中的这一篇博客:https://bbs.huaweicloud.com/forum/thread-12644-1-1.html

  • agent_tiny_demo.c文件中可修改设备侧的连接方式,包括IP、端口,上传数据的内容可在app_data_report()函数中更改。

  • 下发命令可在agent_tiny_cmd_ioctl.c文件中的atiny_write_app_write()函数中进行更改。

  • 官方例程中有讲解平台侧和端侧的配置方法,可根据其讲解进行配置。


1  添加文件

第一步

复制官方例程..\Huawei_LiteOS_DemoSDK_v10\components文件夹(全部文件)替换到基础例程中的文件夹..\User\components(官方例程中有些文件改动较大,有些额外添加的文件)。

需要添加到工程中的文件目录如下,目录下所有的源文件都需要添加至工程中:

mbedtls接口:..\User\components\security\mbedtls\mbedtls_port

mbedtls源码:..\User\components\security\mbedtls\mbedtls-2.6.0\library

coap文件:..\User\components\connectivity\lwm2m\core\er-coap-13

lwm2m文件:..\User\components\connectivity\lwm2m\core

atiny适配文件:..\User\components\connectivity\agent_tiny\osadapter

agent_tiny文件:..\User\components\connectivity\agent_tiny\lwm2m_client

agent_demo文件:..\User\components\connectivity\agent_tiny\examples

at适配文件:..\User\components\connectivity\at_frame


第二步

复制官方例程..\Huawei_LiteOS_DemoSDK_v10\drivers\devices\wifi文件夹(里面有esp8266的驱动)粘贴到基础例程..\User\bsp文件夹下。

复制官方例程..\Huawei_LiteOS_DemoSDK_v10\targets\NB-IoT_STM32L431RxTx_IoTClub\Src\dwt.c文件和..\Huawei_LiteOS_DemoSDK_v10\targets\NB-IoT_STM32L431RxTx_IoTClub\Inc\dwt.h文件粘贴到基础例程..\User\bsp\dwt文件夹下。

将上面的源文件添加到工程中。


第三步

复制gpio和usart驱动文件至基础例程..\User\bsp文件夹下,并将源文件添加到工程中。

其根据系统的需要进行编写,gpio用于控制WiFi使能信号,usart.c与at_hal.c文件进行适配。

全部bsp文件下载地址:https://pan.baidu.com/s/1kz0H9U3thFOifTWyC-10sQ

提取码:8zrg

12.png

第四步

添加头文件路径:

..\Libraries\inc;..\User;..\User\bsp\dwt;..\User\bsp\gpio;..\User\bsp\led;..\User\bsp\usart;..\User\bsp\wifi;..\User\arch\arm\arm-m\include;..\User\components\cmsis;..\User\components\cmsis\1.0;..\User\components\cmsis\2.0;..\User\kernel\include;..\User\kernel\base\include;..\User\kernel\extended\include;..\User\OS_CONFIG;..\User\components\connectivity\lwm2m\core\er-coap-13;..\User\components\connectivity\lwm2m\core;..\User\components\connectivity\agent_tiny\comm\include;..\User\components\connectivity\agent_tiny\lwm2m_client;..\User\components\connectivity\agent_tiny\examples;..\User\components\connectivity\agent_tiny\osadapter;..\User\components\connectivity\at_frame;..\User\components\security\mbedtls\mbedtls_port;..\User\components\security\mbedtls\mbedtls-2.6.0\include\mbedtls;..\User\components\security\mbedtls\mbedtls-2.6.0\include


补充以下宏定义:USE_MBED_TLS,MBEDTLS_CONFIG_FILE=<los_mbedtls_config.h>,LWM2M_LITTLE_ENDIAN,LWM2M_CLIENT_MODE,NDEBUG,WITH_AT_FRAMEWORK,USE_ESP8266

13.png



2  修改错误

在main.c中添加头文件:

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "los_config.h"
#include "los_base.h"
#include "los_sys.h"
#include "los_typedef.h"
#include "los_hwi.h"
#include "los_task.ph"
#include "los_sem.h"
#include "los_event.h"
#include "los_memory.h"
#include "los_queue.ph"
 
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "dwt.h"
#include "bsp_gpio.h"
 
#include "agent_tiny_demo.h"
#if defined WITH_AT_FRAMEWORK
#include "at_api_interface.h"
#endif

编译后会出现很多个错误,逐个更改。

  • at_api_interface.h:#include "stm32l4xx_hal.h" 改为 #include "stm32f10x_conf.h"#include <stdio.h>

  • atiny_adapter.c:#include "stm32f4xx.h"改为#include "stm32f10x.h"#include "stm32f4xx_hal_rng.h"注释掉。

  • at_hal.h:#include "stm32l4xx_hal.h"改为"stm32f10x_conf.h"

  • dwt.h:"stm32l4xx.h"修改为 "stm32f10x.h"

  • at_hal.c:at框架与hal层的接口,需要大面积修改,包括修改思路是将原usart的设置替换成自己的库。代码在最后贴出。

  • atiny_adapter.c:删除extern RNG_HandleTypeDef hrng; STM32F4有一个RNG随机数发生器的功能,在移植的时候为了方便,直接简单带过了哈哈哈,好像也没什么影响:

int atiny_random(unsigned char* output, size_t len)
{
    size_t i;
    uint32_t random_number;
 
    for (i = 0; i < len; i += sizeof(uint32_t))
    {
        random_number = 0xffffffff;
        memcpy(output + i, &random_number,
        sizeof(uint32_t) > len - i ? len - i : sizeof(uint32_t));
    }
 
    return 0;
}


3  修改main.c

重新改写main.c文件。

main.c文件中定义全局变量UINT32 g_TskHandle,供创建任务时使用。

main()函数如下,使用creat_main_task()函数创建了主任务,create_task1()函数创建了运行灯任务task1:

int main(void)
{
    UINT32 uwRet = LOS_OK;
 
    HardWare_Init();
 
    uwRet = LOS_KernelInit();
    if (uwRet != LOS_OK)
    {
        return LOS_NOK;
    }
 
    uwRet = create_task1();
    if (uwRet != LOS_OK)
    {
        return LOS_NOK;
    }
    uwRet = creat_main_task();
    if (uwRet != LOS_OK)
    {
        return LOS_NOK;
    }
 
    LOS_Start();
}

其中硬件初始化Hardware_Init()函数代码如下,包括dwt、LED、USART、GPIO:

VOID HardWare_Init(VOID)
{
    /* Initialize all configured peripherals */
    dwt_delay_init(SystemCoreClock);
    LED_Init();
    USART1_Config();
    GPIO_Config();
    printf("Welcome to IoT-Club, This is STM32F103 Board.\r\n");
}

creat_main_task()函数创建了main_task任务。main_task()函数先进行了AT框架初始化at_api_init()函数。at_api_init()函数分别对at frame和WiFi模块esp8266初始化(分别对应adapter.c文件和esp8266.c文件)。最后agent_tiny_entry()函数进入demo入口:

VOID main_task(VOID)
{
#if defined(WITH_LINUX) || defined(WITH_LWIP)
    hieth_hw_init();
    net_init();
#elif defined(WITH_AT_FRAMEWORK) && defined(USE_ESP8266)
    extern at_adaptor_api at_interface;
    at_api_register(&at_interface);
    at_api_init();
#else
#endif
    //user_hw_init();
    agent_tiny_entry();
}


4  修改esp8266.h

esp8266.h设置了WiFi连接的SSID和密码,需要自行需改。因为移植例程与官方历程都是用usart3进行通信,所以这里不做其他部分修改。另外,如需使用其他的串口或指令不同可进行修改。


5  修改agent_tiny_cmd_ioctl.c

在agent_tiny_cmd_ioctl.c文件中添加头文件"bsp_led.h"。

atiny_write_app_write()函数用于对下发命令做出判断,可对其做出如下修改,控制LED2的开关:

int atiny_write_app_write(void* user_data, int len)
{
    int i;
    char  cmd_data[len];
    memcpy(cmd_data,user_data,len);
  
    printf("################## %s",cmd_data);
    if(strstr(cmd_data,"L_ON")>0) //开补光灯
    {
        LED2_ON();    // 输出高电平
    }
    if(strstr(cmd_data,"L_OFF")>0) //关补光灯
    {
        LED2_OFF();  // 输出低电平
    }
    return ATINY_OK;
}


6  对接数据


7  总结

移植的一个难点在于cotex-M4的库函数到cotex-M3的库函数之间的转化,M4的库添加了很多功能,在移植的时候很多功能只能进行简化改写,因此可能并不像源码那么完善。另外一个难点在于与官方的at_frame相结合,我一直在尝试尽量少的去改写官方源码的代码,最后完成只改动了at_hal.c文件,其余改动均添加在了各个bsp文件中。官方给出的at_frame可以说相当精妙了,很方便,有很高的适配性,只需要移植一遍,便可了解整体框架。后面的协议层也挺给力的,试验一次就成功了。


最后贴出自己改写的at_hal.c文件:

#if defined(WITH_AT_FRAMEWORK)
 
#include "atadapter.h"
#include "bsp_usart.h"
 
extern at_task at;
extern at_config at_user_conf;
 
USART_HandleTypeDef at_usart;
 
//uint32_t list_mux;
 
uint32_t wi = 0;
uint32_t wi_bak= 0;
uint32_t ri = 0;
 
void at_irq_handler(void)
{
    if(USART_GetITStatus(at_usart.Instance, USART_IT_RXNE) != RESET)
    {
        at.recv_buf[wi++] = (uint8_t)(at_usart.Instance->DR & (uint16_t)0x00FF);
        if (wi >= at_user_conf.user_buf_len)wi = 0;
    }
    if (USART_GetITStatus(at_usart.Instance,USART_IT_IDLE) != RESET)
    {
        at.recv_buf[wi++] = (uint8_t)(at_usart.Instance->DR & 0x00FF);
        wi_bak = wi;
        LOS_SemPost(at.recv_sem);
    }
}
 
 
void at_usart_config(void)
{
    USART_HandleTypeDef * usart = &at_usart;
    usart->Instance = at_user_conf.usart;
    usart->Init.USART_BaudRate = at_user_conf.buardrate;
    usart->Init.USART_WordLength = USART_WordLength_8b;
    usart->Init.USART_StopBits = USART_StopBits_1;
    usart->Init.USART_Parity = USART_Parity_No;
    usart->Init.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    usart->Init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_GpioInit(usart);
    USART_Init(usart->Instance,&usart->Init);
    USART_ClearFlag(usart->Instance,USART_FLAG_TC);
    LOS_HwiCreate(at_user_conf.irqn, 0, 0, at_irq_handler, 0);
    USART_ITConfig(usart->Instance, USART_IT_IDLE, ENABLE);
    USART_ITConfig(usart->Instance, USART_IT_RXNE, ENABLE);
    USART_Cmd(usart->Instance, ENABLE);
}
 
 
void at_transmit(uint8_t * cmd, int32_t len,int flag)
{
uint8_t t;  
char * line_end = at_user_conf.line_end;
//    (void)HAL_UART_Transmit(&at_usart, (uint8_t*)cmd, len, 0xffff);
//if(flag == 1)
//    (void)HAL_UART_Transmit(&at_usart, (uint8_t*)line_end, strlen(at_user_conf.line_end), 0xffff);
for(t=0;t<len;t++)
{
USART_SendData(at_usart.Instance,cmd[t]);
while(USART_GetFlagStatus(at_usart.Instance, USART_FLAG_TXE) == RESET);
}
if(flag == 1)
{
for(t=0;t<strlen(line_end);t++)
{
USART_SendData(at_usart.Instance,line_end[t]);
while(USART_GetFlagStatus(at_usart.Instance, USART_FLAG_TXE) == RESET);
}
}
}
 
int read_resp(uint8_t * buf)
{
    uint32_t len = 0;
    uint32_t wi = wi_bak;
    uint32_t tmp_len = 0;
    if (NULL == buf){
        return -1;
    }
 
    if (wi == ri){
        return 0;
    }
 
    if (wi > ri){
        len = wi - ri;
        memcpy(buf, &at.recv_buf[ri], len);
    } 
    else 
    {
        tmp_len = at_user_conf.user_buf_len - ri;
        memcpy(buf, &at.recv_buf[ri], tmp_len);
        memcpy(buf + tmp_len, at.recv_buf, wi);
        len = wi + tmp_len;
    }
    ri = wi;
    return len;
}
#endif


安利一波自己的博客:https://blog.csdn.net/sinat_27066063