我们从2011年坚守至今,只想做存粹的技术论坛。  由于网站在外面,点击附件后要很长世间才弹出下载,请耐心等待,勿重复点击不要用Edge和IE浏览器下载,否则提示不安全下载不了

 找回密码
 立即注册
搜索
查看: 1106|回复: 4

51单片机红外遥控器的读码发射程序

[复制链接]

该用户从未签到

77

主题

359

回帖

0

积分

二级逆天

积分
0

社区居民终身成就奖金点子奖

QQ
发表于 2021-6-27 00:23:17 | 显示全部楼层 |阅读模式
[/free][paragraph]

51单片机红外遥控器读码发射程序码




STC的51单片机红外遥控器读码、发射程序,已试成功
有一台DVD机没有遥控器,正好别的遥控器有的键可以用,但功能不一样。
于是开展本工程,程序原为网上摘的,经过修改均已全部成功。
采用STC的51单片机,STC12C5A60S2,可以直接串口编程,而且是1T的,非常方便。
一、红外遥控器读码
读码程序没怎么修改就成功了。
注意:这里的延时程序是STC12C5A60S2的,如果用别的单片机,需要修改。
#include <STC\STC12C5A60S2.H>
#include <INTRINS.h>
//采用1T周期的STC12C5A60S2单片机,11.0592MHZ
//WXL:一体化接收头默认是输出高电平,有信号时输出低电平;接P3.2脚。
//WXL:这里按“低位在先”
/******************************************************************/
/* 本程序的蓝本从网上搜集,经修改并注释,万能遥控器解码成功 */
/* 晶振:11.0592MHz */
/* 整理与测试:单片机教程网  胡琴 2012.5.15 */
/************************* 说 明 *********************************/
/* 以一个9ms的低电平和4.5ms的高电平为引导码,后跟32位二进制代码 */
/* 前16位为8位用户码及其反码,后16位为8位的操作码及其反码 */
/* 以脉宽为低电平0.565ms、间隔高电平0.56ms、周期为1.125ms的组合表示"0"; */
/* 以脉宽为低电平0.565ms、间隔高电平1.685ms、周期为2.25ms的组合表示"1"。 */
/* 注意:接收码的脉宽与间隔是对发射码取反的,即间隔是0.565ms */
/* 解码后共有四个十六进制码,本程序取第三个作为识别码 */
/*******************************************************************/
#define uchar unsigned char
uchar data IRcode[4]; //定义一个4字节的数组用来存储代码
uchar CodeTemp; //编码字节缓存变量
uchar i,j,k; //延时用的循环变量
sbit IRsignal=P3^2; //HS0038接收头OUT端直接连P3.2(INT0)
sbit P0_0=P0^0; //P0连接到 LED 上
sbit P0_1=P0^1;
sbit P0_2=P0^2;
/**************************延时0.6ms子程序**********************/
void Delay0_6ms(void) //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 7;
j = 112;
do
{
while (--j);
} while (--i);
}
/**************************延时0.9ms子程序**********************/
void Delay0_9ms(void) //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 10;
j = 170;
do
{
while (--j);
} while (--i);
}
/***************************延时1ms子程序**********************/
void Delay1ms(void)
{
unsigned char i, j;
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
/***************************延时4ms子程序**********************/
void Delay4ms(void)
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 44;
j = 3;
do
{
while (--j);
} while (--i);
}
/**************************** 延时子程序 ************************/
void Delay(void)
{
uchar i,j,k;
for(i=200;i>0;i--)
for(j=200;j>0;j--)
for(k=3;k>0;k--)  ;
}
/******************** 中断0解码服务子程序 ********************/
void int0(void) interrupt 0 using 2
{
EA = 0; //??? 可以这样,跳入中断,但仍可对P3.2(INT0)进行电平变化的读取
for(k=0;k<10;k++)
{
Delay0_9ms();
if (IRsignal==1)        //如果0.9ms后IRsignal=1,说明不是引导码,退出中断
{
k=10;
break;
}
else if(k==9)         //如果 持续了10×0.9ms=9ms的低电平,说明是引导码。WXL:一定是从引导码开始
{
while(IRsignal==0);      // WXL:因为红外头默认输出是高电平,故用while(IRsignal==0)很安全,而用while(IRsignal==1)则可能会进入死循环
Delay4ms();       //跳过持续4.5ms的高电平     WXL:要超过4.5ms更好
Delay0_6ms();
for(i=0;i<4;i++)     //分别读取4个字节
{
for(j=1;j<=8;j++)    //每个字节8个bit的判断
{
while(IRsignal==0); //等待上升沿,此处用得很好:因为0.56ms的低电平(接收时)是代码0与1的相同部分
Delay0_9ms(); //从上升沿那一时刻开始延时0.9ms(因为0.9介于0.56(=1.125-0.56)与1.69(=2.25-0.56)之间),再判断IRsignal
if(IRsignal==1) //  如果IRsignal是"1",高位置"1",并向右移一位
{
Delay1ms(); //为什么要延时1ms呢?因为要使IRsignal跳至低电平(即0.56ms的0与1相同部分上)
CodeTemp=CodeTemp 0x80; //此处的算法很好
if(j<8)  CodeTemp=CodeTemp>>1;
}
else       //  如果IRsignal是"0",高位置"0",并向右移一位
if(j<8) CodeTemp=CodeTemp>>1;   //如果IRsignal是"0",则直接向右移一位,自动补"0"
}
IRcode=CodeTemp;
CodeTemp=0;
}   //end for
for(i=0;i<4;i++) //通过串口将代码发出
{
SBUF=IRcode;
while(!TI); //等待一个字节发送完毕
TI=0;
}
Delay();
}    //end else
}   //END for
EA = 1;
}
/***********************串口初始化程序*********************/
void initUart(void)
{
TMOD = 0x20; //
SCON = 0x50; //
PCON = 0x80; //
TH1 = 250; // 9600 bps @ 11.0592MHz
TL1 = 250;
TR1 = 1;
}
/**************************主程序*************************/
void main()
{
//P0=0XFF;
initUart();
IT0 = 1; //INT0为负边沿触发, (1:负边沿触发,0:低电平触发)
EX0 = 1; //外部中断INT0开, (1:开, 0:关 )
EA = 1; //开所有中断
CodeTemp = 0; //初始化红外编码字节缓存变量
Delay();
while(1)
{
}
}
二、红外遥控发射
网上的程序是http://gudeng614.blog.163.com/blog/static/818017420101545648734/
做发射程序费了很大波折,因为网上的程序不好用。
后来不得不用计算机的并口采集了发射数据,发现数据有异常,终于找到了问题所在。
原因是count变量是int的,对其赋值或比较时,汇编语句一句完不成,会被中断服务程序中断,造成count变量赋值或比较出现问题。
解决方法是必须在操作时屏蔽中断。而flag变量是bit的,一句汇编即可完成赋值,故不会有问题。
其间还发现别的遥控器会在起始码前加一个前脉冲,以为是这个问题,其实不是。
注意:由于13us会中断一次,这里是采用1T的单片机。如果采用普通的51单片机,由于是12T的,不知道能不能成功。
//程序从网上修改而来
//由于中断需要13us中断一次,即中断要在几us处理完,因此需要单片机速度比较快,用24MHZ晶振才能保证正常
//但24MHZ晶振,用串口不方便
//这里采用1T周期的STC12C5A60S2单片机,11.0592MHZ,可以兼顾。
//STC12C5A60S2  引脚可灌入20mA电流,直接从正电源→红外LED→串1K电阻→P0.0脚。
//串口1默认选T1作为波特率发生器
//TO用于中断
//发送时,低比特位优先
#include <STC\STC12C5A60S2.H>
#include <INTRINS.h>
sbit  P0_0 = P0^0;
static bit g_OP;            //红外发射管的亮灭
static unsigned int g_count;       //延时计数器
static unsigned int g_endcount;    //终止延时计数
static bit g_flag;       //红外发送标志
unsigned char g_iraddr1;     //十六位地址的第一个字节
unsigned char g_iraddr2;     //十六位地址的第二个字节
//定时器0中断处理
void timeint(void) interrupt 1
{
  g_count++;
  if (g_flag)    g_OP=~g_OP;
  else    g_OP = 1;    //LED不点亮
  P0_0 = g_OP;
}
/////////////////////////////////////////////////////
void SendIRdata_38KHZ(unsigned int temp1, bit temp2)
{
  g_endcount=temp1;
  g_flag=temp2;
  EA=0; g_count=0; EA=1;  //避免中断影响count置数
  while(1)
  {
   EA=0;
   if( g_count < g_endcount ) EA=1;  //避免中断影响count比较
   else
   {
   EA=1;
   break;
   }  
  }  
}
/////////////////////////////////////////////////////
void SendIRdata_BYTE(unsigned char irdata)
{
  unsigned char i;
  for(i=0;i<8;i++)
  {
     //先发送0.56ms的38KHZ红外波(即编码中0.56ms的高电平)
SendIRdata_38KHZ(43, 1);   //13.02*43=0.56ms
    //停止发送红外信号(即编码中的低电平)
     if(irdata & 1)  //判断最低位为1还是0。   低位先发送!!
       SendIRdata_38KHZ(130, 0);         //1为宽电平,13.02*130=1.693ms
    else      SendIRdata_38KHZ(43, 0);   //0为窄电平,13.02*43=0.560ms
    irdata=irdata>>1;
  }
}
/////////////////////////////////////////////////////
void SendIRdata(unsigned char p_irdata)
{
  //有的遥控器会发一个前脉冲,如果不灵,可试试加上前脉冲
  //发送起始码前脉冲,高电平有38KHZ载波
  //SendIRdata_38KHZ(18, 1);
  //发送起始码前脉冲,低电平无38KHZ载波
  //SendIRdata_38KHZ(18, 0);
  //发送9ms的起始码,高电平有38KHZ载波
  SendIRdata_38KHZ(692, 1); //13.02*692=9.010ms
  //发送4.5ms的结果码,低电平无38KHZ载波
  SendIRdata_38KHZ(346, 0);    //13.02*346=4.505ms
  //发送十六位地址的前八位
  SendIRdata_BYTE(g_iraddr1);
  //发送十六位地址的后八位
  SendIRdata_BYTE(g_iraddr2);
  //发送八位数据
  SendIRdata_BYTE(p_irdata);
  //发送八位数据的反码
  SendIRdata_BYTE(~p_irdata);  
  //发送总的结束位1bit
  SendIRdata_38KHZ(43, 1);     //13.02*43=0.56ms
/*  //后面这些可以不用发
  g_endcount=1766;
  g_flag=0;
  EA=0; g_count=0; EA=1;
  while(1){EA=0; if(g_count<g_endcount) EA=1; else { EA=1; break; }  }   
  //发送9ms的起始码,高电平有38KHZ载波
  g_endcount=692;   //13.02*692=9.010ms
  g_flag=1;
  EA=0; g_count=0; EA=1;
  while(1){EA=0; if(g_count<g_endcount) EA=1; else { EA=1; break; }  }   
  //发送4.5ms的结果码,低电平无38KHZ载波
  g_endcount=346;    //13.02*346=4.505ms
  g_flag=0;
  EA=0; g_count=0; EA=1;
  while(1){EA=0; if(g_count<g_endcount) EA=1; else { EA=1; break; }  }   
//发送总的结束位1bit
  g_endcount=43;    //13.02*43=0.56ms
  g_flag=1;
  EA=0; g_count=0; EA=1;
  while(1){EA=0; if(g_count<g_endcount) EA=1; else { EA=1; break; }  }   
*/
  g_flag=0;
}
///////////////////////////////////////////////////////////
void main(void)
{
unsigned char com_data;    //数据字节
  g_count = 0;
  g_flag = 0;
  g_OP = 1;
  P0_0 = g_OP;   //LED接电源正极,不点亮
SCON=0x50;  //串口方式1    01 0 1 0 0 00  模式1,非多机,允许接收,无数据位8,清中断标识TI和RI
  TMOD = 0x22; //(定时器0和1:方式2,自动重装,8位)
TH1=253;  //11.0592MHZ,9600bps。没有设置SMOD,故波特率没有加倍。即:11.0592/12/3/32=9600bps
TL1=253;
TR1=1;    //启动定时器
  TH0 = 244;
  TL0 = 244; //(WXL:即计数12次中断一次,即11.0592MHZ晶振,机器周期是1.085us,12次*1.085=13.02us,这样达38KHZ。  13us一次中断,时间太短了,所以单片机要快)
  ET0 = 1;   //定时器0中断允许
  EA = 1;    //允许CPU中断
  TR0 = 1;   //开始计数
  g_iraddr1=0;       //地址码
  g_iraddr2=255;     //地址反码
RI=0;
while(1)
{
if(RI==1)
{
com_data =SBUF;
RI=0;       //要人工清RI
SendIRdata(com_data);   //发送红外数据
TI=0;
SBUF = com_data;   //输出字符
while(!TI) ;     //空语句判断字符是否发完,TI=1表示发完
TI = 0;         //要人工清TI
}
}
}








来源网络,仅供学习交流
[free]
购买主题 本主题需向作者支付 2 枚金币 才能浏览
回复

使用道具 举报

该用户从未签到

1

主题

6740

回帖

1280

积分

二级逆天

积分
1280

终身成就奖特殊贡献奖原创先锋奖优秀斑竹奖

发表于 2021-6-27 07:17:30 | 显示全部楼层
回复

使用道具 举报

  • TA的每日心情
    开心
    昨天 08:49
  • 签到天数: 159 天

    [LV.7]常住居民III

    3

    主题

    7147

    回帖

    1万

    积分

    PADS20220105初级班

    积分
    10866

    终身成就奖特殊贡献奖原创先锋奖优秀斑竹奖

    发表于 2021-6-27 08:02:14 | 显示全部楼层
    回复

    使用道具 举报

    该用户从未签到

    77

    主题

    359

    回帖

    0

    积分

    二级逆天

    积分
    0

    社区居民终身成就奖金点子奖

    QQ
     楼主| 发表于 2021-8-18 00:09:16 | 显示全部楼层
    回复

    使用道具 举报

    该用户从未签到

    0

    主题

    34

    回帖

    41

    积分

    一级逆天

    积分
    41

    终身成就奖

    发表于 2023-6-10 18:15:51 | 显示全部楼层
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    每日签到,有金币领取。


    Copyright ©2011-2024 NTpcb.com All Right Reserved.  Powered by Discuz! (NTpcb)

    本站信息均由会员发表,不代表NTpcb立场,如侵犯了您的权利请发帖投诉

    ( 闽ICP备2024076463号-1 ) 论坛技术支持QQ群171867948 ,论坛问题,充值问题请联系QQ1308068381

    平平安安
    TOP
    快速回复 返回顶部 返回列表