本篇博文最后修改时间:2017年06月02日,21:49。
一、简介
本文以SimpleBLEPeripheral工程为例,介绍如何通过app的指令对设备进行设置时间、读取时间。
二、实验平台
协议栈版本:ble_cc26xx_2_01_00_44423
编译软件:IAR Embedded Workbench for ARM Version 7.40
硬件平台:CC26xxDK开发板
仿真器:XDS100V3(香瓜)
手机平台:小米4S
APP:BLE读写器
三、版权声明
博主:甜甜的大香瓜
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.NET/feilusia
联系方式:897503845@qq.com
香瓜BLE之CC2541群:127442605
香瓜BLE之CC2640群:557278427
香瓜单片机之STM8/STM32群:164311667
香瓜单片机之Linux群:512598061
香瓜单片机之职场交流群:450154342
香瓜单片机之职场交流群:450154342
甜甜的大香瓜的小店(淘宝店):https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i
四、
实验前提
1、在进行本文步骤前,请先
阅读
以下博文:
暂无
2、在进行本文步骤前,请先
实现以下博文:
1)《CC2640之添加自定义服务》:http://blog.youkuaiyun.com/feilusia/article/details/52333664
五、基础知识
1、什么是RTC?
答:RTC(Real-time clock),也就是实时时钟。它常被用于设备端的时钟计时。
2、手机端已经有时间了,为何还要能通过app设置设备端时间、读取设备端时间?
答:例如智能保温杯项目,商家想根据用户的喝水习惯,在app端给用户合适的健康建议。
这时在智能保温杯中增加RTC时间功能,即可记录下用户一天内喝水的时间,当app连接时将喝水时间上报给app,app即可给出建议“喝水较少,建议多喝水”。
3、CC2640中如何使用RTC?
答:协议栈中已有RTC驱动,使用流程如下:
1)设置RTC时间
①启动RTC计数:调用UTC_init函数。
②填写时间
(
年、月、日、时、分、秒
):填写UTCTimeStruct结构体的数据。
③
转换时间
(
秒
):通过UTC_convertUTCSecs函数,将UTCTimeStruct时间(年、月、日、时、分、秒)转换为UTCTime时间(秒)。
④更新时间:调用UTC_setClock函数,参数是③中转换所得的UTCTime时间。
2)读取RTC时间
①获取RTC时间:调用UTC_convertUTCTime函数。
②转换时间(
年、月、日、时、分、秒):将上面获得的
UTCTime时间(秒),转换为UTCTimeStruct时间(年、月、日、时、分、秒)。
4、CC2640中使用RTC时需要注意什么?
答:
1)一天下来,RTC的时钟计数有个几秒误差是正常的,因此尽量每次app连接时能更新一下最新的时间。
2)特别注意协议栈中的月、日、时三个数据,是从0开始,而不是我们通常习惯的1开始。
typedef struct
{
uint8_t seconds; // 0-59
uint8_t minutes; // 0-59
uint8_t hour; // 0-23
uint8_t day; // 0-30
uint8_t month; // 0-11
uint16_t year; // 2000+
} UTCTimeStruct;
5、既然协议栈中已有RTC的驱动,为何香瓜要再封装一个驱动文件?
答:为了简化使用、并且解决上述第3点的第2)小点注意事项的问题,香瓜自己封装了一个RTC驱动文件。
该文件中一共3个函数,初始化、读、写,读出来的便是最终可直接拿来使用的转换好的时间数据,非常方便使用。
PS:相信你用过之后会觉得协议栈的原始RTC驱动真TMD的难用。
六、实验步骤
1、添加协议栈的RTC驱动
1)添加UTC_clock.c和UTC_clock.h(文件路径在“……\ble_cc26xx_2_01_00_44423\Projects\ble\common\cc26xx\Time”)
2)IAR设置中增加协议栈RTC文件的路径
$PROJ_DIR$/../../../../../../../Projects/ble/common/cc26xx/Time
3)修改UTC_Clock.h
#include <stdint.h>
不增加这个头文件的话,会报错,缺少uint8等数据类型的定义。
2、编写并添加香瓜RTC驱动
1)写一个香瓜RTC驱动源文件GUA_RTC.c(存放在“……\ble_cc26xx_2_01_00_44423\Projects\ble\SimpleBLEPeripheral\CC26xx\Source\Application\GUA”路径下)
//******************************************************************************
//name: GUA_RTC.c
//introduce: 香瓜自定义的RTC驱动
//author: 甜甜的大香瓜
//email: 897503845@qq.com
//QQ group 香瓜BLE之CC2640(557278427)
//changetime: 2016.09.04
//******************************************************************************
#include "GUA_RTC.h"
//******************************************************************************
//name: GUA_RTC_Init
//introduce: 香瓜的RTC初始化
//parameter: none
//return: none
//author: 甜甜的大香瓜
//email: 897503845@qq.com
//QQ group 香瓜BLE之CC2640(557278427)
//changetime: 2016.09.04
//******************************************************************************
void GUA_RTC_Init(void)
{
//初始化UTC.
UTC_init();
}
//******************************************************************************
//name: GUA_RTC_Set
//introduce: 香瓜的RTC设置时间函数
//parameter: pGUA_Timer:传入的时间
//return: none
//author: 甜甜的大香瓜
//email: 897503845@qq.com
//QQ group 香瓜BLE之CC2640(557278427)
//changetime: 2016.09.04
//******************************************************************************
void GUA_RTC_Set(UTCTimeStruct *pGUA_Timer)
{
UTCTimeStruct SetTime;
UTCTime SetTime_seconds;
//转换数据
SetTime.year = pGUA_Timer->year;
SetTime.month = pGUA_Timer->month - 1;
SetTime.day = pGUA_Timer->day - 1;
SetTime.hour = pGUA_Timer->hour - 1;
SetTime.minutes = pGUA_Timer->minutes;
SetTime.seconds = pGUA_Timer->seconds;
//将时间转换为秒
SetTime_seconds = UTC_convertUTCSecs(&SetTime);
//设置时间
UTC_setClock(SetTime_seconds);
}
//******************************************************************************
//name: GUA_RTC_Get
//introduce: 香瓜的RTC获取时间函数
//parameter: pGUA_Timer:传入的时间
//return: none
//author: 甜甜的大香瓜
//email: 897503845@qq.com
//QQ group 香瓜BLE之CC2640(557278427)
//changetime: 2016.09.04
//******************************************************************************
void GUA_RTC_Get(UTCTimeStruct *pGUA_Timer)
{
UTCTimeStruct GetTime;
//获取当前数据
UTC_convertUTCTime(&GetTime, UTC_getClock());
//抓换数据
pGUA_Timer->year = GetTime.year;
pGUA_Timer->month = GetTime.month + 1;
pGUA_Timer->day = GetTime.day + 1;
pGUA_Timer->hour = GetTime.hour + 1;
pGUA_Timer->minutes = GetTime.minutes;
pGUA_Timer->seconds = GetTime.seconds;
}
2)写一个香瓜RTC驱动头文件GUA_RTC.h(存放在“……\ble_cc26xx_2_01_00_44423\Projects\ble\SimpleBLEPeripheral\CC26xx\Source\Application\GUA”路径下)
//******************************************************************************
//name: GUA_RTC.h
//introduce: 香瓜自定义的RTC驱动头文件
//author: 甜甜的大香瓜
//email: 897503845@qq.com
//QQ group 香瓜BLE之CC2640(557278427)
//changetime: 2016.09.04
//******************************************************************************
#ifndef _GUA_RTC_H_
#define _GUA_RTC_H_
/*********************头文件************************/
#include "UTC_Clock.h"
/*********************函数声明************************/
extern void GUA_RTC_Init(void);
extern void GUA_RTC_Set(UTCTimeStruct *pGUA_Timer);
extern void GUA_RTC_Get(UTCTimeStruct *pGUA_Timer);
#endif
3)工程中添加GUA_RTC.c和GUA_RTC.h
4)在IAR设置中添加服务的文件路径
$PROJ_DIR$/../../../Source/Application/GUA
如果已添加过,就不用添加了。
3、在应用层中添加RTC相关的代码
1)添加GUA_RTC头文件(SimpleBLEPeripheral.c中)
#include "GUA_RTC.h"
2)香瓜RTC初始化(SimpleBLEPeripheral.c的SimpleBLEPeripheral_Init中)
//香瓜RTC初始化
GUA_RTC_Init();
初始化RTC,否则时钟不会计数。
3)添加app的处理指令(替换SimpleBLEPeripheral.c的GUA_CharValueChangeEvt函数)
//******************************************************************************
//name: GUA_CharValueChangeEvt
//introduce: 应用层香瓜服务的处理函数
//parameter: paramID:特征值ID
//return: none
//author: 甜甜的大香瓜
//email: 897503845@qq.com
//QQ group 香瓜BLE之CC2640(557278427)
//changetime: 2016.09.04
//******************************************************************************
#define GUA_COMMAND_GET_TIME 0x01
#define GUA_COMMAND_SET_TIME 0x02
static void GUA_CharValueChangeEvt(uint8_t paramID)
{
uint16 notify_Handle;
uint8 bBuf[20] = {0};
uint8 *p = bBuf;
UTCTimeStruct GUA_Timer;
switch(paramID)
{
//char1
case GUAPROFILE_CHAR1:
{
//读出特征值数据
GUAProfile_GetParameter(GUAPROFILE_CHAR1, p);
//根据通信协议进行事件分发,功能码+年(2字节)+月+日+时+分+秒
switch(p[0])
{
//读当前时间
case GUA_COMMAND_GET_TIME:
{
//获取当前时间
GUA_RTC_Get(&GUA_Timer);
//整理发送缓冲区
memset(p, 0xff, GUAPROFILE_CHAR1_LEN);
p[0] = GUA_COMMAND_GET_TIME;
p[1] = GUA_Timer.year >> 8;
p[2] = GUA_Timer.year & 0xff;
p[3] = GUA_Timer.month;
p[4] = GUA_Timer.day;
p[5] = GUA_Timer.hour;
p[6] = GUA_Timer.minutes;
p[7] = GUA_Timer.seconds;
//发送
GAPRole_GetParameter(GAPROLE_CONNHANDLE, ¬ify_Handle);
GUAprofile_Notify(GUAPROFILE_CHAR1, notify_Handle, p, 20);
break;
}
//设置当前时间
case GUA_COMMAND_SET_TIME:
{
//读出要设置的时间
GUA_Timer.year = p[1];
GUA_Timer.year <<= 8;
GUA_Timer.year |= p[2];
GUA_Timer.month = p[3];
GUA_Timer.day = p[4];
GUA_Timer.hour = p[5];
GUA_Timer.minutes = p[6];
GUA_Timer.seconds = p[7];
//设置当前时间
GUA_RTC_Set(&GUA_Timer);
//获取当前时间
GUA_RTC_Get(&GUA_Timer);
//整理发送缓冲区
memset(p, 0xff, GUAPROFILE_CHAR1_LEN);
p[0] = GUA_COMMAND_SET_TIME;
p[1] = GUA_Timer.year >> 8;
p[2] = GUA_Timer.year & 0xff;
p[3] = GUA_Timer.month;
p[4] = GUA_Timer.day;
p[5] = GUA_Timer.hour;
p[6] = GUA_Timer.minutes;
p[7] = GUA_Timer.seconds;
//发送
GAPRole_GetParameter(GAPROLE_CONNHANDLE, ¬ify_Handle);
GUAprofile_Notify(GUAPROFILE_CHAR1, notify_Handle, p, 20);
break;
}
//其他
default:break;
}
break;
}
default:break;
}
}
利用香瓜服务的char1,增加了两条指令:读RTC时间指令、设置RTC时间指令。
七、指令
指令使用简单的通信协议:
功能码(1字节)+年(2字节)+月(1字节)+日(1字节)+时(1字节)+分(1字节)+秒(1字节)+补齐字节(n字节)。
1)读RTC时间指令
01ffffffffffffffffffffffffffffffffffffff
注:
01ffffffffffffffffffffffffffffffffffffff
注:
①0x01:功能码(
读RTC时间指令)。
②其余0xff:补齐字节,补齐至20字节,也就是19个0xff。
2)设置RTC时间指令
0207e00904102d1effffffffffffffffffffffff( 2016年09月04日 16点45分30秒)
2)设置RTC时间指令
0207e00904102d1effffffffffffffffffffffff( 2016年09月04日 16点45分30秒)
注:
①0x02:
功能码(
设置RTC时间指令
)。
②0x07e0:2016(年)
③0x09:9(月)
④0x04:4(日)
⑤
0x10:16(时)
⑥
0x2d:45(分)
⑦
0x1e:30(秒)
⑧其余0xff:补齐字节,补齐至20字节,也就是13个0xff。
八、实验结果
1、读一下RTC默认时间
1)发送读RTC时间指令
2)读到返回的默认的RTC时间
如果去解析,就会发现它是2000年1月1日1时2分28秒。
其实RTC默认是从
2000年1月1日1时0分0秒开始计算的,只是我发送指令读取时是在计数开始的2分28秒之后了。
2、更新RTC时间
1)
发送设置RTC时间指令(2016年09月04日 16点45分30秒)
2)读到返回的默认的RTC时间
跟我们发送的指令一样,是
2016年09月04日 16点45分30秒。
3、两分钟后,再次读RTC时间
1)发送读RTC时间指令
2)读到返回的默认的RTC时间
解析后发现它是2016年09月04日16时47分52秒。
比上一次读取的时间多了2分钟,实验结果基本正确。
香瓜未做更为精确的测试去计算误差,大家自行测试吧。
至此,实验结束。