标签:
家电遥控器通信距离往往要求不高,而红外的成本比其它无线设备要低的多,所以家电遥控器应用中红外始终占据着一席之地。遥控器的基带通信协议很多,大概有几十种,常用的就有 ITT 协议、NEC 协议、Sharp 协议、Philips RC-5 协议、Sony SIRC 协议等。用的最多的就是 NEC 协议了,因此我们 KST-51 开发板配套的遥控器直接采用 NEC 协议,我们这节课也以 NEC 协议标准来讲解一下。
- /***************************Infrared.c 文件程序源代码*****************************/
- #include <reg52.h>
- sbit IR_INPUT = P3^3; //红外接收引脚
- bit irflag = 0; //红外接收标志,收到一帧正确数据后置 1
- unsigned char ircode[4]; //红外代码接收缓冲区
- /* 初始化红外接收功能 */
- void InitInfrared(){
- IR_INPUT = 1; //确保红外接收引脚被释放
- TMOD &= 0x0F; //清零 T1 的控制位
- TMOD |= 0x10; //配置 T1 为模式 1
- TR1 = 0; //停止 T1 计数
- ET1 = 0; //禁止 T1 中断
- IT1 = 1; //设置 INT1 为负边沿触发
- EX1 = 1; //使能 INT1 中断
- }
- /* 获取当前高电平的持续时间 */
- unsigned int GetHighTime(){
- TH1 = 0; //清零 T1 计数初值
- TL1 = 0;
- TR1 = 1; //启动 T1 计数
- while (IR_INPUT){ //红外输入引脚为 1 时循环检测等待,变为 0 时则结束本循环
- //当 T1 计数值大于 0x4000,即高电平持续时间超过约 18ms 时,
- //强制退出循环,是为了避免信号异常时,程序假死在这里。
- if (TH1 >= 0x40){
- break;
- }
- }
- TR1 = 0; //停止 T1 计数
- return (TH1*256 + TL1); //T1 计数值合成为 16bit 整型数,并返回该数
- }
- /* 获取当前低电平的持续时间 */
- unsigned int GetLowTime(){
- TH1 = 0; //清零 T1 计数初值
- TL1 = 0;
- TR1 = 1; //启动 T1 计数
- while (!IR_INPUT){ //红外输入引脚为 0 时循环检测等待,变为 1 时则结束本循环
- //当 T1 计数值大于 0x4000,即低电平持续时间超过约 18ms 时,
- //强制退出循环,是为了避免信号异常时,程序假死在这里。
- if (TH1 >= 0x40){
- break;
- }
- }
- TR1 = 0; //停止 T1 计数
- return (TH1*256 + TL1); //T1 计数值合成为 16bit 整型数,并返回该数
- }
- /* INT1 中断服务函数,执行红外接收及解码 */
- void EXINT1_ISR() interrupt 2{
- unsigned char i, j;
- unsigned char byt;
- unsigned int time;
- //接收并判定引导码的 9ms 低电平
- time = GetLowTime();
- //时间判定范围为 8.5~9.5ms,
- //超过此范围则说明为误码,直接退出
- if ((time<7833) || (time>8755)){
- IE1 = 0; //退出前清零 INT1 中断标志
- return;
- }
- //接收并判定引导码的 4.5ms 高电平
- time = GetHighTime();
- //时间判定范围为 4.0~5.0ms,
- //超过此范围则说明为误码,直接退出
- if ((time<3686) || (time>4608)){
- IE1 = 0;
- return;
- }
- //接收并判定后续的 4 字节数据
- for (i=0; i<4; i++){ //循环接收 4 个字节
- for (j=0; j<8; j++){ //循环接收判定每字节的 8 个 bit
- //接收判定每 bit 的 560us 低电平
- time = GetLowTime();
- //时间判定范围为 340~780us,
- //超过此范围则说明为误码,直接退出
- if ((time<313) || (time>718)){
- IE1 = 0;
- return;
- }
- //接收每 bit 高电平时间,判定该 bit 的值
- time = GetHighTime();
- //时间判定范围为 340~780us,
- //在此范围内说明该 bit 值为 0
- if ((time>313) && (time<718)){
- byt >>= 1; //因低位在先,所以数据右移,高位为 0
- //时间判定范围为 1460~1900us,
- //在此范围内说明该 bit 值为 1
- }else if ((time>1345) && (time<1751)){
- byt >>= 1; //因低位在先,所以数据右移,
- byt |= 0x80; //高位置 1
- }else{ //不在上述范围内则说明为误码,直接退出
- IE1 = 0;
- return;
- }
- }
- ircode[i] = byt; //接收完一个字节后保存到缓冲区
- }
- irflag = 1; //接收完毕后设置标志
- IE1 = 0; //退出前清零 INT1 中断标志
- }
- /*****************************main.c 文件程序源代码******************************/
- #include <reg52.h>
- sbit ADDR3 = P1^3;
- sbit ENLED = P1^4;
- unsigned char code LedChar[] = { //数码管显示字符转换表
- 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
- 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
- };
- unsigned char LedBuff[6] = { //数码管显示缓冲区
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
- };
- unsigned char T0RH = 0; //T0 重载值的高字节
- unsigned char T0RL = 0; //T0 重载值的低字节
- extern bit irflag;
- extern unsigned char ircode[4];
- extern void InitInfrared();
- void ConfigTimer0(unsigned int ms);
- void main(){
- EA = 1; //开总中断
- ENLED = 0; //使能选择数码管
- ADDR3 = 1;
- InitInfrared(); //初始化红外功能
- ConfigTimer0(1); //配置 T0 定时 1ms
- //PT0 = 1; //配置 T0 中断为高优先级,启用本行可消除接收时的闪烁
- while (1){
- if (irflag){ //接收到红外数据时刷新显示
- irflag = 0;
- LedBuff[5] = LedChar[ircode[0] >> 4]; //用户码显示
- LedBuff[4] = LedChar[ircode[0]&0x0F];
- LedBuff[1] = LedChar[ircode[2] >> 4]; //键码显示
- LedBuff[0] = LedChar[ircode[2]&0x0F];
- }
- }
- }
- /* 配置并启动 T0,ms-T0 定时时间 */
- void ConfigTimer0(unsigned int ms){
- unsigned long tmp; //临时变量
- tmp = 11059200 / 12; //定时器计数频率
- tmp = (tmp * ms) / 1000; //计算所需的计数值
- tmp = 65536 - tmp; //计算定时器重载值
- tmp = tmp + 13; //补偿中断响应延时造成的误差
- T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
- T0RL = (unsigned char)tmp;
- TMOD &= 0xF0; //清零 T0 的控制位
- TMOD |= 0x01; //配置 T0 为模式 1
- TH0 = T0RH; //加载 T0 重载值
- TL0 = T0RL;
- ET0 = 1; //使能 T0 中断
- TR0 = 1; //启动 T0
- }
- /* LED 动态扫描刷新函数,需在定时中断中调用 */
- void LedScan(){
- static unsigned char i = 0; //动态扫描索引
- P0 = 0xFF; //关闭所有段选位,显示消隐
- P1 = (P1 & 0xF8) | i; //位选索引值赋值到 P1 口低 3 位
- P0 = LedBuff[i]; //缓冲区中索引位置的数据送到 P0 口
- if (i < sizeof(LedBuff)-1){ //索引递增循环,遍历整个缓冲区
- i++;
- }else{
- i = 0;
- }
- }
- /* T0 中断服务函数,执行数码管扫描显示 */
- void InterruptTimer0() interrupt 1{
- TH0 = T0RH; //重新加载重载值
- TL0 = T0RL;
- LedScan(); //数码管扫描显示
- }
标签:
原文地址:http://blog.csdn.net/softn/article/details/51864934