BC35 NB模块AT指令开发总结

一.BC35 NB模块简介

  BC35-G 是一款高性能、低功耗的 NB-IoT 模块,支持如下表格中所列的六个频段。通过 NB-IoT 无线电通信协议(3GPP Rel. 14),BC35-G 模块可与网络运营商的基础设备建立通信。
在这里插入图片描述
供电 :
VBAT 供电电压范围:3.1V~4.2V
典型供电电压:3.6V

发射功率:
23dBm±2dB

串口:
主串口:用于 AT 命令通信和数据传输,支持的波特率为 4800bps、9600bps(默认)、57600bps、115200bps、230400bps 和 460800bps,用于固件升级,支持的波特率为 115200bps 和 921600bps
调试串口:用于软件调试,仅支持波特率 921600bps

网络协议特性 :
支持 IPv4/IPv6/UDP/CoAP/LwM2M/Non-IP/DTLS/TCP/MQTT 协议

天线接口:
50Ω 特性阻抗

二.TCP传输数据流程

1.模块上电开机----->2.模块联网----->3.建立TCP连接----->4.TCP发送数据----->5.等待返回数据并处理----->6.模块断电关机。

详细程序流程:

相关支持函数:
//串口1,printf 函数
//确保一次发送数据不超过USART1_MAX_SEND_LEN字节
void nb_printf(char* fmt,...)  
{  
 u16 i;
 va_list ap;
 va_start(ap,fmt);
 vsprintf((char*)USART1_TX_BUF,fmt,ap);
 va_end(ap);
 i=strlen((const char*)USART1_TX_BUF);//此次发送数据的长度

    /*采用串口寄存器操作发送数据*/
// for(j=0;j<i;j++)//循环发送数据
// {
//  while((USART1->ISR&0X40)==0);    //循环发送,直到发送完毕   
//  USART1->TDR=USART1_TX_BUF[j];  
// }
    /*采用串口HAL库函数发送数据*/
//    HAL_UART_Transmit(&huart1, (uint8_t*)USART1_TX_BUF,i, 1000); //发送接收到的数据
//    while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) != SET);  //等待发送结束

    /*采用DMA方式发送数据*/
    HAL_USART1_DMA_TX(&USART1TxDMA_Handler,DMA_FLAG_TC2,&huart1,USART1_TX_BUF,i);//使用DMA发送数据
    memset(USART1_TX_BUF,0,sizeof(USART1_TX_BUF));//清空缓存
}
//NB_MODULE发送命令后,检测接收到的应答
//str:期待的应答结果
//返回值:0,没有得到期待的应答结果
//    其他,期待应答结果的位置(str的位置)
u8* nb_send_check_cmd(u8 *str)
{
 char *strx=0;
    USART1_RX_BUF[USART1_RX_COUNT]=0;//添加结束符
    strx=strstr((const char*)USART1_RX_BUF,(const char*)str);
 return (u8*)strx;
}
//向NB_MODULE发送指定数据
//data:发送的数据(不需要添加回车了)
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//waittime:等待时间(单位:100ms)
//返回值:0,发送成功(得到了期待的应答结果)
//       1,发送失败
u8 nb_send_cmd(u8 *data,u8 *ack,u16 waittime)
{
    waittime=waittime*100;
    nb_printf("%s\r\n",data);           //需要发送的是命令
 if(ack&&waittime)                   //需要等待应答
 {
        while(--waittime)                  //等待倒计时
        {
            delay_ms(1);
            if(USART1_IDLE_FLAG)             //接收到期待的应答结果
            {
                if(nb_send_check_cmd(ack))
                {
                   //printf("%s ack:  %s\r\n",data,(u8*)ack);
                   Feed_Dog();                          //喂狗
                   memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));//清空USART1缓存
                   USART1_IDLE_FLAG=0;
                   USART1_RX_COUNT=0;        //串口1接受数据清零
                   return 0;                 //ack正确,返回1
                }
                memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));//清空USART1缓存
                USART1_IDLE_FLAG=0;
                USART1_RX_COUNT=0;//串口1接受数据清零
            } 
        }
 }
 return 1;                                //ack错误,返回0
}
//向NB_MODULE发送指定数据,并读取返回参数值
//data:发送的数据(不需要添加回车了)
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//waittime:等待时间(单位:100ms)
//返回值:0,发送成功(得到了期待的应答结果)
//       1,发送失败
u8 nb_send_cmd_return(u8 *data,u8 *ack,u16 waittime,u8 *parameter)
{
    nb_printf("%s\r\n",data);           //需要发送的是命令
 if(ack&&waittime)                   //需要等待应答
 {
        while(--waittime)                  //等待倒计时
        {
            delay_ms(100);
            if(USART1_IDLE_FLAG)             //接收到期待的应答结果
            {
                if(nb_send_check_cmd(ack))
                {
                   *parameter=USART1_RX_BUF[2];
                   printf("%s ack:  %s\r\n",data,(u8*)ack);
                   Feed_Dog();                          //喂狗
                   memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));//清空USART1缓存
                   USART1_IDLE_FLAG=0;
                   USART1_RX_COUNT=0;        //串口1接受数据清零
                   return 0;                 //ack正确,返回1
                }
                memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));//清空USART1缓存
                USART1_IDLE_FLAG=0;
                USART1_RX_COUNT=0;//串口1接受数据清零
            } 
        }
 }
 return 1;                                //ack错误,返回0
}

2.模块联网
/**
 * @brief NB模块联网
 *          参考手册:p160 手动网络连接
 *
 * @param   void
 *
 * @return  0:连接成功
 *          1:连接失败        
 */
u8 NB_Connect_To_Internet(void)
{
    u8 i=0;
    for(i=0;i<3;i++)
    if(nb_send_cmd((u8 *)"AT+NRB",(u8 *)"REBOOT_CAUSE_APPLICATION_AT",100)==0)break;
    if(i==3)
    {
        printf("模块重启失败...\r\n\r\n");
        return 1;    //失败,返回1
    }
    else printf("模块重启成功...\r\n\r\n");
    
    for(i=0;i<3;i++)
    if(nb_send_cmd((u8 *)"AT+NBAND=5",(u8 *)"OK",10)==0)break;
    if(i==3)
    {
        printf("设置频段失败...\r\n\r\n");
        return 1;    //失败,返回1
    }
    else printf("设置频段成功...\r\n\r\n");

    for(i=0;i<3;i++)
    if(nb_send_cmd((u8 *)"AT+CFUN=1",(u8 *)"OK",40)==0)break;
    if(i==3)
    {
        printf("设置最大功能模式失败...\r\n\r\n");
        return 1;    //失败,返回1
    }
    else printf("设置最大功能模式成功...\r\n\r\n");
    i=0;
    
    for(i=0;i<3;i++)
    if(nb_send_cmd((u8 *)"AT+CEDRXS=0,5",(u8 *)"OK",10)==0)break;
    if(i==3)
    {
        printf("关闭模组eDRX功能失败...\r\n\r\n");
        return 1;    //失败,返回1
    }
    else printf("关闭模组eDRX功能成功...\r\n\r\n");
    
    for(i=0;i<3;i++)
    if(nb_send_cmd((u8 *)"AT+CGATT=1",(u8 *)"OK",20)==0)break;
    if(i==3)
    {
        printf("附着网络失败...\r\n\r\n");
        return 1;    //失败,返回1
    }
    else printf("附着网络成功...\r\n\r\n");
    
    for(i=0;i<10;i++)
    if(nb_send_cmd((u8 *)"AT+CGATT?",(u8 *)"+CGATT:1",20)==0)break;
    if(i==10)
    {
        printf("网络连接失败...\r\n\r\n");
        return 1;
    }
    else 
        printf("网络连接成功...\r\n\r\n");
        return 0;
}
3.建立TCP连接
/**
 * @brief 建立TCP连接
 *
 * @param   ip:需要连接的ip地址
 *          port:需要连接的端口
 *          socket:连接成功后返回创建的socket值
 *
 * @return  0:发送成功
 *          1:发送失败        
 */
u8 NB_TCP_Connect(const u8* ip,const u8* port,u8* socket)
{
    u8 i=0;
    u8 p[50];
    for(i=0;i<3;i++)
    if(nb_send_cmd_return((u8 *)"AT+NSOCR=STREAM,6,0,1",(u8 *)"OK",100,socket)==0)break;    
    if(i<3)printf("创建socket成功...\r\n\r\n");
    else 
    {
        printf("创建socket失败...\r\n\r\n");
        return 1;
    }
    *socket=*socket-48;
    printf("tcp_socket=%d\r\n",*socket);
    sprintf((char*)p,"AT+NSOCO=%d,%s,%s",*socket,ip,port);
    for(i=0;i<3;i++)
    if(nb_send_cmd((u8 *)p,(u8 *)"OK",100))break;  
    if(i<3)printf("TCP连接成功...\r\n\r\n");
    else 
    {
        printf("TCP连接失败...\r\n\r\n");
        return 1;
    }
    return 0;
}
4.TCP发送数据
/**
 * @brief TCP发送数据
 *
 * @param   socket:套接字号
 *          data:发送的数据
 *          len:发送的数据长度
 *
 * @return  0:发送成功
 *          1:发送失败        
 */
u8 tx_buffer[2000]={0};           //定义最终发送数据缓存区
u8 p[2000];                       //封装成最终要发送的帧格式
u8 NB_TCP_Send_Data(u8 socket,u8* data,u16 len)
{
    u8 i=0;
    HexArrayToString(data,(char*)USART1_TX_BUF,len);          //先将原始数据转成字符串
    HexArrayToString(USART1_TX_BUF,(char*)tx_buffer,2*len);   //再讲字符串转成ASCII码
    sprintf((char*)p,"AT+NSOSD=%d,%d,%s,%s,%s",socket,2*len,(char*)tx_buffer,"0x100","101");
    memset(USART1_TX_BUF,0,sizeof(USART1_TX_BUF));//清空缓存,因为下面nb_send_cmd()也需要用到USART1_TX_BUF,因此需要清空
    memset(tx_buffer,0,sizeof(tx_buffer));        //清空缓存,因为下面nb_send_cmd()也需要用到USART1_TX_BUF,因此需要清空
    for(i=0;i<3;i++)
    if(nb_send_cmd((u8 *)p,(u8 *)"101,1",50)==0)break;    
    memset(p,0,sizeof(p));//清空缓存
    if(i<3)
    {
        printf("TCP发送数据成功,且确认被服务器收到...\r\n\r\n");
        return 0;
    }
    else 
    {
        printf("TCP发送数据失败...\r\n\r\n");
        return 1;
    }
}
5.等待返回数据并处理(部分程序)
       while(1)                        //等待云端回数据倒计时
       {
          delay_ms(5);                            //延时5ms判断是否收到数据
          if(USART1_IDLE_FLAG)                     //串口1接收数据完毕,与NB模块通信
          {
               /*判断是否有来自服务器的数据*/
               str1=nb_send_check_cmd((u8 *)"+NSONMI:");//判断接受到的数据是否有+NSONMI:
               if(str1)                                 //确定接收到了+NSONMI:
               {     
                   receive_socket=*(str1+8)-48;                                                  //获得当前socket编号
                   if(USART1_RX_COUNT-14==1)receive_num=*(str1+10)-48;
                   else if(USART1_RX_COUNT-14==2)receive_num=(*(str1+10)-48)*10+*(str1+11)-48;   //获得当前收到的字节数
                   sprintf((char*)q,"%d,%s,%s,%d",receive_socket,IP_address,portnum,receive_num);//组成一个包
                   receive_data_flag=1;                 //接收到数据标志位置位
               }
               
               /*判断是否收到服务器的数据*/
               str2=nb_send_check_cmd((u8*)q);          //判断接受到的数据是否有+NSONMI:
               if(str2)                                 //确定接收到了数据
               {    
                    HexStrToByte(str2+strlen(q)+1,Receive_Buffer,2*receive_num);    //将字符装成HEX并存在Receive_Buffer中,待处理
                    read_data_flag=1;             //数据处理标志位置位
               }
                 memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));//清空缓存
                 USART1_RX_COUNT=0;                  //将接受字节数清零
                 USART1_IDLE_FLAG=0;                 //空闲中断标志复位
           }
           if(receive_data_flag)                     //确认模块接收到来自服务器的数据
           {
               sprintf((char*)p,"AT+NSORF=%d,%d",receive_socket,200);
               nb_printf("%s\r\n",p);                //发送接收数据指令
               receive_data_flag=0;                  //接收到数据标志位复位
           }
           /*需要进行数据处理了*/
           if(read_data_flag)                        //确认需要进行数据处理
           {
	       for(i=0;i<receive_num;i++)
               printf("%x ",Receive_Buffer[i]);     
               printf("\r\n");
               waittime=4000;                                        //接收到一次数据后恢复计时时间
               break;
           }
}

三.UDP传输数据流程

1.模块上电开机----->2.模块联网----->3.建立UDP连接----->4.UDP发送数据----->5.等待返回数据并处理----->6.模块断电关机。

详细程序流程:

相关支持函数:
同上面TCP一致

2.模块联网
同上面TCP一致

3.建立UDP连接
/**
 * @brief 建立UDP连接
 *
 * @param   ip:需要连接的ip地址
 *          port:需要连接的端口
 *          socket:连接成功后返回创建的socket值
 *
 * @return  0:发送成功
 *          1:发送失败        
 */
u8 NB_UDP_Creat_socket(u8* socket)
{
    u8 i=0;
    for(i=0;i<3;i++)
    if(nb_send_cmd_return((u8 *)"AT+NSOCR=DGRAM,17,0,1",(u8 *)"OK",100,socket)==0)break;  
    if(i<3)
    {
        printf("创建socket成功...\r\n\r\n");
        *socket=*socket-48;
        printf("udp_socket=%d\r\n",*socket);
        return 0;
    }
    else printf("创建socket失败...\r\n\r\n");
    return 1;
}
4.UDP发送数据
/**
 * @brief UDP发送数据
 *
 * @param   socket:套接字号
 *          data:发送的数据
 *          len:发送的数据长度
 *
 * @return  0:发送成功
 *          1:发送失败        
 */               
u8 NB_UDP_Send_Data(u8 socket,const u8* ip,const u8* port,u8* data,u16 len)
{
    u16 i=0;
    HexArrayToString(data,(char*)USART1_TX_BUF,len);          //先将原始数据转成字符串
    HexArrayToString(USART1_TX_BUF,(char*)tx_buffer,2*len);   //再讲字符串转成ASCII码
    sprintf((char*)p,"AT+NSOST=%d,%s,%s,%d,%s,%d",socket,ip,port,2*len,(char*)tx_buffer,100);
    memset(USART1_TX_BUF,0,sizeof(USART1_TX_BUF));//清空缓存,因为下面nb_send_cmd()也需要用到USART1_TX_BUF,因此需要清空
    memset(tx_buffer,0,sizeof(tx_buffer));        //清空缓存,因为下面nb_send_cmd()也需要用到USART1_TX_BUF,因此需要清空
    for(i=0;i<3;i++)
    if(nb_send_cmd((u8 *)p,(u8 *)"100,1",100)==0)break;    
    memset(p,0,sizeof(p));//清空缓存
    if(i<3)
    {
       printf("UDP发送数据成功...\r\n\r\n");
       return 0;
    }
    else 
    {
        printf("UDP发送数据失败...\r\n\r\n");
        return 1;
    }
}
5.等待返回数据并处理
同上面TCP一致
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页