NBIOT-BC28模块程序操作接口编写(基于STM32F103ZET6)

项目最终实现效果如下:
在这里插入图片描述
程序设计结构体

typedef struct NETWORK_INFO
{
    //初始化NB模块的状态
    u8 Init_NB_Status ;
    //NB模块的信号强度
    u8 signalCSQ ;
    //IMEI卡号
    char IMEI[16];
    //IMSI卡号
    char IMSI[16];
    //注网标志位
    bool Register_NetWork_Flag ;
    //服务器连接标志位
    bool Connect_Server_Flag ;

} NETWORK_DEVICE_INFO;
extern NETWORK_DEVICE_INFO NBIOT_MODULE_INFO ;

下面实现操作NB的方法,首先是最核心的NB指令发送函数,有了这样一个函数,后面的应用才能写。

/*
 * 函数名:NBIOT_Cmd
 * 描述  :对NBIOT模块发送AT指令
 * 输入  :cmd,待发送的指令
 *         reply1,reply2,期待的响应,为NULL表不需响应,两者为或逻辑关系
 *         waittime,等待响应的时间
 * 返回  : 1,指令发送成功
 *         0,指令发送失败
 * 调用  :被外部调用
 */
bool NBIOT_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime )
{
		bool status = false ;
    USART4_RX_STA = 0;               //从新开始接收新的数据包
    NB_FramLength = 0 ;
    memset(RXBuffer, 0, RXBUFFER_LEN); //清空接收缓冲
    u4_printf("%s\r\n", cmd);

    if ( ( reply1 == 0 ) && ( reply2 == 0 ) )                      //不需要接收数据
        return true;

    Delay_ms ( waittime );                 //延时
    RXBuffer[NB_FramLength]  = '\0';
		printf("RXBuffer:%s\n", RXBuffer);
    if(strstr((char *)RXBuffer, reply2) != NULL)
    {
        printf("ackerror:%s\n", reply2);
        return false ;
    }
		
    if(strstr((char *)RXBuffer, reply1) != NULL)
    {
        printf("acksuccess:%s\n", RXBuffer);
				//如果匹配到断连标志,就重新建立连接
				if(strstr((char *)RXBuffer, "+NSOCLI: 1") != NULL)
        {
            status = NB_Create_TCP("120.78.136.134", 9002);
            if(false == status)
            {
                printf("重新创建TCP连接失败\n");
                return -1 ;
            }
            else
            {
                printf("重新创建TCP连接成功\n");
            }
        }
        return true ;
    }

    return false ;
}

根据实现的发送函数,下面来实现驱动NB模块的接口以及整套初始化流程,可以减少开发者的负担。

一、判断BC28模块是否在线

在对NB模块的编程中,其实就是对串口操作,通常我们会有一个与模块的应答指令,寻问模块是否在线,进而来判断模块是否硬件是否已经连接正确或者模块是否损坏。

//检查模组是否在线
bool checkNBIOT(void)
{
    return NBIOT_Cmd("AT", "OK", NULL, 100);
}

当发出AT时,模组应给主机回复OK作为应答,这样主机就和模组建立通信。

二、BC28基础配置(打开自动寻网、频段设置、优码控制)

根据前面写过的一篇文章,我们还要对BC28做一系列的适配操作,比如,使能自动寻网、设置频段(电信为5,移动为8)、打开优码控制选项第二项、第三项。
文章链接:(https://yangyuanxin.blog.csdn.net/article/details/80724712)
实现对BC28的基础配置功能函数

//NBIOT基础配置===>band 5 ==> 电信卡  8===>移动卡
bool BASE_Config_NBIOT(int band)
{
    char buffer[50] = {0};
    bool status = true ;
    //设置频段
    sprintf(buffer, "AT+NBAND=%d", band);
    status = NBIOT_Cmd(buffer, "OK", NULL, 100);
    //自动寻网
    status = NBIOT_Cmd("AT+NCONFIG=AUTOCONNECT,TRUE", "OK", NULL, 100);
    //打开优码控制2,3项
    status = NBIOT_Cmd("AT+NCONFIG=CR_0354_0338_SCRAMBLING,TRUE", "OK", NULL, 100);
    status = NBIOT_Cmd("AT+NCONFIG=CR_0859_SI_AVOID,TRUE", "OK", NULL, 100);
    return status ;
}

三、IMSI、IMEI号获取

3.1 IMSI 设备识别码

NB模块或者其它的一些通信模块,它都会有一个独有的IMEI号,它是模块生产厂家指定的一个设备识别码,通过指令AT+CGSN=1来获取,功能函数如下:

bool Get_IMEI(void)
{
    bool status = true ;
    status = NBIOT_Cmd("AT+CGSN=1", "OK", "ERROR", 100);

    if(status == true)
    {
        memcpy((char *)NBIOT_MODULE_INFO.IMEI, RXBuffer + 8, 15);
        return true ;
    }

    return false ;
}

3.2 IMSI 国际移动用户识别码

通常该码存储在SIM卡中,我们可以使用AT+CIMI这条指令来获取,这样可以知道卡到底有没有插好或者是否存在,功能编写如下:

//获取IMSI
bool Get_IMSI(void)
{
    bool status = true ;
    status = NBIOT_Cmd("AT+CIMI", "OK", "ERROR", 2000);

    if(status == true)
    {
        memcpy((char *)NBIOT_MODULE_INFO.IMSI, RXBuffer + 2, 15);
        return true ;
    }

    return false ;
}

四、获取注网状态

模块注册相应的运行商成功,就会收到相应的标志,标志已经注册成功,功能编写如下:

//获取入网状态
bool Get_Enter_Net_Status(void)
{
    int status = 0 ;
    bool cmd_status = false ;
    char buffer[30] = {0};
    cmd_status = NBIOT_Cmd("AT+CGATT?", "OK", "ERROR", 5000);
    memcpy(buffer, RXBuffer + 9, 1);
    status = atoi(buffer);

    if(1 == status)
        return true;
    else
        return false ;
}

五、获取模组信号强度

BC28的模组信号级别是0-31,返回99则可能模块还没有初始化完毕,或者信号异常。低于10可以认为信号为低,一般别的通信模组(比如4G,WIFI等)如果低于这个级别,数据可能出现丢包状态,但NB模块号称只要大于8,即可无丢损数据,实现函数如下:

//获取信号强度
int Get_CSQ(void)
{
    int signal_value = -1;
    bool status = true ;
    char csq_buffer[50] = {0};
    status = NBIOT_Cmd("AT+CSQ", "+CSQ", NULL, 100);

    if(status == true)
    {
        memcpy(csq_buffer, RXBuffer + 7, 2);
        signal_value = atoi(csq_buffer);
        return signal_value ;
    }
    return 99 ;
}

五、TCP-IP的创建

这里一定要注意一点,模组刷写的固件带ONT版本的,是不能把数据传到私有的服务器的,只有不带ONT的才可以,版本可以通过AT指令的ATI查看。
在这里插入图片描述
如果版本是带ONT,而你又想传数据到自己的后台,那就请你连接移远的FAE,提供最新的固件和固件烧写工具给你,如图所示,利用软件对NB模组进行固件更新。
在这里插入图片描述
在这里插入图片描述

//创建TCP Socket===>成功返回1,失败返回0
u8 NB_Create_TCP(const char *server_ip, int port)
{
    char buffer[50] = {0};
    bool status = true ;
    //1.创建一个TCP Socket
    status = NBIOT_Cmd("AT+NSOCR=STREAM,6,56000,1", "OK", NULL, 2000);
    //如果创建成功,则连接远程服务器和端口号
    if(true == status)
    {
        sprintf(buffer, "AT+NSOCO=1,%s,%d", server_ip, port);
        status = NBIOT_Cmd(buffer, "OK", NULL, 2000);
        if(true == status)
            return 1 ;
        else
            return 0 ;
    }
    return 0 ;
}

//关闭Socket连接
bool Close_Socket(void)
{
    bool status = true ;
    status = NBIOT_Cmd("AT+NSOCL=0", "OK", NULL, 2000);
    return status ;
}

六、发送数据到TCP服务器

//NBIOT发送数据到后台服务器
/*
	Data_Length:要发送到后台的原始数据的长度
	hex_data:要发送到后台的,但必须将原始数据转换成十六进制编码的数据
*/

bool NB_Send_Data_To_Server(int Data_Length, char *hex_data)
{
    bool status = true ;
		char data_buffer[1024] = {0};
    sprintf(data_buffer, "AT+NSOSD=1,%d,%s", Data_Length, hex_data);
    printf("数据上传:\n");
    printf("%s\n", data_buffer);
    status = NBIOT_Cmd(data_buffer, "OK", "ERROR", 5000);
    return status ;
}

七、模组重启复位

通常给模组复位,一般是设置完参数后,手册要求要进行复位操作,复位大概需要5s的时间,模组才会稳定下来,所以Delay_ms(5000)最好不要丢掉,否则其它的指令可能出现设置失败的情况。

//复位NBIOT模组
bool NB_RESET(void)
{
    bool status = true ;
    status = NBIOT_Cmd("AT+NRB", "OK", NULL, 10000);
    return status ;
}

八、初始化流程编写

/**
 * 功能:初始化NBIOT
 * 参数:None
 * 返回值:初始化结果,非0为初始化成功,0为失败
 */
int initNBIOT(void)
{
    bool status_return = false ;

    while(1)
    {
        switch(NBIOT_MODULE_INFO.Init_NB_Status)
        {
            //1、检查NBIOT模块是否在线
            case 0:
                status_return = checkNBIOT();

                if(false == checkNBIOT)
                {
                    printf("NB模块硬件故障..\n");
                    return 0 ;
                }
                else
                {
                    printf("NB模块正常连接\n");
                    NBIOT_MODULE_INFO.Init_NB_Status = 1 ;
                }

                break ;

            //2、进行NBIOT的基础配置
            case 1:
                status_return = BASE_Config_NBIOT(5);

                if(false == status_return)
                {
                    NBIOT_MODULE_INFO.Init_NB_Status = 0 ;
                    printf("配置自动寻网与优码控制第2、3项失败\n");
                }
                else
                {
                    NBIOT_MODULE_INFO.Init_NB_Status = 2 ;
                    printf("配置自动寻网与优码控制第2、3项成功\n");
                }

                break ;

            //3、复位模组
            case 2:
                status_return = NB_RESET();

                if(false == status_return)
                {
                    printf("模组复位失败\n");
                    NBIOT_MODULE_INFO.Init_NB_Status = 0 ;
                }
                else
                {
                    printf("模组复位成功\n");
                    Delay_ms(2000);
                    NBIOT_MODULE_INFO.Init_NB_Status = 3 ;
                }

                break ;

            //4、获取NB模组号
            case 3:
                status_return = Get_IMEI();

                if(false == status_return)
                {
                    printf("没有模组卡号,模块故障\n");
                    NBIOT_MODULE_INFO.Init_NB_Status = 0 ;
                    break ;
                }
                else
                {
                    NBIOT_MODULE_INFO.Init_NB_Status = 4 ;
                    printf("模组号:%s\n", NBIOT_MODULE_INFO.IMEI);
                }

                break ;

            //获取SIM卡卡号,确认设备是否已经插卡
            case 4:
                status_return = Get_IMSI();

                if(false == status_return)
                {
                    printf("没有插SIM卡,模块无法连接网络\n");
                    NBIOT_MODULE_INFO.Init_NB_Status = 0 ;
                    break ;
                }
                else
                {
                    printf("SIM卡号:%s\n", NBIOT_MODULE_INFO.IMSI);
                    NBIOT_MODULE_INFO.Init_NB_Status = 5 ;
                }

                break ;

            //查看注网状态
            case 5:
                status_return = Get_Enter_Net_Status();

                if(false == status_return)
                {
                    printf("入网失败,请重新复位模块\n");
                    NBIOT_MODULE_INFO.Init_NB_Status = 5 ;
                    break ;
                }
                else
                {
                    printf("模组入网成功..\n");
                    NBIOT_MODULE_INFO.Init_NB_Status = 6 ;
                }

                break ;

            //获取信号强度
            case 6:
                NBIOT_MODULE_INFO.signalCSQ = Get_CSQ();

                if(99 == NBIOT_MODULE_INFO.signalCSQ)
                {
                    printf("设备无信号....\n");
                    NBIOT_MODULE_INFO.Init_NB_Status = 5 ;
                }
                else
                {
                    printf("信号级别:%d\n", NBIOT_MODULE_INFO.signalCSQ);
                    NBIOT_MODULE_INFO.Init_NB_Status = 7 ;
                }

                break ;

            default:
                break ;
        }

        if(7 == NBIOT_MODULE_INFO.Init_NB_Status)
        {
            break ;
        }
    }

    return 1;
}


char* nb_itoa(int num, char* str, int radix)
{
    /*索引表*/
    char temp;
    char index[] = "0123456789ABCDEF";
    unsigned unum;/*中间变量*/
    int i = 0, j, k;

    /*确定unum的值*/
    if(radix == 10 && num < 0) /*十进制负数*/
    {
        unum = (unsigned) - num;
        str[i++] = '-';
    }
    else unum = (unsigned)num; /*其他情况*/

    /*转换*/
    do
    {
        str[i++] = index[unum % (unsigned)radix];
        unum /= radix;
    }
    while(unum);

    str[i] = '\0';

    /*逆序*/
    if(str[0] == '-')
        k = 1; /*十进制负数*/
    else
        k = 0;

    for(j = k; j <= (i - 1) / 2; j++)
    {
        temp = str[j];
        str[j] = str[i - 1 + k - j];
        str[i - 1 + k - j] = temp;
    }

    return str;
}

int nb_Str2Hex(char *str, char *hex)
{
    int high = 0;
    int low = 0;
    int temp = 0;

    if (NULL == str || NULL == hex)
    {
        return -1;
    }

    if (0 == strlen(str))
    {
        return -2;
    }

    while(*str)
    {
        temp = (int)(*str);
        high = temp >> 4;
        low = temp & 15;
        nb_itoa(high, hex, 16);
        hex++;
        nb_itoa(low, hex, 16);
        hex++;
        str++;
    }

    *hex = '\0';
    return 0;
}
Engineer-Bruce_Yang CSDN认证博客专家 嵌入式硬件 单片机 arm开发
本科毕业于华南理工大学,现美国卡罗尔工商管理硕士研究生在读,曾就职于世界名企伟易达、联发科技等,多年嵌入式产品开发经验,在智能玩具、安防产品、平板电脑、手机开发有丰富的实战开发经验,现任深圳市云之手科技有限公司副总经理、研发总工程师。
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页