?? ir.c
字號(hào):
//******************************************************************************
// *
// FileName : 實(shí)驗(yàn)板ir.c ICCAVR V6.31A編譯 *
// Function : 紅外接收 C與匯編混合編程實(shí)例 *
// Date : 2007-01-04 *
// Version : 1.0 *
// *
// Author : 開關(guān)電源 hongtusy@163.com *
// Company : 電子信息技術(shù)咨詢網(wǎng) http://www.itsn.cn *
// *
//***************************描述與記事*****************************************
//實(shí)驗(yàn)板的AVR程序,接收紅外線遙控器的按鍵信號(hào),并將譯碼后的數(shù)字送數(shù)碼管顯示。
//本試驗(yàn)需要配合配套的紅外遙控器(使用6121芯片),使用ATmega8535,使用片內(nèi)1M晶振。
//接線定義:PA2=SW5-7接蜂鳴器,PD3/INT1=SW5-6紅外信號(hào)接收端
// 數(shù)碼管顯示部分,SW1-1~8,SW2-1~3,SW2-6,SW3-8為系統(tǒng)復(fù)位端。
//功能:剛上電,蜂鳴器會(huì)響一聲,然后收到一個(gè)紅外信號(hào)就響一聲,并將鍵值顯示在數(shù)碼管上。
//記事:本程序旨在對(duì)紅外接收的理解與演示,忽略了系統(tǒng)碼,程序適合初學(xué)者使用。
/*解碼的關(guān)鍵是如何識(shí)別"0"和"1",從位的定義我們可以發(fā)現(xiàn)"0"和"1"均以0.565mS的低電平開始,
不同的是高電平的寬度不同,"0"為0.56mS,"1"為1.68mS,所以必須根據(jù)高電平的寬度區(qū)別"0"和
"1",如果從0.565mS低電平過(guò)后,開始延時(shí),0.56mS以后,若讀到的電平為低,說(shuō)明該位為"0",
反之則為"1",為了可靠起見,延時(shí)必須比0.56mS長(zhǎng)些,但又不能超過(guò)1.12mS,否則如果該位為"0",
讀到的已是下一位的高電平,因此取(1.12mS+0.56mS)/2=0.84mS最為可靠,一般取0.84mS即可。
//******************************************************************************/
#include <iom8535v.h> //頭文件,ATmega8535單片機(jī)的寄存器定義
#include "macros.h" //可以使用NOP()以及SEI()等指令.
typedef unsigned char uchar; //宏
typedef unsigned int uint;
#pragma interrupt_handler int1_serving:3 //外部中斷1/紅外信號(hào)中斷入口向量。
uchar Table[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x8F,0xB9,0x86,0x88,0xC6};
/************************************************
函 數(shù) 名: DelaymS()
功 能: 毫秒級(jí)延時(shí)函數(shù)
輸入?yún)?shù): 延遲時(shí)間/系統(tǒng)晶體
輸出參數(shù): 做相應(yīng)的延遲處理
描 述: /
***********************************************/
void DelaymS (uint i)
{
uint j;
for(;i!=0;i--)
{
for (j=50;j!=0;j--);
}
}
/************************************************
函 數(shù) 名: Delay882uS()
功 能: 882微秒延時(shí)函數(shù)
輸入?yún)?shù): 晶振1M,機(jī)器周期為1uS。
輸出參數(shù): 延遲時(shí)間T=a(4b+3)+c
描 述: 在C中調(diào)匯編函數(shù),使用r24,r25不必作特殊的保護(hù)工作。
***********************************************/
void Delay882uS (void)
{
asm(" ldi r24,10 ") //t=1 參數(shù):a
asm("loop3: ldi r25,21 ") //t=1 參數(shù):b
asm("loop4: dec r25 ") //t=1
asm(" nop ") //t=1,校準(zhǔn)用,需改動(dòng)公式。
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,校準(zhǔn)用,參數(shù):c
}
/************************************************
函 數(shù) 名: Delay1000uS()
功 能: 1000微秒延時(shí)函數(shù)
輸入?yún)?shù): 晶振1M,機(jī)器周期為1uS。
輸出參數(shù): 延遲時(shí)間T=a(4b+3)+c
描 述: 在C中調(diào)匯編函數(shù),使用r24,r25不必作特殊的保護(hù)工作。
***********************************************/
void Delay1000uS (void)
{
asm(" ldi r24,4 ") //t=1 參數(shù):a
asm("loop5: ldi r25,61 ") //t=1 參數(shù):b
asm("loop6: dec r25 ") //t=1
asm(" nop ") //t=1,校準(zhǔn)用,需改動(dòng)公式。
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,校準(zhǔn)用,參數(shù):c
}
/************************************************
函 數(shù) 名: key_decode (uchar data)
功 能: 鍵值掃描碼是無(wú)規(guī)律的,我們只能通過(guò)switch來(lái)獲得鍵值。
輸入?yún)?shù): 掃描碼
輸出參數(shù): 翻譯后的鍵值,并顯示
描 述: 本處也可以通過(guò)數(shù)組實(shí)現(xiàn)。
***********************************************/
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;
}
}
/************************************************
函 數(shù) 名: spk()
功 能: 蜂鳴器鳴叫一聲函數(shù)
輸入?yún)?shù):
輸出參數(shù):
描 述: /
***********************************************/
void spk (uchar i)
{
PORTA &= ~(1<<PA2); //蜂鳴器響
DelaymS (i); //延遲
PORTA |= (1<<PA2); //蜂鳴器關(guān)閉
}
/************************************************
函 數(shù) 名: Init_mcu()
功 能: 單片機(jī)初始化函數(shù)
輸入?yún)?shù): /
輸出參數(shù): /
描 述: 相關(guān)口方向的設(shè)置等
***********************************************/
void Init_mcu(void)
{
DDRC = 0xff; //PC口為推挽1輸出
DDRD = 0b11110111; //PD3(INT1)接蜂鳴器為輸入,其余為輸出。
PORTD = 0b10001111; //紅外輸入端需要使用內(nèi)部上拉電阻,只使用第一位數(shù)碼管。
DDRA = 0xff; //PA口為輸出,PA4接蜂鳴器
PORTA = 0xff; //默認(rèn)蜂鳴器不響
}
/************************************************
函 數(shù) 名: Init_int1()
功 能: 外部中斷1初始化函數(shù)
輸入?yún)?shù): /
輸出參數(shù): /
描 述: 設(shè)置外部中斷1為下降沿觸發(fā)
***********************************************/
void init_int1 (void) //外部中斷1初始化
{
MCUCR |= (1<<ISC11); //設(shè)置為下降沿中斷觸發(fā)
MCUCR &= ~(1<<ISC10); //設(shè)置為下降沿中斷觸發(fā)
GICR |= (1<<INT1); //通用中斷控制寄存器,中斷使能
}
/************************************************
函 數(shù) 名: Init_serving()
功 能: 紅外IR接收中斷服務(wù)程序
輸入?yún)?shù): /
輸出參數(shù): /
描 述: 整個(gè)紅外譯碼部分的處理
***********************************************/
void int1_serving (void) //外部中斷1,紅外IR接收中斷服務(wù)程序
{
uchar i,j,k,mid ;
uchar buf[4];
CLI(); //暫時(shí)屏蔽外部中斷
for (i=0;i<9;i++)
{
Delay882uS(); //調(diào)用882uS延遲程序。
if((PIND&0x08)!=0) //判斷INT1端口的狀態(tài)。操作的是PD3,PD3為高嗎?
{
SEI(); //開中斷
return; //如果為高,說(shuō)明是干擾或出錯(cuò),跳出這個(gè)循環(huán)。
}
}
while ((PIND & 0x08) == 0); //等待9ms的低電平結(jié)束,
while ((PIND & 0x08) != 0); //等待4.5ms的高電平結(jié)束,
for (j=0;j<4;j++)
{
k=0;
for (i=0;i<8;i++)
{
while((PIND&0x08)==0); //等待每一個(gè)數(shù)據(jù)位的0.565ms低電平后的高電平
Delay882uS(); //高電平開始后用882微秒的時(shí)間尺去判斷信號(hào)此時(shí)的高低電平狀態(tài)
mid = PIND & 0x08; //讀取端口的值。
if (mid != 0)
{
Delay1000uS(); //為高電平,再延遲1ms,
k |= 1<<i; //讀取1
}
else
{
k &= ~(1<<i); //讀取0
}
}
buf[j] = k ; //保存讀到的數(shù)據(jù)
}
if ((buf[2]|buf[3]) != 0xff) //判斷數(shù)據(jù)的第三字節(jié)和第四字節(jié)的取反后相等嗎?
{
SEI(); //開中斷
return; //如果不相等說(shuō)明是干擾或出錯(cuò),跳出整個(gè)循環(huán)。
}
key_decode (buf[2]); //判斷鍵值并顯示,系統(tǒng)碼即buf[1]和buf[2]忽略。
//PORTC = buf[2]; //直接顯示鍵值
spk(1000); //蜂鳴器響一聲。
SEI(); //開中斷
}
//------------------------main----------------------------
void main (void)
{
Init_mcu(); //單片機(jī)端口初始化,口方向設(shè)置與外部中斷的使用無(wú)關(guān),不影響。
spk(1000); //蜂鳴器響一聲。
init_int1(); //外部中斷1初始化
SEI(); //開中斷
PORTC=0b10111111; ///上電后初始顯示"-"
while (1)
;
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -