一、模块来源
二、规格参数
三、移植过程
我们的目标是将例程移植至MSPM0G3507开发板上【能够实现红外信号接收的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
1、查看资料
在光谱中波长自760nm至400um的电磁波称为红外线,它是一种不可见光。红外线通信的例子我们每个人应该都很熟悉,目前常用的家电设备几乎都可以通过红外遥控的方式进行遥控,比如电视机、空调、投影仪等,都可以见到红外遥控的影子。这种技术应用广泛,相应的应用器件都十分廉价,因此红外遥控是我们日常设备控制的理想方式。
红外线的通讯原理
红外光是以特定的频率脉冲形式发射,接收端收到到信号后,按照约定的协议进行解码,完成数据传输。在消费类电子产品里,脉冲频率普遍采用 30KHz 到 60KHz 这个频段,NEC协议的频率就是38KHZ。 这个以特定的频率发射其实就可以理解为点灯,不要被复杂的词汇难住了,就是控制灯的闪烁频率(亮灭),和刚学单片机完成闪烁灯一样的意思,只不过是灯换了一种类型,都是灯。
接收端的原理: 接收端的芯片对这个红外光比较敏感,可以根据有没有光输出高低电平,如果发送端的闪烁频率是有规律的,接收端收到后输出的高电平和低电平也是有规律对应的,这样发送端和接收端只要约定好,那就可以做数据传输了。
红外线传输协议可以说是所有无线传输协议里成本最低,最方便的传输协议了,但是也有缺点,距离不够长,速度不够快;当然,每个传输协议应用的环境不一样,定位不一样,好坏没法比较,具体要看自己的实际场景选择合适的通信方式。
NEC协议介绍
NEC协议是众多红外线协议中的一种(这里说的协议就是他们数据帧格式定义不一样,数据传输原理都是一样的),我们购买的外能遥控器、淘宝买的mini遥控器、电视机、投影仪几乎都是NEC协议。 像格力空调、美的空调这些设备使用的就是其他协议格式,不是NEC协议,但是只要学会一种协议解析方式,明白了红外线传输原理,其他遥控器协议都可以解出来。
NEC协议一次完整的传输包含: 引导码、8位地址码、8位地址反码、8位命令码、8位命令反码。这里我们主要讲解如何接收红外发送端发送的NEC协议内容。
引导码:由9ms的低电平+4.5ms的高电平组成。
4个字节的数据: 地址码+地址反码+命令码+命令反码。 这里的反码可以用来校验数据是否传输正确,有没有丢包。
重点: NEC协议传输数据位的时候,0和1的区分是依靠收到的高、低电平的持续时间来进行区分的。这是解码关键。
数据发送0码:0.56ms低电平+ 0.56ms的高电平。
数据发送1码:0.56ms低电平+1.68ms的高电平
所以,收到一个数据位的完整时间表示方法是这样的:
收到数据位0: 0.56ms低电平+ 0.56ms的高电平
收到数据位1: 0.56ms低电平+1.68ms的高电平
还有一个重复码,它是由一个 9ms 的低电平和一个 2.5ms 的高电平组成。当一个红外信号连续发送时,可以通过发送重复码的方式快速发送。
2、引脚选择
+ | 3V3 |
- | GND |
DAT | PA07 |
接下来我们配置 SYSCONFIG
- 双击 empty.syscfg 文件,打开它。
- 点击 ADD 添加GPIO配置
- 配置GPIO
Ctrl + S
保存配置文件然后点击编译(可能会报错,我们不用管!)
- 然后我们所有设定的引脚和功能就会在 ti_msp_dl_config.h 中定义。因为这个文件我们包含进了 board.h 所以我们只需要引用 board.h 即可。【这里的 board.h 就充当了芯片头文件的作用】
3、代码编写
我们在 BSP文件夹
中新建inc和src文件夹,新建两个文件 bsp_ir_receiver.c
和 bsp_ir_receiver.h
,并且将头文件路径添加到编译器中。
在文件bsp_ir_receiver.c中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#include "bsp_ir_receiver.h"
#include "stdio.h"
typedef struct INFRARED_DATA{
uint8_t AddressCode; //地址码
uint8_t AddressInverseCode; //地址反码
uint8_t CommandCode; //命令码
uint8_t CommandInverseCode; //命令反码
}_INFRARED_DATA_STRUCT_;
_INFRARED_DATA_STRUCT_ InfraredData;
//红外初始化
void infrared_config(void)
{
NVIC_EnableIRQ(GPIO_INT_IRQN);//开启按键引脚的GPIOA端口中断
}
//获取红外低电平时间
//以微秒us作为时间参考
void get_infrared_low_time( uint32_t *low_time )
{
uint32_t time_val = 0;
while( GET_OUT == 0 )
{
if( time_val>= 500 )
{
*low_time = time_val;
return;
}
delay_us(20);
time_val++;
}
*low_time = time_val;
}
//获取红外高电平时间
//以微秒us作为时间参考
void get_infrared_high_time(uint32_t *high_time)
{
uint32_t time_val = 0;
while( GET_OUT == 1 )
{
if( time_val >= 250 )
{
*high_time = time_val;
return;
}
delay_us(20);
time_val++;
}
*high_time = time_val;
}
/******************************************************************
* 函 数 名 称:guide_and_repeat_code_judgment
* 函 数 说 明:引导 和 重复 码 判断
* 函 数 形 参:无
* 函 数 返 回:1:不是引导码 2:重复码 0:引导码
* 作 者:LC
* 备 注:以20微秒us作为时间参考
引导码:由一个 9ms 的低电平和一个 4.5ms 的高电平组成
重复码:由一个 9ms 的低电平和一个 2.5ms 的高电平组成
******************************************************************/
uint8_t guide_and_repeat_code_judgment(void)
{
uint32_t out_time=0;
get_infrared_low_time(&out_time);
//time>10ms time <8ms
if((out_time > 500) || (out_time < 400))
{
return 1;
}
get_infrared_high_time(&out_time);
// x>5ms 或者 x<2ms
if((out_time > 250) || (out_time < 100))
{
return 1;
}
//如果是重复码 2ms < time < 3ms
if((out_time > 100) && (out_time < 150))
{
return 2;
}
return 0;
}
//红外数据是否正确判断
uint8_t infrared_data_true_judgment(uint8_t *value)
{
//判断地址码是否正确
if( value[0] != (uint8_t)(~value[1]) ) return 0;
//判断命令码是否正确
if( value[2] != (uint8_t)(~value[3]) ) return 1;
lc_printf("%x %x %x %x\r\n",value[0],value[1],value[2],value[3]);
//保存正确数据
InfraredData.AddressCode = value[0];
InfraredData.AddressInverseCode = value[1];
InfraredData.CommandCode = value[2];
InfraredData.CommandInverseCode = value[3];
return 0;
}
//接收红外数据
void receiving_infrared_data(void)
{
uint16_t group_num = 0,data_num = 0;
uint32_t time=0;
uint8_t bit_data = 0;
uint8_t ir_value[5] = {0};
uint8_t guide_and_repeat_code = 0;
//等待引导码
guide_and_repeat_code = guide_and_repeat_code_judgment();
//如果不是引导码则结束解析
if( guide_and_repeat_code == 1 )
{
lc_printf("err\r\n");
return;
}
//共有4组数据
//地址码+地址反码+命令码+命令反码
for(group_num = 0; group_num < 4; group_num++ )
{
//接收一组8位的数据
for( data_num = 0; data_num < 8; data_num++ )
{
//接收低电平
get_infrared_low_time(&time);
//如果不在0.56ms内的低电平,数据错误
if((time > 60) || (time < 20))
{
return ;
}
time = 0;
//接收高电平
get_infrared_high_time(&time);
//如果是在1200us<t<2000us范围内则判断为1
if((time >=60) && (time < 100))
{
bit_data = 1;
}
//如果是在200us<t<1000us范围内则判断为0
else if((time >=10) && (time < 50))
{
bit_data = 0;
}
//groupNum表示第几组数据
ir_value[ group_num ] <<= 1;
//接收的第1个数为高电平;在第二个for循环中,数据会向右移8次
ir_value[ group_num ] |= bit_data;
//用完时间要重新赋值
time=0;
}
}
//判断数据是否正确,正确则保存数据
infrared_data_true_judgment(ir_value);
}
//获取红外发送过来的命令
uint8_t get_infrared_command(void)
{
return InfraredData.CommandCode;
}
//清除红外发送过来的数据
void clear_infrared_command(void)
{
InfraredData.CommandCode = 0x00;
}
void GROUP1_IRQHandler(void)//Group1的中断服务函数
{
//读取Group1的中断寄存器并清除中断标志位
switch( DL_Interrupt_getPendingGroup(DL_INTERRUPT_GROUP_1) )
{
//检查是否是GPIOA端口中断,注意是GPIO_INT_IIDX,不是GPIO_OUT_IIDX
case GPIO_INT_IIDX:
if( GET_OUT == 0 )// 如果是低电平
receiving_infrared_data(); //接收一次红外数据
break;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
在文件bsp_ir_receiver.h中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#ifndef __BSP_IR_RECEIVER_H__
#define __BSP_IR_RECEIVER_H__
#include "board.h"
#define GET_OUT ( ( ( DL_GPIO_readPins(GPIO_PORT,GPIO_DAT_PIN) & GPIO_DAT_PIN ) > 0 ) ? 1 : 0 )
void infrared_config(void);
uint8_t get_infrared_command(void);
void clear_infrared_command(void);
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
四、移植验证
在empty.c中输入代码如下:
#include "ti_msp_dl_config.h"
#include "board.h"
#include "bsp_ir_receiver.h"
int main(void)
{
SYSCFG_DL_init();
// 红外接收初始化
infrared_config();
lc_printf("\nInfrared Demo Start!!!\r\n");
while (1)
{
//如果按下遥控的【1】键
if( get_infrared_command() == 0xA2 )
{
clear_infrared_command();
lc_printf("Press [1] button! \r\n");
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
上电效果:
【代码下载】
- 跳转到
下载中心
去下载CCS模块移植代码:【点击跳转🚀】