CH587 磁轴键盘 ADC 与 ADCS 扫描应用说明
磁轴键盘通过 ADC 读取霍尔传感器电压,再将电压换算为按键行程。CH587 的多通道 ADC 扫描配合 ADCS 扫描轮次输出,可用于控制外部模拟开关,按组采集多个按键。本文结合例程,说明硬件连接思路、轮次含义及软件调用流程,如需例程下载可跳转至本文末尾。
手册下载链接:https://www.wch.cn/downloads/CH587DS1_PDF.html ,当前版本为CH587DS1.PDF V1.0,文末图解标注 PDF 页码与手册印刷页码,便于查阅。
1、 通道与轮次含义
通道表示本轮要读取的 ADC 输入;轮次表示这是第几次执行整组通道扫描。为便于理解,本文把手册中的“ADC 扫描周期数”称为“扫描轮次编号”。例如配置 10 路通道,一轮就是按设定顺序扫描这 10 路;连续执行 8 轮,可配合外部开关读取 8 组信号。
还要区分每个通道内部的重复采样。所附例程一轮扫描 22 路通道,每个通道采样 2 次,因此每轮有 44 个有效采样结果;执行 8 轮共有 352 个结果。每通道采样 2 次,而不是 ADCS 有 2 个轮次。
|
输出的连续低位数 |
一个完整循环的轮数 |
ADCS 状态顺序 |
|
1 位 |
2 轮 |
0 → 1 → 0 |
|
2 位 |
4 轮 |
00 → 01 → 10 → 11 → 00 |
|
3 位 |
8 轮 |
000 → 001 → … → 111 → 000 |
这里的位数指从 bit0 开始使用的连续低位。仅改变软件循环次数,不会自动改变 ADCS 输出使能;例程默认使能全部 3 位,ADCS_ROUND_NUM 为 8。
2 、ADCS 的电气含义
ADCS0、ADCS1、ADCS2 分别承载轮次编号的 bit0、bit1、bit2。0 和 1 对应低、高电平,三根线作为外部模拟开关的地址选择信号。在设置 3 个位状态时,顺序为 ADCS2 ADCS1 ADCS0,例如 010 表示只有 ADCS1 为高电平。
3、 磁轴键盘的硬件连接思路
以 80 键为例,可以使用 10 路 ADC 输入配合 10 个八选一模拟开关。每个开关连接 8 个霍尔传感器的信号输出,公共端连接一路 ADC;所有开关共用 ADCS0~2 三根地址线。传感器供电和开关使能应按实际器件要求连接。
图 1 80 键分组采集连接示意 外部模拟开关共用 ADCS 地址线

输出 000 时,每个开关选中其编号 0 的输入,ADC 读取第 1 组的 10 个键;输出 001 时,选中编号 1 的输入,读取第 2 组。依次完成 8 组,即可覆盖 80 个键。这里的“组”是信号连接分组,不要求与键盘机械布局的行列完全一致。
ADCS 负责输出选择编号,霍尔电压经过模拟开关进入 ADC。三根选择线不能直接替代模拟开关,也不能将多个传感器输出简单并接到同一 ADC 输入。
|
信号 |
M、F封装默认引脚 |
W封装可重映射引脚 |
|
ADCS0 |
PB4 |
PC10 |
|
ADCS1 |
PB5 |
PC11 |
|
ADCS2 |
PB6 |
PC12 |
当前 ADCS_Init 中 ,实际使用 PB4、PB5、PB6,是 M、F 封装使用默认引脚。如使用W封装可映射至PC10~PC12 。
4 、初始化 ADC 扫描与 ADCS
固定扫描方案下,先完成 ADC 输入 GPIO、采样参数、校准、扫描通道顺序、DMA 缓冲区以及中断配置,再启动采样。后续重复采集同一通道组时,保留配置即可,不需要每轮重新初始化。
所附 ADC_Scan 函数把初始化、8 轮采样、打印和关闭资源都放在一起,适合演示。移植到持续运行的键盘程序时,应将初始化与关闭部分从周期采样流程中拆开;若每次都调用原始 ADC_Scan,仍会重复配置并在末尾关闭扫描。
ADCS 的关键配置
/* 默认引脚 PB4 PB5 PB6 */
GPIOB_ModeCfg(GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6, GPIO_ModeOut_PP_5mA);
GPIOB_ResetBits(GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6);
R8_TEM_SENSOR |= RB_SCAN_CONT_EN | RB_SCAN_CYC_OE;
|
寄存器名称 |
寄存器含义 |
|
RB_SCAN_CONT_EN |
使能扫描轮次计数 |
|
RB_SCAN_CYC_OE |
使能 3 位轮次编号的引脚输出 |
|
RB_SCAN_CYCLE |
读取当前轮次计数值的掩码 0x07 |
寄存器名为 R8_TEM_SENSOR,但其中也包含 ADCS 控制字段。修改时应保留其他无关位。当前例程使用按位或使能全部输出;需要只用 1 位或 2 位时,应调整对应输出位和 GPIO 配置,并与外部选择电路保持一致。
扫描通道配置的移植要点
例程配置 22 路输入,scan_ch 数组为 AIN0~AIN21,并通过 ADC_ChannelCfg 和 R32_ADC_SCAN_CFG1~4 配置扫描序列。
改为 10 路时,需要同步调整通道数量、序列打包循环、扫描数量高位及 DMA 范围,不能仅把 ADC_SCAN_CH_NUM 改为 10,因为原打包循环仍按 22 路写入。

原例程设置每通道采样 2 次,使用 adcBuff[i * 2] 和 adcBuff[i * 2 + 1] 读取同一通道的两个样本,打印时加上 RoughCalib_Value。
手册明确 DMA_END 为结束地址且不包含该地址;若只存 N 个 uint16_t 有效结果,边界应按 2N 字节核对。所附例程另加了一个元素的空间,不应将其计入有效结果数量。
5 、每轮采样如何启动与结束
初始化完成后,每采一轮调用 ADC_StartandWait。该函数启动连续转换控制和 ADC 转换,再等待扫描结束中断置位 SCAN_end。
__HIGH_CODE
void ADC_StartandWait()
{
ADC_StartContDMA();
ADC_StartUp();
while (!SCAN_end);
SCAN_end = 0;
}
配套的中断处理如下。中断关闭连续转换,清除扫描结束标志,将 DMA 写入位置恢复到缓冲区起点,然后通知等待函数。
__INTERRUPT
__HIGH_CODE
void ADC_IRQHandler(void)
{
if (R32_ADC_SCAN_CFG2 & RB_ADC_IF_SCAN_END)
{
ADC_StopContDMA();
R32_ADC_SCAN_CFG2 |= RB_ADC_IF_SCAN_END;
R32_ADC_DMA_BEG = (uint32_t)adcBuff & 0x3ffff;
SCAN_end = 1;
}
}
因此,一次 ADC_StartandWait 对应一轮已配置通道组的扫描,并非只采一个通道。
每次开始采样时,ADCS 轮次会同步参与扫描;每完成一轮通道扫描,轮次计数加 1。读取轮次寄存器时,应区分启动前与完成后,避免将本轮数据误标为下一组。
这个等待函数依赖 ADC 中断正常执行。调用前须完成中断使能并保证 SCAN_end 为 0;不要在无法响应 ADC 中断的环境中阻塞调用。
正式键盘固件可增加超时处理,避免异常时一直等待。保留例程的 __HIGH_CODE 及相应 RAM 代码配置。
同一缓冲区在下一轮会被覆盖。每轮返回后应及时完成结果复制或处理,并将数据关联到正确的组号。串口打印仅用于演示,会增加轮间间隔,不应用其运行速度判断键扫性能。
6 、按键数据组织与不足八组的处理
对于 8 组、每组 10 键的方案,应用层可以将结果保存为 key_adc[8][10]。每轮返回后,把当前缓冲区中 10 路通道的有效数据放入对应组。若每通道保留两个样本,应先确定采用平均、筛选还是保留双样本,再进行行程换算。
/* 流程示意 供参考 */
初始化 ADC 通道序列 DMA 和 ADC 中断;
初始化 ADCS 并确认首组编号;
for (;;) {
for (group = 0; group < 8; group++) {
ADC_StartandWait();
将本轮 ADC 数据保存到 key_adc[group];
}
依据校准参数换算行程并更新按键状态;
}
当实际只需要 5 组时,可在第 5 组采样完成后调用 ADCS_Init,使下一次扫描重新从首组开始,而无需采满 8 组。
7 、上板验证要点
先用已知电压区分各组信号,同时观察 ADCS0~2 和 ADC 结果。核对首组编号、状态变化顺序、整组扫描边界及 111 后的回绕;只使用 1 位、2 位或提前复位时,分别验证循环范围与数据对应关系。
模拟开关切换后需要时间让 ADC 输入稳定。应结合霍尔传感器输出阻抗、开关导通电阻、输入电容和 ADC 采样时间检查首个样本,尤其确认组切换后的数据没有串组。必要时调整采样参数或安排丢弃样本,具体取舍以测量结果为准。
最后再加入各键零点与行程校准、滤波、触发释放阈值及上报逻辑。ADCS 与 ADC 负责分组选择和电压采集,完整磁轴键盘还需要这些应用层处理。
例程文件索引
adc_cfg.c:扫描初始化、ADCS 配置、单轮启动等待与演示循环。
Main.c:系统入口、串口调试与 ADC 中断处理。
adc_cfg.h:数据缓冲区与函数声明。
StdPeriphDriver/inc/CH587SFR.h:ADCS 相关寄存器字段定义。
8 、对照手册理解引脚与轮次
先从引脚映射看起。ADCS0、ADCS1、ADCS2 是一个 3 位编号的三个输出位;它们可以共用默认引脚 PB4~PB6,也可以在支持相应引脚的封装上切换到 PC10~PC12。手册中的映射选择字段名为 RB_PIN_ADC_CYC,例程库则使用 RB_PIN_ADC_CYC_1 宏,移植时应以当前头文件定义为准。

图 2 ADCS 引脚映射选择 CH587DS1.PDF V1.0 PDF 第 68 页 印刷第 66 页
上图的 0 和 1 表示“选择哪组 GPIO 引脚”,与 ADCS 输出的 000~111 轮次编号是两种不同的配置概念。例如选择默认引脚后,PB4~PB6 仍会随轮次输出不同电平。引脚功能定义另见 PDF 第 8 页,印刷第 6 页。

图 3 轮次 通道与重复采样的关系 应用示意 不表示实际边沿时序
读图方法:外层是分组轮次,中层是本轮通道队列,内层是单通道重复采样次数。这个例子执行 8 轮,每轮 10 个通道,每通道 2 次,共得到 160 个有效样本,可覆盖 80 个按键并为每键保留两个样本。
9 、对照手册配置计数与通道采样

图 4 ADCS 计数与输出控制 摘自 CH587DS1.PDF V1.0 PDF 第 125 页 印刷第 123 页
图 4 中 bit3 控制计数使能,bit6~bit4 分别控制三个计数位能否输出到引脚;bit2~bit0 是只读计数结果。输出位数控制外部可见的编号位数,不能仅据此认定内部计数器位宽也改变。仅接低 1 位时,外部看到 0、1 交替;接低 2 位时看到 00~11 重复。

图 5 扫描数量与单通道采样次数 摘自 CH587DS1.PDF V1.0 PDF 第 128 页 印刷第 126 页
图 5 中 RB_ADC_SCAN_SEL 为 1 时,扫描数量编码为通道数减 1;RB_EHCH_TIM 的 00、01、10、11 分别对应每通道采样 1、2、3、4 次。例程写入 1 << 20,即选择每通道 2 次。RB_ADC_IF_SCAN_END 为写 1 清零字段,因此中断中的置位写操作用于清除标志。
10 、对照手册理解启动与完成边界
手册第 15.4 节说明,扫描队列第 0 项由 R8_ADC_CHANNEL 选择,其余项由扫描配置寄存器选择,硬件按配置顺序采样。队列编号是扫描顺序中的位置,不必与 AIN 输入编号相同。该节见 PDF 第 131~132 页,印刷第 129~130 页。
图 6 扫描触发方式与结束中断 摘自 CH587DS1.PDF V1.0 PDF 第 132 页 印刷第 130 页
手册区分周期性触发、按通道数量连续触发和按 DMA 地址连续触发。例程 ADC_StartContDMA 置位 RB_ADC_CONT_EN,随后 ADC_StartUp 置位 RB_ADC_START,对应按 DMA 地址连续触发的控制组合;例程同时在扫描结束中断中主动停止连续转换。不要把该函数中的“连续”理解为一次调用就完成全部 8 组。
一轮的结束边界,是队列最后一个通道转换结束并触发扫描结束中断。ADC_StartandWait 等到该中断置位 SCAN_end 后返回,然后应用层处理本轮数据,再发起下一轮。
应用流程
初始化通道与 DMA → 使能 ADCS → 确认当前选择组 → 调用 ADC_StartandWait → 扫描队列逐项转换并写入 DMA → 扫描结束中断停止连续转换 → 保存本轮数据 → 发起下一轮。
(如果不需要等到最大轮数,可在对应轮数采样完成时调用ADCS_Init实现轮数重置);
11、例程下载
通过网盘分享的文件:CH587W_ADC_Scan_ADCS_20261020.zip
链接: https://pan.baidu.com/s/1nds0EMy68Oq_tADZsrvD5Q?pwd=319y 提取码: 319y

浙公网安备 33010602011771号