📄 ir.c
字号:
//******************************************************************************
// *
// FileName : 实验板ir.c ICCAVR V6.31A编译 *
// Function : 红外接收 C与汇编混合编程实例 *
// Date : 2007-01-04 *
// Version : 1.0 *
// *
// Author : 开关电源 hongtusy@163.com *
// Company : 电子信息技术咨询网 http://www.itsn.cn *
// *
//***************************描述与记事*****************************************
//实验板的AVR程序,接收红外线遥控器的按键信号,并将译码后的数字送数码管显示。
//本试验需要配合配套的红外遥控器(使用6121芯片),使用ATmega8535,使用片内1M晶振。
//接线定义:PA2=SW5-7接蜂鸣器,PD3/INT1=SW5-6红外信号接收端
// 数码管显示部分,SW1-1~8,SW2-1~3,SW2-6,SW3-8为系统复位端。
//功能:刚上电,蜂鸣器会响一声,然后收到一个红外信号就响一声,并将键值显示在数码管上。
//记事:本程序旨在对红外接收的理解与演示,忽略了系统码,程序适合初学者使用。
/*解码的关键是如何识别"0"和"1",从位的定义我们可以发现"0"和"1"均以0.565mS的低电平开始,
不同的是高电平的宽度不同,"0"为0.56mS,"1"为1.68mS,所以必须根据高电平的宽度区别"0"和
"1",如果从0.565mS低电平过后,开始延时,0.56mS以后,若读到的电平为低,说明该位为"0",
反之则为"1",为了可靠起见,延时必须比0.56mS长些,但又不能超过1.12mS,否则如果该位为"0",
读到的已是下一位的高电平,因此取(1.12mS+0.56mS)/2=0.84mS最为可靠,一般取0.84mS即可。
//******************************************************************************/
#include <iom8535v.h> //头文件,ATmega8535单片机的寄存器定义
#include "macros.h" //可以使用NOP()以及SEI()等指令.
typedef unsigned char uchar; //宏
typedef unsigned int uint;
#pragma interrupt_handler int1_serving:3 //外部中断1/红外信号中断入口向量。
uchar Table[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x8F,0xB9,0x86,0x88,0xC6};
/************************************************
函 数 名: DelaymS()
功 能: 毫秒级延时函数
输入参数: 延迟时间/系统晶体
输出参数: 做相应的延迟处理
描 述: /
***********************************************/
void DelaymS (uint i)
{
uint j;
for(;i!=0;i--)
{
for (j=50;j!=0;j--);
}
}
/************************************************
函 数 名: Delay882uS()
功 能: 882微秒延时函数
输入参数: 晶振1M,机器周期为1uS。
输出参数: 延迟时间T=a(4b+3)+c
描 述: 在C中调汇编函数,使用r24,r25不必作特殊的保护工作。
***********************************************/
void Delay882uS (void)
{
asm(" ldi r24,10 ") //t=1 参数:a
asm("loop3: ldi r25,21 ") //t=1 参数:b
asm("loop4: dec r25 ") //t=1
asm(" nop ") //t=1,校准用,需改动公式。
asm(" brne loop4 ") //t=2/1
asm(" dec r24 ") //t=1
asm(" brne loop3 ") //t=2/1
asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop"); //t=1,校准用,参数:c
}
/************************************************
函 数 名: Delay1000uS()
功 能: 1000微秒延时函数
输入参数: 晶振1M,机器周期为1uS。
输出参数: 延迟时间T=a(4b+3)+c
描 述: 在C中调汇编函数,使用r24,r25不必作特殊的保护工作。
***********************************************/
void Delay1000uS (void)
{
asm(" ldi r24,4 ") //t=1 参数:a
asm("loop5: ldi r25,61 ") //t=1 参数:b
asm("loop6: dec r25 ") //t=1
asm(" nop ") //t=1,校准用,需改动公式。
asm(" brne loop6 ") //t=2/1
asm(" dec r24 ") //t=1
asm(" brne loop5 ") //t=2/1
asm("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop"); //t=1,校准用,参数:c
}
/************************************************
函 数 名: key_decode (uchar data)
功 能: 键值扫描码是无规律的,我们只能通过switch来获得键值。
输入参数: 扫描码
输出参数: 翻译后的键值,并显示
描 述: 本处也可以通过数组实现。
***********************************************/
void key_decode (uchar data) //译码键值
{
switch (data) //判断扫描码data
{
case 0: PORTC=Table[1];break; //1
case 1: PORTC=Table[2];break; //2
case 2: PORTC=Table[3];break; //3
case 4: PORTC=Table[4];break; //4
case 5: PORTC=Table[5];break; //5
case 6: PORTC=Table[6];break; //6
case 8: PORTC=Table[7];break; //7
case 9: PORTC=Table[8];break; //8
case 10: PORTC=Table[9];break; //9
case 12: PORTC=Table[10];break; //*
case 13: PORTC=Table[0];break; //0
case 14: PORTC=Table[11];break; //#
case 16: PORTC=Table[12];break; //E
case 17: PORTC=Table[13];break; //A
case 18: PORTC=Table[14];break; //C
default: break;
}
}
/************************************************
函 数 名: spk()
功 能: 蜂鸣器鸣叫一声函数
输入参数:
输出参数:
描 述: /
***********************************************/
void spk (uchar i)
{
PORTA &= ~(1<<PA2); //蜂鸣器响
DelaymS (i); //延迟
PORTA |= (1<<PA2); //蜂鸣器关闭
}
/************************************************
函 数 名: Init_mcu()
功 能: 单片机初始化函数
输入参数: /
输出参数: /
描 述: 相关口方向的设置等
***********************************************/
void Init_mcu(void)
{
DDRC = 0xff; //PC口为推挽1输出
DDRD = 0b11110111; //PD3(INT1)接蜂鸣器为输入,其余为输出。
PORTD = 0b10001111; //红外输入端需要使用内部上拉电阻,只使用第一位数码管。
DDRA = 0xff; //PA口为输出,PA4接蜂鸣器
PORTA = 0xff; //默认蜂鸣器不响
}
/************************************************
函 数 名: Init_int1()
功 能: 外部中断1初始化函数
输入参数: /
输出参数: /
描 述: 设置外部中断1为下降沿触发
***********************************************/
void init_int1 (void) //外部中断1初始化
{
MCUCR |= (1<<ISC11); //设置为下降沿中断触发
MCUCR &= ~(1<<ISC10); //设置为下降沿中断触发
GICR |= (1<<INT1); //通用中断控制寄存器,中断使能
}
/************************************************
函 数 名: Init_serving()
功 能: 红外IR接收中断服务程序
输入参数: /
输出参数: /
描 述: 整个红外译码部分的处理
***********************************************/
void int1_serving (void) //外部中断1,红外IR接收中断服务程序
{
uchar i,j,k,mid ;
uchar buf[4];
CLI(); //暂时屏蔽外部中断
for (i=0;i<9;i++)
{
Delay882uS(); //调用882uS延迟程序。
if((PIND&0x08)!=0) //判断INT1端口的状态。操作的是PD3,PD3为高吗?
{
SEI(); //开中断
return; //如果为高,说明是干扰或出错,跳出这个循环。
}
}
while ((PIND & 0x08) == 0); //等待9ms的低电平结束,
while ((PIND & 0x08) != 0); //等待4.5ms的高电平结束,
for (j=0;j<4;j++)
{
k=0;
for (i=0;i<8;i++)
{
while((PIND&0x08)==0); //等待每一个数据位的0.565ms低电平后的高电平
Delay882uS(); //高电平开始后用882微秒的时间尺去判断信号此时的高低电平状态
mid = PIND & 0x08; //读取端口的值。
if (mid != 0)
{
Delay1000uS(); //为高电平,再延迟1ms,
k |= 1<<i; //读取1
}
else
{
k &= ~(1<<i); //读取0
}
}
buf[j] = k ; //保存读到的数据
}
if ((buf[2]|buf[3]) != 0xff) //判断数据的第三字节和第四字节的取反后相等吗?
{
SEI(); //开中断
return; //如果不相等说明是干扰或出错,跳出整个循环。
}
key_decode (buf[2]); //判断键值并显示,系统码即buf[1]和buf[2]忽略。
//PORTC = buf[2]; //直接显示键值
spk(1000); //蜂鸣器响一声。
SEI(); //开中断
}
//------------------------main----------------------------
void main (void)
{
Init_mcu(); //单片机端口初始化,口方向设置与外部中断的使用无关,不影响。
spk(1000); //蜂鸣器响一声。
init_int1(); //外部中断1初始化
SEI(); //开中断
PORTC=0b10111111; ///上电后初始显示"-"
while (1)
;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -