STM32CUBEME--自定义红外NEC解码,定时器TIM捕获方式 概述 本篇文章主要介绍如何使用STM32CubeMX对红外波形进行解码,并通过串口打印。. h& C, _# y! _ t+ q9 @
/ g. Z. @! V5 `* w; a; J" c
3 T8 v7 z* O+ {1 j$ G硬件准备 首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:
& }: Z6 _; f: S1 u. y) Q6 M选择芯片型号 使用STM32CUBEMX选择芯片stm32f030r8,如下所示:
. l- r8 y0 `' J7 P配置时钟源 HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:
" ?2 i d5 i$ a配置时钟树 STM32F0的最高主频到48M,所以配置48即可:4 F9 G3 J5 S" L
串口配置 本次实验使用的串口1进行串口通信,波特率配置为115200。1 K- D1 c. k" @) y4 @1 h
定时器配置 本次使用定时器1的通道2进行检测,配置入下。" e4 B4 t4 Z7 ]9 t
红外接收管 这里使用VS838的接收管,如下所示:! I: A5 R! y6 X# q# {
红外编码 这里使用VS838的接收管,如下所示:
9 t3 n0 I2 v4 L# uNEC协议载波:38khz* I) j5 q/ l5 z! M+ W: B
# R) ]; p2 v! P; g* B# D
, u3 m* W9 A! T5 \自定义红外编码 本文中数据1的低占空比设置为1120us,总时间为1.68ms,不是上图的2.25ms。
' k1 ~7 }0 B2 Q e& k3 B 协议如下:
1 a, x# k/ u: L0 [+ `8 z生成工程设置 注意在生产工程设置中不能出现中文,不然会报错。
6 j+ k& P' U8 d- U/ a代码生成设置 最后设置生成独立的初始化文件:- ?0 r$ R" i7 a; [
生成代码 配置keil 在main.c中,添加头文件,若不添加会出现 identifier "FILE" is undefined报错。
# l! w' W) k' _) x8 b) V( t( O1 ]
" `% D3 C& g. `8 k, w3 r- /* USER CODE BEGIN Includes */
$ @# ~) b1 K0 ^$ v* ?! S7 z% o - #include "stdio.h"
5 `% W l' a3 b - /* USER CODE END Includes */
复制代码 红外接收口定义 。4 q# }- y; g0 r: s
* \8 a5 q' S7 k o8 Z- [- /* USER CODE BEGIN PTD */
7 C0 d. c$ Z4 H; \& d - #define IR_IN1 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_9)
0 F) j5 G: r9 L# D - /* USER CODE END PTD */
复制代码 函数声明和串口重定向:3 k, S7 K' q1 ?: H$ I
, a9 \' L: {0 I: `8 Q3 l- /* USER CODE BEGIN PFP */
% ]" y0 w& e/ u3 U0 q A# f - #ifdef __GNUC__
: ~" Z2 N0 I0 R0 X$ F - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)3 v, O+ y$ z" K
- #else
( C7 ]/ O; y9 J1 t - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
- Z+ V, y+ {* x: @* g" w& t - #endif /* __GNUC__ */
5 P7 t* @1 L3 o4 Q2 V - PUTCHAR_PROTOTYPE
' K0 U! T+ V" o - {
* Y/ K0 b: S" c& o) N% @ - HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);+ c: M% y# b3 j& z3 n8 a2 z
- return ch;6 Z" S; N# K; j7 ]* C, _
- }. P. {: c2 T. C* p7 Y
- /* USER CODE END PFP */
复制代码 定时器配置:: r. g" [' m9 y# @: ?2 s
- /* USER CODE BEGIN 2 */+ z0 W( m+ t/ Z
- HAL_TIM_Base_Start_IT(&htim1);//启动定时器
+ f! M7 i& z) ^$ A+ b - HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_2);//函数用于使能定时器某一通道的输入捕获功能,并使能相应的中断9 Y; u2 H- |7 g# j# \4 b! d" M; B
- printf("IR Capture !! \r\n");+ g1 r3 o! _. U6 u. i6 x
- /* USER CODE END 2 *
复制代码 红外接收代码' Z |2 c4 H# m. W6 P& p1 ]
' E# r, N2 U! ^* O& Z# ~ ^, j) I7 z; O5 C/ r! P) U* W3 J
[4400,5000]是用于捕获4.5ms的信号
) G9 E% J" W# T0 X5 r6 h# r( }& D I, J6 ]+ \, f
* R c& u1 L4 F5 o4 C6 `7 i8 e; d[550,700]是用于捕获560us的数据0信号3 n; F9 \" m1 W! Q& Z1 @
A+ \7 R* _% Y. ]& Q$ j
- e- V$ [) E7 n* S6 e[1100,1250]是用于捕获1120us的数据1信号
, u: J0 {5 F. R& Y& b+ q/ N" ]/ H( n& y. E, l( K
- I9 Z- J, t. m. v
[2000,2500]是用于捕获2240us的截止位信号
0 Q. a8 C. n, f3 x$ S( N6 x0 x- ' S" Y) S+ S r5 h$ S5 I
- /* USER CODE BEGIN 4 */
+ M% n- [, K e+ a+ N" @/ y* n' M - // 捕获中断回调函数,每次捕获到信号就会进入这个回调函数
) j3 @& ~% k4 b* @3 d) U) z2 ?# T - void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
6 a; ~; a, D) c" K4 e5 Q - {
9 j/ e- T) j! Z! G& X7 r" q6 Q - uint32_t fallingCount = 0 ; // 下降沿计数
/ Y- x" }2 D/ \' p) r - uint8_t temp = 0 ;
e8 \( C. t8 b6 t# r' N& L p - // 判断是否是定时器1的外部捕获口26 H" c8 a1 Y2 u6 N
- if(htim->Instance == TIM1)
" m# A8 Y* n+ a7 i- p, @ - {
, O3 k$ H p9 i7 X& U; K6 | - // 捕获到了上升沿
\+ J' b, K, y+ a- m* Y$ H - if(IR_IN1)- r) k/ J6 } B+ A
- {
' q7 j9 `1 B2 V7 q4 w) a - __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING); // 改变捕获极性为下降沿捕获4 F& }/ l. c! s1 G
- __HAL_TIM_SET_COUNTER(htim, 0); // 计数清零,从头开始计
- J! T3 W# N6 R' Y - }
6 v, }0 w. Z- u - else
& U& s2 w. e6 P P, Q4 ]* J/ B - {
5 `$ U/ b. {0 s6 w - fallingCount = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2); // 读取捕获计数,这个时间即为上升沿持续的时间! N( c0 ^% E7 O1 {* o2 q
- __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING); // 改变捕获极性为上升沿捕获; v: U7 t: T; S! n
- if( ((fallingCount > 4400) && (fallingCount <5000))) % l3 D# {( ]& x3 m% r! {5 f
- OK = 1;/// 4.5ms引导电平6 Q5 p* r: g: i* w' F
- else if (((fallingCount > 550) && (fallingCount < 700)))
" j6 t$ }$ Z3 ~ - {
' ]+ [) W0 x! L, N - temp = 0;//560 us,数据为0
J+ b5 L: c5 d7 i4 X' m - }
7 { V% Y# z! k8 ^4 \) ~ - else if (((fallingCount > 1100) && (fallingCount < 1250)))
+ m9 v7 N! c& c. Y2 }. p+ z$ w9 N - {: h5 W3 h: A7 {/ P
- / v" I( i9 s# V3 j( J% W( U# Z% S
- temp = 1;//1120 us,数据为1
, K2 `+ d5 j, r - }" e; X" M# R- q. V+ [' m' [
, E( g* Q) Q) i& H9 y7 |9 l6 {& l- else if (ReadyFlag==0&& ((fallingCount > 2000) && (fallingCount < 2500))) //2.240ms截止码) a9 k9 s2 l; e
- {
; [9 H5 g! a1 b - ReadyFlag = 1 ;+ m3 z% d3 N- I8 z+ C# y
- OK = 0;* b* T, G: z5 m
- }" R+ E) {. \& {6 X l
- if(OK)$ W# z; Z( n \* I9 B
- {
! e# R8 T8 g7 B" w, j) K$ |2 o' t4 V - OrderData <<= 1 ;
( D1 w5 b8 b* l, s% O" Y* @* v7 h - OrderData += temp ;6 {- {& Q0 E8 h! i: a9 |# ^& R
- KeyCount = 0; // 按键次数( i9 s# r* P N9 m
- }
5 l! Z- n. z/ z- U2 R4 ? - }8 M, d" Y4 t9 E( ^# c
- }
% p0 ]0 V" o8 x) L7 C0 _7 S - }
- Y# c3 z5 u. ~, j - /* USER CODE END 4 */
复制代码 主函数。
4 a" K3 O5 F3 q C; a2 Z$ H- /* USER CODE BEGIN WHILE */
$ I' ^" o V1 \ {/ ~' | - while (1)4 ~3 y* \( u" A5 K# ?
- {$ u }9 J" q- @
- /* USER CODE END WHILE */# B9 o6 f- p; K+ I
) |/ W1 ^3 u% Y5 L9 R- H0 b- /* USER CODE BEGIN 3 */
! s8 f8 C$ v5 i/ Z5 b% @6 Z t- S+ M - if(ReadyFlag)
; n0 k0 j6 X/ a; m - {
- i6 s: {4 v& y5 R3 A8 L Q/ D - printf("order=%08X , code=%d\r\n",OrderData,OrderData);$ w+ n& a" K8 p4 k( k' U; t
- OrderData = 0;5 L. u) T1 K6 ]# h- E5 c) P
- OK = 0;
/ n9 s' J/ l$ h. B! B% P - ReadyFlag = 0; 1 R$ j0 C# d" ^% I
- }
4 n, E3 r- X! G - }
复制代码演示效果 红外连续发送5次码值,发送分别为:
& j2 r8 c; e b; h
, J6 _( h5 \1 q7 `/ o
- z, O; F3 P! N1 A H1011(11)
, u: Z, g) y" n3 Y5 X* J11 1010(58)) j T7 c% H' ?/ I0 k; Q( O( \1 t
11 0001(49)
9 D) x/ p* ^# P/ {11 1111(63)
/ f% {( e9 |3 g/ g2 K11 0011(51)
' ?# X+ W# l. J) P! v8 |, N 分别如下所示:1 G( h2 i, R& `4 A% \
9 o" n Z' x8 G
9 ]& ], c0 v3 w, z. b' c X% |, [8 z
2 l" G' A/ v, b
, B% H/ o. B$ h4 z, l3 }0 a( A. U |