STM32F103学习笔记(9)——NB-IoT模块BC26使用
一、简介
BC26 是一款高性能、低功耗、多频段 LTE Cat NB1/Cat NB2*无线通信模块。其尺寸仅为 17.7 mm × 15.8 mm × 2.0 mm,能最大限度地满足终端设备对小尺寸模块产品的需求,同时有效帮助客户减小产品尺寸并优化产品成本.BC26 在封装设计上兼容移远通信 GSM/GPRS 系列 M26 模块以及 NB-IoT 系列 BC28/BC25/BC260Y-CN 模块,方便客户快速、灵活的进行产品设计和升级。BC26 提供丰富的外部接口和协议栈,同时可支持中国移动 OneNET/Andlink、中国电信 IoT/ AEP以及阿里云IoT等物联网云平台,为客户的应用提供极大的便利。
BC26 采用更易于焊接的 LCC 封装,可通过标准 SMT 设备实现模块的快速生产,为客户提供可靠的连接方式,并满足复杂环境下的应用需求。
凭借紧凑的尺寸、超低功耗和超宽工作温度范围,BC26 成为 IoT 应用领域的理想选择,常被用于烟感、无线抄表、共享单车、智能停车、智慧城市、安防、资产追踪、智能家电、可穿戴设备、农业和环境监测以及其它诸多行业,以提供完善的短信和数据传输服务。
BC26资料:链接:https://pan.baidu.com/s/1n8rcRCna8wnMPFwikY3l0g?pwd=vgcm 提取码:vgcm
二、AT指令
发送数据时务必勾选:“加回车换行符”
。否则模块不会响应。在本文中,仅显示响应,省略回车换行符。
2.1 AT
测试AT指令功能是否正常,等待模块返回 OK。
ATOK
2.2 AT+CIMI
该命令用于查询(U)SIM 卡的国际移动用户识别码(IMSI,无双引号的字符串)。IMSI 允许 TE 识别连
接到 MT 的 USIM。
AT+CIMI460001357924680OK
2.3 AT+CGATT=1
设置命令用于将 MT 附着于 PS 域。命令完成后,MT 保持在 V.250 命令状态。如果 MT 已经处于请求状态,则忽略该命令,并且仍将响应 OK。如果 MT 无法实现请求状态,将响应 ERROR 或+CME ERROR。
AT+CGATT=1OK
2.4 AT+CGATT?
查询命令返回当前 PS 域服务状态。
AT+CGATT=?+CGATT: <state>
如:+CGATT: 1OK
整型。PDP 上下文激活状态。
- 0 去附着
- 1 附着
2.5 AT+CEREG?
AT+CEREG?+CEREG: <n>,<stat>
如:+CEREG: 0,1
如:+CEREG: 1,1OK
整型。禁止或允许上报网络注册状态等信息。
- 0 禁止上报网络注册状态 URC
- 1 允许上报网络注册状态 URC +CEREG:
- 2 允许上报网络注册状态和位置信息 URC +CEREG: [,[],[],[]]
- 3 允许上报网络注册状态、位置信息和 EMM 原因值 URC +CEREG: [,[],[],[][,<cause_type>,<reject_cause>]]
- 4 对于请求 PSM 的 UE,允许上报网络注册状态和位置信息 URC +CEREG: [,[],[],[][,[,[],[]]]]
- 5 对于请求 PSM 的 UE,允许上报网络注册状态、位置信息和 EMM 原因值 URC +CEREG: [,[],[],[][,[<cause_type>],[<reject_cause>][,[, []]]]
整型。EPS 注册状态。
- 0 未注册,MT 当前未搜索网络
- 1 已注册,归属网络
- 2 未注册,但 MT 当前正在尝试附着或搜索网络以进行注册
- 3 注册被拒绝
- 4 未知(例如:超出 E-UTRAN 覆盖范围)
- 5 已注册,漫游状态
2.6 AT+QIPADDR
查询 UE 的 IP 地址
AT+QIPADDR+QIPADDR: fe80:0:0:0:3c:ffb8:f4c9:1207+QIPADDR: 2001:14bb:170:4c91:3c: ffh8:f4c9:1207+QIPADDR: 178.55.211.180+QIPADDR: 127.0.0.1OK
2.7 AT+QIOPEN
该命令用于打开套接字服务。
- AT+QIOPEN=?:查询命令参数。
- AT+QIOPEN=,,<service_type>,<IP_address>/<domain_name>,<remote_port>[,<local_po CONNECTrt>[,<access_mode>]] :打开 Socket 服务。
- :整数类型。上下文ID。范围是1-16。
- :整数类型。套接字服务索引。范围是0-11。
- <SERVICE_TYPE>:字符串类型。套接字服务类型。
- “ TCP ” :作为客户端启动TCP连接
- “ UDP ”:作为客户端启动UDP连接
- “TCP LISTENER” :启动TCP服务器以侦听TCP连接
- “UDP SERVICE” :启动UDP服务
- <IP_address>:字符串类型。
- 如果<service_type>是TCP或UDP ,则表示远程服务器的IP地址,例如 “220.180.239.212”。
- 如果<service_type>是TCP LISTENER或UDP SERVICE 地址,请输入“127.0.0.1”。
- <domain_name>:字符串类型。远程服务器的域名地址。
- <remote_port> :远程服务器的端口,仅在<service_type>为“TCP”或“UDP”时有效。范围是0-65535。
- <LOCAL_PORT> :本地端口。范围是0-65535。
- 如果<service_type>是“TCP LISTENER”或“UDP SERVICE”,则此参数必须指定。
- 如果<service_type>是“TCP”或“UDP”。如果<local_port>为0,那么本地端口将是自动分配。否则,将按指定分配本地端口。
- <access_mode> :整数类型。套接字服务的数据访问模式。
- 0: 缓冲区访问模式
- 1:直推模式
- 2:透明访问模式
- :整数类型。操作的错误代码。请参阅第4章。
AT+QIOPEN=1,0,\"TCP\",\"180.97.81.180\",53540,0,1OK+QIOPEN: 0,0
Buffer模式,Push模式,透传模式。通过参数<access_mode>进行配置。
2.8 AT + QISEND
如果指定套接字服务的<access_mode>是缓冲区访问模式或直接推送模式,则数据可以是通过AT + QISEND发送。如果数据成功发送到模块,将返回“ SEND OK ” 。否则它将返回“ SEND FAIL ” 或“ ERROR ” 。“ SEND FAIL ” 表示发送缓冲区已满客户可以尝试重新发送数据。“ERROR”表示在发送过程中遇到错误 数据。客户应该延迟一段时间来发送数据。最大数据长度为1460字。“SEND OK”并不意味着数据已成功发送到服务器。客户可以查询数据是否通过AT + QISEND = ,0命令到达服务器。透传模式下不需要AT指令发送数据
三、TCP应用时序图
四、复位模块
通过拉低 RESET 引脚至少 50ms 可以使模块复位。
五、移植文件
5.1 board_bc26.c
/********************************************************************** INCLUDES*/
#include "stdlib.h"
#include "string.h"
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h" #include "board_bc26.h" static uint8_t sendCmd(char *pCmd, char *pRes, char *pRes2, uint32_t timeOut, uint8_t sendNum);
static void clearBuffer(void);
static void reset(void);/********************************************************************** GLOBAL VARIABLES*/
uint8_t g_usart2RecvFinish = 0; // 串口2接收标志串口接收完成标志
char g_bc26Buf[1024] = {0}; // 接收缓存
volatile uint32_t g_bc26Cnt; // 接收计数 /********************************************************************** PUBLIC FUNCTIONS*/
/**@brief 初始化@param 无@return 1 - 成功;0 - 失败
*/
uint8_t BC26_Init(void)
{ printf("BC26_Init\r\n");uint8_t result = 0;uint8_t step = 0;switch(step){case 0:if(sendCmd("AT\r\n", "OK", NULL, 10, 6)) // 测试AT指令功能是否正常{step++;}else{printf("Err:AT\r\n");reset();break;} case 1:if(sendCmd("AT+CIMI\r\n", "OK", NULL, 20, 1)) // 查询SIM卡是否正常,返回OK则表示SIM卡正常{step++;}else{printf("Err:AT+CIMI\r\n"); // 20秒内,无法识别SIM状态,重启模块reset();break;}case 2:if(sendCmd("AT+CGATT=1\r\n", "OK", "+IP:", 60, 1)) // 激活PDP场景{step++; }else{printf("Err:AT+CGATT=1\r\n"); step++; }case 3:if(sendCmd("AT+CEREG?\r\n", "+CEREG: 0,1", "+CEREG: 1,1", 60, 3)) // 查询模组是否注册上EPS网络{step++; }else{printf("Err:AT+CEREG?\r\n"); step++; }case 4:if(sendCmd("AT+CGATT?\r\n", "+CGATT: 1", NULL, 85, 3)) // 查询当前PS域服务状态{step++;}else{printf("Err:AT+CGATT?\r\n"); // 如果3次都没停止成功或超过85秒没有回应,则重启模块reset();break;}case 5:if(sendCmd("AT+QIPADDR\r\n", "+QIPADDR:", NULL, 60, 3)) // 查询本机IP地址{BC26_Connect();result = 1;}else{printf("Err:AT+QIPADDR\r\n"); // 如果3次都没停止成功或超过60秒没有回应,则重启模块reset();break;}}return result;
}/**@brief 复位引脚配置@param 无@return 无
*/
void BC26_GpioConfig(void)
{GPIO_InitTypeDef gpioInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIOgpioInitStructure.GPIO_Pin = GPIO_Pin_8; // 选择要初始化的GPIOB引脚PB8gpioInitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置引脚工作模式为通用推挽输出 gpioInitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚输出最大速率为50MHzGPIO_Init(GPIOB, &gpioInitStructure); GPIO_SetBits(GPIOB, GPIO_Pin_8);
}/**@brief 连接TCP服务器@param 无@return 无
*/
void BC26_Connect(void)
{if(sendCmd("AT+QICLOSE=0\r\n", "OK", NULL, 20, 1)) // 关闭TCP连接{if(sendCmd("AT+QIOPEN=1,0,\"TCP\",\"180.97.81.180\",53540,0,1\r\n", "+QIOPEN:", 150, 5)) {printf("Connect Success\r\n");} else{printf("Err:AT+QIOPEN=1,0\r\n");reset(); // 没有响应重启模块} }
}/**@brief 发送数据到TCP服务器@param pString -[in] 发送数据@return 无
*/
void BC26_Send(char *pString)
{if(sendCmd("AT+QISEND=0\r\n", ">", NULL, 30, 2)) // 等待60秒,没有响应重启模块 {vTaskDelay(500); // 等待500mschar sendBuf[1024] = {0};sprintf(sendBuf, "%s\r\n\x1A", pString);if(sendCmd(sendBuf, "SEND OK", "OK", 30, 2)){if(sendCmd("AT+QISEND=0,0\r\n", "+QISEND:", NULL, 5, 24)) // 2分钟后(每5秒查询一次,共24次){ /* 发送数据成功,对方收到数据 */}else{printf("Err:AT+QISEND=0\r\n"); if(sendCmd("AT+QICLOSE=0\r\n", "OK", NULL, 20, 1)) // TCP连接出现异常,关闭TCP连接{printf("AT+QICLOSE\r\n");BC26_Connect();}}}else{BC26_Reset(); // 等待60秒,没有响应重启模块} }else{BC26_Reset(); // 等待60秒,没有响应重启模块 }
}/**@brief 从TCP服务器接收数据@param pRecvDataBuf -[out] 接收数据@return 接收数据长度
*/
uint32_t EC200S_Receive(char *pRecvDataBuf)
{uint32_t recvDataLen = 0;if(g_isUsart2RecvFinish) // 如果串口接收完成{if(strstr((const char *)g_bc26Buf, "+QIURC: \"recv\",0,") != NULL) // 如果检索到关键词{memcpy(pRecvDataBuf, g_bc26Buf, g_bc26Cnt);recvDataLen = g_bc26Cnt;}else if(strstr((const char *)g_bc26Buf, "+QIURC: \"closed\",0,") != NULL){BC26_Reset();}clearBuffer();} return recvDataLen;
}/**@brief 重启模块@param 无@return 无
*/
void BC26_Reset(void)
{reset();
}/********************************************************************** LOCAL FUNCTIONS*/
/**@brief 发送AT命令@param pCmd -[in] 命令字符串@param pRes -[in] 需要检测的返回命令字符串@param pRes2 -[in] 需要检测的返回命令字符串@param timeOut -[in] 等待时间@param sendNum -[in] 命令发送次数@return 1 - 成功;0 - 失败
*/
static uint8_t sendCmd(char *pCmd, char *pRes, char *pRes2, uint32_t timeOut, uint8_t sendNum)
{uint8_t i = 0;uint32_t time;clearBuffer(); // 清空缓存 for(i = 0; i < sendNum; i++){time = timeOut * 10;USART_SendString(USART2, pCmd);while(time--){if(g_usart2RecvFinish) // 如果串口接收完成{if(strstr((const char *)g_bc26Buf, pRes) != NULL) // 如果检索到关键词{printf("%s", g_bc26Buf);return 1;}else if(strstr((const char *)g_bc26Buf, pRes2) != NULL)) // 如果检索到关键词2{printf("%s", g_bc26Buf);return 1;}} vTaskDelay(100); // 等待100毫秒}clearBuffer();}return 0;
}/**@brief 清空缓存@param 无@return 无
*/
void clearBuffer(void)
{memset(g_bc26Buf, 0, sizeof(g_bc26Buf));g_bc26Cnt = 0;g_usart2RecvFinish = 0;
}/**@brief 重启模块@param 无@return 无
*/
void reset(void)
{printf("reset\n");GPIO_ResetBits(GPIOB, GPIO_Pin_8);vTaskDelay(60);GPIO_SetBits(GPIOB, GPIO_Pin_8);
}/****************************************************END OF FILE****************************************************/
5.2 board_bc26.h
#ifndef _BOARD_BC26_H_
#define _BOARD_BC26_H_/********************************************************************** INCLUDES*/
#include "stm32f10x.h"/********************************************************************** GLOBAL VARIABLES*/
extern uint8_t g_usart2RecvFinish; // 串口2接收标志串口接收完成标志
extern char g_bc26Buf[1024]; // 接收缓存
extern uint32_t g_bc26Cnt; // 接收计数/********************************************************************** API FUNCTIONS*/
uint8_t BC26_Init(void);
void BC26_GpioConfig(void);
void BC26_Connect(void);
void BC26_Send(char *pString);
uint32_t BC26_Receive(char *pRecvDataBuf);
void BC26_Reset(void);#endif /* _BOARD_BC26_H_ */
六、使用方法
BC26_GpioConfig();
BC26_Init();
while(1) // 任务都是一个无限循环,不能返回
{BC26_Send("TEST");vTaskDelay(10000); char recvDataBuf[256] = {0};int recvDataLen = BC26_Receive(recvDataBuf);
}
/**@brief 串口2收发中断@param 无@return 无
*/
void USART2_IRQHandler(void)
{if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) // 接收中断{g_usart2RecvFinish = 1; // 串口2接收标志if(g_bc26Cnt >= sizeof(g_bc26Buf)){g_bc26Cnt = 0; // 防止串口被刷爆}g_bc26sBuf[g_bc26Cnt++] = USART2->DR;USART_ClearFlag(USART2, USART_FLAG_RXNE);}
}
• 由 Leung 写于 2022 年 8 月 26 日
• 参考:移远BC35-G模组(NB-IoT 通信模组)AT指令测试 UDP 通信过程
NB-IOT(BC26)相关AT指令——UDP/TCP传输
NB260软件设计手册
STM32F103学习笔记(9)——NB-IoT模块BC26使用相关推荐
- STM32F103学习笔记(2)——收音机模块TEA5767使用
一.简介 TEA5767是由菲利普公司推出的一款低功耗立体声收音机接收器芯片.频率范围从76-108MHz自动数字调谐.高灵敏度,高稳定性,低噪音,收音模块.一片低功耗电调谐调频立体声收音机电路,其内 ...
- 【物联网学习笔记——人人学IoT系列】三、窄带无线,海量物联
目录 1. NB-IoT 1.1 NB-IoT背景知识 1.2 NB-IoT的网络总体架构 2. NB-IoT中的Niubility技术 2.1 NB-IoT物理层 2.1.1 NB-IoT上行技术 ...
- Python学习笔记:常用第三方模块3
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:常用第三方模块(1)
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:常用内建模块7XML
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:常用内建模块5
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:常用内建模块2:collections
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- STM32F103学习笔记(5)——数码管驱动TM1650使用
一.简介 TM1650 是一种带键盘扫描接口的 LED(发光二极管显示器)驱动控制专用电路.内部集成有 MCU 输入输出控制数字接口.数据锁存器.LED 驱动.键盘扫描.辉度调节等电路.TM1650 ...
- 【物联网学习笔记——人人学IoT系列】二、IoT平台,能力开放
目录 1. 解锁物联网平台,与OceanConnect相识 1.1 物联网发展的挑战 1.1.1 新业务上线周期长 1.1.2 标准不统一.集成困难 1.1.3 网络联接复杂 1.2 应对挑战的方案 ...
- 【物联网学习笔记——人人学IoT系列】一、初识物联网
目录 1. 物联网初探 1.1 物联网(Internet of Things)早期概念定义 1.2 物联网概念发展历程 1.3 发展历史时期划分 1.3.1 概念期 1.3.2 发展期 1.3.3 成 ...
最新文章
- MySQL数据库高可用集群搭建-PXC集群部署
- 判断三角形java代码_小猿圈Java循环嵌套语法的使用介绍
- react16 渲染流程
- aidl使用_借助 AIDL 理解 Android Binder 机制——Binder 来龙去脉
- 对DbRuleAuthorizationProvider的修改
- python循环五角星做法_python实现while循环打印星星的四种形状
- 32位linux运行64位jdk,linux64位操作系统装32位jdk解决方法
- SQL:在使用分组函数统计并进行分组时,发现有两条除了统计数据不一样,其他都一样的数据
- 2019 ICPC Asia Yinchuan Regional(9 / 13)
- Python rabbitmq的使用(五)
- php检查函数是否存在,php判断类是否存在函数class_exists用法分析
- C#中的文件流和文本流
- 如何将分表汇总到总表_总表输入数据,自动拆分到分表,你会吗?
- 解决部分控件,自动获取焦点的情况
- Spring的线程安全
- 全志A31编译脚本 .
- Android版添加phonegap--融云即时通讯插件教程
- 阿里云的图片在小程序内不显示
- 迅雷看看引领高清内容多屏合一新趋势
- [转]firefox浏览器油猴脚本-让网页背景成苹果蓝,保护眼睛