管理员
最后登录1970-1-1
在线时间 小时
注册时间2013-3-25
|
下面的是整个配套的程序,针对霸道和指南者两个开发板。
文档:
零死角玩转STM32-电容按键检测.pdf
(807.29 KB, 下载次数: 195)
霸道:
【霸道】-TIM—输入捕获之电容按键检测.zip
(403.79 KB, 下载次数: 115)
指南者:
【指南者】-TIM—输入捕获之电容按键检测.zip
(404.99 KB, 下载次数: 122)
1-电容按键原理图,基于野火STM32 霸道和指南者 这两个开发板。原理图中的TPAD1就是一块圆形的铜皮,铜皮的周围是一大片隔开的GND,这样就构成了一个电容。
2-原理简述
开发板上电之后,电容按键默认已经充满了电,要想测得电容按键的充电时间, 就必须先把电容按键的电放掉,方法为让接电容按键的IO输出低电平即可。放电完毕之后,再把连接电容按键的IO配置为输入,然后通过输入捕获的方法测量电容按键的充电时间,这个充电时间是没有手指触摸的情况下的充电时间。当有手指触摸的情况下,相当于电容变大,充电时间会变长,我们只需要对比这两个时间就可以知道电容按键是否有手指触摸。
下面的是电容按键的复位函数,就是把电容放电。
- /**
- * @brief 复位电容按键,放电,重新充电
- * @param 无
- * @retval 无
- * 说明:
- * 开发板上电之后,电容按键默认已经充满了电,要想测得电容按键的充电时间
- * 就必须先把电容按键的电放掉,方法为让接电容按键的IO输出低电平即可
- * 放电完毕之后,再把连接电容按键的IO配置为输入,然后通过输入捕获的方法
- * 测量电容按键的充电时间,这个充电时间是没有手指触摸的情况下的充电时间
- *
- * 当有手指触摸的情况下,充电时间会变长,我们只需要对比这两个时间就可以
- * 知道电容按键是否有手指触摸
- */
- void TPAD_Reset(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- // 输入捕获通道1 GPIO 初始化
- RCC_APB2PeriphClockCmd(TPAD_TIM_CH_GPIO_CLK, ENABLE);
- GPIO_InitStructure.GPIO_Pin = TPAD_TIM_CH_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);
-
- // 连接TPAD的IO配置为输出,然后输出低电平,延时一会,确保电容按键放电完毕
- GPIO_ResetBits(TPAD_TIM_CH_PORT,TPAD_TIM_CH_PIN);
-
- // 放电是很快的,一般是us级别
- SysTick_Delay_Ms( 5 );
-
- // 连接TPAD的IO配置为输入,用于输入捕获
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);
- }
复制代码 3-获取输入捕获的值
当电容按键复位之后,即放电结束之后,我们调用uint16_t TPAD_Get_Val(void)函数,该函数返回的值是捕获比较寄存器的值。具体的原理是:电容按键在复位放电结束之后,由上拉电阻给电容充电,当电容充电到1.8V的时候,就会被IO口捕获到,我们事先先初始化好定时器的输入捕获为上升沿捕获,当捕获到上升沿之后,当前计数器的值会被锁存到捕获寄存器,我们只需要读取捕获寄存器的值即可,当读取了捕获寄存器的值之后,捕获标志会被清0。当电容按键有被手指触摸和没有被手指触摸的情况下,捕获到的值是不一样的。在程序中,我们只需要比较这两个捕获的值就可以知道是否有手指触摸了电容按键。在指南者中,电容按键没有被手指触摸的情况下,捕获寄存器的值为71,霸道的值为218,这两个值非常稳定,因为硬件已经确定了。虽然指南者跟霸道的电容按键的面积大小差不多,但是捕获的值却相差比较大,那是因为指南者是双面板,霸道是四层板的缘故。
- /**
- * @brief 获取定时器捕获值
- * @param 无
- * @retval 定时器捕获值。如果超时,则直接返回定时器的计数值。
- */
- uint16_t TPAD_Get_Val(void)
- {
- // 每次捕获的时候,必须先复位放电
- TPAD_Reset ();
-
- // 当电容按键复位放电之后,计数器清0开始计数
- TIM_SetCounter (TPAD_TIM,0);
- // 清除相关的标志位
- TIM_ClearITPendingBit (TPAD_TIM, TPAD_TIM_IT_CCx | TIM_IT_Update );
-
- // 等待捕获上升沿,当电容按键充电到1.8V左右的时候,就会被认为是上升沿
- while(TIM_GetFlagStatus (TPAD_TIM, TPAD_TIM_IT_CCx) == RESET)
- {
- // 如果超时了,直接返回CNT的值
- if ( TIM_GetCounter (TPAD_TIM) > TPAD_TIM_Period - 500 )
- {
- return TIM_GetCounter (TPAD_TIM);
- }
- }
-
- // 获取捕获比较寄存器的值
- return TPAD_TIM_GetCapturex_FUN(TPAD_TIM);
- }
复制代码 4-定时器输入捕获初始化
我们这里配置定时器的时钟为1M,即计数器计数一次的时间为1us,电容按键的充电时间基本都在ms以内,所以这个频率完全足够。
- static void TPAD_TIM_Mode_Config(void)
- {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_ICInitTypeDef TIM_ICInitStructure;
- // 开启定时器时钟,即内部时钟CK_INT=72M
- TPAD_TIM_APBxClock_FUN(TPAD_TIM_CLK,ENABLE);
- /*--------------------时基结构体初始化-------------------------*/
- // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
- TIM_TimeBaseStructure.TIM_Period=TPAD_TIM_Period;
- // 驱动CNT计数器的时钟 = Fck_int/(psc+1)
- TIM_TimeBaseStructure.TIM_Prescaler= TPAD_TIM_Prescaler;
- // 时钟分频因子 ,配置死区时间时需要用到
- TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
- // 计数器计数模式,设置为向上计数
- TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
- // 重复计数器的值,没用到不用管
- TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
- // 初始化定时器
- TIM_TimeBaseInit(TPAD_TIM, &TIM_TimeBaseStructure);
- /*--------------------输入捕获结构体初始化-------------------*/
- // 配置输入捕获的通道,需要根据具体的GPIO来配置
- TIM_ICInitStructure.TIM_Channel = TPAD_TIM_CHANNEL_x;
- // 输入捕获信号的极性配置
- TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
- // 输入通道和捕获通道的映射关系,有直连和非直连两种
- TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
- // 输入的需要被捕获的信号的分频系数
- TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
- // 输入的需要被捕获的信号的滤波系数
- TIM_ICInitStructure.TIM_ICFilter = 0;
- // 定时器输入捕获初始化
- TIM_ICInit(TPAD_TIM, &TIM_ICInitStructure);
-
- // 使能计数器
- TIM_Cmd(TPAD_TIM, ENABLE);
- }
复制代码 5-主函数
在主函数里面,我们调用temp = TPAD_Get_Val();函数来获取捕获值,霸道开发板中,电容按键没有触摸的情况下,捕获值是稳定在218,当有手触摸时,捕获值一直大于300,当你的手的面积大一点的情况下,会去到500,所以我们可以简单的判断只要捕获值大于300时候,就表示电容按键有被按下。我们这个程序是最简单的,非常容易懂,如果真正的项目中,我们需要读取取值然后取平均值。当然,原理我们懂了之后,后面的都是小菜一碟。
- int main(void)
- {
- uint16_t temp;
-
- /* led 端口配置 */
- LED_GPIO_Config();
-
- /* 蜂鸣器初始化 */
- Beep_Init();
- /* 串口初始化 */
- USART_Config();
- printf ( "\r\n野火STM32 输入捕获电容按键检测实验\r\n" );
- printf ( "\r\n触摸电容按键,蜂鸣器则会响\r\n" );
-
- TPAD_TIM_Init();
- temp = TPAD_Get_Val();
-
- // 调试的时候可以把捕获的值打印出来,看看默认的充电时间是多少
- printf("电容按键默认充电时间为: %d us\n",temp);
-
- while(1)
- {
- temp = TPAD_Get_Val();
- if( temp > 300 )
- {
- BEEP_ON();
- SysTick_Delay_Ms(10);
- BEEP_OFF();
- }
- }
- }
复制代码
|
|