写点什么

STM32+M5311 对接 OneNET 项目记录

作者:矜辰所致
  • 2022 年 8 月 30 日
    江苏
  • 本文字数:8197 字

    阅读完需:约 27 分钟

STM32+M5311对接 OneNET 项目记录
做过的一个演示项目,一款判断人体进出的语言播报方案,通过LwM2M 协议连接 OneNET :硬件平台:M5311 + STM32F103云平台:中国移动 OneNET语音芯片:WT(唯创知音) WT588D传感器探头:  SHARP(夏普)  GP2Y0A21YK0F 文章意在于对本次项目做个笔记,方便以后再次用到。
复制代码


前言

本文是个人笔记,文章只讲基本流程,不讲细节,但是所有的流程会讲到位,根据整体的思路自己可以进行设计。


最后所有的资料原理图和程序都会上传至资源。

一、硬件部分

整个项目硬件本相对来说是最简单的,硬件设计可以参考《M5311 硬件设计手册》,下面上一下各部分原理图,因为本文主要记录的是 M5311 的使用,STM32 我就当大家都很熟悉了,上个最小系统,然后语音模块 WT588D 芯片:

1.1 M5311 芯片部分

1.2 SIM 卡部分

1.3 控制与指示部分

1.4 STM32 部分

1.5 WT588D 部分

1.6 功放部分

1.7 电源部分


其他的细节图这里就不上了,只要把主要的这几个地方设计好,其他的地方是很简单的。

二、对接流程

一般来说,对于开发者,这种对接流程是整个工程中相对比较复杂的。


但是中移动官方已经给我们提供了详细的说明文档:《M531X_OneNET 参考手册》,因为模块是中移动的,云平台也是中移动的,所以对接资料还是很到位的,这里我只做个简单总结:

2.1 整理流程图

2.2 注册码

一般来说都是对接重庆的平台,M5311 直接使用这个码就可以:


/*设置模组侧设备注册码*/char* Onenet_key = "AT+MIPLCREATE=56,130038F10003F2002A04001100000000000010196E\62696F7462742E6865636C6F7564732E636F6D3A35363833000131F300080000000000,0,56,0\r\n";//设置模组侧设备注册码
复制代码

2.3 OneNeT 指令集接入汇总

说明部分截取文档中的说明:



2.3.1 资源说明

对于上面的 Object 3200 资源对应关系,有一个表格(下面只列出了部分),在上传资源《资源表》文档有完整的说明:






如果设备超过了保活时间就会离线,此时无法发送消息,需要重新上线,但是不需要再进行注册码登记了,直接发送资源配置与登录即可,保活时间单位为 s

三、软件部分

本项目的重点就在于 M5311 的驱动部分,解决了 M5311 的驱动,其他基本没有问题。

3.1 基本定义

M5311 的驱动需要根据文档的说明来,首先我们得根据自己的需求做一个初始的定义:


3.2 AT 命令发送函数

其次实现 AT 指令发送的函数:


3.3 M5311 初始化函数

初始化函数中除了对模块的复位操作,还有重要的地方就是获取 SIM 卡的 IMEI 和 IMSI,这个在后面平台添加设备的时候需要填写 SIM 卡的这两个参数。


初始化函数如下图:



其他的地方直接看下面源代码把。


虽然所有资料我会上传至资料,但是还要积分下载,这里我把本项目核心的 M5311 驱动部分代码直接贴上,需要的小伙伴直接看这个就行了


/******* 正常程序中等待返回指令,不能死等,如果设备没有插卡或者卡不正常,就永远启动不了,进入不了正常的门禁程序每个步骤使用函数定义,每个步骤规定尝试次数,使用if判断 即便失败,也能够进入正常程序
2020/2/18模组侧 OneNET 数据收发流程序列 命令 描述1 AT+MIPLNOTIFY=0,0,3200,0,5750,1,4,"abcd",0,0,147 数据上传2 AT+MIPLREADRSP=0,32705,1,3200,0,5750,1,4,"abcd",0,0 Read 操作回复3 AT+MIPLWRITERSP=0,25845,2 Write 操作回复4 AT+MIPLEXECUTERSP=0,18166,2 Execute 操作回复
data type1 string 2 opaque 3 integer 4 float 5 bool
+MIPLNOTIFY ExampleAT+MIPLNOTIFY=0,1477,3202,0,5600,4,3,"1.2",0,0,35OK+MIPLEVENT:0,26,35AT+MIPLNOTIFY=0,1478,3202,2,5600,4,5,"-0.08",2,1OKAT+MIPLNOTIFY=0,1478,3202,2,5601,4,3,"-0.08",1,2OKAT+MIPLNOTIFY=0,1478,3202,2,5602,4,5,"-0.08",0,0OK4.6.9. AT+MIPLREADRSP
+MIPLREADRSP Example+MIPLREAD:0,289,3200,0,5750AT+MIPLREADRSP=0,289,1,3202,0,5750,1,5,"-0.08",0,0 //"-0.08前面是长度",5 再前面2个是数据类型 1OK
示例+MIPLREAD:<ref>,<mid>,<objid>,<insid>,<resid>参数说明<ref> OneNET 设备实例 ID。<mid> 消息 ID。<objid>Object ID。<insid>Instance ID,如果为-1,需要读取该 object 下的所有资源。<resid>Resource ID,如果为-1,需要读取该 instance 下的所有资源。
+MIPLREAD:0,18172,3200,0,5750AT+MIPLREADRSP=0,18172,11 //错误读取OK+MIPLREAD:0,18172,3200,0,-1 AT+MIPLREADRSP=0,18172,1,3200,0,5500,5,1,"0",2,1 //最后一个1,第一条报文OKAT+MIPLREADRSP=0,18172,1,3200,0,5501,3,3,"-12",1,2 //最后一个为2,中间报文OKAT+MIPLREADRSP=0,18172,1,3200,0,5750,1,4,"test",0,0 //最后一个为0,最后一条报文OK
+MIPLWRITERSP Example+MIPLWRITE:0,321,3200,0,5750,1,3,123,0AT+MIPLWRITERSP=0,321,2OK
2020/2/19AT+MIPLDISCOVERRSP该命令用于设置指定 object 的所需资源列表。举例:/查表可得:此处设定 数字输入 3个资源列表:1、数字输入状态 2、数字输入计数器 3、应用类型/AT+MIPLDISCOVERRSP=0,3200,1,14,”5500;5501;5750” OK
说明:设备注册时间例程为 3000S,时间范围为 有符号的 4字节整形 [-2147483648, 2147483647];建议设置为一两天,快到时间更新:模组侧设备存活时间更新流程序列 命令 描述AT+MIPLUPDATE=0,3000,0 //存活时间更新流程,继续存活3000S

******/#include"common.h"

// typedef enum// {// //! Waiting for the synchronisation +MIPLxxxx// GET_SYNC_STATE=0, // //! // GET_ref_STATE,// //! // GET_mid_STATE,// //! // GET_objid_STATE,// //!// GET_insid_STATE,// GET_resid_STATE// } STATES_GET_PACKET;

char* AT = "AT";char* AT_RST = "AT+CMRB";char* IMEI = "AT+GSN";char* IMSI = "AT+CIMI";char* Open_led = "AT+CMSYSCTRL=0,2";char* Close_sleep = "AT+SM=LOCK_FOREVER";// char* RSSI = "AT+CSQ";// char* CEREG = "AT+CEREG?";char RSSI[] = "AT+CSQ";char CEREG[] = "AT+CEREG?";/*设置模组侧设备注册码*/char* Onenet_key = "AT+MIPLCREATE=56,130038F10003F2002A04001100000000000010196E\62696F7462742E6865636C6F7564732E636F6D3A35363833000131F300080000000000,0,56,0\r\n";//设置模组侧设备注册码char* LWM_object_T = "AT+MIPLADDOBJ=0,3303,1,\"1\",0,1"; //订阅 Object 3303 资源设置char* LWM_Resource_T = "AT+MIPLDISCOVERRSP=0,3303,1,4,\"5700\"";//订阅 Resource 5700 资源设置 char* LWM_object_H = "AT+MIPLADDOBJ=0,3304,1,\"1\",0,1";//订阅 Object 3304 资源设置char* LWM_Resource_H = "AT+MIPLDISCOVERRSP=0,3304,1,4,\"5700\""; //订阅 Resource 5700 资源设置char* Onenet_connect = "AT+MIPLOPEN=0,65000,30"; //设备登录到 OneNET 平台,一天为86400秒,16位 65535 ,定时65000S,到64500时间更新char LWM_object_Pir[] = "AT+MIPLADDOBJ=0,3300,1,\"1\",0,0"; //3300通用传感器char LWM_Resource_Pir[] = "AT+MIPLDISCOVERRSP=0,3303,1,4,\"5502\"";//订阅 Resource 5502 资源设置 ,bool类型,分别对应进出
char* Time_refresh = "AT+MIPLUPDATE=0,65000,0"; //平台时间更新char* T_begin= "AT+MIPLNOTIFY=0,0,3303,0,5700,4,4,\"";char* T_end = "\",0,0";

void T_Send_Test(u8 t_data){ char Send_onenet_T[50] = ""; sprintf(Send_onenet_T,"AT+MIPLNOTIFY=0,0,3303,0,5700,4,4,\"%d\",0,0",t_data); Iot_SendCmd(Send_onenet_T,"OK",1000); }

/******************************************************************************* 发送字符串 并解析返回值是否正确 cmd为传入值 reply 为校验返回值 wait 为延时*******************************************************************************/int Iot_SendCmd(char* cmd, char* reply, int wait){ u8 i; memset(&struct_usart3.USART_BUFF, 0, sizeof(struct_usart3.USART_BUFF)); //先清空缓冲区 struct_usart3.USART_Length = 0; printf("[NBiot_SendCmd] %s\r\n 等待时间 %d ms\r\n", cmd,wait); delay_ms(100); uart3_send_buff((u8*)cmd,strlen(cmd)); if (wait >= 1000){ for (i = 0; i < (wait / 1000); i++){ delay_ms(1000); } } else delay_ms(wait);
if(strcmp(reply , "") == 0) return 0 ; // 返回值为空 if (struct_usart3.USART_Length != 0){ if (strstr((char*)struct_usart3.USART_BUFF, reply)){ printf("\r\n%s\r\n", struct_usart3.USART_BUFF); return 1; } else if (strstr((char*)struct_usart3.USART_BUFF, "ERROR")){ printf("ERROR...\r\n"); return 0; } else{ printf("\r\n%s\r\n", struct_usart3.USART_BUFF); return 0; } } return 0 ; }
void Iot_SendNOCheck(char* cmd){ uart3_send_buff((u8*)cmd,strlen(cmd));}
void m5311_on(void){ //硬件复位 GPIO_SetBits(GPIOB,GPIO_Pin_7); delay_ms(1200); GPIO_ResetBits(GPIOB,GPIO_Pin_7); delay_ms(200);}
/************** * 重启模块 *************/
/************** * 重启模块,如果失败,尝试3次 *************/int Rst_mode(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(AT_RST,"READY",3000); if(res == 1) return res; } return res ; }
/************** * AT,如果失败,尝试3次 *************/int AT_OK() { int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(AT,"OK",1000); if(res == 1) return res; } return res ; }
/************** * 关闭睡眠,如果失败,尝试3次 *************/int Closesleep_mode() { int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(Close_sleep,"OK",1000); if(res == 1) return res; } return res ; }
int Check_CEREG() { int res = 0 ; int i = 0; for(i=0;i<6;i++){ res = Iot_SendCmd(CEREG,"1",1500); if(res == 1) return res; } return res ; }
/************** * Onenet注册码 ,如果失败,尝试3次 *************/int Onenet_create(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(Onenet_key,"+MIP",1500); if(res == 1) return res; } return res ; }
/*订阅Object,LWM2M协议标准 */int Lwm2m_object_Pir(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(LWM_object_Pir,"OK",1000); if(res == 1) return res; } return res ; }

int Lwm2m_object_T(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(LWM_object_T,"OK",1000); if(res == 1) return res; } return res ; }
int Lwm2m_object_H(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(LWM_object_H,"OK",1000); if(res == 1) return res; } return res ; }
/*订阅Resource*/
int Lwm2m_resource_Pir(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(LWM_Resource_Pir,"OK",1000); if(res == 1) return res; } return res ; }
int Lwm2m_resource_T(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(LWM_Resource_T,"OK",1000); if(res == 1) return res; } return res ; }
int Lwm2m_resource_H(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(LWM_Resource_H,"OK",1000); if(res == 1) return res; } return res ; }
/************** * Onenet登录 ,如果失败,尝试3次 *************/int Onenet_sign_in(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(Onenet_connect,"OK",1000); //测试查看返回结果再确定如何使用 if(res == 1) return res; } return res ; }

int Onenet_time_refresh(){ int res = 0 ; int i = 0; for(i=0;i<4;i++){ res = Iot_SendCmd(Time_refresh,"OK",1000); //测试查看返回结果再确定如何使用 if(res == 1) return res; } return res ; }
/*采用这种逻辑,产品不会因为NB网络问题导致,正常的门禁播报不能实现*/#ifdef TTESTvoid m5311_init(void){ m5311_on(); }#elsevoid m5311_init(void){ m5311_on(); printf("等待软复位……\r\n"); if(Rst_mode()){ if(AT_OK()){ printf("复位成功……,AT指令测试成功,打开LED指示灯\r\n"); Iot_SendCmd(Open_led, "OK", 1000);//打开LED指示灯,正常程序不需要 if(Closesleep_mode()){ printf("关闭睡眠模式,查询NB卡的IMEI和IMSI\r\n"); Iot_SendCmd(IMEI,"OK", 1000); //获取IMEI Iot_SendCmd(IMSI,"OK", 1000); //获取IMSI printf("查看信号质量\r\n"); if(Check_CEREG()){ printf("信号正常,一切准备就绪\r\n"); } } } }}#endif/***** onenet 连接 while (!Send_NBIOT(Onenet_key, "+MIP", 500)); //这个消息经常返回出错,原因不明。 while (!Send_NBIOT(LWM_object_T, "OK", 1000)); while (!Send_NBIOT(LWM_Resource_T, "OK", 1000)); while (!Send_NBIOT(LWM_object_H, "OK", 1000)); while (!Send_NBIOT(LWM_Resource_H, "OK", 1000)); while (!Send_NBIOT(Onenet_connect, "OK", 1000)); Serial.println("Connect_onenet!!!");
*******/#ifdef TTESTvoid onenet_init(void){ printf("开始测试……,请手动输入指令\r\n"); }#elsevoid onenet_init(){ printf("开始创建设备,如果创建过,返回错误也没关系,直接跳过这一步\r\n"); Onenet_create(); Lwm2m_object_Pir(); Lwm2m_resource_Pir(); if(Onenet_sign_in()){ printf("ONENET 登录成功!\r\n"); } else; Onenet_ON = TRUE; //这里不好判断是不是真的连接上了,所以初始化以后目前都认为是连接上了}#endif
/*
数据处理
缓存数据处理判断先测试一下,空闲标志位 = 1时候处理, 再测试 长度 部位0 情况处理。
有一个问题,就是缓存什么时候清空,应该是判断完了以后就清空,要不人随时可能来数据,冲乱数据位
void T_Send_Test(u8 t_data){ char Send_onenet_T[50] = ""; sprintf(Send_onenet_T,"AT+MIPLNOTIFY=0,0,3303,0,5700,4,4,\"%d\",0,0",t_data); Iot_SendCmd(Send_onenet_T,"OK",1000); }
*/void EXECUTER_back(char *cmd){ char Send_EXECUTER_back[50] = ""; sprintf(Send_EXECUTER_back,"AT+MIPLEXECUTERSP=0,%s,2",cmd); Iot_SendNOCheck(Send_EXECUTER_back); printf("%s\r\n",Send_EXECUTER_back); }
void call_back(){ u8 i = 0; u8 j = 0; u8 u8Count =0; char msg[10] = {0}; if(struct_usart3.flag == 1){ printf("收到服务器数据:%s \r\n",struct_usart3.USART_BUFF); if (strstr((char*)struct_usart3.USART_BUFF, "+MIPLEXECUTE")){ printf("指令数据……\r\n"); if(strstr((char*)struct_usart3.USART_BUFF, "chone")){command_on = TRUE;command = 1;} else if(strstr((char*)struct_usart3.USART_BUFF, "chtwo")){command_on = TRUE;command = 2;} else if(strstr((char*)struct_usart3.USART_BUFF, "chthree")){command_on = TRUE;command = 3;} else if(strstr((char*)struct_usart3.USART_BUFF, "chfour")){command_on = TRUE;command = 4;} else if(strstr((char*)struct_usart3.USART_BUFF, "chfive")){command_on = TRUE;command = 5;} else if(strstr((char*)struct_usart3.USART_BUFF, "chsix")){command_on = TRUE;command = 6;} else if(strstr((char*)struct_usart3.USART_BUFF, "chseven")){command_on = TRUE;command = 7;} else if(strstr((char*)struct_usart3.USART_BUFF, "cheight")){command_on = TRUE;command = 8;} else if(strstr((char*)struct_usart3.USART_BUFF, "chnine")){command_on = TRUE;command = 9;} else if(strstr((char*)struct_usart3.USART_BUFF, "chten")){command_on = TRUE;command = 10;} else; //+MIPLREAD:0,289,3200,0,5750 //AT+MIPLREADRSP=0,32705,1,3200,0,5750,1,4,"abcd",0,0 Read 操作回复, //+MIPLEXECUTE:0,51638,3301,0,5601,4,"ping" //AT+MIPLEXECUTERSP=<ref>,<msgid>,<result> //AT+MIPLEXECUTERSP=0,51638,2 for(i=0;i<strlen(struct_usart3.USART_BUFF);i++){ if((char)struct_usart3.USART_BUFF[i] == ':') break; } i++;//0 i++;//, i++;//数字第一位,这里如果不继续加一位,下面的for会直接跳出,因为第一个if就是',' u8Count =i; for(;i<(strlen(struct_usart3.USART_BUFF)-u8Count);i++){ if((char)struct_usart3.USART_BUFF[i] != ','){ msg[j++] = struct_usart3.USART_BUFF[i]; } else break; }
printf("指令回复……\r\n"); EXECUTER_back(msg); printf("指令回复完毕……\r\n");
} else if(strstr((char*)struct_usart3.USART_BUFF, "+MIPLWRITE")){ printf("写数据……\r\n"); } else if(strstr((char*)struct_usart3.USART_BUFF, "+MIPLREAD")){ printf("读数据……\r\n"); } else printf("不需要的数据\r\n"); printf("清楚缓存……\r\n"); struct_usart3.flag = 0; struct_usart3.USART_Length = 0; memset(&struct_usart3.USART_BUFF, 0, sizeof(struct_usart3.USART_BUFF)); //清空缓冲区 } }
复制代码

四、云平台部分

云平台设置部分,使用截图演示一遍。

4.1 创建添加产品

在 OneNET 主界面右上角 进入控制台 界面,选择 NB-IoT 物联网套件,如图:



进入 NB-IoT 物联网套件页面以后,如果以前有产品会有产品列表:



这里我们点击添加产品:


4.2 添加设备

点击需要添加设备的产品进行添加设备,按如下操作:



这里填写的 IMEI 和 IMSI 是根据上文 3.3 M5311 初始化函数获取到的,新的 SIM 卡添加设备需要在 第一次上电的时候查看一下这两个参数:



这里我就不添加了,直接用以前的设备做个展示:



添加好了设备以后模块通过我们的正常流程就能与 OneNET 交互信息了,里面的一些详情和资源可以自己研究查看一下,比如资源属性:



这个 5502 是和 2.3.1 资源说明 一样的,属性意义在《资源表》文档中有说明:



本片记录就到这里,需要全部资源的小伙伴可以去下载,或者直接找我要也可以!

发布于: 刚刚阅读数: 3
用户头像

矜辰所致

关注

不浮夸,不将就,认真对待学知识的我们! 2022.08.02 加入

不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开! 为了活下去的嵌入式工程师,画画板子,敲敲代码,玩玩RTOS,搞搞Linux ...

评论

发布
暂无评论
STM32+M5311对接 OneNET 项目记录_stm32_矜辰所致_InfoQ写作社区