【杰理蓝牙开发】AC695x 按键ADC接口分析
0. 个人简介 && 授权须知
📋 个人简介
- 💖 作者简介:大家好,我是喜欢记录零碎知识点的菜鸟打工人。😎
- 📝 个人主页:欢迎访问我的博客主页🔥
- 🎉 支持我:点赞👍+收藏⭐️+留言📝
- 📣 系列专栏:杰理蓝牙开发专栏 🍁 🍁
- 💬格言:写文档啊不是写文章,重要的还是直白!🔥
转载文章,禁止声明原创;不允许直接二次转载,转载请根据原文链接联系作者
若无需改版,在文首清楚标注作者及来源/原文链接,并删除【原创声明】,即可直接转载。
但对于未注明转载来源/原文链接的文章,我将保留追述的权利。作者:积跬步、至千里
1. APP消息管理
【系统事件分类】
-
模式事件
- 按键、设备、其他
-
公共事件
- 按键、设备、蓝牙、其他
【系统事件处理】
产生系统事件时
- 先到【模式事件】中查询是否有匹配的事件,若果有,则执行事件处理函数,然后结束,若没有,执行下一步
- 再到【公共事件】中查询是否有匹配的事件,若果有,则执行事件处理函数,然后结束,若没有,则事件作废
蓝牙模式的设备事件如果不做处理,那么会把事件丢到公共事件中的公共蓝牙事件去 处理,而不是丢到公共事件的公共设备事件去处理
2. adc 按键接口
2.1 驱动部分
adc 按键的初始化流程函数接口如下所示:
【初始化后,系统开始2ms为周期采集 adc 通道的值】
main()
-> task_create(app_task_handler, NULL, "app_core");
-> app_init();
-> board_init();
-> adc_init();
-> _adc_init(1);
-> sys_s_hi_timer_add(NULL, adc_scan, 2); //定时器 2ms 扫描一次
-> adc_scan();
-> adc_sample(); // adc 采样函数
依次采集 AD_CH_LDOREF 和 AD_CH_VBAT 这两个通道的 adc 值
【添加按键的扫描驱动,这个是在ADC扫描函数之后】
main()
-> task_create(app_task_handler, NULL, "app_core");
-> app_init();
-> board_init();
-> board_devices_init();
-> key_driver_init();
{
-> err = adkey_init(&adkey_data); // 初始化 ADC
-> // 定义了哪些按键,就初始化哪些按键
//按键扫描,扫描所有定义的按键
-> sys_s_hi_timer_add((void *)&adkey_scan_para, key_driver_scan, adkey_scan_para.scan_time);
}
其中 adkey_scan_para
变量是定义的全局按键驱动扫描参数结构体,注意定义的 key_type
为 KEY_DRIVER_TYPE_AD
//按键驱动扫描参数列表
struct key_driver_para adkey_scan_para = {
.scan_time = 10, //按键扫描频率, 单位: ms
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
.filter_time = 2, //按键消抖延时;
.long_time = 75, //按键判定长按数量
.hold_time = (75 + 15), //按键判定HOLD数量
.click_delay_time = 20, //按键被抬起后等待连击延时数量
.key_type = KEY_DRIVER_TYPE_AD, // **********************注意定义的类型*******************
.get_value = ad_get_key_value, // 返回定义的 ADC 通道的 按键值,也即是 adkey_data 变量中定义的哪个按键
};
key_driver_scan
函数负责扫描所有注册的按键驱动,消抖,单击、双击、长按、短按…………,伪代码逻辑如下:
最终会通过 sys_event_notify(&e)
接口向系统通知发生了什么类型的事件。
比如:发生了 按键事件,按键为 ``ADC IO口的第六个按键,类型为
KEY_DRIVER_TYPE_AD`
key_driver_scan()
{
cur_key_value = scan_para->get_value(); // 判断当前是哪个按键
// 经过各种判断,最后打包 struct sys_event e; 这个变量
e.type = SYS_KEY_EVENT; // 类型为 按键
e.u.key.init = 1;
e.u.key.type = scan_para->key_type; //区分按键类型,ADC中自定义类型为 KEY_DRIVER_TYPE_AD,在变量 adkey_scan_para 中
e.u.key.event = key_event; // 判断按键事件类型为,长按、短按、保持、松开、等具体的类型
e.u.key.value = key_value; // 比如ADC中一个IO口可能连接了9个按键,该值定义是哪个按键被按下
e.u.key.tmr = timer_get_ms();
scan_para->click_cnt = 0; //单击次数清0
scan_para->notify_value = NO_KEY;
sys_event_notify(&e); // ******************************向系统通知事件触发的接口******************
}
2.2 应用层部分
board_ac695x_demo_cfg.h
中,设置 ADC
的引脚为 ADC3/PA10
#define TCFG_ADKEY_PORT IO_PORTA_10 //AD按键端口(需要注意选择的IO口是否支持AD功能)
#define TCFG_ADKEY_AD_CHANNEL AD_CH_PA10
2.2.1 定义事件处理函数
定义一个全局变量 adkey_data
作为该部分的数据结构,定义 AD按键对应的引脚,ADC通道等值
系统通知有事件发生时,应用层应该定义相应的事件处理函数
SYS_EVENT_HANDLER(SYS_KEY_EVENT, app_key_event_remap, 3);
// SYS_KEY_EVENT 对应的事件处理函数
int app_key_event_remap(struct sys_event *e)
{
struct key_event *key = &e->u.key;
int msg = KEY_NULL;
switch (key->type) {
case KEY_DRIVER_TYPE_AD: // ************发生这个类型的按键事件时,自定义事件处理函数****************
break;
case KEY_DRIVER_TYPE_RTCVDD_AD: // 示例:如果发生这个事件
#if TCFG_ADKEY_ENABLE
msg = adkey_event_to_msg(app_curr_task, key); //从表中获取事件类型
#endif
break;
defalut:break
}
e->u.key.event = msg;
e->u.key.value = 0;//
return TRUE;//notify数据
}
SYS_EVENT_HANDLER(SYS_KEY_EVENT, app_key_event_remap, 3); // 注册完毕后,系统会自动执行
2.2.2 查表获取事件类型
msg = adkey_event_to_msg(app_curr_task, key); //从表中获取事件类型
// msg 为 某模式,例如 fm 模式下的 adkey table ,中的某个事件类型
/*
按键1动作: 单击 长击 保持 抬起 双击 三击
事件类型: A1 A2 A3 A4 A5 A6
*/
假设当前 task
类型为 fm_task
,则查表过程如下:
3. fm task 中获取按键消息
adc 按键只有一组,但是可以实现在不同的任务下实现不同的功能。
在 fm 模式下,通过按键实现事件触发的接口原理分析如下:
app_fm_task();
-> fm_event_handler((struct sys_event *)(&msg[1]);
-> fm_key_event_opr(event);
-> /*不同的 event 对应不同的时间处理函数*/
比如,暂停播放对应的 adc 按键为: 按键2 的单击事件