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

【经验分享】STM32实例-红外遥控实验②-程序设计

[复制链接]
STMCU小助手 发布时间:2022-6-26 18:24
    本实验使用到硬件资源如下:
(1)D1 指示灯
(2)串口 1
(3)红外遥控器和红外接收头
    D1 指示灯、串口 1 电路在前面章节都介绍过,这里就不多说,红外遥控器属于外部器件,只有红外接收头集成在开发板上,其电路如下图所示:
微信图片_20220626182411.png
$ |: T0 |% w, \3 x
    从电路图中可以看到,红外接收头的数据输出管脚连接在 STM32F1 芯片的PG15管脚上,这里我们使用PG15 引脚内部上拉,所以可以省去一个上拉电阻,不会有影响,当然也可以接一个 10K 的上拉电阻。通过配置 PG15 引脚为外部中断功能,按照 NEC 协议进行解码。
    D1 指示灯用来提示系统运行状态,红外遥控器用来发射红外键值的编码信
号,通过红外接收头进行解码,并将解码后的数据通过串口 1 打印输出。
    本实例所要实现的功能是:使用外部中断功能将遥控器键值编码数据解码后通过串口打印输出,同时控制 D1指示灯闪烁,提示系统运行。程序框架如下:
(1)使能 PG15 端口及 AFIO 时钟,映射 PG15 至外部中断线上,初始化 EXTI等
(2)编写红外解码函数(在 EXTI 中断处理)
(3)编写主函数
    外部中断的配置在“外部中断实验”章节中都有介绍,不清楚的可以回过头
看下。下面我们打开“ 红外遥控实验”工程,在APP 工程组中添加 hwjs.c 文件(里面包含了红外解码驱动程序),在 StdPeriph_Driver 工程组中添加stm32f10x_exti.c 库文件。EXTI 操作的库函数都放在stm32f10x_exti.c和stm32f10x_exti.h文件中, 所以使用到EXTI就必须加入 stm32f10x_exti.c文件,同时还要包含对应的头文件路径。
    这里我们分析几个重要函数。

* \; u* |7 s0 ]& s) c$ |
外部中断初始化函数
    我们知道红外接收头数据输出管脚是接在 PG15 上, 所以配置 PG15 为外部中断功能,初始化代码如下:
  1. /****************************************************************6 l- E- Z" X7 z0 v
  2. * 函 数 名 : Hwjs_Init
    ) k2 y8 T: _" X
  3. * 函数功能 : 红外端口初始化函数 时钟端口及外部中断初始化! f( j; n8 }- l) N: T* ?
  4. * 输 入 : 无! P5 n- L4 g7 c2 u
  5. * 输 出 : 无/ l* N  l- l) r& v3 k
  6. *****************************************************************/
    ( ?4 F% ]+ Q6 l# \
  7. void Hwjs_Init()9 B# e1 K" X0 A: @
  8. {7 D1 u$ p* V1 H. q
  9. GPIO_InitTypeDef GPIO_InitStructure;9 l! H% v5 M! n$ o( V6 J- a; B  X
  10. EXTI_InitTypeDef EXTI_InitStructure;' b8 S( v( A9 k, x
  11. NVIC_InitTypeDef NVIC_InitStructure;
    # Q" V8 e6 i  p7 e! e- X1 M" }
  12. /* 开启 GPIO 时钟及管脚复用时钟 */% |5 e: V7 H- J
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG|RCC_APB2Periph_AFIO,ENABLE);2 t; Y9 E( C, z  P$ }* U6 p. r4 T
  14. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;//红外接收
    ) Y8 i& q4 _2 u8 J
  15. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
    7 P4 B# r8 ?% k5 x0 A
  16. GPIO_Init(GPIOG,&GPIO_InitStructure);
    0 B/ i# a9 v2 ]9 n& w
  17. GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource15); //选择 GPIO 管脚用作外部中断线路8 T/ ?- R/ p2 E
  18. EXTI_ClearITPendingBit(EXTI_Line15);7 n7 p5 `5 A  E/ c: ?& D. }. ~" M
  19. /* 设置外部中断的模式 */
      u1 b+ N! {6 l9 o
  20. EXTI_InitStructure.EXTI_Line=EXTI_Line15;! x3 b# \9 v0 C/ k# @: y2 U% r8 S
  21. EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
    4 P2 U) c1 i# L
  22. EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;. h" f8 p7 C  f% j
  23. EXTI_InitStructure.EXTI_LineCmd=ENABLE;/ X+ _: X" \4 i1 j0 p7 K+ a
  24. EXTI_Init(&EXTI_InitStructure);
    ) \4 k) s' i: |$ }' \. h8 F% F
  25. /* 设置 NVIC 参数 */
    . f% |4 }: X% M5 F9 A2 L
  26. NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //打开全局中断+ c6 R0 I) A4 {. a
  27. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级为 0
    : O1 M: D' n+ L" q
  28. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级为1
    8 }! i& M* _" E/ _
  29. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
    ! b# B1 L! {  A/ E  ~" K
  30. NVIC_Init(&NVIC_InitStructure);" C, J7 t, m, |8 N
  31. }
复制代码

5 c2 d3 o# `, K
    在Hwjs_Init()函数中,首先使能 GPIOG 端口和 AFIO 时钟,然后将PG15 映射到外部中断线 15 上, 并配置 PG15 为上拉输入模式, 最后初始化 EXTI 及NVIC,这里需要注意,PG15 的外部中断通道是 EXTI15_10_IRQn。

* T2 x6 o6 ^- d) u( _9 d
红外解码函数2 d/ \9 C/ e0 c7 ~; z( l3 e( q2 `% x
    初始化外部中断后,中断就已经开启了,当 PG15 引脚上来了一个下降沿,就会触发一次中断,在中断内我们可以计算高电平时间,通过高电平时间判断是否进入引导码及数据 0 和1。具体代码如下:
  1. void EXTI15_10_IRQHandler(void) //红外遥控外部中断4 ~1 l9 w7 Y0 U( K. i
  2. {
    ; l: Z, M, s, v5 R- w
  3. u8 Tim=0,Ok=0,Data,Num=0;
    / M; l5 J7 f. d, V
  4. while(1), a- ?, e0 G- x+ y+ {1 X
  5. {
    . V0 U4 ^; o4 {( F
  6. if(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_15)==1)
    7 I% O' f" ]4 Z
  7. {
    9 z/ n. W4 @6 N, F. R
  8. Tim=HW_jssj();//获得此次高电平时间3 Y* @5 F$ I) t' r
  9. if(Tim>=250) break;//不是有用的信号
    9 S  t" d. @3 ]' k! J4 Q+ X5 Y
  10. if(Tim>=200 && Tim<250)
    % l/ G% V& q9 ?/ c* k: h2 q1 w
  11. {- K, ?8 j) X" h* g. f
  12. Ok=1;//收到起始信号& Z  G9 K& j" m' ^0 B9 J4 F, E6 [) J& {
  13. }4 Y& O! l  [; k, r' n( I- E
  14. else if(Tim>=60 && Tim<90)
    " v* G; c# F, ^
  15. {
    : W8 K, C% g( d4 X: @# B
  16. Data=1;//收到数据 1( d2 S' v# H) Y) c! x
  17. }8 {& r! ^4 A0 ?6 Y5 H
  18. else if(Tim>=10 && Tim<50)& H2 e, }3 _4 v( @* k1 d$ s
  19. {% D# ]$ n5 i6 @9 ], v7 n/ t5 ^
  20. Data=0;//收到数据 0
    . |$ T# r3 J) u* X5 M* E5 b
  21. }; l  ]! l: {& L  x* y& U
  22. if(Ok==1)- s3 \8 S7 d! B# m+ R
  23. {* @+ K7 [$ i1 L  m1 ]4 H7 s4 p
  24. hw_jsm<<=1;
    8 \( L9 I9 N% K% H# e& T( m8 T0 L( ?
  25. hw_jsm+=Data;
    ; Y% W+ v% S8 Q- f2 t
  26. if(Num>=32)
    , B3 ], |. X% H" ]8 P2 q7 s
  27. {
    . f" Y; p$ |( x7 b
  28. hw_jsbz=1;
    + J" q7 k/ ?3 K. ]  ?& Q$ u5 Z
  29. break;! d# ^5 _8 K- U3 ?
  30. }, G; n8 z6 D( {& w
  31. }9 e3 u' C; B2 \8 f# z) S
  32. Num++;
    # e( @" A! H+ }6 g) O3 T& F2 F& D# @1 a
  33. }6 j7 g7 R) g9 v
  34. }6 T5 i; A, z8 D
  35. EXTI_ClearITPendingBit(EXTI_Line15);: v0 j0 I! y! f, E. a1 q9 \0 Z
  36. }
复制代码

7 L* _' [# m/ J2 m
    中断函数内调用了 HW_jssj函数获取高电平时间,此函数代码如下:
  1. /****************************************************************8 ~7 B) I9 U  g. C7 u9 J' x' o
  2. * 函 数 名 : HW_jssj
    3 @. h0 `0 `  z9 ^/ N
  3. * 函数功能 : 高电平持续时间,将记录的时间保存在t中返回,其中一次大约20us8 U& M; I# H2 v
  4. * 输 入 : 无
    ! g1 r* h- c' k( Z  L
  5. * 输 出 : t
    / b! ^2 h/ ^+ N' I2 l+ {9 w2 v
  6. *****************************************************************/
    3 x2 Y& n5 ^/ F% j! V/ w$ y
  7. u8 HW_jssj()
    & H# z, L( p/ S0 _% S' a' n
  8. {
    9 D5 ?: K* @* u, }2 O$ c- M% n
  9. u8 t=0;
    1 p; G" f. j/ s, t5 h
  10. while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_15)==1)//高电平
      f, a, Z+ Q+ C2 v/ n# {7 T
  11. {
    / p' }3 P; O! o( I; j' [
  12. t++;
    3 |3 c: \0 Q! C, w* _# }
  13. delay_us(20);
    + `2 ^) ]/ U3 [* p
  14. if(t>=250) return t;//超时溢出+ L! |, K* Y; [/ d4 F: s4 E  X, @
  15. }5 T) V  e6 b& {0 J$ n
  16. return t;
    , s+ f3 u: Z, q- \
  17. }
复制代码
2 p0 `/ {- B7 p: ^( |
    通过此函数返回值就可以计算高电平时间,t 累加一次积累的时间为20us。中断函数内,将此函数返回值保存在变量 Tim 中,通过 Tim 值就可以判断是否进入引导码,如果是引导码,就可以接着判断接收的数据是1 还是 0,然后将数据进行按低位在前高位在后顺序保存在 hw_jsm 内,当接收完 32 位数据后将hw_jsbz 标志位置 1,并退出解码函数。这里要注意,判断是否为引导码、数据1 和 0时,我们不要硬性的固定在高电平区分时间上,而应该给它一个在固定值旁的范围判断,以防止因为干扰而导致误操作。引导码及数据 0 和 1 的高电平区分时间在前面介绍 NEC 码已经讲解了,不清楚的可以回过头看下。

2 N% j$ G; t3 l
主函数
& u, r6 `0 E8 {, C) L
    编写好外部中断初始化和红外解码函数后,接下来就可以编写主函数了,代码如下:
  1. /****************************************************************0 {% \( U' h* P# t- C! D5 N5 b9 b
  2. * 函 数 名 : main( w( P0 s$ h: ~  P% L/ F$ {
  3. * 函数功能 : 主函数5 ^& I" t# @% b" U% H+ J/ l: Q
  4. * 输 入 : 无1 ]& m! S- N$ p' x* i2 k3 X6 J* a
  5. * 输 出 : 无
    6 J2 {/ t) [( b, t( F0 G9 L
  6. *****************************************************************/
    2 S' }  g( n5 y$ D) j
  7. int main()' V% L4 E& v) m6 ]
  8. {% W0 o9 I8 \7 S9 Y3 |7 w9 V
  9. u8 i=0;/ R8 m! k' w3 y
  10. SysTick_Init(72);
    - M  ^" O& Q: P/ c0 E+ |
  11. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2 组
    ! Q: v4 w" c+ S) F* ~" m
  12. LED_Init();
    4 P6 R$ [7 X4 a: [
  13. USART1_Init(9600);% _2 G5 T+ h  B9 W7 J8 R8 e  k5 ?9 S' f
  14. Hwjs_Init();! B  p. U& h6 \2 f0 k8 W
  15. while(1)
    ; J( ^& y# R# F7 F: _: U4 E
  16. {
    6 c6 o/ w6 d  ~0 W/ I+ L6 `3 \
  17. if(hw_jsbz==1) //如果红外接收到
    * R& r) P0 n  F
  18. {
    & O& b. a7 G- J1 y
  19. hw_jsbz=0; //清零
    7 L6 v; T3 g( C6 c! |0 M
  20. printf("红外接收码 %0.8X\r\n",hw_jsm); //打印% z7 S4 J: Y4 A! W- ]& J
  21. hw_jsm=0; //接收码清零: r+ c! `, V: L6 p
  22. }9 O% \1 w! L) |% B2 w8 v
  23. i++;0 g7 i8 b: W2 v
  24. if(i%20==0)- l; }& E% _1 t8 s) s7 Q; Z3 f+ t
  25. {
    8 A7 _: _+ Y6 X
  26. led1=!led1;6 R% i1 l1 f; m  U* Z! P6 s
  27. }. b) u0 I% O/ C- p  B8 V$ d
  28. delay_ms(10);
    , R" m2 H/ j! O9 b. `% ^* K+ c
  29. }
    . o, V% p# C# D* w9 u
  30. }
复制代码
2 ~( f- _8 e6 Y# S2 s
    主函数实现的功能很简单,首先调用之前编写好的硬件初始化函数,包括
SysTick系统时钟, 中断分组, LED初始化等。然后调用我们前面编写的Hwjs_Init函数初始化 PG15 外部中断功能,最后进入 while 循环,通过 hw_jsbz 标志判断是否解码成功,如果成功将解码后的数据 hw_jsm 打印输出,同时控制 D1 指示灯闪烁,提示系统正常运行。
$ W) _0 z* x9 t
实验现象7 O, O7 K6 C' P, s! p6 q
    将工程程序编译后下载到开发板内,可以看到 D1 指示灯不断闪烁,表示程序正常运行。当按下红外遥控器键时,串口将打印输出解码后的数据(地址码+地址反码+控制码+控制反码)。如果想在串口调试助手上看到输出信息,可以打开 “串口调试助手” , 首先勾选下标号1 DTR框,然后再取消勾选。这是因为此串口助手启动时会把系统复位住,通过 DTR状态切换下即可。然后设置好波特率等参数后,串口助手上即会收到串口发送过来的信息。(串口助手上先勾选下标号 1 DTR 框,然后再取消勾选)如下图所示:
微信图片_20220626182401.png

5 [" u0 I6 a. G0 ~4 A  u  Q
    我们配的遥控器所有键的地址码与反码都是相同的,不同的是控制码和控制反码,其实知道了控制码就知道了控制反码,所以如果要使用红外遥控控制其他设备,可以通过区分控制码来实现。

+ Z4 n! C4 g1 U) @* P' u$ y
收藏 评论0 发布时间:2022-6-26 18:24

举报

0个回答

所属标签

相似分享

官网相关资源

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