ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CC2640R2F_蓝牙5.0_通信协议之控LED

2021-02-07 17:34:14  阅读:250  来源: 互联网

标签:5.0 之控 字节 0x00 通信协议 uint8 naChar1 break User


 

简介

        本文以 SimpleBLEPeripheral 最小工程为例,介绍如何在一个可读、可写、可通知、10字节长
的特征值 charX基础上,添加一个用户自定义的通信协议,并用安卓手机蓝牙app (这里用的是BLE调试宝软件)发送指令实现  LED 点灯,并且有状态值通知返回到调试软件上。

实验平台

       CC2640R2F  平台
      ①协议栈版本:CC2640R2 SDK v1.40.00.45
      ②编译软件:CCS    7.3.0.00019
      ③硬件平台:CC2640R2F 开发板
      ④仿真器: XDS100V3 下载器

手机端与设备端的通信协议

通信协议格式(10字节)
包头有效数据长度功能码有效数据 校验和补齐字节
1字节1字节1字节0~6字节1字节0~6字节

 

 

 

数据包各字段详解

       1、包头:固定位OxFE

       2、有效数据长度: "有效数据"段的长度,取位为0~6

       3、功能码和有效数据

       4、校验和:数据包中校验和之前的数据总和,    即“包头+有效数据长度+功能码+有效数据"

       5、补齐字节:补齐字节用于将整个数据命令包补齐为10字节.固定值OxFF.长度则根据数据长度而变.

功能码意义:   

        手机端发送指令            OxFE 0x01 0x00 EN CRC

        设备端响应指令            OxFE Ox00 0x00 0x00

       设备端返回错误指令      OxFE Ox00 0x80 0x7E

EN(关灯控制)    0x00 (关灯)   . 0x01 (开灯)

CRC为校验和

功能码值    0x00      开关灯控制 

                  0x80     命令错误

这里简单做一个通信协议规定了指令集一共有两条:开关LED指令、应答错误指令

例:     关灯    fe 01 00 00  ff        至于想返回什么状态数值按自己的需要吧

         开灯     fe 01 00 01 00

可自行对照上面的通信协议加强理解该指令

代码

注意:  这只是片段核心代码,要想完全复原,需自行修改或添加特征值或新增服务,不在赘述,搜一搜就出来了

//事件定时器初始化
 
Util_constructClock(&User_BlePeriodicClock,SimpleBLEPeripheral_clockHandler,0,0,false,SBP_BLE_EVT);
  Util_constructClock(&User_BleFuncPeriodicClock,SimpleBLEPeripheral_clockHandler,0,0,false,SBP_BLE_FUNC_EVT);
  Util_constructClock(&User_BleErrPeriodicClock,SimpleBLEPeripheral_clockHandler,0,0,false,SBP_BLE_ERR_EVT);


//*****************************************************
//应用层处理函数
static void ALM_Profile_CharValueChangeEvt(uint8 paramId)
{

    // 判断是哪个特征值
    switch(paramId)
    {
    // 特征值 1
    case ALMPROFILE_CHAR1:
    {
        Util_startClock(&User_BlePeriodicClock);//手机APP发送了指令就启动事件定时器
        break;
    }

    // 其他
    default:
        break;
    }
}

//****************************************************************
//用户自定义事件
 if(events & SBP_BLE_EVT)
            {
                uint8 nRet;
                uint8 naChar1[ALMPROFILE_CHAR1_LEN] = {0};
                //读取特征值 1 的数值
                ALMProfile_GetParameter(ALMPROFILE_CHAR1, naChar1);

                //判断接收值是正确性
                nRet = Communication_Judgment(naChar1);
                if(1 == nRet)
                {
                    switch(naChar1[2])
                    {
                        case 0x00:
                            Util_startClock(&User_BleFuncPeriodicClock);
                            break;

                            //功能码无效
                        default:
                            Util_startClock(&User_BleErrPeriodicClock);
                            break;
                    }

                }
                //数据不正确,则反馈报错
                else
                {
                    Util_startClock(&User_BleErrPeriodicClock);//启动错误定时器事件
                }

            }
if(events & SBP_BLE_FUNC_EVT)
            {
                uint8 nFunc;
                uint8 naValidData[6];
                uint8 nValidData_Len;
                uint8 naChar1[ALMPROFILE_CHAR1_LEN] = {0};

                //读出 接收数据到缓冲区
                ALMProfile_GetParameter(ALMPROFILE_CHAR1, naChar1);

                switch(naChar1[3])
                {

                    case 0x00:
                    {
                        User_PinSet(U_LED1,PIN_MODE_OFF);//关灯
                        break;
                    }
                    case 0x01:
                    {
                        User_PinSet(U_LED1,PIN_MODE_ON);//开灯
                        break;
                    }
                    default: break;
                }

                //功能码填充
                nFunc = 0x00;
                //有效数据的长度
                nValidData_Len = naChar1[1];

                for(uint8_t i=0;i<nValidData_Len;i++)
                {
                    //有效数据填充
                    naValidData[i] = naChar1[3+i];
                }

                Communication_DataPackage_Send(ALMPROFILE_CHAR1,nFunc,naValidData,nValidData_Len);

            }

 if(events & SBP_BLE_ERR_EVT)
            {
                uint8 nFunc;
                uint8 naValidData[6];
                uint8 nValidData_Len;
                uint8 naChar1[ALMPROFILE_CHAR1_LEN] = {0};

                //读出 接收数据到缓冲区
                ALMProfile_GetParameter(ALMPROFILE_CHAR1, naChar1);

                //功能码填充
                nFunc = 0x80;
                //有效数据的长度
                nValidData_Len = naChar1[1];

                for(uint8_t i=0;i<nValidData_Len;i++)
                {
                    //有效数据填充
                    naValidData[i] = naChar1[3+i];
                }

                Communication_DataPackage_Send(ALMPROFILE_CHAR1,nFunc,naValidData,nValidData_Len);

            }



//********************************************************************


/**
    @brief:   通讯数据判断
    @param:   npReceive: 接收缓冲区首地址
    @return:  true: 数据包正确       false: 数据包错误
**/
uint8_t Communication_Judgment(uint8_t *npReceive)
{
    uint8_t nSof    = *npReceive;
    uint8_t nLen    = *(npReceive+1);
    uint8_t nFunc   = *(npReceive+2);
    uint8_t *nData   = npReceive+3;
    uint8_t nCrc    = *(npReceive+3+nLen);
    uint8_t nCrcCount = 0;

    //判断起始位正确性
    if(nSof != 0xfe)
    {
        return 0;//COMMUNICATION_JUDGMENT_FALSE;
    }

    //计算校验和      包头+有效数据长度+功能码+有效数据
    nCrcCount += nSof;
    nCrcCount += nLen;
    nCrcCount += nFunc;

    while(nLen--)
    {
        nCrcCount += *(nData+nLen);
    }

    //比较校验和
    if(nCrc != nCrcCount)
    {
        return 0;//COMMUNICATION_JUDGMENT_FALSE;
    }
    //数据包正确
    return 1;//COMMUNICATION_JUDGMENT_TRUE;
}


/**
    @brief: 通讯数据打包发送
    @param: param: 特征值通道参数
    @param: connHandle 连接句柄
    @param: u_Func 功能码
    @param: npValidData 有效数据首地址
    @param: ValidDataLen 要发送的数据长度
    @return:
**/
void Communication_DataPackage_Send(uint8_t param,uint8_t u_Func,uint8_t *npValidData,uint8_t ValidDataLen)
{
    uint8_t naDataPackage[ALMPROFILE_CHAR1_LEN];
    uint8_t nNum;

    //初始化发送缓冲区
    memset(naDataPackage,0x00,ALMPROFILE_CHAR1_LEN);

    //填充数据
    naDataPackage[0] = 0xfe;                            //包头
    naDataPackage[1] = ValidDataLen;                    //有效数据长度
    naDataPackage[2] = u_Func;                          //功能码
    memcpy(naDataPackage + 3,npValidData,ValidDataLen); //有效数据

    naDataPackage[3 + ValidDataLen] = 0;                //校验和清零
    for(nNum = 0; nNum < (3+ValidDataLen);nNum++)
    {
        naDataPackage[3+ValidDataLen] += naDataPackage[nNum];//校验和累加
    }

    //发送数据
      ALMProfile_Notify(param,naDataPackage,ALMPROFILE_CHAR1_LEN);
}


//****************************************************



/**
 @brief Notify发送函数
 @param param 特征值通道参数
 @param connHandle 连接句柄
 @param pValue 指向要通知的数据
 @param len 要通知的数据长度,范围为0~SIMPLEPROFILE_CHAR6,最多20个字节
 @return SUCCESS - 成功;FAILURE - 失败
*/
bStatus_t ALMProfile_Notify(uint8 param, uint8 *pValue, uint8 len)
{
    attHandleValueNoti_t  attHandleValueNoti;
    gattCharCfg_t *pItem = s_pALMProfileChar1Config;
    uint16 value;
    bStatus_t ret = SUCCESS;
 
    switch(param)
    {
    // 特征1
    case ALMPROFILE_CHAR1:
        // 读出CCC
        value = GATTServApp_ReadCharCfg(pItem->connHandle, s_pALMProfileChar1Config);
 
        // 判断CCC是否被打开
        if(value & GATT_CLIENT_CFG_NOTIFY)
        {
            // 分配发送数据缓冲区
            attHandleValueNoti.pValue = GATT_bm_alloc(pItem->connHandle,
                                                      ATT_HANDLE_VALUE_NOTI,
                                                      ALMPROFILE_CHAR1_LEN, NULL);
 
            // 分配成功,则发送数据
            if(attHandleValueNoti.pValue != NULL)
            {
                // 填充数据
                attHandleValueNoti.handle = s_ALMProfileAttrTbl[ATTRTBL_ALM_CHAR1_IDX].handle;
                attHandleValueNoti.len = len;
                memcpy(attHandleValueNoti.pValue, pValue, len);

                OLED_writeStringValue("CCC connHandle:",pItem->connHandle,10,OLED_LINE7);
 
                // 发送数据
                if(GATT_Notification(pItem->connHandle, &attHandleValueNoti, FALSE) != SUCCESS)
                {
                    GATT_bm_free((gattMsg_t *)&attHandleValueNoti, ATT_HANDLE_VALUE_NOTI);
                }
            }
            else
                ret = FAILURE;
        }
        else
            ret = FAILURE;
        break;
 
    default:
        ret = FAILURE;
        break;
    }

    return (ret);
}

//**********************************************

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:5.0,之控,字节,0x00,通信协议,uint8,naChar1,break,User
来源: https://blog.csdn.net/jack25_/article/details/113742408

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有