特征
一个ADC,12位精度,逐次逼近型
9路单端输入
微分误差非线性误差DNL: +/-1.5 LSB;积分非线性误差 INL: +/-3 LSB
采样率200kSPS
轨到轨 VREF ~ AGND测量
模拟电压2.7-3.6V,数字电压1.2V
自动掉电
低功耗2170uW (at 200k SPS), < 1uA
配置
时钟源
ADC_S (CLK_DIVCTL7[20:19])
分频
ADC_N (CLK_DIVCTL7[31:24])
使能外设时钟
ADCCKEN (CLK_PCLKEN1[24]).
复位外设控制器
ADCRST(SYS_APBIPRST1[24])
写1复位,写0结束复位。
引脚配置
功能
量化
1LSB=VREF/4096
通道选择
采样
采样必须满足如下条件
从下可以看出,如果Rsrc大,也就是驱动电流小,则fclk要小,也就是采样时间要长,也就是需要的充电时间要长。
参考电压选择
时序
其中REFCNT (ADC_CONF[19:16])
设置Wait阶段的额外等待参考电压稳定时间。
SAMPCNT (ADC_CONF[19:16])
设置额外的采样和保持时间。
寄存器
ADC_CTL
控制启动,上电,使能模块
ADC_CONF
设置采样次数,等待参考电压稳定的时间REFCNT ,
通道选择,参考电压选择,正常转化使能
NAC_EN (ADC_CONF[2]) 置位启动转换。
ADC_IER
中断使能
ADC_ISR
转换状态
ADC_DATA
转换结果
硬件资源
引脚
PB0 AIN[0] MFP8
PB2 AIN[2] MFP8
PB4 AIN[4] MFP8
PB6 AIN[6] MFP8
四线电阻屏采样原理
上述四个ADC引脚实际是用来作为四线电阻屏采样使用的。
四线电阻屏的等效示意如下:
GND:推挽输出低
VCC:推挽输出高
Hi-Z:无上下拉,输入
ADC:模拟输入
代码编写
void lcd_touch_init(void)
{
/* 1.时钟配置使能 /
/ 使能外设时钟 寄存器有保护 所以调用库函数 /
//M32(REG_CLK_PCLKEN1) |= 1u<<24;
/ Enable ADC engine clock /
nu_sys_ipclk_enable(ADCCKEN);
/ 2.复位模块 /
/ 复位模块 寄存器有保护 所以调用库函数 /
//M32(REG_SYS_APBIPRST1)|= 1u<<24;
//M32(REG_SYS_APBIPRST1)&= ~(1u<<24);
/ Reset the ADC IP */
nu_sys_ip_reset(ADCRST);
/*选择时钟源 bit[20:19]
00 = ADC_SrcCLK is from XIN.
01 = Reserved.
10 = ADC_SrcCLK is from APLLFOut.
11 = ADC_SrcCLK is from UPLLFOut.
/
M32(REG_CLK_DIVCTL7) = (M32(REG_CLK_DIVCTL7) & (~(3u<<19))) | (0u<<19); / 选择外部12M ADC_S=0 */
/*bit[31:24]
ADC_CLK = ADC_SrcCLK / (ADC_N + 1).
/
M32(REG_CLK_DIVCTL7) = (M32(REG_CLK_DIVCTL7) & (~(0xFFu<<24))) | (2u<<24); / ADC_N=2 3分频 4M */
/* 配置ADC */
M32(REG_ADC_CTL) |= 1u<<0; /* Power on ADC. */
M32(REG_ADC_CTL) |= 1u<<1; /* Power on internal bandgap. */
M32(REG_ADC_CONF) = (M32(REG_ADC_CONF) & (~(0xFFu<<24))) | (64<<24); /* SAMPCNT = 64 */
M32(REG_ADC_CONF) = (M32(REG_ADC_CONF) & (~(0x0F<<16))) | (1u<<16); /* REFCNT = 1 2 等待电源稳定2^REFCNT各时钟*/
M32(REG_ADC_CONF) = (M32(REG_ADC_CONF) & (~(0x03<<6))) | (3u<<6); /* 参考电压选择 11 = AGND33 vs AVDD33. 00 = AGND33 vs VREF input.*/
M32(REG_ADC_CONF) |= 1u<<2; /* 使能转换 */
}
uint16_t lcd_touch_getx(void)
{
/* 1.引脚配置 */
/* PB0推挽输出低 */
rt_pin_mode(NU_GET_PININDEX(NU_PB, 0), PIN_MODE_OUTPUT);
rt_pin_write(NU_GET_PININDEX(NU_PB, 0), PIN_LOW);
/* PB2推挽输出高 */
rt_pin_mode(NU_GET_PININDEX(NU_PB, 2), PIN_MODE_OUTPUT);
rt_pin_write(NU_GET_PININDEX(NU_PB, 2), PIN_HIGH);
/* PB4输入 无上下拉 关闭输入 */
rt_pin_mode(NU_GET_PININDEX(NU_PB, 4), PIN_MODE_INPUT);
//GPIO_DISABLE_DIGITAL_PATH(GPIOB,1<<4);
/* PB6输入 无上下拉 关闭输入 ADC*/
rt_pin_mode(NU_GET_PININDEX(NU_PB, 6), PIN_MODE_INPUT);
//GPIO_DISABLE_DIGITAL_PATH(GPIOB,1<<6);
M32(REG_SYS_GPB_MFPL) = (M32(REG_SYS_GPB_MFPL) & 0xF0FFFFFF) | 0x08000000; /*PB6 MFP8 */
M32(REG_ADC_CONF) = (M32(REG_ADC_CONF) & (~(0x0F<<12))) | (6u<<12); /* 选择通道6 */
M32(REG_ADC_ISR) |= (1u<<10) | (1u<<0); /* 写1清标志 */
M32(REG_ADC_CTL) |= 1u<<8; /* 启动转换 */
while((M32(REG_ADC_ISR) & (1u<<10)) == 0); /*等待转换完 */
M32(REG_ADC_ISR) = M32(REG_ADC_ISR); /* 写1清标志 */
M32(REG_SYS_GPB_MFPL) = (M32(REG_SYS_GPB_MFPL) & 0xF0FFFFFF) | 0x00000000; /*PB6 MFP0 恢复为IO模式*/
return M32(REG_ADC_DATA);
}
uint16_t lcd_touch_gety(void)
{
/* 1.引脚配置 */
/* PB4推挽输出低 */
rt_pin_mode(NU_GET_PININDEX(NU_PB, 4), PIN_MODE_OUTPUT);
rt_pin_write(NU_GET_PININDEX(NU_PB, 4), PIN_LOW);
/* PB6推挽输出高 */
rt_pin_mode(NU_GET_PININDEX(NU_PB, 6), PIN_MODE_OUTPUT);
rt_pin_write(NU_GET_PININDEX(NU_PB, 6), PIN_HIGH);
rt_thread_mdelay(100);
rt_pin_write(NU_GET_PININDEX(NU_PB, 6), PIN_LOW);
rt_thread_mdelay(100);
/* PB0输入 无上下拉 关闭输入 */
rt_pin_mode(NU_GET_PININDEX(NU_PB, 0), PIN_MODE_INPUT);
//GPIO_DISABLE_DIGITAL_PATH(GPIOB,1<<0);
/* PB2输入 无上下拉 关闭输入 ADC*/
rt_pin_mode(NU_GET_PININDEX(NU_PB, 2), PIN_MODE_INPUT);
//GPIO_DISABLE_DIGITAL_PATH(GPIOB,1<<2);
M32(REG_SYS_GPB_MFPL) = (M32(REG_SYS_GPB_MFPL) & 0xFFFFF0FF) | 0x00000800; /*PB2 MFP8 */
M32(REG_ADC_CONF) = (M32(REG_ADC_CONF) & (~(0x0F<<12))) | (2u<<12); /* 选择通道2 */
M32(REG_ADC_ISR) |= (1u<<10) | (1u<<0); /* 写1清标志 */
M32(REG_ADC_CTL) |= 1u<<8; /* 启动转换 */
while((M32(REG_ADC_ISR) & (1u<<10)) == 0); /*等待转换完 */
M32(REG_ADC_ISR) = M32(REG_ADC_ISR); /* 写1清标志 */
M32(REG_SYS_GPB_MFPL) = (M32(REG_SYS_GPB_MFPL) & 0xFFFFF0FF) | 0x00000000; /*PB2 MFP0 恢复为IO模式*/
return M32(REG_ADC_DATA);
}
main主循环中
#if TOUCH_TEST
uint16_t x = lcd_touch_getx();
uint16_t y = lcd_touch_gety();
rt_kprintf("/*%d,%d*/\r\n",x,y);
rt_thread_mdelay(50);
#endif
测试
使用serial studio可视化采集到的ADC数据
从屏幕上匀速划过,可以看到X Y轴会线性变化
总结
完成触摸屏ADC的采集后,后面就是优化采集精度和校准算法。
后面再移植到GUI支持触摸。
原作者:qinyunti