1、在范例程序中提供了一个完整的框架,可以快速测试,但是,工程中需要自定义蓝牙服务和特征才能实现需要的功能,这个就需要使用自定义蓝牙服务的功能。
AT32WB415的蓝牙服务从逻辑上非常清晰,按照蓝牙系统架构如下图,从硬件基础层,链路层,直到应用层分层协同运行,才能实现低功耗蓝牙的完整功能。因为按照标准协议提供了完整的协议栈,对于开发者,直接在应用层进行调整就能实现任务。对于这个系统,修改的只是位于Host部分的GAP和GATT服务,而底层的控制层Controller只用到LE controller部分。
GAP是通用访问配置文件(Generic Access Profile)的首字母缩写,用来控制蓝牙的connection和advertising,设备对外界的可见性,并确定两个设备如何(或不能)相互沟通。GAP定义了设备的各种角色,但要记住的两个关键概念是中央(Central)设备和外围(Peripheral)设
备。
GATT定义了两个蓝牙低功耗设备使用称为服务(Service)和特征(Characteristic)的概念来回传输数据的方式。它使用称为属性协议(ATT, Attribute Protocol)的通用数据协议,该协议用于在一个简单的查询表中存储服务,特性和相关数据,表中每个条目使用16位ID。一旦在两个设备之间建立专用连接,GATT即可发挥作用,这意味着已经完成了由GAP管理的广播流
程。
在确定了GATT连接后,用户就可以进入自定义开发的Services和Characteristics部分。基于如下嵌套的Profile结构体
Service用于将数据分解为逻辑实体,并包含称为Characteristic的特定数据块。Service可以具有一个或多个Characteristic,并且每个Service通过称为UUID的唯一数字ID将其自身与其他服务区分开来,UUID可以是16位(对于正式采用的BLE服务)或128位(对于自定义服务)。
GATT事务中的最低级别概念是特性(Characteristic),其封装单个数据点。与Service类似,每个Characteristic通过预定义的16位或128位UUID进行区分,您可以自由使用Bluetooth SIG定义的标准Characteristic或定义您自己的自定义Characteristic,只有您的外围设备和
SW可以理解。
2、基于AT Command的蓝牙服务
AT32WB415的蓝牙服务比较独特的是基于ATCommand的,具体逻辑图如下,
居于蓝线内的就是AT32WB415的双核,一个是主MCU,另一个就是专用的蓝牙控制器,远程的APP可以通过蓝牙建立连接,居于双核之间的通信就是AT命令的应答。
AT command命令集用到海斯命令集(Hayescommand set)基本指令集的部分,以AT开始,告知调制解调器后面跟着是调制解调器指令,每一行以 AT 为起始,基本指令集一个大写字符跟着一个数值,例如:M1。常用的指令,
AT,用于测试是否连接
AT+BAUDx,用于修改波特率
AT+NAMExxxx,修改蓝牙(BD name)名 称,存入 Flash 中
AT+IOGET,读取远程 IO 电平
等等,
在AT32WB415的开发中AT命令模式和透传模式是冲突的,所以自定义服务的功能在透传模式下无法使用,在标准范例程序中,通过USER按键来切换两种模式。
3、开发自定义芯片内温度传感器读取蓝牙服务
3.1 首先参考数据手册,其中芯片内置一个温度传感器,可以通过ADC通道读取芯片内的温度。
代码依次初始化ADC端口,使用轮询的方式就可以定时读取ADC0的内部温度传感器读数并在printf()指令的定义在串口的控制台显示数据。
int main(void)
{
__IO uint32_t index = 0;
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
system_clock_config();
at32_board_init();
at32_led_off(LED2);
at32_led_off(LED3);
at32_led_off(LED4);
uart_print_init(115200);
dma_config();
adc_config();
printf("internal_temperature_sensor \r\n");
adc_ordinary_software_trigger_enable(ADC1, TRUE);
while(1)
{
at32_led_on(LED2);
delay_sec(1);
while(dma_flag_get(DMA1_FDT1_FLAG) == RESET);
dma_flag_clear(DMA1_FDT1_FLAG);
printf("internal_temperature = %f deg C\r\n",(ADC_TEMP_BASE - (double)adc1_ordinary_value * ADC_VREF / 4096) / ADC_TEMP_SLOPE + 25);
}
}
3.2 在蓝牙内核定义温度服务,需要以下6个文件
custom.c, custom.h
custom_task.c, custom_task.h
app_custom.c,app_custom.h
在app_task.c 文件中找到appm_msg_handler 函数,新增处理 custom ID 的 case选项,
在 app.c 中新增项目到服务列表appm_svc_list
在 app.c 中新增函数列表以建立 database
在 app.c 中找到 appm_init 函数,在其中添加 app_temp_init 函数
在 rwip_task.h 中的 TASK_API_ID 中新增自定义服务的 ID
在 prf.c 中添加 temp_prf_itf_get 函数的声明
以及添加 customs_prf_itf_get 函数的调用
对应的函数需要完成代码的编写,这样把新的服务添加到软件框架中去,对应的函数需要参考标准读写的框架正确编写,就可以完成蓝牙侧的修改了。
3.3 在自定义服务中完成自定义特征的读写
增加温度特征的定义为0xc106,
并在文件中添加到GATT_DB的数据库,
4、在主MCU中实现内部温度传感器的读取
首先在原来的工程中增加库
在at_cmd_handler函数中定义读取ADC的代码,
这样就把读取的数据和蓝牙模块连接起来。
但是还是不能很好协同,只执行了一个周期就停止了。
基本的库和外设访问正常,不过,涉及资源如中断,时钟等都需要很好地理解才能跑出来通畅的工程。
而且其中还有共享内存管理的工作,蓝牙对射频资源的访问是通过直接写入外设的内存地址实现的,这样的细节还没有找到合适的文档参考,目前只能还是先直接套用。
后续调试的工作量还是比较大的。