⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ir.c

📁 单片机红外通讯控制 C语言编写 源程序。
💻 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 + -