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

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

[复制链接]
STMCU小助手 发布时间:2022-6-13 21:21
01. 电容触摸按键简介
0 g3 p4 s" h  h( F3 L, r9 A触摸按键相对于传统的机械按键有寿命长、占用空间少、易于操作等诸多优点。大家看看如今的手机,触摸屏、触摸按键大行其道,而传统的机械按键,正在逐步从手机上面消失。接下来给大家介绍一种简单的触摸按键:电容式触摸按键。9 H& o0 M, x+ S5 v; e
# T2 S6 U, J" N, Y
利用探索者 STM32F4 开发板上的触摸按键(TPAD)来实现对 DS1 的亮灭控制。这里 TPAD 其实就是探索者 STM32F4 开发板上的一小块覆铜区域,实现原理如图所示:
/ ^0 S# P) _; L: @8 v
/ g: p. n, ~& M4 G6 {1 X DY]R_{KJ]ZXSR25PZI5`D75.png
' g& X+ p& V8 c: u* I; M. ]6 v+ n2 y3 y6 ?5 K
我们使用的是检测电容充放电时间的方法来判断是否有触摸,图中 R 是外接的电容充电电阻,Cs 是没有触摸按下时 TPAD 与 PCB 之间的杂散电容。而 Cx 则是有手指按下的时候,手指与 TPAD 之间形成的电容。图中的开关是电容放电开关(由实际使用时,由 STM32F4 的IO 代替)。8 k  y% Q  A* a5 K/ r6 t8 V2 Q
" V. I  F5 I, ?/ n! C6 M2 Y/ [/ I8 X& L
先用开关将 Cs(或 Cs+Cx)上的电放尽,然后断开开关,让 R 给 Cs(或 Cs+Cx)充电,当没有手指触摸的时候,Cs 的充电曲线如图中的 A 曲线。而当有手指触摸的时候,手指和 TPAD之间引入了新的电容 Cx,此时 Cs+Cx 的充电曲线如图中的 B 曲线。从上图可以看出,A、B两种情况下,Vc 达到 Vth 的时间分别为 Tcs 和 Tcs+Tcx。7 f: @/ l1 v2 i3 K: @
. b( S7 k$ J8 W$ t
其中,除了 Cs 和 Cx 我们需要计算,其他都是已知的,根据电容充放电公式:
4 H4 T0 W0 R! g. ?/ Y+ u% @3 S5 M$ ?3 I9 M5 z. d3 h. m
Vc=V0(1-e^(-t/RC))*
9 O" Y4 V3 Y& ?  n: c/ m: _. V9 g4 d! y# |! \
其中 Vc 为电容电压,V0 为充电电压,R 为充电电阻,C 为电容容值,e 为自然底数,t 为充电时间。根据这个公式,我们就可以计算出 Cs 和 Cx。利用这个公式,我们还可以把探索者开发板作为一个简单的电容计,直接可以测电容容量了。. R3 ?) E3 v! Y8 t6 W; a
: f, M/ D# D" w3 F, M, a
我们只要能够区分 Tcs 和 Tcs+Tcx,就已经可以实现触摸检测了,当充电时间在 Tcs 附近,就可以认为没有触摸,而当充电时间大于 Tcs+Tx 时,就认为有触摸按下(Tx为检测阀值)。; g, @4 j: K+ |4 }- h0 \
2 D, Z* ], I6 L+ d
我们使用 PA5(TIM2_CH1)来检测 TPAD 是否有触摸,在每次检测之前,我们先配置PA5 为推挽输出,将电容 Cs(或 Cs+Cx)放电,然后配置 PA5 为浮空输入,利用外部上拉电阻给电容 Cs(Cs+Cx)充电,同时开启 TIM2_CH1 的输入捕获,检测上升沿,当检测到上升沿的时候,就认为电容充电完成了,完成一次捕获检测。) W. C7 h# w, e7 E) k

4 w; F/ D9 h0 d7 d0 i3 o在 MCU 每次复位重启的时候,我们执行一次捕获检测(可以认为没触摸),记录此时的值,记为 tpad_default_val,作为判断的依据。在后续的捕获检测,我们就通过与 tpad_default_val 的对比,来判断是不是有触摸发生。
4 ]7 ]- y: c! Q1 u2 s: a: D, T; e5 Q5 g
02. 硬件设计
1 t5 G# P7 Z& p用到的硬件资源有:" h* R" x; y3 p7 A+ [6 F
1) 指示灯 DS0 和 DS1
7 `. s  v5 W1 F2 Y7 p) P& u1 ~2) 定时器 TIM2
1 e; i$ h5 N* B; ~4 {3) 触摸按键 TPAD5 P& D( \. S: G
. P4 ?+ I# g% G/ k) G) W) e8 d
需要通过 TIM2_CH1(PA5)采集 TPAD 的信号,所以需要用跳线帽短接多功能端口(P12)的 TPAD 和 ADC,以实现 TPAD 连接到PA5。如图所示:
2 Y. N! d- d7 b1 [
8 u8 k1 C( c3 g3 E: R FKW7FR$CC3UR72DH97GI2~T.png
* y& x) M* z) g
7 W0 P+ j% S7 d% a8 ~03. 功能描述2 o# j" }; _6 ^- v( A
实现一个简单的电容触摸按键,通过该按键控制 DS1 的亮灭。) J2 O0 p$ B2 W
4 ?& @1 \' L7 H( y2 q
04. 程序示例  _( x; h# F4 |- H% w) ?# _: g
tpad.h5 V4 K( y9 o; e  l5 h
- ^( z( `7 z8 `9 w) Q0 d+ p! I
  1. #ifndef __TPAD_H# s  e. t2 t& K% y' e) V% h
  2. #define __TPAD_H5 K; z7 t- Z+ P$ _' \" p
  3. #include "sys.h"
    # }; \1 L8 b7 l# |1 |, w! b$ q, u, C
  4.            8 U8 x4 W' ]; C$ y; ^- s
  5. //空载的时候(没有手按下),计数器需要的时间7 u0 R  O. S( D) O! K# u2 C1 B
  6. //这个值应该在每次开机的时候被初始化一次; N; c  k) e' N0 T* k
  7. extern vu16 tpad_default_val;% [0 i4 H/ p/ q$ j. ?+ b
  8.                                                                        
    6 U5 G/ f" j  d8 A6 K
  9. void TPAD_Reset(void);6 u+ a% B5 E5 u9 \8 I6 K
  10. u16  TPAD_Get_Val(void);
    $ w/ u. j4 M/ K% u( P2 Q
  11. u16 TPAD_Get_MaxVal(u8 n);
    / t: Z& [6 t7 U& J# j4 C* x8 N
  12. u8   TPAD_Init(u8 systick);: p$ A: q' U2 @/ w
  13. u8   TPAD_Scan(u8 mode);
    1 _; R0 y; w! g
  14. void TIM2_CH1_Cap_Init(u32 arr,u16 psc);     
    / Y; j: s! d7 G+ G/ R7 n
  15. #endif
复制代码

2 {0 d, U. k3 o$ {$ X% Q9 c3 Itpad.c
* @* l1 z) ]0 f0 c, w+ L, z# \" N2 b4 E% m- T& k
  1. #define TPAD_ARR_MAX_VAL  0XFFFFFFFF        //最大的ARR值(TIM2是32位定时器)          " r/ K* O) K; K5 @3 s7 ^0 X! ^
  2. vu16 tpad_default_val=0;                                //空载的时候(没有手按下),计数器需要的时间: h  J5 ]5 Q9 P
  3. //初始化触摸按键
    4 T$ a$ a& h+ p& x/ S
  4. //获得空载的时候触摸按键的取值.2 \9 |* B! X: w' t( f/ U" v8 S2 \
  5. //psc:分频系数,越小,灵敏度越高.
    , o3 }" |0 X4 r( X6 c
  6. //返回值:0,初始化成功;1,初始化失败4 g/ {; q% l3 ~6 F0 K. Z
  7. u8 TPAD_Init(u8 psc)
    5 D7 [( b2 d3 k: }
  8. {4 z  }# Y2 \5 r0 K+ I" k
  9.         u16 buf[10];
    ! b. y6 h( U8 Z2 @2 p" U- a+ b
  10.         u16 temp;% J" k# [8 z# b" I0 D: d
  11.         u8 j,i;
    $ z3 p5 j" G* X* C: c) ~' [. b+ k
  12.         TIM2_CH1_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//设置分频系数. m3 Z  y2 u4 f& b- x  @
  13.         for(i=0;i<10;i++)//连续读取10次
    / W8 l5 R& t: K2 J$ t2 q
  14.         {                                 
    ) o# i* L% \9 m2 A& p
  15.                 buf<i>=TPAD_Get_Val();$ e0 N4 t! W! J
  16.                 delay_ms(10);            
    % F; ]8 {% N5 h3 I2 ?
  17.         }                                    $ f1 M' Q1 l+ f2 J2 `/ x5 ?5 [7 v, \
  18.         for(i=0;i<9;i++)//排序
    ; u* e' k/ ]) y( ]& g, @
  19.         {$ H& [  {0 a1 y4 W6 @/ o
  20.                 for(j=i+1;j<10;j++)0 r" b, _( o' W9 _( N
  21.                 {- f& f$ M6 t$ V/ d5 @5 d
  22.                         if(buf<i>>buf[j])//升序排列* q) }* t& t+ ], K; E( M
  23.                         {4 A+ A( r! L, t) T
  24.                                 temp=buf<i>;
      v' i1 l% O* v0 l5 l7 _% `1 y, x
  25.                                 buf<i>=buf[j];
    " b* }! d$ q* v
  26.                                 buf[j]=temp;/ t( S# J  d8 e1 e  j7 O
  27.                         }
      m4 N! B5 t+ M4 [3 j
  28.                 }$ y% E  R( L8 O* R0 _
  29.         }, f  s( d4 `- h  f
  30.         temp=0;* M! g) F8 j- l4 ^: M8 f/ G
  31.         for(i=2;i<8;i++)temp+=buf<i>;//取中间的8个数据进行平均
    : L* H+ z' ?' [2 t0 T& C( Q
  32.         tpad_default_val=temp/6;( W( P* m! V+ T4 P% m
  33.         printf("tpad_default_val:%d\r\n",tpad_default_val);        
    ) Q# H4 w' {; k* j* ]
  34.         if(tpad_default_val>TPAD_ARR_MAX_VAL/2)return 1;//初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常!
    & x8 B. C4 @& |6 S1 n9 `& S3 Z, W
  35.         return 0;                                                                            6 L7 [1 K4 c  I+ ^8 u  a3 C
  36. }
    $ c$ m) O0 t4 b( e) A0 P0 z' Q5 D
  37. //复位一次
    2 K3 J+ a/ h8 Z2 k/ Y$ p& n; ~
  38. //释放电容电量,并清除定时器的计数值' Q  i. {& y9 }
  39. void TPAD_Reset(void)- }3 E4 t* ~6 b" s2 a/ O8 O. F& x
  40. {                + e. P: O- W8 y) V6 |
  41.         GPIO_InitTypeDef GPIO_InitStructure;$ c+ m& e0 j4 H+ C* I
  42.         % V5 _  l! q8 ?" _) s
  43.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  //PA52 W6 ?' j( ^; Q0 V4 ~+ l
  44.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出3 t& t+ L/ }0 B! c: B7 {
  45.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        //速度100MHz0 D" h2 I! W: I
  46.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽 " V) y+ x7 s7 I4 C! @
  47.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
    / w- u- f& T6 I  \
  48.         GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA52 Y9 Y) s( z% v3 |+ q" @9 P
  49.          
    & y3 b: V- ~1 T' C' E2 U) O  W# l
  50.         GPIO_ResetBits(GPIOA,GPIO_Pin_5);//输出0,放电
    5 \9 z9 {1 V' i5 X* d6 z
  51. ' {6 P  H: o+ h) d9 F$ e1 D
  52.         delay_ms(5);" g* ]6 ^% i0 n0 I7 L
  53.         TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清除中断标志0 n. k3 X& S* e9 J& Y/ r
  54.         TIM_SetCounter(TIM2,0);                //归0
    ; P3 T0 g: f* z
  55.         
    8 T% F* |3 k% w: V# `" W* P" ]/ R
  56. 0 k# D3 f6 o$ j( [
  57.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PA5: N4 O7 v5 Y- r; l) a% |0 L
  58.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
    5 T  Q5 ~3 t% ^( b/ C$ n7 ^
  59.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//速度100MHz; A6 [% r; a% N% v
  60.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽   ^- E) ?7 r- p  J* ~: W
  61.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//不带上下拉 ' r( Y* d9 q. o% x! A: K5 ]
  62.         GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA5. L, `2 U) P. N0 t; k, p" E
  63.         
    . u1 r% A/ N! y. y$ O  a
  64. }
    3 p" E1 g& h7 M( H: ?/ [
  65. //得到定时器捕获值
    6 n5 l, @. F& ?/ ]9 x( I* c
  66. //如果超时,则直接返回定时器的计数值., v( c# C7 w8 g$ A  n( t7 q: o4 V0 ^
  67. //返回值:捕获值/计数值(超时的情况下返回)# n, t6 }& ]: L3 M. G7 \: F
  68. u16 TPAD_Get_Val(void)
    $ v" o, O  x" |3 o1 ~
  69. {                                   ; R0 I; k9 c4 m( o! c  p! D3 n
  70.         TPAD_Reset();
    . M+ c& w9 O0 U8 D0 t
  71.         while(TIM_GetFlagStatus(TIM2, TIM_IT_CC1) == RESET)//等待捕获上升沿
    * [; D* k( a* P0 H% K8 D
  72.         {
    ) X2 X# w/ v. ^& ~
  73.                 if(TIM_GetCounter(TIM2)>TPAD_ARR_MAX_VAL-500)return TIM_GetCounter(TIM2);//超时了,直接返回CNT的值
    5 [" x7 {( U( e" o$ K* w
  74.         };        
    ) W' B9 N( G! q0 m9 g1 X
  75.         return TIM_GetCapture1(TIM2);         
    8 g. @  E0 J8 g& O0 ]& i
  76. }           
    & V, Z3 R  k2 z7 O- U0 a& l
  77. //读取n次,取最大值
    ; O0 e8 K% S4 V& F& f3 V
  78. //n:连续获取的次数& f& }8 g5 c# ]; O! g
  79. //返回值:n次读数里面读到的最大读数值6 R' g; o4 U# o$ V
  80. u16 TPAD_Get_MaxVal(u8 n)
    / C' M  X! G) j8 ~
  81. {
    4 u' r/ O3 E: I2 ?  m+ c
  82.         u16 temp=0;  v1 k+ |$ U2 ~. A
  83.         u16 res=0; 4 n& m$ k: j! q/ b1 R! X
  84.         while(n--)
    % z+ b- u. I/ }- h6 v5 D" ^/ a
  85.         {
    6 J' r9 y. j6 [4 m' H; Z
  86.                 temp=TPAD_Get_Val();//得到一次值
    $ n2 \2 s0 ]5 H) K9 A
  87.                 if(temp>res)res=temp;
    - d8 s: ~" i: h2 ^
  88.         };, i; c( I6 C4 G) D
  89.         return res;* j8 ?, G8 a* I( Q  v8 W& i/ @7 `
  90. }  . P# L7 i/ M, Y& i7 Z
  91. //扫描触摸按键
    9 {/ l9 c' D& S/ _
  92. //mode:0,不支持连续触发(按下一次必须松开才能按下一次);1,支持连续触发(可以一直按下)# x- E, ?) _( o9 y
  93. //返回值:0,没有按下;1,有按下;                                                                                 
    + J. Z3 s8 h  |0 p+ J) T) r
  94. #define TPAD_GATE_VAL         100        //触摸的门限值,也就是必须大于tpad_default_val+TPAD_GATE_VAL,才认为是有效触摸.
    8 Z' ~  Q" ~3 N  J" `) U+ l5 `
  95. u8 TPAD_Scan(u8 mode)- F7 V3 d/ q- Y. P/ Y# E
  96. {; R4 ]3 \5 G$ y1 Q
  97.         static u8 keyen=0;        //0,可以开始检测;>0,还不能开始检测         
    " q4 l# k. m! U' [# [
  98.         u8 res=0;* D: v" {/ E5 x/ c% P- n: }  Z
  99.         u8 sample=3;                //默认采样次数为3次         # J3 R* v+ E% F8 C2 B
  100.         u16 rval;
    2 N+ `6 U% l$ b1 s' S
  101.         if(mode); S  U$ |' d9 M# Q2 B' e
  102.         {
    1 W/ @1 s" l! f1 V$ O
  103.                 sample=6;        //支持连按的时候,设置采样次数为6次
    + y5 ~; P% j5 N
  104.                 keyen=0;        //支持连按         
    7 Q9 o1 n$ n1 i  o; ^0 O0 e1 v
  105.         }
    6 q+ \2 C2 H' H: X6 C3 u; p
  106.         rval=TPAD_Get_MaxVal(sample); : ~# Y. |% |0 b& Y& y; k+ x4 {7 O
  107.         if(rval>(tpad_default_val+TPAD_GATE_VAL)&&rval<(10*tpad_default_val))//大于tpad_default_val+TPAD_GATE_VAL,且小于10倍tpad_default_val,则有效" J' S# h9 C# r0 J0 c
  108.         {                                                         
    0 ^! }/ d- u, m1 Y( ]
  109.                 if((keyen==0)&&(rval>(tpad_default_val+TPAD_GATE_VAL)))        //大于tpad_default_val+TPAD_GATE_VAL,有效
    8 \( k" m# p- g6 a: F
  110.                 {9 m" u: x- r% g# ~& j8 c0 K) Y5 B
  111.                         res=1;
    * x( E/ K9 U, T4 Z' C- [7 z2 c
  112.                 }           " B1 m2 p& {% {% O4 A( ^
  113.                 //printf("r:%d\r\n",rval);                                                                            + e2 q8 m/ R, p0 y" n# M5 Z% a) U2 l, D1 H
  114.                 keyen=3;                                //至少要再过3次之后才能按键有效   8 q. ]& {" O- }8 s
  115.         } + Y$ b- l! s! y
  116.         if(keyen)keyen--;                                                                                                                                                          % m7 y& K8 u2 G" u7 k7 W
  117.         return res;" V7 ?6 Z8 y* _
  118. }         
    % |2 X9 A, d9 C- P
  119. //定时器2通道2输入捕获配置         . @8 T* \+ q1 e& i
  120. //arr:自动重装值
    + c, n! x0 R; m( T9 r+ V& Z
  121. //psc:时钟预分频数7 r: I1 e+ e9 \4 v! M0 U
  122. void TIM2_CH1_Cap_Init(u32 arr,u16 psc)3 p- D7 _3 ^- }- {
  123. {9 [! ?4 k: O; R% v5 o
  124.         GPIO_InitTypeDef  GPIO_InitStructure;
    1 x* t% }. P  B+ ^. m
  125.   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;9 M! v3 `$ I# i/ W& c5 j, m$ m7 \
  126.         TIM_ICInitTypeDef  TIM2_ICInitStructure;
    0 g0 b& p! Y& [% T+ e# o- Z
  127.         
    : i+ A- |- t9 S/ Q; B
  128.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);            //TIM2时钟使能    ( j& q9 \: h, D- c1 y
  129.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);         //使能PORTA时钟        / H6 M+ }9 R* I* {+ \" N

  130. $ s+ z% Y" j0 p+ ^4 |  W7 J" o
  131.         8 I' K" l( i6 ~# D( Q# l( n9 I
  132.         GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM2); //GPIOA5复用位定时器2# Q/ f1 g' E/ m1 E0 g

  133. " a  t7 Y6 p4 i( V% W8 T: q
  134.          
    ' A% U, t* Z4 J7 `! S. {9 H& @2 \
  135.          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //GPIOA54 y$ Q% t# n3 k4 c8 G
  136.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能6 K, k/ ~5 x1 P2 @  s8 V' i
  137.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        //速度100MHz: }& N: s, l$ o
  138.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
    9 `# y/ o8 X/ b9 f( Z
  139.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//不带上下拉
    - _# y4 {& e+ G2 ?, }3 u  V+ {
  140.         GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA50 C1 t% z: R4 j) Q5 H
  141. 1 q2 c2 T# t" D  c
  142.         3 s1 ^, W$ v; T& q6 `# E
  143.   //初始化TIM2  $ I# t; x) v0 u
  144.         TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值   , s# ?" T2 J0 q" _0 X6 m; |
  145.         TIM_TimeBaseStructure.TIM_Prescaler =psc;         //预分频器            3 k1 D) R. u% Y3 B1 P9 Z
  146.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    * t- ~  c* H. |( y
  147.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式+ o3 I) H1 b) Q( k; G7 S* p
  148.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位+ ^/ G& d/ ^! F  w
  149.         
    + V8 m7 i' e/ }& L/ w1 q& o. h
  150.         //初始化通道1& m, j7 v* L1 S- `' f
  151.   TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01         选择输入端 IC1映射到TIM2上; u7 r  ^  j5 V8 Z: z+ E
  152.   TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;        //上升沿捕获( h2 u2 v7 j+ ]# g* m
  153.   TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; / B) K# f# r, p
  154.   TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;         //配置输入分频,不分频
    ( J3 n# K( i1 t0 N0 T
  155.   TIM2_ICInitStructure.TIM_ICFilter = 0x00;//IC2F=0000 配置输入滤波器 不滤波
    6 W! r; ^# b% y% ~
  156.   TIM_ICInit(TIM2, &TIM2_ICInitStructure);//初始化TIM2 IC1, P# H' l( ]- f0 A
  157.                                                                                                                          . i6 P9 N' a& @/ u, y$ i- I
  158.         TIM_Cmd(TIM2,ENABLE );         //使能定时器2) |+ w" X1 q+ ~& U4 L6 M# ^6 h
  159. }</i></i></i></i></i>
复制代码

3 \$ E' \5 t' F& C6 umain.c
. L1 E0 W" e& H" _6 ]% r  `- Z
7 p% G" C: B, F
  1. #include "sys.h"
    9 a3 L. I. J9 x! [
  2. #include "delay.h"9 S  T) x9 p) s& O. M
  3. #include "usart.h"2 H# b, O5 s9 G; l3 e# r8 i0 U# I
  4. #include "led.h"; Q' f& c  M( f7 q  `
  5. #include "tpad.h"
    ( O. B) }$ Z( }, y6 j9 h

  6. $ o! a6 J3 M) t$ b) L+ h( J6 ?" m

  7. ' i, N* T0 D' p% k* u& t
  8. int main(void)
    8 |" h: _3 l: I9 {8 y5 Z2 u
  9. { 4 Z/ {1 o4 g) u9 \% L* ]
  10.         u8 t=0;
    , l) s: l5 r- [
  11.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    2 W% S6 G" H8 ~* X1 n) ~' I9 t: A5 v
  12.         delay_init(168);     //初始化延时函数
      W5 U; Q- \; m8 X3 i
  13.         uart_init(115200);         //初始化串口波特率为115200
    ) }/ B6 O: n2 t/ x9 d
  14.         LED_Init();                                         //初始化LED' E% a# U  n% i9 g5 c; Y, f
  15.         
    8 U  M* M9 ]& k, g/ U
  16.         TPAD_Init(8);                                //初始化触摸按键,以84/4=21Mhz频率计数
    9 ?$ h4 r7 l+ A: e$ D3 A
  17.            while(1)3 ~# h( z- a" `; a( r! B
  18.         {                                                                                                            
    " n' O. m8 G- ^4 M( ~; o
  19.                  if(TPAD_Scan(0))        //成功捕获到了一次上升沿(此函数执行时间至少15ms); c/ b# A' P; c4 c; f8 q
  20.                 {
    # t: o, E: f" k: }6 J
  21.                         LED1=!LED1;                //LED1取反
    & n& k; P1 p! g" ^4 V
  22.                 }
    0 k5 m; B* ?# U4 c8 p4 |! Y
  23.                 t++;# _6 }) F2 t+ q) x7 l  N8 J
  24.                 if(t==15)                 
    1 A! B8 z$ z1 G+ ~; X( c
  25.                 {& _4 x- s0 G/ G+ n
  26.                         t=0;
    2 O+ S0 m& Q7 Z( N
  27.                         LED0=!LED0;                //LED0取反,提示程序正在运行" U! X) }! K1 G+ A! S' l9 W2 `
  28.                 }: Z9 H% `( P( Q% V5 o* r
  29.                 delay_ms(10);" L% B' H" L# v
  30.         }4 G! I0 e6 N* p# w' z/ d
  31. }% m) k: [5 W/ J( e1 ^1 C
  32. - O4 A* y% H: c( J. {5 F" v7 d6 c
复制代码
1 o6 D8 I; e9 X0 f
收藏 评论0 发布时间:2022-6-13 21:21

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版