红外接收头很常见,具体就不细说了,这里记录重点:1 h2 b6 n5 S( [' B: N, \( h
. @9 R) U L& Q- n6 i
NEC的特征
- J9 @5 H9 d6 T1:使用38 kHz 载波频率
* J3 O- w8 X8 H& P& y6 p2:引导码间隔是9 ms + 4.5 ms+ }( I0 p5 @5 L6 q: ~" |4 ]
3:使用16 位客户代码3 G4 e9 w# N, A! S* I# W9 Q. S
4:使用8 位数据代码和8 位取反的数据代码
; U& B; W7 o K
) j2 |8 P# c( g5 d; ?当发射器按键按下后,即有遥控码发出,所按的键不同遥控编码也不同。这种遥控码具有以下特征:采用脉宽调制的串行码,以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”,其波形如图所示。
+ G' W% H! [8 p1 V1 F, r) W* {. S. |
1 \' f3 ?) W9 z' }" Z
" N# w5 p+ O8 q, U4 q5 W& G+ ~
) G) h4 n" |6 r& r
8 E2 X# [# b2 Q
- @4 ]. z. T4 E& }0 n4 Y* Y! E* K: ~$ V( C+ f; T& N( y
这里我采用同一个定时器TIM3的两个通道分别用来做红外的接收和发送,接收用通道3的输入捕获,发送用通道4的输出比较,程序采用分时复用的方式完成收发一体的实验效果。默认处于接收状态,在按键触发时切换成发射状态发送红外数据,发送完成后再次默认切换成接收。* i; X2 M6 e J l- K; m- I0 w9 c2 C
1 |" u, ~; U4 n, N7 D) H4 C
上接收部分的代码:! d, W, A8 S! A; W- Z
) E, W3 y6 s4 u1 [& V" r2 r- #define NEC_HEAD (u16)(4500)
* p7 G, |% g( \* S% Q; `6 y2 p1 i0 G E3 n - #define NEC_ZERO (u16)(560)
: E7 f: j0 y1 D& D; ^: i - #define NEC_ONE (u16)(1680)
7 Z+ P8 q1 p( |& w$ K - #define NEC_CONTINUE (u16)(2500)- n( _5 W: U" \# K8 E/ ]
0 L) L4 x! N/ ?. T& A1 N9 y- #define NEC_HEAD_MIN (u16)(NEC_HEAD*0.8f)
. O, c$ g9 Y# v$ S4 j - #define NEC_HEAD_MAX (u16)(NEC_HEAD*1.2f)
H4 ~) ^8 D6 F" }. F- Z+ E, d - 4 t/ G& r! T0 G' Q
- #define NEC_ZERO_MIN (u16)(NEC_ZERO*0.8f)
5 {4 [$ Z0 g1 G8 |$ G - #define NEC_ZERO_MAX (u16)(NEC_ZERO*1.2f)
" N6 ]5 x7 m# D" O4 J - ; Y8 N0 k, _0 T: t! A7 e0 R* E
- #define NEC_ONE_MIN (u16)(NEC_ONE*0.8f)# O2 p. N, y6 |# k0 {) j- g2 }. }4 P
- #define NEC_ONE_MAX (u16)(NEC_ONE*1.2f); G& O- v1 U7 D) I( m) L
- + ]! n. M$ w* O- B h s- {% l* b+ Z- D7 o
- #define NEC_CONTINUE_MIN (u16)(NEC_CONTINUE*0.8f)
( \- g' T& b! M1 f7 N - #define NEC_CONTINUE_MAX (u16)(NEC_CONTINUE*1.2f)
8 P5 S* p7 c, s0 v$ l0 n - - {) S: q& J" f8 Q4 q' t, f- B* S* H
- 2 _1 I# ^+ j$ y( l# t
- //红外遥控接收初始化
; t5 j. S( M7 P; L5 a& G7 n6 R - void NEC_RX_Configuration(void). I% g+ |0 Q9 K
- {, T9 a) ~, E- E$ i2 k3 C3 f
- GPIO_InitTypeDef GPIO_InitStructure;) }4 p( |8 L, r! z, D
- NVIC_InitTypeDef NVIC_InitStructure;
: ~/ T/ N' F& E& x - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
5 F4 ~7 V, Y! Z, e6 f8 M+ o: g - TIM_ICInitTypeDef TIM_ICInitStructure;//输入捕获
5 M: k: S# S% g9 k, D+ s+ t- i7 O r - 1 H% ~( J! J; G0 V* X
- RCC_APB2PeriphClockCmd(NEC_RX_RCC|NEC_TX_RCC,ENABLE); //使能PORT时钟% ^0 r* B+ d2 L3 ?1 G/ ]+ }' N* l
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //TIM3 时钟使能
( @7 U0 R5 {% I% p9 o" w; F - ; J2 P, p& u' M! p
- GPIO_InitStructure.GPIO_Pin = NEC_RX_PIN;
0 |0 R( K5 _ a - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 上拉输入
4 C, A3 R, E. o y* q7 p; w3 ]* q - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;& O# p0 U) |. j7 @$ z
- GPIO_Init(NEC_RX_PORT, &GPIO_InitStructure);" u& `) t$ E% d3 G
, `4 m# Q; E K- e+ }3 F- GPIO_InitStructure.GPIO_Pin = NEC_TX_PIN; + n/ p" J; @' B+ r" z, V& ~6 }
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
' b" ~6 b4 |1 A1 e6 b - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;) h" d. P, [" e2 u) M) B
- GPIO_Init(NEC_TX_PORT, &GPIO_InitStructure);! |3 y+ T- R! r w9 U" a
" F! Z4 [4 M: C% Y6 L' H- TIM_TimeBaseStructure.TIM_Period = 10000; //设定计数器自动重装值 最大10ms溢出
0 ~+ r8 P/ F @ - TIM_TimeBaseStructure.TIM_Prescaler =71; //预分频器,1M的计数频率,1us加1.7 y5 e. ]& Q! Z# H6 L8 e6 l. c: ^
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
2 h# w; O8 D6 @: g; R3 t - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
' T' Z3 W# u4 O4 V8 w3 d - TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx3 k& a. F6 ~/ d( I# {+ U
- , z* B, [! `8 }5 i- Z
- TIM_ICInitStructure.TIM_Channel = TIM_Channel_3; // 选择输入端 IC3映射到TI3上
. g4 m# G \' K; y- p" @ - TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获2 r, R7 z3 x. l8 Y/ v# J
- TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;7 W! |5 f/ t K* Z3 N D2 D
- TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
0 U7 Y0 m* w, }5 F% H& J - TIM_ICInitStructure.TIM_ICFilter = 0x03;//IC4F=0011 配置输入滤波器 8个定时器时钟周期滤波
2 d: }! o) x. _- w1 B8 T6 \* X - TIM_ICInit(TIM3, &TIM_ICInitStructure);//初始化定时器输入捕获通道& ?& X* [+ y3 s$ |. z
- 2 y/ i' o/ c* m4 K
- NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
* i3 B* q. r# o5 F+ z. E0 q2 u - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级' o& `: x& n: ]% h4 L
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级; t. V4 H5 e8 B) g3 ^; o
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
1 B! Q+ p6 ~4 j5 V - NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
( D C$ r+ j6 j - 1 g9 N' f2 j7 p7 V# x1 [ H5 [
- TIM_ITConfig( TIM3,TIM_IT_Update|TIM_IT_CC3,ENABLE);//允许更新中断 ,允许CC3IE捕获中断
' A4 a5 @: A( ^3 Y4 g5 Y( ]8 t% I - , K$ C$ z p; \4 f8 C
- TIM_ARRPreloadConfig(TIM3,ENABLE); //重装载9 L) \6 z( R$ A" ~% ^
- # ` [* {; x3 m1 d
- TIM_Cmd(TIM3,ENABLE ); //使能定时器3+ l& \6 C) y0 e- ?- s
- }6 m( x# b! n+ [0 N+ k, U, ~7 C
& Q2 [: v" E b; b9 [: P- //遥控器接收状态
7 J' X) Z7 N, Q* E# e' D- R* V) P - //[7]:收到了引导码标志
# e' |7 k- {- O* A, M3 v* h# i - //[6]:得到了一个按键的所有信息! c' V3 q7 K$ X9 ?/ U9 Y
- //[5]:保留7 U, t( y3 q9 z4 m( t- m2 ~
- //[4]:标记上升沿是否已经被捕获7 x7 d, W J2 v, P C6 V1 a
- //[3:0]:溢出计时器
4 E$ J$ ]1 q( t; O, R, _ o - u8 RmtSta=0;, a L- m. E- p }
- u16 Dval; //下降沿时计数器的值
- i4 W+ W4 ~9 j7 X - u32 RmtRec=0; //红外接收到的数据
/ s9 @& v- r4 {3 v1 B3 E4 _ - u8 RmtCnt=0; //按键按下的次数
/ k9 n8 e1 j1 N) w; f - //定时器4中断服务程序
% E. Q0 U9 _& c* L& \3 t; I' C1 \9 ] - void TIM3_IRQHandler(void). y# W! }. W7 s/ O L- }
- {) h; o, u5 t, | }
- if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET) //更新中断
) p5 x) q9 O, p: n7 G+ l& P4 m - {' x% P; S, C; G9 O" a0 @7 G! w
- if(RmtSta&(1<<7)) //上次有数据被接收到了
9 [" v% ?3 b: c2 R- i - {
( ?: ^1 a$ t: p: F! k3 J! o/ @ - RmtSta&=~(1<<4); //取消上升沿已经被捕获标记8 N, N! u$ O3 H1 d* i
- if((RmtSta&0X0F)==0X00)RmtSta|=1<<6; //标记已经完成一次按键的键值信息采集
3 H( \! `& y- z# P' u3 A - if((RmtSta&0X0F)<14)RmtSta++;
: Z6 |9 u5 g* T+ P) p' ? - else- o3 C2 O! S* W9 q; O9 Z) g% u
- {0 ~# s2 t' J* [
- RmtSta&=~(1<<7); //清空引导标识
4 k# W( c8 I: a( e - RmtSta&=0XF0; //清空计数器2 a6 x# i |' z
- }) K! H3 L5 y0 @3 `) k
- }+ t y1 k% U$ e _; G* F. E
- }
3 B: W, Q, E/ w& M' [ - if(TIM_GetITStatus(TIM3,TIM_IT_CC3)!=RESET)3 k+ G0 {5 U1 h1 i& J, q
- {
_6 W8 Q2 I% M+ \( j: \ - if(NEC_READ_RX())//上升沿捕获 z- L+ H" L D x8 v
- {
8 P* i" Y4 m3 p; }+ c0 A - TIM_OC3PolarityConfig(TIM3,TIM_ICPolarity_Falling); //CC3P=1 设置为下降沿捕获
* Y* F* J4 i# r" H" S6 L/ K - TIM_SetCounter(TIM3,0); //清空定时器值9 Q, f! P3 p4 I) G0 t3 s
- RmtSta|=(1<<4); //标记上升沿已经被捕获: `; K& \; _. U, E% s: w
- } 0 M" f3 R* H& N& _
- else //下降沿捕获
% N. l5 ^1 L) i- X1 ?0 z - {
- S; V V: p' O( v; y - Dval=TIM_GetCapture3(TIM3); //读取CCR3也可以清CC3IF标志位 U$ A# N; |3 N
- TIM_OC3PolarityConfig(TIM3,TIM_ICPolarity_Rising); //CC3P=0 设置为上升沿捕获
, Z H& X- A. _1 N! o - if(RmtSta&0X10) //完成一次高电平捕获9 Z, M3 F' @% k( [$ _' ^# Y0 v
- {
- I# n$ m, W$ A1 n2 V" H/ x, v$ X - if(RmtSta&(1<<7))//接收到了引导码
1 c6 o5 ~( ?4 f$ p* L2 z - {
; Z9 B% K3 x, x9 ~ - if(Dval>NEC_ZERO_MIN && Dval<NEC_ZERO_MAX){ //560为标准值,560us
6 S, u/ e& J; a( S% ` - 3 l0 {5 z8 {( r! A
- RmtRec<<=1; //左移一位.# s, ]# t' l/ A N( g1 i9 P
- RmtRec|=0; //接收到0
0 i0 E t% A& ?# T$ T/ N M - } 6 b9 V& _1 e f& J. R8 F" O/ y
- else if(Dval>NEC_ONE_MIN && Dval<NEC_ONE_MAX){ //1680为标准值,1680us
+ j4 @5 r0 m3 D d2 q% S- t
W" B7 ]; u4 N4 r- RmtRec<<=1; //左移一位.0 v8 ~7 w# i9 W- B* Z: b% B
- RmtRec|=1; //接收到1% I% A) Y1 R) n$ r9 Y; v
- }
% x+ D3 ]4 Y) z% n5 e R- P. Z - else if(Dval>NEC_CONTINUE_MIN && Dval<NEC_CONTINUE_MAX){ //得到按键键值增加的信息 2500为标准值2.5ms' r; ?- x o/ u# i: V; _
; ]( ~) w( O$ j m7 m, k2 V- RmtCnt++; //按键次数增加1次
/ {; o. @9 t) l6 d6 z8 _. X - RmtSta&=0XF0; //清空计时器
! c, K* Z; ^8 a, d6 T8 a7 {( O - }2 n0 h8 E# B# R0 V7 t% w
- } ; j1 q) Q: u! G+ ?
- else if(Dval>NEC_HEAD_MIN&&Dval<NEC_HEAD_MAX) //4500为标准值4.5ms
2 q2 s% ] R; i, z+ c - {
" L* {% D6 D; q( M - RmtSta|=1<<7; //标记成功接收到了引导码; V3 h. C! y) ]; W2 ]1 O ` d
- RmtCnt=0; //清除按键次数计数器
: {+ x2 ^) Y7 g0 S6 F& s - }) Q0 g, H3 k6 j2 W+ T# y ^7 ~
- }
7 f9 B* [6 ?9 b# [% s, U/ ? y - RmtSta&=~(1<<4);
, z2 s! p3 z6 A8 P# B3 A - }" e# w! Q/ ^. }- _* F0 i& a4 [
- }
7 E- ]7 Y0 ?6 O; p) r1 l - TIM_ClearITPendingBit(TIM3,TIM_IT_Update|TIM_IT_CC3);
/ l6 j$ @* C0 `7 E - }
$ g8 V( N6 z3 E8 V& Q8 D - 8 E" V0 g& w0 Q; ]! j0 Y3 s
- void NEC_GetValue(u16 *addr,u16 *value)6 M3 y1 |2 `9 ^
- {
% m! F! k* W# C - u8 t1,t2;
7 s2 |! {. y& r. S) ]! q* T \ - *addr = 0;
D% G2 W7 `+ _% N5 _! v6 Z - *value = 0;! T, X: }! \* J/ i9 T. a5 t
- if(RmtSta&(1<<6)){ //得到一个按键的所有信息了) }! H3 Y. P+ J! ^# [, p7 _, D
- 2 t7 [8 K" D. ^! k
- t1=RmtRec>>24; //得到地址码
9 N, k* W+ _/ s; [- T - t2=(RmtRec>>16)&0xff; //得到地址反码/ P2 c2 }" P' e+ j, d9 v
- if(t1==(u8)~t2) { //检验遥控识别码(ID)及地址
% u. w0 p7 e0 t( A9 M - 2 D) X2 ?2 i4 n8 l8 m: a
- *addr = (t1<<8) | (t2);: N3 {3 I- g7 | I* \- w
- t1=RmtRec>>8;
1 R: q0 L; l; K! A* k7 l6 M - t2=RmtRec;$ O2 _; I" }$ m7 H" |" f3 A3 z
- if(t1==(u8)~t2){ 1 b4 o6 D! H7 C7 N! r3 A
- *value = (t1<<8) | (t2);
+ ?! R. p+ q2 B* P0 |/ o% g a- u - }& U0 m& m7 X/ G+ R: U% c
- else{
! E, O8 O+ K# z; y2 o6 [ - *addr = 0;
4 P, d5 M3 _" E7 d - *value=0;
& G0 Z5 j: I! |% t7 l - }
% }3 S# e0 ^6 T7 F4 [$ u - }+ y& q( S- t9 c5 b) b& a7 `) q; Q" U
- if((*value==0)||((RmtSta&(1<<7))==0)){//按键数据错误/遥控已经没有按下了/ I" L% a& x! ?
- 8 f j: m1 x7 j6 B
- RmtSta&=~(1<<6);//清除接收到有效按键标识; I- ]( b5 A" T/ W. i0 W3 s
- RmtCnt=0; //清除按键次数计数器& k8 }- e; \2 v5 K$ }
- }
! V- N% k b( \. _2 M5 b; c - }+ a6 j% y l! \9 ~$ Z6 h1 f
- }
复制代码
5 o+ |4 u. i7 M7 |& i" v接收部分在配置上比较简单,配置一个1us计数拼了,周期为10000(也就是10ms)的计数器,同时开启更新中断和捕获中断,
$ u- s. q) r& F! N
) ?$ |' o, E* A1 E0 J在更新中断,和捕获中断里面分别对接数据进行处理,这里要提一下就是捕获中断分上升沿捕获和下降沿捕获,在捕获到某一个电平后需要更新一下捕获的中断源。在每一次捕获的同时对时间间隔进行判断,判断的结果有引导码、数据码、重复码等,这里就不多解释了。5 W m- D0 d4 r& X+ w' G
1 R8 Z$ a2 P, m5 k
上发射部分代码:, b3 E: ]; {' \3 Z' i' Z/ }' p
8 P5 C0 O1 |& b1 j3 q# {- /****************************************************************************************/ A6 N6 o; P( b0 {; E: A& l
- #define CARRIER_38KHz() TIM_SetCompare4(TIM3,9)
5 ], b- i) I L0 { - #define NO_CARRIER() TIM_SetCompare4(TIM3,0)- ?/ o; J# a0 x3 ~& ~
- ! v+ W8 @. f& q
- void NEC_TX_Configuration(void) //红外传感器接收头引脚初始化
1 k5 B1 L' j2 x; v2 d - { U3 p$ ], j" @
- GPIO_InitTypeDef GPIO_InitStructure;
& D b" q( I5 |/ q. X9 Q' T/ F
' t I7 f" {0 G7 L, p/ ^; V0 m: U- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;! |! U4 [( g: Z
- TIM_OCInitTypeDef TIM_OCInitStructure; //输出比较 3 u8 L* t6 _4 e9 T
-
) Y, l* }8 |+ ]; r9 M - RCC_APB2PeriphClockCmd(NEC_TX_RCC,ENABLE); //使能PORT时钟6 J6 g: u9 P3 U5 O8 M+ O' V; J
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //TIM3 时钟使能4 u, Q4 f- W( ?+ ?4 r
/ f) d; v) \/ q" |3 y9 n- GPIO_InitStructure.GPIO_Pin = NEC_TX_PIN;
& {# d) f- ?( L) p# i. E8 q - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出' \( }2 c1 Z' W8 Q. q( a5 k. f
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;2 W% v7 H1 v7 v8 Y [) j* b
- GPIO_Init(NEC_TX_PORT, &GPIO_InitStructure);( S, v I) F% E, \- s$ n
- % _5 k7 o8 K: `+ g' i2 m, ^
- TIM_Cmd(TIM3,DISABLE);
7 N/ y6 ~; F B7 d: E6 ` - TIM_ITConfig( TIM3,TIM_IT_Update|TIM_IT_CC3,DISABLE); //关闭TIM3中断
0 C2 `! `5 Q: B2 b' O* R
s5 _% M7 u R" p- TIM_TimeBaseStructure.TIM_Period = 25; //设定计数器自动重装值 最大10ms溢出1 X1 t) l. y/ R# M$ P, v. h
- TIM_TimeBaseStructure.TIM_Prescaler =71; //预分频器,1M的计数频率,1us加1.7 y Y4 V) N$ H; z% n
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
7 _! p- g4 j- B8 _9 A. \ - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
+ _: S" W5 B$ [# ~) A - TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
& R, C0 s6 u* G- I- {* ?
7 ]( I+ Q# t r( ]7 a- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置PWM1模式
6 p3 r1 N {. C7 v1 h - TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能" z# ]) z% e. d6 z2 K
- TIM_OCInitStructure.TIM_Pulse = 0; //设置捕获比较寄存器的值 K- O+ B1 q" t. Z
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置有效电平为高电平/ w. G% @ u/ \. m- o
- TIM_OC4Init(TIM3, &TIM_OCInitStructure); //生效初始化设置4 h3 s _$ M6 S( y) g+ X
- TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能输出比较预装载
, u, T# B7 G9 \4 ^ -
! b% O( O1 v/ G- b) T - TIM_Cmd(TIM3,ENABLE);, n2 {; n8 j5 ~3 q* V" H
- }6 t( B; d. |. L: v
: S& P- a2 L- R: e- static void NEC_Send_Head(void){4 `+ |" g5 @; C6 ?
- CARRIER_38KHz(); //比较值为1/3载波, B8 M9 t4 }+ X. n8 k% W1 h8 ^- B
- Delay_us(9000);
' @- Y/ e+ e( X+ b - NO_CARRIER(); //不载波
2 y5 w8 e/ S8 B4 q - Delay_us(4500);
- D, w5 G! P' A" K& t2 v - }8 I: k. |! X1 P( N
' b* f x" N3 L% z- static void NEC_Send_BYTE(u8 value)
+ v7 u% C) j! u L H8 c0 C - {
% U, v3 E. Y( ^- R - u8 i;
K' j; U/ u) X# m) v7 \ -
5 ~7 K1 M+ C2 e8 \- R - for(i=0;i<8;i++)+ v4 Q! J" [ Z, k; q7 |
- {; w" K$ S: e) o( |% G5 c% m+ t
- if( value & 0x80 ){- k8 |7 z, B* q# r7 M& `( m6 w5 H# p
- CARRIER_38KHz(); //比较值为1/3载波& I3 A; }8 v0 t
- Delay_us(560);
. N1 i- q$ ?- G; o9 d - NO_CARRIER(); //不载波( e9 ]: p$ D4 a! w/ E/ H w
- Delay_us(1680);. O6 p- m) @2 F, B4 A3 ~: C" ?
- }7 _0 u7 O1 l' \2 d! _
- else{
8 y# z }! a& }7 q) `4 P - CARRIER_38KHz(); //比较值为1/3载波
0 c# x6 Z8 k$ Y Q) k - Delay_us(560);
- O! g6 O4 z& R7 U+ d - NO_CARRIER(); //不载波
) F% ]" @- a& ] - Delay_us(560);
3 n9 j6 o3 r, H3 C! Y! e - }5 I+ c# b1 [$ |: b( S4 z
- value<<=1;- {, Z4 V S4 P1 G7 T, G
- }: x3 M0 }5 u4 x8 w( T
- }. O8 S2 w# l2 N, G5 E. u
! I' V# `/ o+ t( {+ r' \- static void NEC_Send_Repeat(u8 repeatcnt)
/ n9 x. |3 t7 H# j& n - {" l2 _) [1 W3 N& P O
- u8 i;
. O0 ~/ U+ a2 ^: \8 V% j4 W X$ o - $ P9 s( t5 Y& a; b3 u
- if(repeatcnt==0) //如果没有重复码就直接设置无载波,发射管进行空闲状态
6 o7 N3 j8 Z: p& t( \ - {- w- k: s J2 h3 y4 R9 g3 f
- CARRIER_38KHz();- b* c) J: X9 L1 q
- Delay_us(560);, S& ?" P/ @ M) A* y A$ M
- NO_CARRIER(); 3 M# h8 O& c! `2 U) g' C
- }- ^) a$ _( q5 r. e8 o
- else * G( B* R9 ?7 \ Q9 _
- {
6 ]6 D* ?' a: g: H - for(i=0;i<repeatcnt;++i)4 N/ e% ? ?3 S# {
- {3 j, F1 g7 z q9 q1 s9 L
- CARRIER_38KHz();- N( W! W! ]5 z$ S- D# @0 u- H
- Delay_us(560);
4 E: C4 }: j# H5 e; x! | - NO_CARRIER();
( s$ C. t" ]8 l - Delay_ms(98);0 B2 ]. g- ^" T$ e
- CARRIER_38KHz();8 h S8 J/ U4 ?) U* C; ~ D! G
- Delay_us(9000); ]$ w2 m) O. r+ l9 H( ~
- NO_CARRIER();
4 B! W: P4 c( d {# } - Delay_us(2250);
9 n( }" T v6 l t4 N0 A9 M+ V - }" _+ @8 ^ L e' }' x8 d
- 1 [5 @# v: k0 K4 M* S
- CARRIER_38KHz();
! j' Z9 R) Y+ |( u" o; n8 O - Delay_us(560);* v2 d* t# r6 b# U Z4 m
- NO_CARRIER(); * n+ r+ ~: ~0 X" u! q
- }
) Y8 S# p2 [0 F: D$ Q - }. |/ I4 a5 k# e5 _7 q- }' K
# |2 T7 W0 _- L+ C6 p5 @- + G2 [; d! O8 E# Z* _8 ]& e
- void NEC_Send(u8 addr,u8 value,u8 cnt){
5 c% l3 v0 |7 M: I - & V/ }) s8 H5 y' P! T
- NEC_TX_Configuration();2 U$ ^1 ], L9 B) |
-
% r F5 {2 A2 o( X - NEC_Send_Head(); //发送起始码+ e& [( a& O; \: T+ {
- NEC_Send_BYTE(addr); //发送地址码H
7 b+ D1 g; Q5 n1 T - NEC_Send_BYTE(~addr); //发送地址码L
6 l9 @1 A5 a7 _: r5 U1 y - NEC_Send_BYTE(value); //发送命令码H5 V* L/ ^; n; H& B) h) _7 U& l
- NEC_Send_BYTE(~value); //发送命令码L
3 C C% f% T: K5 v, L - NEC_Send_Repeat(cnt); //发送重复码
1 D/ V+ w. Z' ~7 l$ v - 3 \; [$ {5 {9 ~( i% H" Y
- NEC_RX_Configuration();
! _4 C* h/ |, N& R - }
复制代码
9 E5 p N+ s. E+ z) M发送部分首先是重新配置定时器3,在配置里面计数频率依然是1us,也就是1MHz,计数周期修改成了25,也就是26个周期(0也算一个),这样算下来的话1MHz / 26 ≈ 38.4615KHz,这个跟红外接收差不多能匹配,当然红外接收头这里用的是38K的,所以配置成38K的,市面上也有不是38K的,比如36K,40K等。然后是载波,载波这里用的是差不多1/3的载波,从哪里可以体现呢?可以看到有这样一个宏定义:- #define CARRIER_38KHz() TIM_SetCompare4(TIM3,9); P: a% A) R9 _- N
- #define NO_CARRIER() TIM_SetCompare4(TIM3,0)
复制代码 3 t8 d# M' _, p) u3 z i% _
载波的时候比较值设置的是9,没有载波的时候是0,9和26就约等于一个1/3的关系。- t( ~0 g% f: k* G6 @3 ?
! q1 g m$ [# o: u" ~ M最后就是发射部分,细节不说了,按照NEC协议进行发送,依次是引导码、地址码、地址反码、数据码、数据反码、重复码等。可以看到发射数据前后加了有NEC发送和NEC接收的配置,这里就是关键的分时部分,因为程序主要出于接收,在触发器(这里使用的按键)触发的时候才会发射红外数据。4 n& u" L" H/ U# B# g
I% p1 b& o2 j$ [% v
上述就是NEC底层部分。上层应用也贴出来以供参考
& m& t) E# H( \3 \& A% m2 U3 X+ z3 r2 V/ ~" W
6 `) F$ M. L% I) ]
- keyvalue = Key_Scan();) x" A4 ` L( e5 |8 u
- if(keyvalue != KEY_NONE){; l6 a0 ]$ W; ^3 n: m
- NEC_Send(taddr,tvalue,0);6 U$ o$ b. |+ N& y$ X( X+ Z2 \
- taddr++;: ^2 F6 |3 A2 g9 W* W) M1 h1 W
- tvalue++;; y; j- | L; e- r7 I6 l/ Y
- }
; Q8 s6 u0 z1 I b! e" G R- F$ \1 p - + }* ^% |/ y& D% B F
- NEC_GetValue(&addr,&value);
+ r1 l" ?6 n2 q# Q0 C - ( o$ N( Q$ v( J9 a0 R
- if((value>>8)){
- y. v! v: d; y4 w8 n! m5 F1 h S$ X: L - printf(" %04x,%04x \r\n",addr,value);' P4 \% u) q x. u+ z! k/ u: R2 q6 i8 K
- printf(" addr: %d,key: %d,cnt: %d\r\n",(addr>>8),(value>>8),RmtCnt);
$ I S3 a2 e. D6 P( ]0 h - Oled_ShowNum(36,32,(addr>>8),3,8,16);: N" x& p& r- ?0 e# k6 [
- Oled_ShowNum(96,32,(value>>8),3,8,16);+ Y$ a$ w& R# I. n7 e0 b2 v
- Oled_ShowNum(36,48,RmtCnt,3,8,16);4 c. k: J& l" {( h3 I9 R# l7 b
- Oled_RefreshGram();
6 v K7 F' t0 i/ w - }
9 R# u5 j3 h% l5 y$ x - 0 J8 h/ G6 p) B/ O# m& R9 x' R
- Delay_ms(10);
3 [4 Y5 h; O$ O& e - if(++t==50){
% v) |( T" K. b, l - t=0;) E( c& {. ]8 A* v- Q
- Led_Tog();+ x/ T1 w+ N- {% K( F. n& u% w
- }
复制代码
! l$ ]! |& C" j: }7 G8 _最后要说一点的就是关于系统的延时,延时部分需要慎重,此处我也是踩了一坑,也一便记录下来。4 X2 d1 Q+ {$ u5 l ~4 R
# M4 D2 c8 y* a, r# D7 H1 Q
原来的底层:) N+ B9 n- E( X$ t& v1 [2 R s
1 Q. F* v1 c7 I4 a0 y1 M+ j3 g
- //u32 System_ms=0;
8 n+ a, |; }0 \. q1 F0 B" A
3 D0 u3 ~( Z: @ ?9 p: Q/ Q- //u32 usTicks;8 a! b" ]# Z$ A6 N
- //void Systick_Configuration(void)
6 V) x4 A. x+ \/ k9 y( `! R6 j - //{
P$ F4 {0 R1 y6 v7 I6 F7 F - // RCC_ClocksTypeDef RCC_ClocksStucture;7 N& V D. {* o- s0 q" i# v4 j
- // RCC_GetClocksFreq(&RCC_ClocksStucture); $ Y$ V1 \1 b7 G) k- M* p
- // usTicks = RCC_ClocksStucture.SYSCLK_Frequency/1000000;9 y! w' d/ {; m$ p6 }) @ p
- // SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
+ C: T6 ?/ y X1 e$ M - // SysTick_Config(RCC_ClocksStucture.SYSCLK_Frequency/1000);2 a8 G, _% W& s% Q! x: @' i; w
- //}3 G& @3 K! S4 ~# ]; n* s+ @: e
- $ l4 d, S- `* [- E
- //u32 GetSystick_us(void)
8 o& g% t- D1 e6 S) Q - //{6 U8 c' O; S* K+ t0 n* B
- // register u32 ms,cycle_cnt;
( h$ [) G3 H/ { R - // do{ O/ @. W8 k+ b
- // ms = System_ms;9 ^/ ^& G; I: p( ]. N3 p
- // cycle_cnt = SysTick->VAL;" |; O& {+ E+ |6 o! o9 |
- // }while(ms != System_ms);5 c5 U; L. Y1 q
- // return (System_ms*1000) + (usTicks * 1000 - cycle_cnt) / usTicks;/ M. V( Z$ h( O" |( P
- //}/ t7 Y" n6 x& {' x2 Z0 o6 p {8 [
3 Q, _& Q- v$ }1 {4 ?- //u32 GetSystick_ms(void)
0 b7 A) j6 q/ {2 W, y - //{
4 N7 Z5 @8 K* W8 b- J1 X - // return System_ms;
8 D6 Q7 s' Z4 p+ }% [1 [ - //}/ D: x1 J Y5 }1 b% ]2 I- G9 ^7 @
- + n: a+ i7 _" q3 V4 n
- //void Delay_us(u32 nus)7 \5 I+ ?( y( J6 `- }6 h
- //{+ m5 e t5 y$ d! H4 \
- // u32 now = GetSystick_us();
' ~9 k( _, m2 E+ X% u* G; f" }8 [ - // while(GetSystick_us() - now < nus);+ D4 n' m% E) H) I7 [
- //}/ w1 n" I3 H, @5 F" X
. ?3 o6 c( q$ J/ E$ c! O- //void Delay_ms(u32 nms)
3 t! G: j- p$ v. L - //{
6 t0 U: j$ f i$ P# Q. T - // while(nms--)
( O! e! R% {2 d( A - // Delay_us(1000);0 b5 F/ Z5 |% ^
- //} A7 i" ?* j n. G4 I+ k4 s
- 0 n" n3 ^! w2 M& Q' ?& {
- void SysTick_Handler(void); A/ d8 @# c( l7 R) ]
- {$ r* O+ v: l- G% O5 v# u$ ]
- // System_ms++;
0 [% l8 r2 ?# d% p |6 @1 b* C8 Y - }
复制代码 ' T8 D5 C! h% l( y( [
这里用到的延时us和ms函数都会调用获取时基函数,这样的话ms还好一点,到us级别就不是很准,再有就是滴答中断里面也有时基去计数,再低级的中断那也是中断,会打断前台程序的运行。
2 \- M5 h, s- {( A& o$ v0 W e
% p m# c( @6 G# c' c( r7 m; g改过之后的:
9 n5 g/ A" Q' u. f1 N5 A
0 I! A2 G( ^9 ^: @8 C2 T& [) ~& r( I- void Systick_Configuration(void), ~# }4 n# {6 V1 z2 a( t' e6 A
- {
# b% _; B3 M& g U2 F - SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //设置时钟源8分频
. c, L) Q4 ]/ H8 F/ E; e - SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //使能中断
! S$ X9 t' k5 j' i- M( U - SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开定时器0 Y# p0 C5 V e4 h8 a1 y
- SysTick->LOAD = 9; //随意设置一个重装载值
5 a" \6 O! L, l/ T7 J" k- s - }5 @9 ~* r% b! Y" _9 z2 t
- 5 e# ?0 B- P2 D \
- : Y- v( m% `7 t& F4 P
- void Delay_us(u32 xus)7 ]% X! W0 R$ ]* q) g" E
- {
, Q) e; k' Y) @, X% m) F - SysTick->LOAD = 9 * xus; //计9次为1us,xus则重装载值要*9' V6 o2 Y% l6 v. [# L! Z$ a
- SysTick->VAL = 0; //计数器归零
! L6 Z% ]- I8 h% ~! s% P - while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); //等待计数完成# S' g# \ _* l4 M' B: J1 {
- }$ y+ x1 B( T7 K5 N$ m1 z
* @. O/ N: `0 ?+ P- ; f) `2 L( P: j$ `/ C
- void Delay_ms(u32 xms)
8 h' R" q Z2 X/ a; l+ T - {
, \! p8 z3 c' L- q$ h) U, h: Q - SysTick->LOAD = 9000; //计9次为1us,1000次为1ms
2 c5 t% E2 W) Y- m; ? Y9 Q+ N - SysTick->VAL = 0; //计数器归零
: V( v* K4 h# u: h* G - while (xms--)
; B" K( q8 s3 M+ U r - {
& F: x0 e4 i7 {; f4 x& m - while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); //等待单次计数完成
/ l3 _: B+ {( ^) F8 o: [ - }
6 i" `7 K" L* b! U* c! U - }
复制代码
5 r; F. g9 T1 }3 I! [- @6 O这样的话中断依然打开,但是中断里是空的,其次延时函数也因为不调用获取时基直接判断寄存器而更加精确!, G- E# k" S: v6 X) h1 }- j1 T5 k1 p
. v- v5 h) f3 U+ Y
4 \% w, D( D' ?5 G
|