你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 电容触摸按键

[复制链接]
STMCU小助手 发布时间:2022-6-13 21:21
01. 电容触摸按键简介3 A. h6 F; O( Y9 \: v6 B* o1 R) k
触摸按键相对于传统的机械按键有寿命长、占用空间少、易于操作等诸多优点。大家看看如今的手机,触摸屏、触摸按键大行其道,而传统的机械按键,正在逐步从手机上面消失。接下来给大家介绍一种简单的触摸按键:电容式触摸按键。
9 X# }' `) Z# t/ ?. X. J4 o# B% {# q2 d! ?1 o8 N8 d; O
利用探索者 STM32F4 开发板上的触摸按键(TPAD)来实现对 DS1 的亮灭控制。这里 TPAD 其实就是探索者 STM32F4 开发板上的一小块覆铜区域,实现原理如图所示:
9 c2 h2 ~: _' S3 W8 s; Y6 ]
* Q2 R/ d7 P0 h  J# f" h5 S5 ^ DY]R_{KJ]ZXSR25PZI5`D75.png
/ X2 R/ ^0 `5 Y1 j6 x4 F* j! k, |1 X
( ~& z2 s3 @' l; m  W我们使用的是检测电容充放电时间的方法来判断是否有触摸,图中 R 是外接的电容充电电阻,Cs 是没有触摸按下时 TPAD 与 PCB 之间的杂散电容。而 Cx 则是有手指按下的时候,手指与 TPAD 之间形成的电容。图中的开关是电容放电开关(由实际使用时,由 STM32F4 的IO 代替)。/ E: O' @; H- m0 n" r4 s' p
& M- e+ L6 G$ `& C5 b8 |
先用开关将 Cs(或 Cs+Cx)上的电放尽,然后断开开关,让 R 给 Cs(或 Cs+Cx)充电,当没有手指触摸的时候,Cs 的充电曲线如图中的 A 曲线。而当有手指触摸的时候,手指和 TPAD之间引入了新的电容 Cx,此时 Cs+Cx 的充电曲线如图中的 B 曲线。从上图可以看出,A、B两种情况下,Vc 达到 Vth 的时间分别为 Tcs 和 Tcs+Tcx。% g2 \$ \0 Y4 g0 M0 ~

5 X9 [' p: M( I' T4 p其中,除了 Cs 和 Cx 我们需要计算,其他都是已知的,根据电容充放电公式:5 X$ {  x  v. d
: M# X  i$ e- j$ Y# R
Vc=V0(1-e^(-t/RC))*
9 \% {2 B2 \. {8 V% y: v( A% O# C$ d, l, r- `, U
其中 Vc 为电容电压,V0 为充电电压,R 为充电电阻,C 为电容容值,e 为自然底数,t 为充电时间。根据这个公式,我们就可以计算出 Cs 和 Cx。利用这个公式,我们还可以把探索者开发板作为一个简单的电容计,直接可以测电容容量了。
7 }9 _$ s9 Y1 a7 {3 Z  a# `- i$ z& [4 C" M' n) X
我们只要能够区分 Tcs 和 Tcs+Tcx,就已经可以实现触摸检测了,当充电时间在 Tcs 附近,就可以认为没有触摸,而当充电时间大于 Tcs+Tx 时,就认为有触摸按下(Tx为检测阀值)。
- \0 l! `* h/ M2 v  P+ e: ?) U& U
( R7 [( [! \5 L4 r# ?# U我们使用 PA5(TIM2_CH1)来检测 TPAD 是否有触摸,在每次检测之前,我们先配置PA5 为推挽输出,将电容 Cs(或 Cs+Cx)放电,然后配置 PA5 为浮空输入,利用外部上拉电阻给电容 Cs(Cs+Cx)充电,同时开启 TIM2_CH1 的输入捕获,检测上升沿,当检测到上升沿的时候,就认为电容充电完成了,完成一次捕获检测。( x: o/ h0 S: t9 g6 A- c/ E

) Z! N* D) V# @6 [: N在 MCU 每次复位重启的时候,我们执行一次捕获检测(可以认为没触摸),记录此时的值,记为 tpad_default_val,作为判断的依据。在后续的捕获检测,我们就通过与 tpad_default_val 的对比,来判断是不是有触摸发生。2 c; ?! M" Q/ k0 T' S" U
* ?" f8 z$ A3 z) b8 f
02. 硬件设计8 L5 l; |, z& u
用到的硬件资源有:0 ?, J1 E9 m4 z% u, A2 D$ |
1) 指示灯 DS0 和 DS1  I  ~0 v' k- H/ K9 d  i
2) 定时器 TIM2
' ]( H' i% q- U! J: o3) 触摸按键 TPAD
$ l/ T6 i9 M- _6 v( F: w, o+ k! O" Z% j1 b+ X: \/ z6 n" U
需要通过 TIM2_CH1(PA5)采集 TPAD 的信号,所以需要用跳线帽短接多功能端口(P12)的 TPAD 和 ADC,以实现 TPAD 连接到PA5。如图所示:
/ }- p! z3 y( V$ u
5 E- {- N( b' L# q1 c4 \4 r FKW7FR$CC3UR72DH97GI2~T.png
2 _. q+ L  O1 p7 j
6 ?" N" s3 J& K$ h: p: i0 V) _03. 功能描述
5 Q, X$ c8 D: S' u- N实现一个简单的电容触摸按键,通过该按键控制 DS1 的亮灭。
" y8 ^1 T  q/ p% x! @! X1 H+ R+ N* ~8 s3 A/ j
04. 程序示例
  @  f8 t  ?. x6 F& R( s3 qtpad.h
% H2 g7 u: v% x3 \4 |) S
( h& c  e) U& R1 A. X
  1. #ifndef __TPAD_H) c8 ?! k3 H5 X7 t- C: V
  2. #define __TPAD_H
    9 r" r6 U. g3 Y1 H6 x
  3. #include "sys.h"
    . D$ O- |- i9 u6 k7 L, m6 F
  4.            $ {; x( s9 a7 E- T7 t2 y, W
  5. //空载的时候(没有手按下),计数器需要的时间
    # _5 h) Y# q+ J# W6 b
  6. //这个值应该在每次开机的时候被初始化一次
    ; C5 J: O$ E- L' Q3 U3 p$ X
  7. extern vu16 tpad_default_val;  n1 H# C1 k8 Z6 Z2 u2 u
  8.                                                                        * g: h' K3 A) D5 E8 t
  9. void TPAD_Reset(void);
    5 C& m) i4 v! p' X- \/ T8 B% e
  10. u16  TPAD_Get_Val(void);3 O9 L  g1 ?) J- a9 v* R
  11. u16 TPAD_Get_MaxVal(u8 n);# x9 ]; e" z' U. \: T2 h- U/ N
  12. u8   TPAD_Init(u8 systick);
    ) W2 T0 ?$ x' |8 J; t" [/ r
  13. u8   TPAD_Scan(u8 mode);) U' Y! M" r8 z# D! K
  14. void TIM2_CH1_Cap_Init(u32 arr,u16 psc);     7 ~3 S  {$ {3 L
  15. #endif
复制代码
: E2 A% I7 y' z" }8 n
tpad.c
5 x' ^/ s+ L  T* P) O+ D! E5 O1 o2 E1 j3 R
  1. #define TPAD_ARR_MAX_VAL  0XFFFFFFFF        //最大的ARR值(TIM2是32位定时器)          7 W9 m' J  S" u8 t- J
  2. vu16 tpad_default_val=0;                                //空载的时候(没有手按下),计数器需要的时间
    4 E6 y8 i' Y% ~2 c# v. d
  3. //初始化触摸按键
    + W. X9 F: F* ^; x7 i/ w! |1 k
  4. //获得空载的时候触摸按键的取值.
    5 Y, }  f: K; k1 a0 k0 B! f% M
  5. //psc:分频系数,越小,灵敏度越高.
      z2 ?8 I( I; V+ a. _7 _
  6. //返回值:0,初始化成功;1,初始化失败
    ! a; h3 `3 y# H4 I! M+ t% n
  7. u8 TPAD_Init(u8 psc)
    2 g" j! F/ N6 B2 g- F0 j6 J
  8. {
    9 @7 [; D  y; R- K+ f; m
  9.         u16 buf[10];- N; B- r; V$ J$ e
  10.         u16 temp;
    % ~# ^3 f2 z' S; Z) E
  11.         u8 j,i;
    % i- m8 C- a4 W5 ~
  12.         TIM2_CH1_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//设置分频系数
    ! M! X% a5 l* \% Q! x  Y5 n
  13.         for(i=0;i<10;i++)//连续读取10次. h& H7 f) n, X+ Y' Q; I
  14.         {                                 
    ( v/ i& b1 D  ?* h% D
  15.                 buf<i>=TPAD_Get_Val();
    ; c+ ~% W9 G  N
  16.                 delay_ms(10);            * n5 B( X" I- n4 t
  17.         }                                    6 n4 R/ J( X8 V8 q
  18.         for(i=0;i<9;i++)//排序7 o7 o. @; J- }9 H, D6 g  h2 b/ V* h
  19.         {
    8 P4 ^! p  d5 C$ i2 l
  20.                 for(j=i+1;j<10;j++). @- L. f+ ~  {) Q+ I6 ]6 l) }
  21.                 {% A" Z, c9 X- R7 x2 X! x
  22.                         if(buf<i>>buf[j])//升序排列' W& q' v$ L" G, v' \, `
  23.                         {
    / a+ `& b. D. f6 h; {6 K
  24.                                 temp=buf<i>;5 p) _1 s! j: _6 s% l2 X+ C0 b3 f
  25.                                 buf<i>=buf[j];  W3 P+ @1 n( L7 j
  26.                                 buf[j]=temp;
    ) r9 h$ t$ `% O9 y9 t6 X; o! R
  27.                         }
    ) @4 W$ f) G, e& R* _, i. _1 }
  28.                 }
    / y) `7 q- v! M, Y; n
  29.         }* H7 u8 `- N. j  v% g  j; y
  30.         temp=0;
    . |- c; M# r, @9 G
  31.         for(i=2;i<8;i++)temp+=buf<i>;//取中间的8个数据进行平均
    " l! y; r0 M3 z3 m
  32.         tpad_default_val=temp/6;6 S, n. R' O6 |+ p3 G4 C
  33.         printf("tpad_default_val:%d\r\n",tpad_default_val);        
    9 u3 X# Q3 ~# V4 p! d- F/ q
  34.         if(tpad_default_val>TPAD_ARR_MAX_VAL/2)return 1;//初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常!0 ?, M4 n8 l, T% \/ q
  35.         return 0;                                                                            / |! J# f5 C0 e/ o6 J3 P! p
  36. }8 i0 z. q, O! z+ d: [/ e
  37. //复位一次
    6 d" l* p4 Q3 _/ s# |, e
  38. //释放电容电量,并清除定时器的计数值
    ( ?1 Q9 A+ m6 Q# ?( a
  39. void TPAD_Reset(void)
    1 O2 H4 ^8 o( q1 B& A! U2 `
  40. {                - x/ o, z, {# K+ }! ^: `# v
  41.         GPIO_InitTypeDef GPIO_InitStructure;
    ! J1 |4 u: G9 @  q8 w# f
  42.         % r- f/ K+ D! D0 u8 R# _9 \0 f
  43.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  //PA5
    1 ~5 k& i, p! j$ l9 u2 t
  44.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出
    % i0 K1 `" X# Z0 D7 U$ k
  45.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        //速度100MHz* d" t8 m) m$ C* G) Z9 A
  46.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽
    3 z6 A9 C4 w1 ]# g* E7 {/ {9 S6 ]
  47.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
    5 ^: a( d- h9 `. t. o' b
  48.         GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA5
    - ^4 P" `/ y2 N: [/ l
  49.          
    $ F3 Z& ?4 r( z- \# H. ]' N
  50.         GPIO_ResetBits(GPIOA,GPIO_Pin_5);//输出0,放电6 M9 Q$ x  b* x/ o

  51. : B- F- O! r/ S( e
  52.         delay_ms(5);
    % {  m2 b9 ^" }" t" e6 q% [0 ~$ @
  53.         TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清除中断标志: ~' ~" ~9 k) @, q
  54.         TIM_SetCounter(TIM2,0);                //归0
    0 G; F! Q2 i* e
  55.         
    $ e6 F% q+ u/ \4 k) v: V- E

  56. 2 l# @1 Z, @' d5 Z
  57.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PA5+ r; N9 `# `( p+ D5 Y
  58.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
    . `! u* B+ }9 h6 ~% z
  59.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//速度100MHz% x/ L, j2 Z. \! b: u
  60.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽 & ]0 [; t4 O* ?, c( k- n2 _; E7 g
  61.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//不带上下拉 2 o) {1 x3 C5 r! N' e
  62.         GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA5
    , x3 u' O7 P6 F, p$ d7 K; A
  63.         2 `8 e3 H- Z9 N! |% |
  64. }0 j8 h. x0 c0 o) h9 G& h7 h) |
  65. //得到定时器捕获值
    % N; _0 y$ y( G5 f5 d; r
  66. //如果超时,则直接返回定时器的计数值.
    ( c# e) p; B% c& `. ]
  67. //返回值:捕获值/计数值(超时的情况下返回)
    ! D3 {" W+ V3 ?& |6 g/ y
  68. u16 TPAD_Get_Val(void)
    9 d2 }* a; q0 o( i# T
  69. {                                   9 ?1 ~4 x$ ~$ M( S
  70.         TPAD_Reset();
    4 ^) S5 _5 [: {" ]! _! C  U
  71.         while(TIM_GetFlagStatus(TIM2, TIM_IT_CC1) == RESET)//等待捕获上升沿
    + \8 Y* l0 j, @  ~+ p
  72.         {% l' x- y8 x* ?' ~; q9 r* d
  73.                 if(TIM_GetCounter(TIM2)>TPAD_ARR_MAX_VAL-500)return TIM_GetCounter(TIM2);//超时了,直接返回CNT的值
    1 ]6 u& M  d" x! G% l
  74.         };        2 D+ M  F* ]  d: D5 I! t% X' d1 u
  75.         return TIM_GetCapture1(TIM2);         # t% l- [  W3 A  i0 p9 }" [
  76. }           
    0 R# S# w) \5 G% N" Z
  77. //读取n次,取最大值
    3 b7 _0 N( ?2 J  Z7 S
  78. //n:连续获取的次数( P2 v/ J! ]* {# d9 }
  79. //返回值:n次读数里面读到的最大读数值
    ! i- x$ k) E1 P7 H0 \3 x
  80. u16 TPAD_Get_MaxVal(u8 n)- o4 q- l3 J) p1 W
  81. {! }& b2 a( T1 q" ?/ W$ Y, [2 o
  82.         u16 temp=0;
    . H* {' b: I3 k" C- x& @: Z
  83.         u16 res=0; # w' Q2 P8 g. ^* R) S
  84.         while(n--)( H+ [7 B2 d7 H1 O
  85.         {  G- W4 R' A  T# E+ Y
  86.                 temp=TPAD_Get_Val();//得到一次值7 r) ~4 ~0 l' l3 P9 |" v
  87.                 if(temp>res)res=temp;4 f' X% a; Z: C# p9 Q7 n9 w
  88.         };
    8 H# G7 z3 d7 J7 @% F( }% d
  89.         return res;! c) K" V  y3 W" c, o4 ~: A
  90. }  
    , ^( D& N& d- l& X' _% \, }) Z
  91. //扫描触摸按键) e& P1 [) Y" ]
  92. //mode:0,不支持连续触发(按下一次必须松开才能按下一次);1,支持连续触发(可以一直按下)
    # }- h! v1 }- r# c( g
  93. //返回值:0,没有按下;1,有按下;                                                                                  * u  z( \, z) i
  94. #define TPAD_GATE_VAL         100        //触摸的门限值,也就是必须大于tpad_default_val+TPAD_GATE_VAL,才认为是有效触摸.# X" M8 e1 s6 d. c
  95. u8 TPAD_Scan(u8 mode)
    0 j. d8 Y  b$ U  a- c
  96. {
    - w+ g3 i# X8 r1 M* |& p/ J/ ^
  97.         static u8 keyen=0;        //0,可以开始检测;>0,还不能开始检测         
    $ E- w  L& F$ o) f6 Q* a) k
  98.         u8 res=0;
    # x0 p! Z( \: E1 [" _
  99.         u8 sample=3;                //默认采样次数为3次         
    4 @: ^7 ]# g2 s% X9 Z0 b5 Q$ a
  100.         u16 rval;& d/ ?- G7 B' ?7 a9 U! f6 e, h& {
  101.         if(mode)
    5 w- d2 z1 w4 B9 y" m) j6 G* u9 a
  102.         {
    " j: p2 B$ N/ F& C' V2 E
  103.                 sample=6;        //支持连按的时候,设置采样次数为6次& S, N* {9 J5 S( l- f2 @
  104.                 keyen=0;        //支持连按          ! i% \+ K6 `) M* w: M9 M( q/ U6 U
  105.         }. {) J/ M; ~8 c9 c7 B
  106.         rval=TPAD_Get_MaxVal(sample); * U$ E2 X% L& J
  107.         if(rval>(tpad_default_val+TPAD_GATE_VAL)&&rval<(10*tpad_default_val))//大于tpad_default_val+TPAD_GATE_VAL,且小于10倍tpad_default_val,则有效8 w, [+ O8 {- C
  108.         {                                                         
    + X! j$ L' [, d* z
  109.                 if((keyen==0)&&(rval>(tpad_default_val+TPAD_GATE_VAL)))        //大于tpad_default_val+TPAD_GATE_VAL,有效- |0 v# Z- X, i% M$ h
  110.                 {) G% `) t$ ?' ]6 W
  111.                         res=1;
    7 d" c+ Y- u1 H! {5 v% z7 Z0 E! K
  112.                 }           / G5 Z$ Q; f7 u1 k0 e7 K9 X" S( v
  113.                 //printf("r:%d\r\n",rval);                                                                            : t4 W, [  _2 ?
  114.                 keyen=3;                                //至少要再过3次之后才能按键有效   1 A$ _' v. v/ P7 Q5 V; {% v# C
  115.         }
    2 U% k2 |( @* W* @
  116.         if(keyen)keyen--;                                                                                                                                                          ! ]3 _& ~6 k* y0 z
  117.         return res;
    , D, L$ @" s: t! i# d$ @
  118. }         + d# ]5 |! B  A6 a' V3 k/ X2 H
  119. //定时器2通道2输入捕获配置         
    4 J1 p* ^  a% Q7 Y, K% v
  120. //arr:自动重装值- I; d5 J% A3 W# c" Q& z4 O* G3 y
  121. //psc:时钟预分频数
    1 n" s* x) G' H/ L5 q7 P* L
  122. void TIM2_CH1_Cap_Init(u32 arr,u16 psc), X4 y9 X# Z- {" X: V/ w' X
  123. {: j0 m, }7 G  W2 F, i, c) N, U9 t
  124.         GPIO_InitTypeDef  GPIO_InitStructure; 3 v! L2 `) u& Z. J" l. Q
  125.   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;4 N$ D: n% W: r+ Z
  126.         TIM_ICInitTypeDef  TIM2_ICInitStructure;
    & P6 c5 p% b) s
  127.         & s: i: v& Q& ~8 F# v
  128.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);            //TIM2时钟使能      d4 @, t- s* K$ c2 ?% M
  129.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);         //使能PORTA时钟          Y8 P! r8 t8 Y4 g0 w
  130. ' t" y0 ^5 g( r% u6 L( S  f/ c
  131.         6 _4 [  V3 g7 S
  132.         GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM2); //GPIOA5复用位定时器2; A5 ~6 R9 F" m

  133. & L& l* m( v7 @
  134.          
    ) s$ ~2 P4 Y' J8 a9 ?/ ]. u7 U1 a
  135.          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //GPIOA5
    " [( T- `: L* m( V$ h& i
  136.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
      I6 O+ L& L9 r
  137.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        //速度100MHz
    % S4 q, q4 k. _+ B0 V; [
  138.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出/ g4 Y& \/ u- g7 E( C4 j( Y
  139.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//不带上下拉
    , V, ^4 L0 i+ d$ |  M/ z+ ~3 d
  140.         GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA55 J" N! k5 r& r4 R

  141. ( y$ D0 K2 f0 E/ B
  142.         9 g" I( G1 o5 I% F0 m) @
  143.   //初始化TIM2  
    8 |9 n% q: [3 n0 w3 W- g4 t7 ?- @) @
  144.         TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值   
    ' U2 B+ L+ C1 A- ^: u
  145.         TIM_TimeBaseStructure.TIM_Prescaler =psc;         //预分频器            
    0 k( ]5 p) Y! ?% i+ U$ q
  146.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    - m- W! i0 l. }) L5 B
  147.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    " Z( p/ c2 M1 A. `7 M8 l
  148.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位3 ?/ C3 ^  f; h( _4 V, j+ z  j5 q
  149.         ' V4 D/ {* S7 D( W2 P2 h
  150.         //初始化通道1
    , e. U9 w# ~' k: y4 i& B
  151.   TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01         选择输入端 IC1映射到TIM2上7 _) n- h2 z) O: Y/ ]
  152.   TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;        //上升沿捕获! A' j/ L( Q' d' ~- h4 i$ \
  153.   TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; ' v2 |# t" M8 A% ^4 D
  154.   TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;         //配置输入分频,不分频 1 ?! Q& M! }$ y7 p/ k5 u2 ^
  155.   TIM2_ICInitStructure.TIM_ICFilter = 0x00;//IC2F=0000 配置输入滤波器 不滤波
    : l" d& E/ q0 J0 v, v
  156.   TIM_ICInit(TIM2, &TIM2_ICInitStructure);//初始化TIM2 IC1. U3 s/ B; h) a% s3 b/ f
  157.                                                                                                                          : ?/ t5 g& t. ]
  158.         TIM_Cmd(TIM2,ENABLE );         //使能定时器2& I  V* i, g8 @1 }. w( h; y
  159. }</i></i></i></i></i>
复制代码

6 K0 {$ ]7 [! {5 i2 T' \! Hmain.c
7 }" o8 ?. L' g- {* i6 A8 e3 g2 Y+ G6 N5 h/ p6 H
  1. #include "sys.h": A- |3 ^# @. c+ N9 U' G6 {( c0 {
  2. #include "delay.h"
    0 C6 g- _# U9 K) m+ p& s. p9 g/ d
  3. #include "usart.h"
    $ V& b- e9 X& h, z! C
  4. #include "led.h": u3 T, V) c+ v. C- O6 W2 U
  5. #include "tpad.h"
    9 i  T' H$ h0 W
  6. 2 G6 |5 T3 k1 K! A  v$ ?
  7.   q/ ?( p! X& T" ~
  8. int main(void)
    0 c% |) }% J1 G8 c) A* s. T% B
  9. {
      ?! K' s' h, u2 X5 E+ ]
  10.         u8 t=0;
    7 n2 j$ ^' z3 h9 L
  11.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    : e* J6 @6 `0 s9 j- u& g
  12.         delay_init(168);     //初始化延时函数
    $ i# d2 g- E/ g$ A" |, o+ C
  13.         uart_init(115200);         //初始化串口波特率为115200* }/ O0 g0 x; E% K/ y
  14.         LED_Init();                                         //初始化LED
    3 P. k5 G4 ~' P0 w- w
  15.         
    & N+ \* v' R' O2 q5 X" {
  16.         TPAD_Init(8);                                //初始化触摸按键,以84/4=21Mhz频率计数
    * Q5 x2 Z: r* J/ t
  17.            while(1)6 ^: i4 \) h" j  }5 S
  18.         {                                                                                                            
    ( ]- x, v3 ~  e4 I& F  \3 I
  19.                  if(TPAD_Scan(0))        //成功捕获到了一次上升沿(此函数执行时间至少15ms)% h/ b- k+ l6 u6 y- Y/ i' L1 [. K
  20.                 {: |% N" W( h0 Q! e8 a" {( v
  21.                         LED1=!LED1;                //LED1取反
    9 ?% o" j4 `/ r! z1 w5 A
  22.                 }
    - P) Y# v2 |9 ]  n8 P2 g* |& W6 [
  23.                 t++;
    + F/ K7 q: H( B: N6 u
  24.                 if(t==15)                 8 d8 o! t. t& G% {9 x0 r% `* }# ?
  25.                 {  t. D  F3 J. i# g9 {
  26.                         t=0;
    % G1 K8 R+ o% a! G' X
  27.                         LED0=!LED0;                //LED0取反,提示程序正在运行
    # W9 A% w3 N8 D; \% m# h
  28.                 }
    ! m' }+ W4 g" E5 G& p( \
  29.                 delay_ms(10);6 E  l8 Z, L* ~& i" N" B1 L- f8 e) e, K. K
  30.         }1 _6 A1 Y! Z$ p  m
  31. }
    * L, r9 F7 ~. D# K3 b
  32. 7 l& a- x6 |# e* x
复制代码
8 H" H  m3 E: O0 n* M, w
赞 收藏 评论0 发布时间:2022-6-13 21:21

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版