?? redcode.c
字號:
//紅外編碼解碼主程序v1.0
//能處理大部分紅外遙控器
//對紅外指令連續(xù)發(fā)送兩次以上的遙控器有效,紅外指令代碼須小于54位
//redcode.c
#include "string.h"
#include "iic.h"
#include "math.h"
#define CODELEN 256 /*定義一個(gè)代碼的存儲長度*/
typedef unsigned long ulong;
enum {re_len=6};
data uchar aa[7]={0x45,0x46,0x47,0x48,0x49,0x50,0x51};
uint k=0;
uint j;
idata uint tempkey;
idata uint codelen,codelen0,codelen1;
idata uchar lenth0,lenth1;
sbit sigin=P3^4;//0038紅外接收器輸入管腳
sbit sigout=P3^0;//控制紅外發(fā)射管
sbit mode=P3^3;//模式選擇管腳,選擇為學(xué)習(xí)代碼還是發(fā)射代碼
sbit ledg=P3^2;//指示led1控制管腳
sbit ledl=P3^1;//指示led2控制管腳
bit keydown;
bit isodd;
bit sig;
sbit kv0=P3^5;//鍵盤數(shù)據(jù)口
sbit kv1=P1^1;
sbit kv2=P1^2;
sbit kv3=P1^3;
sbit kv4=P1^4;
sbit kv5=P1^5;
bit iskeyboard;
bit iserror;
bit ramerror;
bit detectend;
bit ismode;
bit isnew0,isnew1,isnew2;
idata uchar v_val;
uint keysave;
xdata uint sigdata[400];//接收發(fā)送代碼緩沖區(qū),占用800字節(jié)外部內(nèi)存空間
idata uint head0;
union intchar{
uint tempval;
struct {uchar hi;uchar low;}bytek;
}tcf;//巧用聯(lián)合體,使之字節(jié)操作和uint型操作轉(zhuǎn)化方便,便于數(shù)據(jù)存取
union intchar flashd,flashd2;
uchar store;
uchar senddata;
void testcon();
uchar scankey();
void getkey();
void paramini(void);
void pca0ini();
void encode(void);
uchar keyv();
void error();
void decode();
void readdata(void);
void sendcode();
void copyflash();
void xramcheck();
uchar keyv2();
void resett0(void){//將T0計(jì)數(shù)器值從設(shè)為0
TH0=0;
TL0=0;
TR0=1;
}
uint readt0(void){//讀取T0計(jì)數(shù)器值
uint tmp;
TR0=0;
tmp=(uint)TH0*256;//可用union intchar型數(shù)據(jù),則可避免運(yùn)算
tmp+=TL0;
resett0();//讀完后將計(jì)數(shù)器值清零,并啟動(dòng)定時(shí)器
return tmp;
}
void t0ini(){//設(shè)置T0為16bit定時(shí)器模式
TMOD=0x11;
TCON=0x01;
}
void main(){
uchar t=0;
config();
sigout=0;
t0ini();
EA=0;
P2|=0xfc;
P1|=0x3e;
for(k=0,j=0;k<50;k++){//自動(dòng)檢查是鍵盤輸入還是其他MCU并口輸入
//若另一個(gè)MCU直接與該機(jī)相連,則可與其kv5-kv0相連,kv5-kv0的值即為代碼索引
//與MCU相連,則MCU不發(fā)送代碼,所以代碼索引值為0
//與鍵盤相連,則鍵盤沒有按鍵按下,則返回時(shí)kv5-kv0均為1,由此可判斷
//輸入接口是MCU還是鍵盤
if(keyv()<8)
j++;
}
if(j>30)
iskeyboard=0;//判斷出為MCU輸入
else
iskeyboard=1;//判斷出為鍵盤輸入
for(k=0;k<20;k++){//若為鍵盤輸入,則ledg和ledl指示燈均同時(shí)閃爍
//若為MCU輸入,則只有l(wèi)edl指示燈閃爍
ledl=1;
ledg=1;
delay1ms(100);
if(!iskeyboard){
ledg=0;
}
ledl=0;
delay1ms(100);
}
xramcheck();//檢查外部內(nèi)存是否正常工作
if(ramerror)
for(k=0;k<50;k++){//若外部內(nèi)存不正常,則ledg和ledl交叉閃爍
ledl=1;
ledg=0;
delay1ms(100);
ledl=0;
ledg=1;
delay1ms(100);
}
ledl=0;
ledg=0;
pca0ini();
TR0=0;
mode=1;
ismode=mode;
while(1){
ismode=mode;
if(ismode){//接收代碼模式
if(scankey()==0)
goto again0;
else
decode();
}
else{//發(fā)送代碼模式
if(scankey()==0)
goto again0;
else
sendcode();
}
again0:;
}
}
void getkey(){//將鍵盤值轉(zhuǎn)化為EEPROM首入地址
ledl=0;
keysave*=CODELEN;//將鍵盤值與代碼存儲長度相乘即為存儲首地址
//鍵盤上一個(gè)按鍵代表一個(gè)代碼
//采用全局變量可減少參數(shù)傳遞和賦值,可提高代碼執(zhí)行效率,
//但移植性變?nèi)?}
void testcon(){//對紅外接收的處理程序,將正確接收的值存入sigdata數(shù)組
tcf.tempval=keysave;//keysave為當(dāng)前紅外代碼的存儲首地址
//tempkey=keysave;//
testagain:
j=0;
sigin=1;//將0038紅外信號輸入口置1,才能保證對端口電平的正確讀取
//否則若sigin端口值為0,而實(shí)際0038輸入值為1,則會(huì)被端口值下拉至0,不能正確
//讀取其實(shí)際端口電平
ledg=1;
ledl=0;
codelen=0;
iserror=0;
ledl=0;
EA=0;
k=0;
while(1){
sig=sigin;//對硬件端口的判斷操作指令讀取的是端口值,而不是實(shí)際電平值,建議
//將端口電平值先讀取到bit 布爾變量中,再進(jìn)行判斷
//比如由上操作知sigin端口值恒為1,而端口實(shí)際電平值可為0,也可為1
//若直接if(sigin)則讀取的是恒為1
if(!sig)//一直檢測0038紅外輸入信號,若有紅外輸入信號,則該值為0
break;
}
resett0();//將T0計(jì)數(shù)器清零
TF0=0;//將T0溢出標(biāo)志清零
detectend=0;
sig=sigin;
while(!sig){//等待高電平出現(xiàn)
if(TF0){
TF0=0;//若定時(shí)器溢出,說明低電平時(shí)間過長,不是有效編碼信號,重新檢測
iserror=1;
goto testagain;
}
sig=sigin;
}
head0=readt0();//此時(shí)sigin低電平結(jié)束,讀取T0計(jì)數(shù)器值為低電平的持續(xù)時(shí)間
tcf.tempval=head0;//此為幀首特征,將幀首低電平值存入head0變量中
sigdata[j]=tcf.tempval;//同時(shí)將數(shù)據(jù)存入外部內(nèi)存緩沖區(qū)中
j++;
while(1){
sig=sigin;
while(sig){//等待低電平出現(xiàn)
if(TF0){//若定時(shí)器溢出,則高電平值為非正常編碼
TF0=0;
if(j<15){//若接收的代碼長度小于15/2=7個(gè),則認(rèn)為接收到的為干擾信號
//重新開始檢測
iserror=1;
goto testagain;
}
else{
sigdata[j]=0xfff4;//若接收代碼大于7個(gè),則認(rèn)為接收到幀間隔,結(jié)束幀
//同時(shí)給高電平的持續(xù)時(shí)間賦為0xfff4,并結(jié)束檢測
j+=3;
goto testconend;
}
}
sig=sigin;
}
tcf.tempval=readt0();
sigdata[j]=tcf.tempval;//存儲高電平持續(xù)時(shí)間值
j++;
if(j>200){//若代碼長度大于200/2=100個(gè),則認(rèn)為出錯(cuò),結(jié)束檢測
error();
goto testend;
}
if(detectend)//若檢測到幀結(jié)束,則結(jié)束檢測
//幀結(jié)束的判斷依靠檢測到兩個(gè)幀起始來判斷
goto testconend;
sig=sigin;
while(!sig){//當(dāng)前為低電平,等待高電平
if(TF0){
TF0=0;//若定時(shí)器溢出,則認(rèn)為當(dāng)前檢測無效
error();//調(diào)用錯(cuò)誤處理函數(shù)
goto testend;//結(jié)束檢測,若重新檢測可能在無法排除某種錯(cuò)誤時(shí),陷入
//死循環(huán)檢測,使得程序魯棒性下降
}
sig=sigin;
}
tcf.tempval=readt0();
sigdata[j]=tcf.tempval;
j++;
if(abs(tcf.tempval-head0)<100){//判斷當(dāng)前低電平持續(xù)時(shí)間值與幀起始head0的差距
//若差值小于100,則認(rèn)為第二次檢測到幀起始,100為經(jīng)驗(yàn)值,讀者可根據(jù)
//實(shí)際情況適當(dāng)調(diào)整
if(j>10){//若代碼長度大于10/2=5,則認(rèn)為正確檢測到重復(fù)幀的幀起始
detectend=1;
goto segnext1;//此時(shí)還沒有結(jié)束檢測,測量完高電平寬度才結(jié)束當(dāng)前幀檢測
}
else{//若代碼長度小于5,則認(rèn)為受干擾
error();//調(diào)用錯(cuò)誤處理函數(shù),退出檢測
goto testend;
}
}
if(j>200){//若代碼長度大于100則認(rèn)為出錯(cuò),退出檢測
error();
goto testend;
}
segnext1:;
}
testconend:
codelen=j-2;//由于是檢測到重復(fù)幀的幀起始(低電平+高電平)才認(rèn)為檢測到幀結(jié)束,
//所以數(shù)據(jù)長度為j-2
codelen0=200+codelen;
detectend=0;//重新開始檢測
sigdata[201]=sigdata[j-1];//將重復(fù)幀的幀頭高電平數(shù)據(jù)存入外部內(nèi)存
sigdata[200]=sigdata[j-2];//將重復(fù)幀的幀頭低電平數(shù)據(jù)存入外部內(nèi)存
j=202;
//對重復(fù)幀采用類似的檢測方法,且將數(shù)據(jù)存入外部內(nèi)存
while(1){
sig=sigin;
while(!sig){
if(TF0){
TF0=0;
error();
goto testend;
}
sig=sigin;
}
tcf.tempval=readt0();
sigdata[j]=tcf.tempval;
j++;
if(j>400){//數(shù)據(jù)過長,認(rèn)為是錯(cuò)誤
error();
goto testend;
}
segnext2:
sig=sigin;
while(sig){
if(TF0){
TF0=0;
error();
goto testend;
}
sig=sigin;
}
tcf.tempval=readt0();
sigdata[j]=tcf.tempval;
j++;
if(j>400){
error();
goto testend;
}
if(j>codelen0)//依據(jù)第一次檢測的幀長度決定重復(fù)幀的幀結(jié)尾
goto testconend2;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -