程序实现
程序主要要完成三大功能:38KHZ载波信号的产生、红外接收头TL0038输出电平的检测、发光二极管和蜂鸣器的驱动。
本程序使用8位定时计数器T/C0溢出中断使PD0产生38KHZ的方波信号,然后驱动红外线发射管。T/C0计数器是单一向上计数器,其计数值TCNT0一旦计数到0XFF后,T/C0马上产生溢出中断。因此,我们可以通过设置TCNT0的初始值来调整中断产生的频率。每产生一次中断就改变一次PD0的电平状态,从而在PD0口产生38KHZ的方波信号。Atmega8采用内部8MHZ的RC时钟信号,T/C0的时钟源采用系统时钟8分频,即每计一个数(TCNT0增加1)需要1us的时间。38KZH的时钟周期大约为26us左右,因此,半周期需要计数13次左右,即TCNT0初始值为256-13=243。另外,我们还需要在38KHZ的载波信号上调制上一个码信号,也就是说38KHZ的载波信号不是一直在产生,而是间断的发射。如下图所示:
同时,程序通过不断地读取PC5脚的电平值来判断TL0038是否接收到红外信号。一旦连续检测到多次PC5为低电平,则立即打开蜂鸣器和红色的LED。之所以要连续检测多次,主要是防止TL0038上产生杂波信号而误报警。
源代码如下:
- /**************************************************************************
- 实验2:简单的被动式红外线报警器
- PB1: 绿色LED
- PB0: 红色LED
- PD7: 蜂鸣器
- PC5: 连接TL0083的输出端
- PD0: 红外LED
- 2004年8月4日
- ***************************************************************************/
- #include <iom8v.h>//和单片机类型相对应的头文件,选择Atmega8做实验;
- #include <macros.h>
- void delay_nus(unsigned int n);//函数声明,本实验中会用到这两个函数
- void delay_nms(unsigned int n);
- void main(void)//主函数
- { //L6
- unsigned int i;
- unsigned char n;
- OSCCAL=0X9E;//系统时钟校准,不同的芯片和不同的频率,
- //其校准值是不一样的
- TCCR0=BIT(CS01);//T/C0时钟8分频
- TIMSK=BIT(TOIE0);//允许定时器T/C0溢出中断
- SEI();//开中断
- DDRD|=BIT(0)|BIT(7);//设置PD0、7为输出口
- DDRC&=~BIT(5);//设置PC5为输入口
- DDRB|=BIT(1)|BIT(0);//定义B口的PB0、PB1为输出口
- PORTB|=BIT(1);//PB1口输出高电平,绿灯亮
- while(1)
- { //L5
- for (n=0;n<10;n++)
- { //L4
- delay_nus(60);
- if ((PINC&0B00100000)==0) //检测PC5是否为低电平
- { //L3
- i++;
- if (i>8)//如果连续检测到有301-399次PC5都为低电平,则报警
- { //L2
- CLI();
- for(i=0;i<10;i++)
- { //L1
- PORTB&=~BIT(1);//关闭绿灯
- PORTD|=BIT(7);//打开蜂鸣器
- PORTB^=BIT(0);//翻转PB1口,红灯快闪
- delay_nms(300);
- } //L1
- PORTD&=~BIT(7);//关闭蜂鸣器
- PORTB&=~BIT(0);//关闭红灯
- i=0;
- SEI();
- } //L2 */
- PORTB|=BIT(1);//打开绿灯
- } //L3
- } //L4
- //-------------------码调制----------------------------/
- CLI();//PD0连续2ms都无输出
- PORTD&=~BIT(0);
- delay_nms(2);
- TCNT0=245;
- SEI();//PD0连续600us产生38KHZ信号
- //delay_nus(100);
- } //L5 */
- } //L6
- #pragma interrupt_handler LED0:iv_TIMER0_OVF//指定中断服务程序的入口
- void LED0(void)//产生38KHz的方波信号
- {
- PORTD^=BIT(0);//翻转PD0口电平
- TCNT0=245;
- }
- void delay_nus(unsigned int n)//n微秒延时函数
- {
- unsigned int i;
- for (i=0;i<n;i++)
- {
- asm("nop");
- }
- }
- void delay_nms(unsigned int n)//n毫秒延时函数
- {
- unsigned int i;
- for (i=0;i<n;i++) //执行n次1毫秒延时
- delay_nus(1000);
- }