力天电子开发板,上面存在一个TL1838红外接收头,我们可以利用它做一些遥控器之类的,关于TL1838的资料,可以在网络上收集到,我不多说了,具体原理也同样,文章最后我留一个网友博客链接自己参考。
下面看程序,在力天开发板上,TL1838接在PD6上,PD6有ICP功能,就是输入捕捉功能,具体你可以看AVR的datasheet,我的开发环境为IAR5.11B,晶振16M,
先看第一种方法:
void TL1838_init() //初始化函数
{
DDRD_Bit6=0; //设置ICP1引脚为输入
PORTD_Bit6=1; //使能ICP1引脚上拉电阻
TCNT1=0x00; //初值为0
TIMSK_TICIE1=1; //输入捕抓中断使能;
TCCR1B=(1<//下降沿触发,8分频,0.5us.
__enable_interrupt();
}
#pragma vector = TIMER1_CAPT_vect
/*这里我解释一下,输入捕捉产生中断的时候,就TCNT1寄存器的值赋值到ICR1中这样我们就可以获得2个下降沿见的时间间隔,由于,我TCNT1清零了,所以,每次在中断函数中读取的ICR1就是2个下降沿见的时间间隔,我们就直接可以进行判断了。在进入中断函数的时候,中断标志自动清零,软件不需要清零。*/
__interrupt void TIMER1_CAPT(void)
{
TCNT1=0x00;
ICP_CurrentValue=ICR1; //读取ICP输入捕捉事件的发生时刻
if(ICP_CurrentValue>1900&&ICP_CurrentValue<2450)
Inter_Time=0;
else if(ICP_CurrentValue>4100&&ICP_CurrentValue<4690)
Inter_Time=1;
else if(ICP_CurrentValue>26650&&ICP_CurrentValue<27200) //判断前导码
{
TL1838_Address=0;
TL1838_KeyData=0;
count=0;
return;
}
else {return;}
count++;
if(count<16)
{
TL1838_Address=TL1838_Address|Inter_Time;
TL1838_Address=TL1838_Address<<1;
}
else if(count==16)
TL1838_Address=TL1838_Address|Inter_Time;
else if(count<32)
{
TL1838_KeyData=TL1838_KeyData|Inter_Time;
TL1838_KeyData=TL1838_KeyData<<1;
}
else if(count==32)
{
TL1838_KeyData=TL1838_KeyData|Inter_Time;
Uart_Transmit(0x11);
Uart_Transmit(TL1838_KeyData&0x00ff); //接收完32位后通过串口发送键值
Uart_Transmit(TL1838_KeyData>>8);
}
}
接下来看第二种方法:
第二种方法,我是参考网友的,主要的区别是在ICR1的值。
void TL1838_init() //初始化函数
{
DDRD_Bit6=0; //设置ICP1引脚为输入
PORTD_Bit6=1; //使能ICP1引脚上拉电阻
TCNT1=0x00; //初值为0
TIMSK_TICIE1=1; //输入捕抓中断使能;
TCCR1B=(1<
__enable_interrupt();
}
#pragma vector = TIMER1_CAPT_vect
/*主要的区别是,
中断产生以后没有清零TCNT1,下次捕捉中断读取的ICR1值是在前一次中断ICR1的基础上累积的值,所以TCNT1肯定会计数到OXFFFF,然后从0开始计数,这样就会发生ICP_LastValue大于ICP_CurrentValue的情况,所以,我要先给ICP_CurrentValue加上一个0xFFFF+1,然后再减去ICP_LastValue。所以我在这里说明一下,网友是按照这个思路来写程序的。*/
__interrupt void TIMER1_CAPT(void)
{
ICP_CurrentValue=ICR1; //读取ICP输入捕捉事件的发生时刻
if(ICP_LastValue>ICP_CurrentValue)
Inter_Time=0xffff+ICP_CurrentValue+1-(ICP_LastValue); //计算两个下降沿之间用去的时间
else
Inter_Time=ICP_CurrentValue-ICP_LastValue;
//TIFR|=BIT(ICF1); //该语句可要可不要,因为中断执行 //时ICF1自动清0,也可用该语句来实现软件清0
ICP_LastValue=ICP_CurrentValue;
if(Inter_Time>1900&&Inter_Time<2450)
Inter_Time=0;
else if(Inter_Time>4100&&Inter_Time<4690)
Inter_Time=1;
else if(Inter_Time>26650&&Inter_Time<27200)//判断前导码
{
TL1838_Address=0;
TL1838_KeyData=0;
count=0;
return;
}
else {return;}
//去除干扰,当接收的是准备进前导码时的下降沿和截止码时,
//该语句起作用,没有该语句,则只能接收一次
count++;
if(count<16)
{
TL1838_Address=TL1838_Address|Inter_Time;
TL1838_Address=TL1838_Address<<1;
}
else if(count==16)
TL1838_Address=TL1838_Address|Inter_Time;
else if(count<32)
{
TL1838_KeyData=TL1838_KeyData|Inter_Time;
TL1838_KeyData=TL1838_KeyData<<1;
}
else if(count==32)
{
TL1838_KeyData=TL1838_KeyData|Inter_Time;
Uart_Transmit(0x11);
Uart_Transmit(TL1838_KeyData&0x00ff);
Uart_Transmit(TL1838_KeyData>>8); //接收完32位后发送键值到串口
}
}
程序烧写到AVR里面,需要一个红外遥控器,然后就可以利用串口调试助手接收键值了,
我没有遥控器,所以我就利用了一下,正点原子STM32开发板上配带的红外遥控器了,因为频率是38KHZ,所以也可以使用TL1838来接收。下面看图片,左边是我从串口手抄下来的键值,和右边的遥控器一一对应。
上面的图片,第一个数据5D2A,应该是5DA2,我抄错了,下图片是我重新读取的,同是也读取了用户识别码,为Ox00FF.
网友的博客链接,可以参考一下。
http://liziqiang261.blog.163.com/blog/static/1506444902011215113933154/
http://www.ourmpu.com/mcujx/hwyk11.htm
阅读(4818) | 评论(0) | 转发(0) |