要使用 M031/M032 系列微控制器 读取触摸屏信号并分析手指位置,需结合触摸屏硬件(如电阻式或电容式)和 MCU 的 ADC(模数转换器)功能。以下是详细步骤和代码示例:
1. 硬件连接
假设使用 4 线电阻触摸屏(常见类型):
- 触摸屏引脚:
XP(X+)、XN(X-)、YP(Y+)、YN(Y-)
- 连接至 MCU:
XP → ADC 输入引脚(如 PB0)
XN → 数字输出引脚(如 PB1)
YP → ADC 输入引脚(如 PB2)
YN → 数字输出引脚(如 PB3)
2. 测量原理
- X 坐标测量:
- 驱动
XP = 高电平,XN = 低电平(形成 X 方向电场)
- 从
YP 读取 ADC 值(电压与 X 位置成正比)
- Y 坐标测量:
- 驱动
YP = 高电平,YN = 低电平(形成 Y 方向电场)
- 从
XP 读取 ADC 值(电压与 Y 位置成正比)
3. 代码实现(基于 NuMicro SDK)
a. 初始化 GPIO 和 ADC
#include "NuMicro.h"
// 引脚定义
#define XP_PIN PB0
#define XN_PIN PB1
#define YP_PIN PB2
#define YN_PIN PB3
void ADC_Init(void) {
// 启用 ADC 时钟
CLK_EnableModuleClock(ADC_MODULE);
// 配置 ADC 时钟分频(PCLK / 255)
CLK_SetModuleClock(ADC_MODULE, CLK_CLKSEL1_ADCSEL_PCLK0, CLK_CLKDIV0_ADC(255));
// 初始化 ADC
ADC_Open(ADC, ADC_ADCR_DIFFEN_SINGLE_END, ADC_ADCR_ADMD_SINGLE, 0);
ADC_ENABLE_INT(ADC, ADC_ADF_INT); // 启用中断(可选)
ADC_SET_DMOF(ADC, 0); // 右对齐数据
}
void GPIO_Init(void) {
// 配置 XP/XN/YP/YN 引脚
GPIO_SetMode(PB, BIT0, GPIO_MODE_INPUT); // XP 初始为高阻输入
GPIO_SetMode(PB, BIT1, GPIO_MODE_OUTPUT); // XN 为输出
GPIO_SetMode(PB, BIT2, GPIO_MODE_INPUT); // YP 初始为高阻输入
GPIO_SetMode(PB, BIT3, GPIO_MODE_OUTPUT); // YN 为输出
}
b. X 坐标测量函数
uint32_t Read_Touch_X(void) {
// 设置 X 方向电场
GPIO_SetMode(PB, BIT0, GPIO_MODE_OUTPUT);
GPIO_SetMode(PB, BIT2, GPIO_MODE_INPUT); // YP 作为 ADC 输入
PB0 = 1; // XP = 高电平
PB1 = 0; // XN = 低电平
PB3 = 1; // YN 悬空(高阻态)
ADC_CLR_INT_FLAG(ADC, ADC_ADF_INT);
ADC_ENABLE_ADC(ADC); // 启动 ADC
ADC_START_CONV(ADC); // 开始转换
while(ADC_GET_INT_FLAG(ADC, ADC_ADF_INT) == 0); // 等待转换完成
uint32_t x_value = ADC_GET_CONVERSION_DATA(ADC, 0); // 读取 ADC 值
return x_value;
}
c. Y 坐标测量函数
uint32_t Read_Touch_Y(void) {
// 设置 Y 方向电场
GPIO_SetMode(PB, BIT2, GPIO_MODE_OUTPUT);
GPIO_SetMode(PB, BIT0, GPIO_MODE_INPUT); // XP 作为 ADC 输入
PB2 = 1; // YP = 高电平
PB3 = 0; // YN = 低电平
PB1 = 1; // XN 悬空(高阻态)
ADC_CLR_INT_FLAG(ADC, ADC_ADF_INT);
ADC_ENABLE_ADC(ADC);
ADC_START_CONV(ADC);
while(ADC_GET_INT_FLAG(ADC, ADC_ADF_INT) == 0);
uint32_t y_value = ADC_GET_CONVERSION_DATA(ADC, 0);
return y_value;
}
d. 主循环(获取坐标)
int main(void) {
SYS_Init(); // 系统初始化
ADC_Init();
GPIO_Init();
while(1) {
uint32_t x_adc = Read_Touch_X();
uint32_t y_adc = Read_Touch_Y();
// 转换为实际坐标(需校准)
// uint16_t x = (x_adc * SCREEN_WIDTH) / ADC_MAX;
// uint16_t y = (y_adc * SCREEN_HEIGHT) / ADC_MAX;
CLK_SysTickDelay(100000); // 延时防抖
}
}
4. 关键注意事项
防抖处理:
- 连续采样 3~5 次取平均,避免噪声干扰。
- 添加延时(如
CLK_SysTickDelay(100))稳定电压。
校准:
触摸检测:
- 增加压力检测(如测量 Z 轴电阻值)。
- 若 ADC 值接近 0 或最大值,视为无触摸。
电容触摸屏:
- 需专用电容触摸 IC(如 FT6x06),通过 I²C 读取坐标。
- 示例代码:
I2C_WriteByte(I2C_PORT, TOUCH_ADDR, REG_READ_COORD);
uint8_t buf[4];
I2C_ReadMultiBytes(I2C_PORT, TOUCH_ADDR, buf, 4); // 读取 X/Y 坐标
5. 优化建议
- 中断模式:配置触摸中断引脚(若有),替代轮询节省功耗。
- 低功耗:空闲时关闭触摸驱动电压。
- 滤波算法:使用中值滤波或滑动窗口平滑 ADC 数据。
通过上述步骤,即可在 M031/M032 上实现触摸屏位置检测。实际应用中需根据触摸屏规格书调整驱动逻辑和参数。