|

楼主 |
发表于 2023-12-28 11:37:27
|
显示全部楼层
//8脚单片机,型号为 STC15F104W SOP8封装,或STC15F类的,时钟频率:11.0592MHz
/*程序功能:TM1650驱动程序加红外遥控解码程序 。遥控解码后显示在数码管上(还没有上机实验,我改为0到9999自动走字,走到9999就定住)
时钟频率:11.0592MHz
*/
#include<stc15.h>//
unsigned int st,a;//---------------------------------我加的
unsigned char q,b,s,g;//---------------------------我加的
sbit scl = P3^3; //TM1650时钟通讯IO
sbit sda = P3^2;//TM1650数据通讯IO
sbit ir= P3^4;//红外输入口
sbit led = P3^5;//测试用指示灯,在调试红外遥控时可用
unsigned char ir_time = 0; //红外信号的时间,这个寄存器是为了在解码0/1(数据)的时候,用来计低电平的时间
bit ir_d = 0;//红外信号的高低标志位,
bit ir_ok = 0;//解码OK
unsigned char shuwei = 0;//解码的长度
unsigned char shuwei1 = 0;//解码的长度
unsigned char buzhou = 0;//解码的步骤
unsigned char ir_dat = 0;//红外的8位数据
unsigned char num[]={0,0,0,0};//红外的4组8位的数据,就是用户码,用户码反码,数据码,数据码反码
code unsigned char shuma[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //子模0-9,A,B,C,D,E,F
unsigned char reg1 = 0; //通用寄存器1
unsigned char reg2 = 0; //通用寄存器2??这两个寄存器在转换成可显示的数据要用到
void delay(unsigned int time)
{
while(time--);
}
void tm1650_start(); //TM1650通讯的开始信号
void tm1650_end();//TM1650通讯的结束信号
void tm1650_ack();//TM1650通讯的应答信号
void write_1();//TM1650数据通讯 写1
void write_0();//TM1650数据通讯 写0
void write_byte(unsigned char tem);//写一个字节
void TM0_Isr() interrupt 1 //红外解码,定时器的时基是50us中断一次
{
INT_CLKO &= 0xef; //关闭外部中断
if(buzhou==0)//步骤0,判断9ms的低电平
{
if(!ir)
{
ir_time++;
if(ir_time>185)//低电平超时,每一次因为错误退出解码时,一点要清掉用到的那些寄存器!!!!!!这里一点要注意,下面的退出里面也是要清掉
{
ir_d = 0;
ir_time = 0;
buzhou = 0;
TR0 = 0;
INT_CLKO |= 0x10;
}
}
else
{
if((ir_time>175)&&(ir_time<185)) //低电平OK,是正确的9ms ,就跳到步骤1? ? (9mS除以50uS=180,所以这里的值就设为175和185之间,因为要考虑到一点的误差)
{
ir_time = 0;
led ^= 1; // 去屏蔽----------------------------------------------------------------------111111
buzhou = 1;
}
else//不是正确的9ms
{
buzhou = 0;
TR0 = 0;
INT_CLKO |= 0x10;
}
}
}
if(buzhou==1)//步骤1,判断4.5ms的高电平
{
if(ir)
{
ir_time++;
if(ir_time>95) //高电平超时
{
ir_d = 0;
ir_time = 0;
buzhou = 0;
TR0 = 0;
INT_CLKO |= 0x10;
}
}
else
{
if((ir_time>85)&&(ir_time<95))//4.5ms高电平OK,就跳到步骤2??这里还可以添加判断连码的程序,如果这里的时间是2mS 那就是连码
{
ir_time = 0;
led ^= 1; //-------------------------------------22222
buzhou = 2;
ir_d = 0;
}
else//不OK
{
buzhou = 0;
TR0 = 0;
INT_CLKO |= 0x10;
}
}
}
if(buzhou==2) //步骤2开始解码数据
{
if(!ir_d)//如果低电平标志为0时,这里是用来判断低电平的时间
{
if(!ir) //如果红外端口为低
{
ir_time++; //计低电平的时间
if(ir_time>13) //低电平时间超时,就退出解码
{
ir_d = 0;
ir_time = 0;
buzhou = 0;
TR0 = 0;
INT_CLKO |= 0x10;
shuwei = 0;
shuwei1 = 0;
}
}
else//如果转为高电平了,
{
ir_d = 1; //低电平标志位置一,要去判断高电平的时间了
ir_time = 0;//时间清零
}
}
else//如果低电平标志位为1,就是进入判断IR高电平的时间了,这个高电平的时间就是判断数据是0还是1
{
if(ir) //如果IR为高
{
ir_time++;//计高电平的是按
if(ir_time>34)//超时了就退出解码
{
ir_d = 0;
ir_time = 0;
buzhou = 0;
TR0 = 0;
INT_CLKO |= 0x10;
shuwei = 0;
shuwei1 = 0;
}
}
else//如果IR为低了,就可以判断高电频的时间了
{
if(ir_time>16)//时间大于16*50us??就是数据1
ir_dat |= 0x80;
else//否则就是数据0
ir_dat &= 0x7f;
shuwei++;
if(shuwei==8) //8bit 组成1byte
{
num[shuwei1]=ir_dat;
shuwei = 0;
shuwei1++;//总共4byte
if(shuwei1==4)//4组数据接收完了就接收解码
{
if(num[2]==0x45) //----------------------------
led = 0; //----------------------------------
else //-------------------------------------
led = 1; //--------------------------------
ir_ok = 1; //解码成功标志位置一
buzhou = 0;
TR0 = 0;
INT_CLKO |= 0x10;
shuwei1 = 0;
}
}
ir_dat>>=1;
ir_time = 0;
ir_d = 0;
}
}
}
}
void INT2_Isr() interrupt 10//IR为低 就进入此中断,开启解码,解码中这个中断是关闭的,只有退出了解码,才会进入这个中断
{
if(!ir)
{
buzhou = 0;
ir_d = 0;
shuwei = 0;
shuwei1 = 0;
ir_time = 0;
TR0 = 1;
}
}
void main()
{
P3M0 = 0x00;
P3M1 = 0x00;
P3 = 0xff;
AUXR |= 0x80; //定时器时钟1T模式
TMOD = 0x00;//模式0
TL0 = 0xD7;//设置定时初值
TH0 = 0xFD; //定时器0设为50us中断一次
TR0 = 0;//启动定时器
ET0 = 1;//使能定时器中断
INT_CLKO |= 0x10;//(EX2 = 1)使能INT2中断
EA = 1;
while(1)
{
tm1650_start(); //给从机 (即是tm1650芯片) 一个开始信号
write_byte(0x48); //写一个字节8位,就是发数码显示模式到从机(即是tm1650芯片)0x48是不能改变的。
tm1650_ack(); //从机应答
write_byte(0x11); //0x11,(1级亮度,开显示,7段,不显示小数点)。这里的指令数据 详情参阅TM1650的datasheet
//0x19,(1级亮度,开显示,8段,显示小数点)
tm1650_ack(); //从机应答
tm1650_end(); //结束
//上面的语句已经让tm1650芯片做好了准备工作---------------------------------------------------------------------------------------------------------------------
//a=9999; //a可以是0-9999的任意一个十进制数
//以下4个语句,把9999这个十进制数分拆//能正常显示9999,验证了,OK
q=a/1000;//求出千位上的数字
b=(a-q*1000)/100;//求出百位上的数字
s=(a-q*1000-b*100)/10;//求出十位上的数字
g=(a-q*1000-b*100-s*10);//求出个位上的数字
//下面就可以分别给各位的数码值让它显示了(先高位,再低位)。格式:开始----发位选的数据------------应答----发段选,即要在本位显示的数字------应答----结束
//tm1650芯片DIG1管脚接的数码管 开始----发位选的数据(千位)----应答---发段选,即(千位)要在本位显示的数字-------应答----结束
//DIG2接的数码管 开始----发位选的数据(百位)----应答---发段选,即(百位)要在本位显示的数字-------应答----结束
//DIG3接的数码管 开始----发位选的数据(十位)----应答---发段选,即(十位)要在本位显示的数字-------应答----结束
//DIG4接的数码管 开始----发位选的数据(个位)----应答---发段选,即(个位)要在本位显示的数字-------应答----结束
tm1650_start();//开始信号
write_byte(0x68);//发送千位的位地址 位选
tm1650_ack();
write_byte(shuma[q]); //发送千位的数字 // write_byte(shuma[reg1]);//千位的数字 段选(可变量)
tm1650_ack();
tm1650_end();
tm1650_start();
write_byte(0x6a);//百位的位地址 位选
tm1650_ack();
write_byte(shuma);//发送百位的数字 // write_byte(0x71);//write_byte(shuma[reg2]);//百位数字 段选(可变量)
tm1650_ack();
tm1650_end();
tm1650_start();
write_byte(0x6c);//十位的位地址 位选---------------
tm1650_ack();
write_byte(shuma);//发送十位的数字 //write_byte(0x77);//2 十位 write_byte(0x5b);十位数字 段选 固定显示2------------------------------write_byte(0x77);对的
tm1650_ack();
tm1650_end();
tm1650_start();
write_byte(0x6e);//个位的位地址 位选----固定显示
tm1650_ack();
write_byte(shuma[g]);//发送个位的数字//write_byte(0x66);//个位数字 段选 固定显示4。write_byte(0x3f);//个位固定显示0,这里固定显示02,是因为我们解码的数据是第2组数据,也就是数据码(第0组数据是用户码,1是用户码反码,2是数据码,3是数据码反码)
//write_byte(0x06);//个位固定显示1,
//{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //子模0-9,A,B,C,D,E,F
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
tm1650_ack();
tm1650_end();
//------------------------------------------------------------------------------------------------------------------------------------------------
delay(65530);//让a动起来。OK,验证了。
if(a<9999)a=a+1;//a的量能变了,数码管很快从0显示到9999,十位数位的字每1秒加1.
if(ir_ok)
{
ir_ok = 0; //清掉解码标志位
reg1 = (num[2]&0x0f);//??数据低4位送显示? ?? ?? ?? ???把数据转为0-F//-----==
reg2 = (num[2]&0xf0);//数据的高四位送显示 //----------
reg2>>=4;
}
}
}
void tm1650_start()
{
sda = 1;
scl = 1;
delay(10);
sda = 0;
delay(5);
}
void tm1650_end()
{
sda = 0;
scl = 1;
delay(6);
sda = 1;
delay(2);
}
void tm1650_ack()
{
while(sda);
delay(5);
scl = 1;
delay(5);
scl = 0;
delay(5);
}
void write_1()
{
sda = 1;
scl = 0;
delay(5);
scl = 1;
delay(10);
scl = 0;
delay(5);
sda = 0;
}
void write_0()
{
sda = 0;
scl = 0;
delay(5);
scl = 1;
delay(10);
scl = 0;
}
void write_byte(unsigned char tem)
{
unsigned char i;
for(i=8;i>0;i--)
{
if(tem&0x80)
write_1();
else
write_0();
tem<<=1;
}
}
/* void exter0() interrupt 1 //定时器0的中断程序
{
st++;
if(st==4000)st=0;
if(st==200)
{a++;
if(a>9999)a=0;
}
|
|