bsp_tpad.h

  1. #ifndef __BSP_TPAD_H
  2. #define __BSP_TPAD_H
  3. #include "stm32f10x.h"
  4. #include "bsp_SysTick.h"
  5. #include "bsp_usart.h"
  6. /************通用定时器TIM参数定义,只限TIM2、3、4、5************/
  7. // 当使用不同的定时器的时候,对应的GPIO是不一样的,这点要注意
  8. // 我们这里默认使用TIM5
  9. #define TPAD_TIM TIM5
  10. #define TPAD_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
  11. #define TPAD_TIM_CLK RCC_APB1Periph_TIM5
  12. #define TPAD_TIM_Period 0XFFFF
  13. #define TPAD_TIM_Prescaler 71
  14. // TIM 输入捕获通道GPIO相关宏定义
  15. #define TPAD_TIM_CH_GPIO_CLK RCC_APB2Periph_GPIOA
  16. #define TPAD_TIM_CH_PORT GPIOA
  17. #define TPAD_TIM_CH_PIN GPIO_Pin_1
  18. #define TPAD_TIM_CHANNEL_x TIM_Channel_2
  19. // 中断相关宏定义
  20. #define TPAD_TIM_IT_CCx TIM_IT_CC2
  21. #define TPAD_TIM_IRQ TIM5_IRQn
  22. #define TPAD_TIM_INT_FUN TIM5_IRQHandler
  23. // 获取捕获寄存器值函数宏定义
  24. #define TPAD_TIM_GetCapturex_FUN TIM_GetCapture2
  25. // 捕获信号极性函数宏定义
  26. #define TPAD_TIM_OCxPolarityConfig_FUN TIM_OC2PolarityConfig
  27. // 电容按键被按下的时候门限值,需要根据不同的硬件实际测试,
  28. // 减小这个门限值可以提高响应速度
  29. #define TPAD_GATE_VAL 100
  30. // 电容按键空载的时候的最大和最小的充电时间,不同的硬件不一样,霸道稳定在218
  31. #define TPAD_DEFAULT_VAL_MIN 210
  32. #define TPAD_DEFAULT_VAL_MAX 230
  33. #define TPAD_ON 1
  34. #define TPAD_OFF 0
  35. /**************************函数声明********************************/
  36. uint8_t TPAD_Init(void);
  37. uint8_t TPAD_Scan(void);
  38. #endif /* __BSP_TPAD_H */

bsp_tpad.c

  1. #include "bsp_tpad.h"
  2. // 电容按键空载的时候充电时间
  3. uint16_t tpad_default_val;
  4. static void TPAD_TIM_GPIO_Config(void)
  5. {
  6. GPIO_InitTypeDef GPIO_InitStructure;
  7. // 输入捕获通道 GPIO 初始化
  8. RCC_APB2PeriphClockCmd(TPAD_TIM_CH_GPIO_CLK, ENABLE);
  9. GPIO_InitStructure.GPIO_Pin = TPAD_TIM_CH_PIN;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  11. GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);
  12. }
  13. ///*
  14. // * 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有
  15. // * TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,
  16. // * 另外三个成员是通用定时器和高级定时器才有.
  17. // *-----------------------------------------------------------------------------
  18. // *typedef struct
  19. // *{ TIM_Prescaler 都有
  20. // * TIM_CounterMode TIMx,x[6,7]没有,其他都有
  21. // * TIM_Period 都有
  22. // * TIM_ClockDivision TIMx,x[6,7]没有,其他都有
  23. // * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有
  24. // *}TIM_TimeBaseInitTypeDef;
  25. // *-----------------------------------------------------------------------------
  26. // */
  27. /* ---------------- PWM信号 周期和占空比的计算--------------- */
  28. // ARR :自动重装载寄存器的值
  29. // CLK_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1)
  30. // PWM 信号的周期 T = ARR * (1/CLK_cnt) = ARR*(PSC+1) / 72M
  31. // 占空比P=CCR/(ARR+1)
  32. static void TPAD_TIM_Mode_Config(void)
  33. {
  34. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  35. TIM_ICInitTypeDef TIM_ICInitStructure;
  36. // 开启定时器时钟,即内部时钟CK_INT=72M
  37. TPAD_TIM_APBxClock_FUN(TPAD_TIM_CLK,ENABLE);
  38. /*--------------------时基结构体初始化-------------------------*/
  39. // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
  40. TIM_TimeBaseStructure.TIM_Period=TPAD_TIM_Period;
  41. // 驱动CNT计数器的时钟 = Fck_int/(psc+1)
  42. TIM_TimeBaseStructure.TIM_Prescaler= TPAD_TIM_Prescaler;
  43. // 时钟分频因子 ,配置死区时间时需要用到
  44. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  45. // 计数器计数模式,设置为向上计数
  46. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  47. // 重复计数器的值,没用到不用管
  48. TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
  49. // 初始化定时器
  50. TIM_TimeBaseInit(TPAD_TIM, &TIM_TimeBaseStructure);
  51. /*--------------------输入捕获结构体初始化-------------------*/
  52. // 配置输入捕获的通道,需要根据具体的GPIO来配置
  53. TIM_ICInitStructure.TIM_Channel = TPAD_TIM_CHANNEL_x;
  54. // 输入捕获信号的极性配置
  55. TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  56. // 输入通道和捕获通道的映射关系,有直连和非直连两种
  57. TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  58. // 输入的需要被捕获的信号的分频系数
  59. TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  60. // 输入的需要被捕获的信号的滤波系数
  61. TIM_ICInitStructure.TIM_ICFilter = 0;
  62. // 定时器输入捕获初始化
  63. TIM_ICInit(TPAD_TIM, &TIM_ICInitStructure);
  64. // 使能计数器
  65. TIM_Cmd(TPAD_TIM, ENABLE);
  66. }
  67. /*===========================================================================================*/
  68. /**
  69. * @brief 复位电容按键,放电,重新充电
  70. * @param 无
  71. * @retval 无
  72. * 说明:
  73. * 开发板上电之后,电容按键默认已经充满了电,要想测得电容按键的充电时间
  74. * 就必须先把电容按键的电放掉,方法为让接电容按键的IO输出低电平即可
  75. * 放电完毕之后,再把连接电容按键的IO配置为输入,然后通过输入捕获的方法
  76. * 测量电容按键的充电时间,这个充电时间是没有手指触摸的情况下的充电时间
  77. * 而且这个空载的充电时间非常稳定,因为电路板的硬件已经确定了
  78. *
  79. * 当有手指触摸的情况下,充电时间会变长,我们只需要对比这两个时间就可以
  80. * 知道电容按键是否有手指触摸
  81. */
  82. void TPAD_Reset(void)
  83. {
  84. GPIO_InitTypeDef GPIO_InitStructure;
  85. // 输入捕获通道1 GPIO 初始化
  86. RCC_APB2PeriphClockCmd(TPAD_TIM_CH_GPIO_CLK, ENABLE);
  87. GPIO_InitStructure.GPIO_Pin = TPAD_TIM_CH_PIN;
  88. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  89. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  90. GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);
  91. // 连接TPAD的IO配置为输出,然后输出低电平,延时一会,确保电容按键放电完毕
  92. GPIO_ResetBits(TPAD_TIM_CH_PORT,TPAD_TIM_CH_PIN);
  93. // 放电是很快的,一般是us级别
  94. SysTick_Delay_Ms( 5 );
  95. // 连接TPAD的IO配置为输入,用于输入捕获
  96. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  97. GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);
  98. }
  99. /**
  100. * @brief 获取定时器捕获值
  101. * @param 无
  102. * @retval 定时器捕获值。如果超时,则直接返回定时器的计数值。
  103. */
  104. uint16_t TPAD_Get_Val(void)
  105. {
  106. // 每次捕获的时候,必须先复位放电
  107. TPAD_Reset();
  108. // 当电容按键复位放电之后,计数器清0开始计数
  109. TIM_SetCounter (TPAD_TIM,0);
  110. // 清除相关的标志位
  111. TIM_ClearITPendingBit (TPAD_TIM, TPAD_TIM_IT_CCx | TIM_IT_Update);
  112. // 等待捕获上升沿,当电容按键充电到1.8V左右的时候,就会被认为是上升沿
  113. while(TIM_GetFlagStatus (TPAD_TIM, TPAD_TIM_IT_CCx) == RESET)
  114. {
  115. // 如果超时了,直接返回CNT的值
  116. // 一般充电时间都是在ms级别以内,很少会超过定时器的最大计数值
  117. if (TIM_GetCounter(TPAD_TIM) > TPAD_TIM_Period-100)
  118. {
  119. return TIM_GetCounter (TPAD_TIM);
  120. }
  121. }
  122. // 获取捕获比较寄存器的值
  123. return TPAD_TIM_GetCapturex_FUN(TPAD_TIM);
  124. }
  125. void TPAD_TIM_Init(void)
  126. {
  127. TPAD_TIM_GPIO_Config();
  128. TPAD_TIM_Mode_Config();
  129. }
  130. /**
  131. * @brief 初始化触摸按键,获得空载的时候触摸按键的充电时间
  132. * @param 无
  133. * @retval 0:成功,1:失败
  134. * @note 空载值一般很稳定,由硬件电路决定,该函数只需要调用一次即可
  135. * 而且这个空载的充电时间每个硬件都不一样,最好实际测试下
  136. */
  137. uint8_t TPAD_Init(void)
  138. {
  139. uint16_t temp;
  140. // 电容按键用到的输入捕获的IO和捕获模式参数初始化
  141. TPAD_TIM_Init();
  142. temp = TPAD_Get_Val();
  143. // 电容按键空载的充电时间非常稳定,不同的硬件充电时间不一样
  144. // 需要实际测试所得,霸道 上的电容按键空载充电时间稳定在218
  145. // 如果你觉得单次测量不准确,你可以多次测量然后取个平均值
  146. if( (TPAD_DEFAULT_VAL_MIN<temp) && (temp<TPAD_DEFAULT_VAL_MAX) )
  147. {
  148. tpad_default_val = temp;
  149. // 调试的时候可以把捕获的值打印出来,看看默认的充电时间是多少
  150. printf("电容按键默认充电时间为: %d us\n",tpad_default_val);
  151. return 0; // 成功
  152. }
  153. else
  154. {
  155. return 1; // 失败
  156. }
  157. }
  158. /**
  159. * @brief 读取若干次定时器捕获值,并返回最大值。
  160. * @param num :读取次数
  161. * @retval 读取到的最大定时器捕获值
  162. */
  163. uint16_t TPAD_Get_MaxVal( uint8_t num )
  164. {
  165. uint16_t temp=0, res=0;
  166. while(num--)
  167. {
  168. temp = TPAD_Get_Val();
  169. if( temp > res )
  170. res = temp;
  171. }
  172. return res;
  173. }
  174. /**
  175. * @brief 按键扫描函数
  176. * @param 无
  177. * @retval 1:按键有效,0:按键无效
  178. */
  179. uint8_t TPAD_Scan(void)
  180. {
  181. // keyen:按键检测使能标志
  182. // 0:可以开始检测
  183. // >0:还不能开始检测,表示按键一直被按下
  184. // 注意:keytn 这个变量由 static 修饰,相当于一个全局变量,但是因为是在函数内部定义,
  185. // 所以是相当于这个函数的全局变量,每次修改之前保留的是上一次的值
  186. static uint8_t keyen=0;
  187. uint8_t res=0,sample=3;
  188. uint16_t scan_val;
  189. // 根据sample值采样多次,并取最大值,小的一般是干扰或者是误触摸
  190. scan_val = TPAD_Get_MaxVal(sample);
  191. // 当扫描的值大于空载值加上默认的门限值之后,表示按键按下
  192. // 这个TPAD_GATE_VAL根据硬件决定,需要实际测试
  193. if(scan_val > (tpad_default_val+TPAD_GATE_VAL))
  194. {
  195. // 再次检测,类似于机械按键的去抖
  196. scan_val = TPAD_Get_MaxVal(sample);
  197. if( ( keyen == 0 )&& (scan_val > (tpad_default_val+TPAD_GATE_VAL)))
  198. res = 1; // 有效的按键
  199. // 如果按键一直被按下,keyen的值会一直在keyen的初始值和keyen-1之间循环,永远不会等于0
  200. keyen = 2;
  201. }
  202. // 当按键没有被按下或者keyen>0时,会执行keyen--
  203. if( keyen > 0)
  204. keyen--;
  205. return res;
  206. }
  207. /*********************************************END OF FILE**********************/

bsp_SysTick.h

  1. #ifndef __SYSTICK_H
  2. #define __SYSTICK_H
  3. #include "stm32f10x.h"
  4. void SysTick_Init(void);
  5. void Delay_us(__IO u32 nTime);
  6. #define Delay_ms(x) Delay_us(1000*x) //单位ms
  7. void SysTick_Delay_Us( __IO uint32_t us);
  8. void SysTick_Delay_Ms( __IO uint32_t ms);
  9. #endif /* __SYSTICK_H */

bsp_SysTick.c

  1. #include "bsp_SysTick.h"
  2. #include "core_cm3.h"
  3. #include "misc.h"
  4. static __IO u32 TimingDelay;
  5. /**
  6. * @brief 启动系统滴答定时器 SysTick
  7. * @param 无
  8. * @retval 无
  9. */
  10. void SysTick_Init(void)
  11. {
  12. /* SystemFrequency / 1000 1ms中断一次
  13. * SystemFrequency / 100000 10us中断一次
  14. * SystemFrequency / 1000000 1us中断一次
  15. */
  16. // if (SysTick_Config(SystemFrequency / 100000)) // ST3.0.0库版本
  17. if (SysTick_Config(SystemCoreClock / 1000000)) // ST3.5.0库版本
  18. {
  19. /* Capture error */
  20. while (1);
  21. }
  22. }
  23. /**
  24. * @brief us延时程序,10us为一个单位
  25. * @param
  26. * @arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
  27. * @retval 无
  28. */
  29. void Delay_us(__IO u32 nTime)
  30. {
  31. TimingDelay = nTime;
  32. // 使能滴答定时器
  33. SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
  34. while(TimingDelay != 0);
  35. }
  36. /**
  37. * @brief 获取节拍程序
  38. * @param 无
  39. * @retval 无
  40. * @attention 在 SysTick 中断函数 SysTick_Handler()调用
  41. */
  42. void TimingDelay_Decrement(void)
  43. {
  44. if (TimingDelay != 0x00)
  45. {
  46. TimingDelay--;
  47. }
  48. }
  49. #if 0
  50. // 这个 固件库函数 在 core_cm3.h中
  51. static __INLINE uint32_t SysTick_Config(uint32_t ticks)
  52. {
  53. // reload 寄存器为24bit,最大值为2^24
  54. if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);
  55. // 配置 reload 寄存器的初始值
  56. SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
  57. // 配置中断优先级为 1<<4-1 = 15,优先级为最低
  58. NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
  59. // 配置 counter 计数器的值
  60. SysTick->VAL = 0;
  61. // 配置systick 的时钟为 72M
  62. // 使能中断
  63. // 使能systick
  64. SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
  65. SysTick_CTRL_TICKINT_Msk |
  66. SysTick_CTRL_ENABLE_Msk;
  67. return (0);
  68. }
  69. #endif
  70. // couter 减1的时间 等于 1/systick_clk
  71. // 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序,
  72. // 同时 CTRL 的 countflag 位会置1
  73. // 这一个循环的时间为 reload * (1/systick_clk)
  74. void SysTick_Delay_Us( __IO uint32_t us)
  75. {
  76. uint32_t i;
  77. SysTick_Config(SystemCoreClock/1000000);
  78. for(i=0;i<us;i++)
  79. {
  80. // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
  81. while( !((SysTick->CTRL)&(1<<16)) );
  82. }
  83. // 关闭SysTick定时器
  84. SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
  85. }
  86. void SysTick_Delay_Ms( __IO uint32_t ms)
  87. {
  88. uint32_t i;
  89. SysTick_Config(SystemCoreClock/1000);
  90. for(i=0;i<ms;i++)
  91. {
  92. // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
  93. // 当置1时,读取该位会清0
  94. while( !((SysTick->CTRL)&(1<<16)) );
  95. }
  96. // 关闭SysTick定时器
  97. SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
  98. }
  99. /*********************************************END OF FILE**********************/

bsp_tpad.h

  1. #ifndef __BSP_TPAD_H
  2. #define __BSP_TPAD_H
  3. #include "stm32f10x.h"
  4. #include "bsp_SysTick.h"
  5. #include "bsp_usart.h"
  6. /************通用定时器TIM参数定义,只限TIM2、3、4、5************/
  7. // 当使用不同的定时器的时候,对应的GPIO是不一样的,这点要注意
  8. // 我们这里默认使用TIM5
  9. #define TPAD_TIM TIM5
  10. #define TPAD_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
  11. #define TPAD_TIM_CLK RCC_APB1Periph_TIM5
  12. #define TPAD_TIM_Period 0XFFFF
  13. #define TPAD_TIM_Prescaler 71
  14. // TIM 输入捕获通道GPIO相关宏定义
  15. #define TPAD_TIM_CH_GPIO_CLK RCC_APB2Periph_GPIOA
  16. #define TPAD_TIM_CH_PORT GPIOA
  17. #define TPAD_TIM_CH_PIN GPIO_Pin_1
  18. #define TPAD_TIM_CHANNEL_x TIM_Channel_2
  19. // 中断相关宏定义
  20. #define TPAD_TIM_IT_CCx TIM_IT_CC2
  21. #define TPAD_TIM_IRQ TIM5_IRQn
  22. #define TPAD_TIM_INT_FUN TIM5_IRQHandler
  23. // 获取捕获寄存器值函数宏定义
  24. #define TPAD_TIM_GetCapturex_FUN TIM_GetCapture2
  25. // 捕获信号极性函数宏定义
  26. #define TPAD_TIM_OCxPolarityConfig_FUN TIM_OC2PolarityConfig
  27. // 电容按键被按下的时候门限值,需要根据不同的硬件实际测试,
  28. // 减小这个门限值可以提高响应速度
  29. #define TPAD_GATE_VAL 100
  30. // 电容按键空载的时候的最大和最小的充电时间,不同的硬件不一样,霸道稳定在218
  31. #define TPAD_DEFAULT_VAL_MIN 210
  32. #define TPAD_DEFAULT_VAL_MAX 230
  33. #define TPAD_ON 1
  34. #define TPAD_OFF 0
  35. /**************************函数声明********************************/
  36. uint8_t TPAD_Init(void);
  37. uint8_t TPAD_Scan(void);
  38. #endif /* __BSP_TPAD_H */

bsp_tpad.c

  1. #include "bsp_tpad.h"
  2. // 电容按键空载的时候充电时间
  3. uint16_t tpad_default_val;
  4. static void TPAD_TIM_GPIO_Config(void)
  5. {
  6. GPIO_InitTypeDef GPIO_InitStructure;
  7. // 输入捕获通道 GPIO 初始化
  8. RCC_APB2PeriphClockCmd(TPAD_TIM_CH_GPIO_CLK, ENABLE);
  9. GPIO_InitStructure.GPIO_Pin = TPAD_TIM_CH_PIN;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  11. GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);
  12. }
  13. ///*
  14. // * 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有
  15. // * TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,
  16. // * 另外三个成员是通用定时器和高级定时器才有.
  17. // *-----------------------------------------------------------------------------
  18. // *typedef struct
  19. // *{ TIM_Prescaler 都有
  20. // * TIM_CounterMode TIMx,x[6,7]没有,其他都有
  21. // * TIM_Period 都有
  22. // * TIM_ClockDivision TIMx,x[6,7]没有,其他都有
  23. // * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有
  24. // *}TIM_TimeBaseInitTypeDef;
  25. // *-----------------------------------------------------------------------------
  26. // */
  27. /* ---------------- PWM信号 周期和占空比的计算--------------- */
  28. // ARR :自动重装载寄存器的值
  29. // CLK_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1)
  30. // PWM 信号的周期 T = ARR * (1/CLK_cnt) = ARR*(PSC+1) / 72M
  31. // 占空比P=CCR/(ARR+1)
  32. static void TPAD_TIM_Mode_Config(void)
  33. {
  34. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  35. TIM_ICInitTypeDef TIM_ICInitStructure;
  36. // 开启定时器时钟,即内部时钟CK_INT=72M
  37. TPAD_TIM_APBxClock_FUN(TPAD_TIM_CLK,ENABLE);
  38. /*--------------------时基结构体初始化-------------------------*/
  39. // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
  40. TIM_TimeBaseStructure.TIM_Period=TPAD_TIM_Period;
  41. // 驱动CNT计数器的时钟 = Fck_int/(psc+1)
  42. TIM_TimeBaseStructure.TIM_Prescaler= TPAD_TIM_Prescaler;
  43. // 时钟分频因子 ,配置死区时间时需要用到
  44. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  45. // 计数器计数模式,设置为向上计数
  46. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  47. // 重复计数器的值,没用到不用管
  48. TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
  49. // 初始化定时器
  50. TIM_TimeBaseInit(TPAD_TIM, &TIM_TimeBaseStructure);
  51. /*--------------------输入捕获结构体初始化-------------------*/
  52. // 配置输入捕获的通道,需要根据具体的GPIO来配置
  53. TIM_ICInitStructure.TIM_Channel = TPAD_TIM_CHANNEL_x;
  54. // 输入捕获信号的极性配置
  55. TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  56. // 输入通道和捕获通道的映射关系,有直连和非直连两种
  57. TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  58. // 输入的需要被捕获的信号的分频系数
  59. TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  60. // 输入的需要被捕获的信号的滤波系数
  61. TIM_ICInitStructure.TIM_ICFilter = 0;
  62. // 定时器输入捕获初始化
  63. TIM_ICInit(TPAD_TIM, &TIM_ICInitStructure);
  64. // 使能计数器
  65. TIM_Cmd(TPAD_TIM, ENABLE);
  66. }
  67. /*===========================================================================================*/
  68. /**
  69. * @brief 复位电容按键,放电,重新充电
  70. * @param 无
  71. * @retval 无
  72. * 说明:
  73. * 开发板上电之后,电容按键默认已经充满了电,要想测得电容按键的充电时间
  74. * 就必须先把电容按键的电放掉,方法为让接电容按键的IO输出低电平即可
  75. * 放电完毕之后,再把连接电容按键的IO配置为输入,然后通过输入捕获的方法
  76. * 测量电容按键的充电时间,这个充电时间是没有手指触摸的情况下的充电时间
  77. * 而且这个空载的充电时间非常稳定,因为电路板的硬件已经确定了
  78. *
  79. * 当有手指触摸的情况下,充电时间会变长,我们只需要对比这两个时间就可以
  80. * 知道电容按键是否有手指触摸
  81. */
  82. void TPAD_Reset(void)
  83. {
  84. GPIO_InitTypeDef GPIO_InitStructure;
  85. // 输入捕获通道1 GPIO 初始化
  86. RCC_APB2PeriphClockCmd(TPAD_TIM_CH_GPIO_CLK, ENABLE);
  87. GPIO_InitStructure.GPIO_Pin = TPAD_TIM_CH_PIN;
  88. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  89. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  90. GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);
  91. // 连接TPAD的IO配置为输出,然后输出低电平,延时一会,确保电容按键放电完毕
  92. GPIO_ResetBits(TPAD_TIM_CH_PORT,TPAD_TIM_CH_PIN);
  93. // 放电是很快的,一般是us级别
  94. SysTick_Delay_Ms( 5 );
  95. // 连接TPAD的IO配置为输入,用于输入捕获
  96. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  97. GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);
  98. }
  99. /**
  100. * @brief 获取定时器捕获值
  101. * @param 无
  102. * @retval 定时器捕获值。如果超时,则直接返回定时器的计数值。
  103. */
  104. uint16_t TPAD_Get_Val(void)
  105. {
  106. // 每次捕获的时候,必须先复位放电
  107. TPAD_Reset();
  108. // 当电容按键复位放电之后,计数器清0开始计数
  109. TIM_SetCounter (TPAD_TIM,0);
  110. // 清除相关的标志位
  111. TIM_ClearITPendingBit (TPAD_TIM, TPAD_TIM_IT_CCx | TIM_IT_Update);
  112. // 等待捕获上升沿,当电容按键充电到1.8V左右的时候,就会被认为是上升沿
  113. while(TIM_GetFlagStatus (TPAD_TIM, TPAD_TIM_IT_CCx) == RESET)
  114. {
  115. // 如果超时了,直接返回CNT的值
  116. // 一般充电时间都是在ms级别以内,很少会超过定时器的最大计数值
  117. if (TIM_GetCounter(TPAD_TIM) > TPAD_TIM_Period-100)
  118. {
  119. return TIM_GetCounter (TPAD_TIM);
  120. }
  121. }
  122. // 获取捕获比较寄存器的值
  123. return TPAD_TIM_GetCapturex_FUN(TPAD_TIM);
  124. }
  125. void TPAD_TIM_Init(void)
  126. {
  127. TPAD_TIM_GPIO_Config();
  128. TPAD_TIM_Mode_Config();
  129. }
  130. /**
  131. * @brief 初始化触摸按键,获得空载的时候触摸按键的充电时间
  132. * @param 无
  133. * @retval 0:成功,1:失败
  134. * @note 空载值一般很稳定,由硬件电路决定,该函数只需要调用一次即可
  135. * 而且这个空载的充电时间每个硬件都不一样,最好实际测试下
  136. */
  137. uint8_t TPAD_Init(void)
  138. {
  139. uint16_t temp;
  140. // 电容按键用到的输入捕获的IO和捕获模式参数初始化
  141. TPAD_TIM_Init();
  142. temp = TPAD_Get_Val();
  143. // 电容按键空载的充电时间非常稳定,不同的硬件充电时间不一样
  144. // 需要实际测试所得,霸道 上的电容按键空载充电时间稳定在218
  145. // 如果你觉得单次测量不准确,你可以多次测量然后取个平均值
  146. if( (TPAD_DEFAULT_VAL_MIN<temp) && (temp<TPAD_DEFAULT_VAL_MAX) )
  147. {
  148. tpad_default_val = temp;
  149. // 调试的时候可以把捕获的值打印出来,看看默认的充电时间是多少
  150. printf("电容按键默认充电时间为: %d us\n",tpad_default_val);
  151. return 0; // 成功
  152. }
  153. else
  154. {
  155. return 1; // 失败
  156. }
  157. }
  158. /**
  159. * @brief 读取若干次定时器捕获值,并返回最大值。
  160. * @param num :读取次数
  161. * @retval 读取到的最大定时器捕获值
  162. */
  163. uint16_t TPAD_Get_MaxVal( uint8_t num )
  164. {
  165. uint16_t temp=0, res=0;
  166. while(num--)
  167. {
  168. temp = TPAD_Get_Val();
  169. if( temp > res )
  170. res = temp;
  171. }
  172. return res;
  173. }
  174. /**
  175. * @brief 按键扫描函数
  176. * @param 无
  177. * @retval 1:按键有效,0:按键无效
  178. */
  179. uint8_t TPAD_Scan(void)
  180. {
  181. // keyen:按键检测使能标志
  182. // 0:可以开始检测
  183. // >0:还不能开始检测,表示按键一直被按下
  184. // 注意:keytn 这个变量由 static 修饰,相当于一个全局变量,但是因为是在函数内部定义,
  185. // 所以是相当于这个函数的全局变量,每次修改之前保留的是上一次的值
  186. static uint8_t keyen=0;
  187. uint8_t res=0,sample=3;
  188. uint16_t scan_val;
  189. // 根据sample值采样多次,并取最大值,小的一般是干扰或者是误触摸
  190. scan_val = TPAD_Get_MaxVal(sample);
  191. // 当扫描的值大于空载值加上默认的门限值之后,表示按键按下
  192. // 这个TPAD_GATE_VAL根据硬件决定,需要实际测试
  193. if(scan_val > (tpad_default_val+TPAD_GATE_VAL))
  194. {
  195. // 再次检测,类似于机械按键的去抖
  196. scan_val = TPAD_Get_MaxVal(sample);
  197. if( ( keyen == 0 )&& (scan_val > (tpad_default_val+TPAD_GATE_VAL)))
  198. res = 1; // 有效的按键
  199. // 如果按键一直被按下,keyen的值会一直在keyen的初始值和keyen-1之间循环,永远不会等于0
  200. keyen = 2;
  201. }
  202. // 当按键没有被按下或者keyen>0时,会执行keyen--
  203. if( keyen > 0)
  204. keyen--;
  205. return res;
  206. }
  207. /*********************************************END OF FILE**********************/

main.c

  1. // TIM—通用-捕获-电容按键检测 应用
  2. #include "stm32f10x.h"
  3. #include "bsp_led.h"
  4. #include "bsp_usart.h"
  5. #include "bsp_tpad.h"
  6. #include "bsp_SysTick.h"
  7. #include "bsp_beep.h"
  8. /**
  9. * @brief 主函数
  10. * @param 无
  11. * @retval 无
  12. */
  13. int main(void)
  14. {
  15. /* 蜂鸣器初始化 */
  16. Beep_Init();
  17. /* 串口初始化 */
  18. USART_Config();
  19. printf ( "\r\n野火STM32 输入捕获电容按键检测实验\r\n" );
  20. printf ( "\r\n触摸电容按键,蜂鸣器则会响\r\n" );
  21. // 初始化电容按键
  22. while( TPAD_Init() );
  23. while(1)
  24. {
  25. if( TPAD_Scan() == TPAD_ON )
  26. {
  27. BEEP_ON();
  28. SysTick_Delay_Ms(25);
  29. BEEP_OFF();
  30. }
  31. }
  32. }
  33. /*********************************************END OF FILE**********************/

程序下载:

34-TIM—输入捕获之电容按键检测.zip