一、前言
1.1 功能介紹
隨著科技的進步和人們生活水平的提高,紅外遙控器已經(jīng)成為了日常生活中不可或缺的電子設備之一,廣泛應用于電視、空調(diào)、音響等多種家電產(chǎn)品中。 傳統(tǒng)的紅外遙控器通常只能實現(xiàn)預設的有限功能,無法滿足用戶對設備更加智能化、個性化的控制需求。
STC90C51作為一款功能強大的8位微控制器,具備高性能、低功耗和豐富的I/O端口資源,非常適合用于實現(xiàn)紅外遙控信號的解碼和控制。本項目利用STC90C51微控制器,結合定時器和外部中斷機制,實現(xiàn)NEC紅外線協(xié)議的解碼,從而實現(xiàn)對紅外遙控器的控制功能。
NEC紅外線協(xié)議是一種常見的紅外遙控通信協(xié)議,具有傳輸速度快、編碼簡單、可靠性高等特點。通過解碼NEC紅外線協(xié)議,可以獲取遙控器發(fā)送的按鍵信息,進而實現(xiàn)對設備的遠程控制。在本項目中,我們將利用STC90C51的定時器功能,設置合適的定時參數(shù),以檢測紅外信號的脈沖寬度和間隔。同時,利用外部中斷機制,實時監(jiān)測紅外接收管的狀態(tài)變化,捕捉紅外信號的起始和結束時刻。
通過解碼NEC紅外線協(xié)議,我們可以獲取遙控器發(fā)送的按鍵編碼,并將其轉(zhuǎn)換為對應的控制指令。在本項目中,我們將以開關控制為例,實現(xiàn)對目標設備的遠程控制。具體而言,當遙控器發(fā)送“開”或“關”的按鍵編碼時,STC90C51將解碼該編碼,并發(fā)送相應的控制指令給目標設備,以實現(xiàn)設備的開關控制。
本項目的開發(fā)背景不僅體現(xiàn)了現(xiàn)代家居和電子設備對遠程控制技術的需求,也展示了STC90C51微控制器在嵌入式系統(tǒng)設計和開發(fā)中的強大功能。通過實現(xiàn)NEC紅外線協(xié)議的解碼和控制,本項目將為用戶帶來更加便捷、智能的遠程控制體驗,推動智能家居和物聯(lián)網(wǎng)技術的發(fā)展。
1.2 NEC協(xié)議介紹
NEC協(xié)議是一種紅外線通信協(xié)議,廣泛應用于家電遙控器和其他紅外線設備之間的通信。該協(xié)議具有簡單、易于實現(xiàn)和廣泛兼容的特點,使得不同品牌和型號的紅外設備能夠互相通信和控制。
NEC協(xié)議的工作原理基于38kHz的紅外線載波頻率,通過發(fā)送特定格式的數(shù)據(jù)包來傳輸信息。每個數(shù)據(jù)包由連續(xù)的脈沖和間隔組成,其中脈沖表示邏輯1,間隔表示邏輯0。數(shù)據(jù)包的結構包括同步碼(Sync Header)、地址碼、地址碼的反碼、命令碼以及命令碼的反碼。
同步碼是數(shù)據(jù)包開始的標識,通常是一個持續(xù)約9ms的高電平脈沖(Mark),用于同步接收器和發(fā)送器之間的通信。地址碼和命令碼是每個按鍵特定的標識,用于識別按下的是哪個按鍵。地址碼和地址碼的反碼用于驗證遙控器發(fā)送的數(shù)據(jù)是否正確,而命令碼和命令碼的反碼則用于執(zhí)行相應的操作。
在NEC協(xié)議中,數(shù)據(jù)以二進制格式進行傳輸,確保了信息的準確性和高效性。此外,NEC協(xié)議還定義了一個重復碼,當用戶長按遙控器上的某個按鍵時,遙控器會發(fā)送該按鍵的重復碼,以避免連續(xù)發(fā)送相同的命令。
NEC協(xié)議是一種基于紅外線通信的協(xié)議,通過發(fā)送特定格式的數(shù)據(jù)包來實現(xiàn)不同設備之間的通信和控制。它具有簡單、易于實現(xiàn)和廣泛兼容的特點,被廣泛應用于家電遙控器等紅外設備中。
二、代碼實現(xiàn)
2.1 main.c
#include <reg51.h>
#include "delay.h"
#include "key.h"
#include "type.h"
#include "led.h"
#include "uart.h"
#include "timer.h"
#include "exti.h"
#include "infrared.h"
int main()
{
UART_Init(); //初始化串口波特率為4800
Infrared_Init(); //初始化紅外功能
while(1)
{
if(Infrared_RX_Flag) //接收到紅外數(shù)據(jù)
{
Infrared_RX_Flag=0; //清楚標志
printf("user1:%d,user2:%drn",(int)Infrared_RX_Buff[0],(int)((u8)(~Infrared_RX_Buff[1])));
printf("key1:%d,key2:%drn",(int)Infrared_RX_Buff[2],(int)((u8)(~Infrared_RX_Buff[3])));
}
}
}
2.2 INFRARED.c
#include "Infrared.h"
u8 Infrared_RX_Flag=0; //紅外接收標志,收到一幀正確數(shù)據(jù)后置1
u8 Infrared_RX_Buff[4];//紅外代碼接收緩沖區(qū)
/*
函數(shù)功能: 開始紅外線解碼之前的相關初始化
實驗板的晶振頻率是12MHZ
51單片機標準架構下一個機器周期是12個時鐘周期,如果晶振頻率是12MHZ,那一個機器周期的時間就是12/12微秒。
也就是說定時器的計數(shù)器+1的時間就是12/12=1us。
*/
void Infrared_Init(void)
{
Infrared_GPIO=1;//紅外接收引腳默認保持高電平輸出
TMOD&=0xF0; //清除配置
TMOD|=0x01; //配置定時器0,工作在16位計數(shù)模式
TR0=0; //停止定時器0計數(shù)
ET0=0; //禁止定時器0中斷
IT0=1; //開啟外部中斷0,下降沿觸發(fā)
EX0=1; //允許外部中斷0中斷
}
/*
函數(shù)功能: 檢測高電平持續(xù)的時間
*/
u16 Infrared_GetTimeH(void)
{
TH0=0; //定時器0重裝值為0
TL0=0; //定時器0重裝值為0
TR0=1; //啟動定時器0開始計數(shù)
while(Infrared_GPIO)//等待高電平結束
{
if(TH0>0x40)//防止超時
{
break;
}
}
TR0=0;//停止定時器0計數(shù)
return TH0<<8|TL0;//T0計數(shù)值合成為16位整數(shù)返回
}
/*
檢測低電平持續(xù)的時間
*/
u16 Infrared_GetTimeL(void)
{
TH0=0;//定時器0的高8位重裝值
TL0=0;//定時器0的低8位重裝值
TR0=1;//開啟定時器0
while(Infrared_GPIO==0)//等待低電平結束
{
if(TH0>0x40)//防止超時
{
break;
}
}
TR0=0;//停止定時器0計數(shù)
return TH0<<8|TL0;//T0計數(shù)值合成為16位整數(shù)返回
}
/*
外部中斷0中斷服務函數(shù)
*/
void EXTI0_IRQHandler() interrupt 0
{
u8 i, j;
u16 time;
u8 byte;
time=Infrared_GetTimeL(); //獲取出現(xiàn)低電平的時間
if((time<7800)||(time>9300))//判斷低電平時間是否符合9ms范圍
{ //超過此范圍則說明為誤碼,直接退出
IE0=0; //清除外部中斷0中斷標志
return;
}
time=Infrared_GetTimeH(); //獲取出現(xiàn)高電平的時間
if((time<3500)||(time>4700))//高電平是否符合4.5ms范圍
{ //超過此范圍則說明為誤碼,直接退出
IE0=0; //清除外部中斷0中斷標志
return;
}
//接收32位數(shù)據(jù)位
for(i=0;i<4;i++)
{
for(j=0;j<8;j++)
{
time=Infrared_GetTimeL(); //獲取低電平持續(xù)時間,標準的間隔時間為560us范圍
if((time<300)||(time>700)) //判斷范圍是否合理
{
IE0=0;//清除外部中斷0中斷標志
return;
}
//1和0是靠高電平持續(xù)的長短來區(qū)分的
time=Infrared_GetTimeH(); //獲取高電平持續(xù)時間
if(time>300&&time<700) //0的標準時間為560us
{
byte>>=1;
}
else if(time>1400&&time<1800) //1的標準時間是1680us
{
byte>>=1;
byte|=0x80;
}
else //不在上面的判斷范圍內(nèi)說明是錯誤碼,直接退出
{
IE0=0;//清除外部中斷0中標
return;
}
}
Infrared_RX_Buff[i]=byte;//接收完一個字節(jié)后保存到緩沖區(qū)
}
Infrared_RX_Flag=1;//接收完畢后設置標志
IE0=0;//退出前清除外部中斷0中斷標志
}
2.3 INFRARED.h
#ifndef _INFRAREAD_H
#define _INFRAREAD_H
#include <reg51.h>
#include "type.h"
sbit Infrared_GPIO=P3^2;//紅外接收引腳--外部中斷0
void Infrared_Init();//紅外線接收初始化
u16 Time_H();//檢測高電平
u16 Time_L();//檢測低電平
extern u8 Infrared_RX_Flag; //紅外接收標志,收到一幀正確數(shù)據(jù)后置1
extern u8 Infrared_RX_Buff[4]; //紅外代碼接收緩沖區(qū)
#endif