此編碼為常見的紅外遙控編碼, 可以完成紅外遙控或紅外資料的傳輸
主要演算法:編碼: 用3278Hz頻率(P2.0第二功能輸出ACLK)驅動紅外二極體發送資料(應為38KHz 紅外接收頭要求, 我用的是近距離模擬的, 考慮到計時器資源寶貴, 暫用32K代替, 經驗證近距離可以完成傳輸, 使用是可以改為由TA的P1.2輸出, 稍微改下程式即可:初始化TA, 讓P1.2口輸出38K的pwm波, 巨集定義中的BIT_0/1改為P1.2口的第二功能開關即可)
發送時先由TB的CCR0的中斷控制時間完成9ms的紅外發射和4.5ms的停止 然後用CCR0和CCR4的中斷完成資料的發送
解碼:CCR5定時沒450ms中斷一次對資料進行檢測發現低電平進入資料幀判斷 若引導碼和起始碼正確則進入資料接收邏輯,
編解碼波形(NEC)
//________________ __ __ __
// | | | | | |
// | | | | | |
// | | | | | |
// | | | | | |
// | | | | | |.....................................
// | | | | | |
// | | | | | |
// |________| |_| |__| "0"高:0.56ms+低:0.565ms=1.125ms
//|||"0"| "1"| "1"高:0.56ms+低:1.69ms =2.25ms
//||||8位元資料->||
//
//可以完成編碼 解碼 注釋掉#define DECODE移去解碼部分 #define ENCODE移去編碼
//sendFlg是發送完成標誌, 完成後置1 未完成時連發資料無效
//
//佔用資源:TB CCR0中斷 CCR4 CCR5中斷 CCR0賦值為1125 時鐘1MHz
//紅外輸出端P2.0 32768Hz
//P2.1為紅外輸入埠
程式#define DECODE //解碼
#define ENCODE //編碼
#include "msp430x16x.h"
#include "紅外編解碼.h"
/**********************************巨集定義**************************************/
#ifdef ENCODE/*=======編碼=======*/
#define BIT_0 P2SEL&=~BIT0 //紅外編碼後的低電平
#define BIT_1 P2SEL|=BIT0 //紅外編碼後的高電平
#define SENDDAT TBCCTL0|=CCIE //啟動資料發送 發送已存入addr0和dat0的資料
//發送資料位元高位部分 開始發資料位元
#define SENDBIT TBCCR4=565-1;TBCCTL4|=CCIE
#define SEND_END TBCCTL0&=~CCIE;TBCCTL4&=~CCIE //發送結束 關中斷
#endif/*=======編碼=======*/
#ifdef DECODE/*=======解碼=======*/
#define DATIN ((P2IN&BIT1)>>1) //資料登錄
#endif/*=======解碼=======*/
/******************************************************************************/
#ifdef DECODE/*=======解碼=======*/
//解碼後保存資料
char addr1;
char dat1;
char readFlg = 0;//成功讀紅外資料標誌
#endif/*=======解碼=======*/
#ifdef ENCODE/*=======編碼=======*/
//要編碼的資料 發送緩存
char addr0;
char dat0;
char sendFlg = 1;//發送完成標誌
#endif/*=======編碼=======*/
//初始化TB
void int_TB()
{
TBCTL = TBSSEL_2 + TBCLR + MC_1; //TB時鐘源:SMCLK 增模式
TBCCR0 = 1125 - 1;
TBCCTL5 |= CCIE;
TBCCR5 = 450;
}
//有關埠初始化
void int_io()
{
#ifdef ENCODE/*=======編碼=======*/
//ACLK輸出作為編碼的載波
P2OUT &=~ BIT0;
P2DIR |= BIT0;
#endif/*=======編碼=======*/
#ifdef DECODE/*=======解碼=======*/
//解碼輸入埠P2.1
/*P2IES |= BIT1;
P2IFG &=~ BIT1;
P2IE |=BIT1;*/
#endif/*=======解碼=======*/
}
//初始化紅外相關資源
void int_hw()
{
int_TB();
int_io();
}
#ifdef ENCODE/*=======編碼=======*/
//編碼發送資料,eos標誌最後資料一般為1, 發送多位元組資料時, 最後一位元組是1
void sendDat(char addr,char dat)
{
if(sendFlg)//上次發送完成
{
//資料存入發送緩存
addr0 = addr;
dat0 = dat;
//開始發送
SENDDAT;
}
}
#endif/*=======編碼=======*/
#ifdef DECODE
//紅外資料解碼函數
void datDecode(unsigned int tAddr, unsigned int tDat)
{
if(((tAddr>>8)&0xff)==(tAddr&0xff))//位址高位低位元相等 位址位元資料正確
{
addr1 = tAddr&0xff;
if(((tDat>>8)&0xff)==((~tDat)&0xff))//資料高位低位元反 資料位元資料正確
{
dat1 = ~(tDat&0xff);
readFlg = 1;
}
else
{
readFlg = 2;
}
}
else
{
readFlg = 2;
}
}
#endif
//中斷
#ifdef ENCODE/*=======編碼=======*/
//TB0中斷 編碼
#pragma vector=TIMERB0_VECTOR
__interrupt void Timer_B (void)
{
static char i = 0; //計數 起始
static char state = 0; //狀態 起始:0 數據:1
static char cnt = 0; //發送計數
if(state==0)
{
if(i==0)
{
BIT_1;
//完成標誌置0 開始發送
sendFlg = 0;
}
else if(i==8)
{
BIT_0;
}
else if(i==11)
{
SENDBIT;
state = 1;
i = 255;
}
}
else if(state==1)
{
BIT_0;
if(cnt
{
if(addr0&(1
{
if(i==1)
{
SENDBIT;
i = 255;
cnt++; //發送加1
}
}
else
{
SENDBIT;
i = 255;
cnt++; //發送加1
}
}
else if(cnt
{
if(addr0&(1
{
if(i==1)
{
SENDBIT;
i = 255;
cnt++; //發送加1
}
}
else
{
SENDBIT;
i = 255;
cnt++; //發送加1
}
}
else if(cnt
{
if(dat0&(1
{
if(i==1)
{
SENDBIT;
i = 255;
cnt++; //發送加1
}
}
else //是0延時+1:1.125ms
{
SENDBIT;
i = 255;
cnt++; //發送加1
}
}
else if(cnt
{
if((~dat0)&(1
{
if(i==1)
{
SENDBIT;
i = 255;
cnt++; //發送加1
}
}
else //是0延時+1:1.125ms
{
SENDBIT;
i = 255;
cnt++; //發送加1
}
}
/*else if(cnt==32)//最後多發一位0, 否則無法識別最後一位
{
SENDBIT;
i = 255;
cnt++; //發送加1
}*/
else
{
//完成標誌置1
sendFlg = 1;
//變數歸零
state = 0;
cnt = 0;
i = 255;
SEND_END;//停止發送
BIT_0;
}
}
i++; //計數加1
TBCCTL4 &=~ CCIFG;//中斷標誌清除
}
#endif/*=======編碼=======*/
//TB1中斷
#pragma vector=TIMERB1_VECTOR
__interrupt void Timer_B1(void)
{
static int i = 0; //計數變數 接收用
static char state = 0; //代表接收狀態的變數
static char cnt = 0;//讀取位數計數
switch( TBIV )
{
case 0x08: // TBCCR4 編碼發送資料位元部分
#ifdef ENCODE/*=======編碼=======*/
BIT_1;
TBCCTL4 &=~ CCIE;
#endif/*=======編碼=======*/
break;
case 0x0a: // TBCCR5 解碼用
#ifdef DECODE/*=======解碼=======*/
TBCCR5 = (TBR+440>1124)?(TBR+440-1124):(TBR+440);
if(TBCCR5>1124) TBCCR5 = 1124;//防止TBCCR5出界
i++;
if(DATIN==0&&readFlg>0)//上次讀取完成(可能有錯誤 readFlg=2 錯誤資料) 又有資料到來
{
readFlg = 0;
i = 0;
}
if(state==0&&readFlg == 0)//起始碼
{
if(i
{
readFlg = 2;
}
else if(i>26&&DATIN==0X01)//引導碼正確 準備讀數據
{
state = 1;//1狀態 讀數據
i = 0;
}
}
else if(state==1)//數據
{
static unsigned int tAddr = 0;//位址位元臨時變數
static unsigned int tDat = 0;//資料位元臨時變數
static char datFlg = 0;
if(cnt
{
if(DATIN==0x00&&datFlg==0)
{
datFlg = 1;//有數據
i = 0;
}
if((i==2||i==3)&&datFlg&&DATIN==0X00)
{
tAddr |= (0X00)
i = 0;
datFlg = 1;
cnt++;
return;
}
else if((i==3)&&DATIN==0X01&&datFlg)
{
tAddr |= (0X01)
i = 0;
datFlg = 0;
cnt++;
}
else if(i>3)
{
readFlg = 2;
cnt = 0;
datFlg = 0;
tAddr = 0;
tDat = 0;
state = 0;
}
}
else if(cnt
{
if(DATIN==0x00&&datFlg==0)
{
datFlg = 1;//有數據
i = 0;
}
if((i==2||i==3)&&datFlg&&DATIN==0X00)
{
tDat |= (0X00)
i = 0;
datFlg = 1;
cnt++;
return;
}
else if((i==3)&&DATIN==0X01&&datFlg)
{
tDat |= (0X01)
i = 0;
datFlg = 0;
cnt++;
}
else if(i>3)
{
readFlg = 2;
cnt = 0;
datFlg = 0;
tAddr = 0;
tDat = 0;
state = 0;
}
}
else
{
datDecode(tAddr, tDat);
//解碼結束
i = 0;
cnt = 0;
state = 0;
datFlg = 0;
tAddr = 0;
tDat = 0;
}
}
#endif/*=======解碼=======*/
break;
case 0x0e: //overflow 溢出, 未用
break;
}
}
/*
#ifdef DECODE=======解碼=======*/
//PORT2中斷 此中斷僅解碼接收資料用
/*#pragma vector=PORT2_VECTOR
__interrupt void PORT2_ISR(void)
{
switch(DATIFG&BIT1)
{
case 2:
//開始接收資料
DATREAD;
break;
}
DATIFG = 0;//清除標誌位元
}
#endif=====
本文素材來自電子發燒友論壇