发 帖  
原厂入驻New

[经验] 【大联大世平ON Semiconductor BLE5.0 RSL10开发板试用体验】结项报告--纯蓝牙版共享单车锁

2020-8-31 20:33:36  91 RSL10
分享
0
    做共享单车车锁有几年了,蓝牙芯片也用了好几种,精挑细选比来比去,最后感觉还是Nordic的nRF51和nRF52系列的比较好用。开放的OpenCPU无论从开发的简便性,还是从功能或是功耗的角度考虑,Nordic的蓝牙芯片都比较适合。尤其是IO口具有类似MUX功能,也就是任意一个管脚可以随意指定功能,无论是UART、I2C、SPI、PWM等数字通讯接口,甚至可以当作ADC的模拟输入来使用,没有诸如STM32等MCU只能复用为某种特定功能的限制。这样一来,从硬件画板子到嵌入式软件开发,都极大的减少了工作量,提高了效率。所以Nordic的nRF5x系列一直是我的最爱,直到遇见了安森美的RSL10蓝牙5.0芯片。
    真的没有想到这些nRF5x的过人之处RSL10也都具备,同时提供的SDK开发包比Nordic的更加简洁明了,不需要更新之后还得替换为对应版本的Bootloader,这一点比Nordic做的更好。只是我孤陋寡闻,现在才知道还有这么个好东西。感谢电子发烧友和大联大世平提供的RSL10 BLE 5.0的开发板,使我不再局限于一种选择。经过一段时间的学习,对RSL10的方方面面进行了了解,发现RSL10绝对能担得起我的项目的重任。为了弥补遗憾,我要用RSL10重新完成项目,时光倒流至立项之初。。。。。。(请调整时钟,以下内容为两三年之前)

    共享单车的大火正在烧遍全国各地,总结起来大概有两种形态,高配版和低配版。
    高配版:2G无线通讯、GNSS定位、手机蓝牙操作、震动或倾倒报警等等功能;
    低配版:纯蓝牙操作,通过用户手机和服务器交互。
    为了理解起来简单,可以看成低配版是高配版的一部分功能(虽然实现起来并不是),在市场的需求中,也不是说运营商单纯为了节省成本才使用低配版,一些场景下低配版比高配版更加适合。比如一些山区、景区等地,2G基站数量相对较少,网络通讯质量较差甚至无法通讯,高配版完全没有意义;再如,功能越全越费电,人工电池又不现实(虽然有这样做的,但是对自行车来说是自讨苦吃),普遍的做法是加装太阳能板充电(花毂骑行发电已淘汰),但是对于连续阴雨天或长期低照度地区不一定合适,至少不如一块电池待机三年的纯蓝牙版便于维护。

    基于以上不完全的理由,低配版的纯蓝牙车锁是有必要的。但是既然是低配版,那么也会突出一些要求:
    1.低功耗:不可充电电池至少待机两年以上。待机不是关机,还要时刻广播数据等待用户手机扫码连接控制;
    2.低成本:蓝牙芯片做主控不再使用其他的MCU,那些被动配置的蓝牙芯片全部排除掉,只能使用具有OpenCPU的蓝牙芯片;
    3.可扩展:虽说是纯蓝牙车锁,但是有些用户可能会要求连接自己特有的外设,如读卡器等实现支持RFID卡开锁,所以要预留UART、I2C之类的接口;
    4.性能强:除去要支持外设,本身的数据通讯也要经过加解密、控制电机等功能,性能弱的话用户体验会非常不好;
    。。。。。。
    还有若干特定要求,这里不再细说。

    要求定下来了,那么选型的范围也就缩小了,符合条件的有nRF51、CC2540、QN902x、RSL10等。CC2540是51内核,好不好不予评论,但是实现一些功能很不方便,软件模拟性能又会下降,还可能影响其他队时序要求比较高的功能,所以首先排除。QN9020、nRF51、RSL10都不错,M0的内核都能满足,但是最开始已经说过,MUX更加好用,所以QN902x也排除掉,那么替换掉nRF51最后选择的是RSL10。

    芯片选型完毕,后面开始实现功能。功能上也有一些值得注意的地方,先来看看机械部分的结构。
机械.jpg
    以比较早期的类似摩拜车锁的锁销控制结构为例,上下分别有两个微动开关,用于检测当前锁销所处的位置。锁销共有三种状态:不可锁、可锁和锁车。其实摩拜的功能只有可锁和锁车,不可锁是我添加的,因为纯蓝牙锁需要依靠用户手机来和服务器交互,在锁车之前蓝牙必须和用户手机已经连接,但是由于多种原因,用户在扫码开锁之后并不一定能保证蓝牙始终连接,所以要增加一个不可锁的状态,用户在锁车时需要先点击App上的锁车按钮后再去锁车,以保证锁车信息可以上传至服务器。注:该结构只是做实验使用,不构成侵权,请摩拜悉知。
流程图.png

    其实关键点只有两个,一个是电机的控制,另一个就是通讯协议及加解密。电机控制好办,根据电机转动的时间,使电机凸轮停止在固定的位置即可实现锁销的三种状态。只是蓝牙通讯部分,在这段学习期间,一直想自建工程并且自己实现蓝牙的通讯,由于本人愚钝,自建的工程始终不能正确广播数据,而例程中的BASS服务也始终不能去掉。时间来不及了,只能借助例程,然后添加自定义的功能了,惭愧惭愧。
    例程ble_peripheral_server_bond,共包含有五个文件:
    app.c:程序主文件,main入口函数;
    app_bass.c:BAT服务,一直想把这个去掉,但是去掉就没有广播了;
    app_config.c:硬件初始化及广播数据的参数设置;
    app_customss.c:自定义通讯服务,对外提供读写接口,下手改造的就是它了;
    app_msg_handler.c:处理各种消息的文件,可以不用管;
    虽然这个例程已经被我精简过若干遍了,但是都以失败而告终,为了便于比对说明还是规规矩矩不做改变,只增加内容。本着最大限度地降低合性的原则,对于app_customss.c文件,只在CUSTOMSS_RXCharCallback函数中对外发送一个消息。这个函数就是当蓝牙接收到手机发送的消息时触发的,并且可以获得手机发送的数据。所以首先要对这些数据进行解密,然后根据指令执行对应的动作。为了实现这些功能,需要增加一个对该消息的接收函数以便后续处理。参照之前的帖子http://bbs.elecfans.com/jishu_1971327_1_1.html需要增加代码的地方主要有
    1.app.h的enum appm_msg消息定义中增加:APP_BLE
    2.app.c的main函数中增加MsgHandler_Add(APP_BLE, APP_BLE_Handler);
    3.app_customss.c的CUSTOMSS_RXCharCallback函数中增加ke_msg_send_basic(APP_BLE, TASK_APP, length);
        #define GPO_MOTOR                        6
        #define GPI_TOP                                7
        #define INT_BOTTOM                        5
        #define IRQ_BTN                                0
uint8_t SecretKey[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //自定义密钥
void APP_BLE_Handler(ke_msg_id_t const msg_id, void const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
        uint8_t Buf[16] = {0x00}, Data[16] = {0x05};
        AES128_ECB_Decrypt(app_env_cs.from_air_buffer, SecretKey, Buf);
        switch (Buf[1])
        {
                case 0x06: //开锁
                        Sys_GPIO_Set_High(GPO_MOTOR); //转动电机
                        while ((DIO->DATA & GPIO7_HIGH) != GPIO7_HIGH) ; //等待顶部微动开关闭合
                        Sys_GPIO_Set_Low(GPO_MOTOR); //停止电机
                        Data[2] = 0x01; //自定义协议
                        break;
               
                case 0x0C: //关锁
                        Sys_GPIO_Set_High(GPO_MOTOR); //转动电机
                        while ((DIO->DATA & GPIO7_HIGH) == GPIO7_HIGH) ; //等待顶部微动开关放开
                        Sys_GPIO_Set_Low(GPO_MOTOR); //停止电机
                        Data[2] = 0x02; //自定义协议
                        break;
               
                default: return;
        }
        AES128_ECB_Encrypt(Buf, SecretKey, Data);
        GATTC_SendEvtCmd(0, GATTC_NOti€€FY, 0, GATTM_GetHandle(CS_TX_VALUE_VAL0), 16, Data); //发送反馈结果到手机
}
void DIO0_IRQHandler(void)
{
        uint8_t Buf[16] = {0x05, 0x01}, Data[16] = {0x00};
       
        if ((DIO->DATA & GPIO5_HIGH) != GPIO5_HIGH) //检测到底部微动开关闭合
        {
                AES128_ECB_Encrypt(Buf, SecretKey, Data);
                GATTC_SendEvtCmd(0, GATTC_NOTIFY, 0, GATTM_GetHandle(CS_TX_VALUE_VAL0), 16, Data); //发送反馈结果到手机
        }
}
    代码中引用了AES128加解密功能,RSL10有相关例程。不过硬件只支持加密,而软件加解密的例程写的又比较繁琐,所以我用了自己的AES单元,功能是一样的,网上类似的代码也有很多,随意使用。当然,修改的东西不只是这一点点,其他一些细小的改造也是必要的,比如蓝牙数据变量要在头文件中声明才可以跨文件调用、关闭例程本身的LED超时控制、重新定义IO口和中断等,这里就不再详细说明,都会包括在后面提供的工程里。由于是开发板,增加电机控制等其他电路不方便,就是用板载LED灯来代替电机的使能,按钮就模拟锁车状态吧。

    接下来编译并运行,设置断点可观察接收到的数据以及执行的动作。使用Nordic的蓝牙调试工具模拟手机App来收发数据,只要通讯协议的数据对应上就可以了。
APP1.jpg APP2.jpg APP3.jpg
运行.png
   
    可以看到当手机发送开锁指令时,电机转动直到检测到开关闭合信号为止,并反馈结果;接收到锁车指令后同样电机转动,离开微动开关即可达到待锁状态;按下按键模拟手动锁车,并把锁车信息发送到手机以便和服务器进行交互完成结算收费功能。
    到这里整个工程就算完成了,在此提供给工程文件下载权当参考,只是一个框架,鉴权的过程及一些容错处理没有加入进来,其他的功能请自由发挥吧。
工程.rar
ble_peripheral_server_bond.rar (201.28 KB, 下载次数: 2)
    最后能否恳请官方提供一个最简单的没有bass服务的例程,以帮助我实现最简化的目的,不甚感激,谢谢!


只有小组成员才能发言,加入小组>>

78个成员聚集在这个小组

加入小组

创建小组步骤

关闭

站长推荐 上一条 /7 下一条

快速回复 返回顶部 返回列表