利用C8051F340的PCA捕获功能捕获红外电平进行红外解码
下面的代码 移植自http://www.amobbs.com/forum.php?mod=viewthread&tid=5004479&highlight=PCA
能顺利进入PCA捕获中断,但是无法解码, 不知道原因在哪里!
有知道,请多指教!
#define IRSIZE486
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define uint8 unsigned char
#define uint16unsigned int
#define uint32unsigned long
sbit IrInput = P3^0; //红外线接收头输出端口
sbit IrOutput = P3^1; //控制红外发射管
sbit LED1=P2^2;//LED指示灯端口
sbit LED2=P2^3;//LED指示灯端口
unsigned char byteData;
unsigned char xdata v;
unsigned char xdataIrKeyVal=0; //解码键值
bit B_Z; //丢弃第一次捕获标志
bit vt = 0; //解码完成标志位
unsigned intt;
unsigned long nn;
void delay(uint d)
{
uint i;
for(i=0;i<d;i++);
}
/********************************************
函数:10ms × n 延时程序@12MHz
*********************************************/
void YS10ms(uchar n)
{
uchar i,j,k;
for(i=n;i!=0;i--)
for(j=198;j!=0;j--)
for(k=150;k!=0;k--);
}
/******************************************************************
端口初始化程序
******************************************************************/
void port_init(void)
{
//红外捕捉,P3.0红外输入,串口输出
P0SKIP = 0xCF; //跳过前面I/O端口
P1SKIP = 0xFF; //跳过前面I/O端口
P2SKIP = 0xFF; //跳过前面I/O端口
P3SKIP = 0xFE;
XBR0 = 0x01; // Enable UART on P0.4(TX) and P0.5(RX)
XBR1 = 0x41; //交叉开关打开,将PCA输出配置到P3.0脚(CEX0)
P0MDOUT |= 0x10; // Enable UTX as push-pull output
//1 1 1 1 1 1 0 0
P2MDOUT= 0xfc;
P3MDOUT= 0x03; // 使能P3.0为推挽输出
}
/***************************************************************************************
**函数名称: PCA0_Init
**函数功能: PCA0初始化
**输入参数: 无
**输出参数: 无
***************************************************************************************/
void PCA0_Init(void) //PCA0初始化
{
int i;
PCA0CN = 0x00; // Stop counter; clear all flags
PCA0L = 0; // PCA0 Counter
PCA0H = 0;
PCA0CPH0 = 0x00; //PCA0 Capture 0
PCA0CPL0 = 0x00;
PCA0MD = 0x80; // 系统时钟
EIE1 |= 0x10; //EPCA0 = 1,允许PCA0中断 C8051F340
PCA0CPM0= 0x11; //模块0下降沿中断允许, 模块0负沿捕捉使能与配匹使能
B_Z = 1;
t = 0;
for(i=0;i<IRSIZE;i++)
{
v=0; //存储区清0
}
}
/***************************************************************************************
**函数名称: PCA0_INT
**函数功能: PCA0中断处理, PCA中断捕获程序(电位跳变捕获模式)
**输入参数: 无
**输出参数: 无
***************************************************************************************/
void PCA_ISR (void) interrupt 11
{
if (CF == 1) //计数器溢出中断,是否是PCA定时器溢出
{
CF = 0; //计数器溢出标志清零,必须用软件清零,硬件不能自动清零
v++; //PCA定时器溢出计数,保存数据最高字节
if( v>1 ) //设置允许溢出次数,>131ms 终止捕获
{
CR = 0;
CF = 0;
// CCAPM2 = 0;
PCA0CPM0= 0;
CCF0=0;
vt = 1; //捕获完成标志
v=0;
LED1 = 0;
return;
}
}
if (CCF0) //是否是电位跳变, If Module 0 caused the interrupt
{
CCF0 = 0;// Clear module 0 interrupt flag.必须软件清0 (PCA 模块0标志)
//CL = 0; //先赋值低位
//CH = 0;
PCA0L = 0; // PCA0 Counter
PCA0H = 0;
if(B_Z)
{
CR =1; //启动PCA定时器
B_Z=0;
return;
} //丢弃第一次捕获数据
t++;
v = PCA0CPH0; //保存数据高字节
t++;
v = PCA0CPL0; //保存数据低字节
t++;
LED1 =~LED1;
}
if(t >= IRSIZE) //捕获162个数据(1个电平时间3字节存放)
{
// CCAPM2 = 0;
PCA0CPM0= 0;
CCF0=0;
CR = 0;
CF = 0;
LED1 = 0;
vt = 1; //捕获完成标志
}
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:HEX转ASCII
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
unsigned char HEX2ASCII(unsigned char dat)
{
dat &= 0x0f;
if(dat <= 9) return(dat+'0'); //数字0~9('0' 0x30)
return (dat-10+'A'); //字母A~F('A' 0x41,'a' 0x61)
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:串口发送
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void TxS(uint8 i)
{
SBUF0=i;
while(!TI0);
TI0=0;
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:字符串发送
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void ZIFUC(uint8 code *p) //发送一串字符串
{
for(; *p != 0; p++) TxS(*p); //遇到停止符0结束
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:整形数据送串口显示
入口:tem = 整形数据(送入1~4字节整形数据)
num = 以什么进制显示,2:二进制,10:十进制,16:十六进制
i = 显示低几位 (以二进制显示时)
= 显示个位算起几位数(以十进制显示时)
= 显示几字节 (以十六进制显示时)
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void JZ(uint32 tem,uint8 num,uint8 i)
{
unsigned int j,z;
bit BT=0;
switch(num)
{
case2: /* tem = _lror_(tem,i-1); //以二进制显示
while(i--)
{
if(tem & 1)ZIFUC("1");
else ZIFUC("0");
tem = _lrol_(tem,1);
} */
//* 【 另一种算法 】
tem <<= (32-i);
while(i--)
{
if(tem & 0x80000000)ZIFUC('1');
else ZIFUC('0');
tem <<= 1;
}
break;
case 10:
for(j=0;j<i;j++)//以十进制显示
{
z = tem%10; //nv=个位,nv=十位,······
tem /= 10;
}
while(i--)
{
if(z || (i==0))BT=1; //数据有效标志
if(BT)TxS(HEX2ASCII(z)); //数据有效前的“0”不显示,
elseZIFUC(" "); //用空格替换。
}
break;
case 16:
for(j=4-i;j<4;j++)//十六进制显示
{
z = ((unsigned int *)&tem);
TxS(HEX2ASCII(z>>4)); //发送高4位
TxS(HEX2ASCII(z)); //发送低4位
}
break;
}
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:串口发送主程序
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void ChuanKou()
{
unsigned char i;
unsigned int j,T;
ZIFUC("\r\n\r\n ****** 接收完成 ******");
ZIFUC("\r\n\r\n ( 以下是遥控器发射脉冲的波形数据 )");
ZIFUC("\r\n\r\n序号高电平时间(us)低电平时间(us)\r\n\r\n");
i=0;
for(j=0;j<IRSIZE;)
{
((uchar *)&nn) = 0;
((uchar *)&nn) = v;
((uchar *)&nn) = v;
((uchar *)&nn) = v;
ZIFUC("");
JZ(i,10,2); //序号
ZIFUC(" ");
JZ(nn,10,8); //高电平时间
((uchar *)&nn) = 0;
((uchar *)&nn) = v;
((uchar *)&nn) = v;
((uchar *)&nn) = v;
ZIFUC(" ");
JZ(nn,10,8); //低电平时间
if( (i%8)==0 )ZIFUC("\r\n\r\n");
else ZIFUC("\r\n");
i++;
}
///////////////// NEC解码 ////////////////
j=9; //引导码丢弃
for(i=0;i<32;i++)
{
j++;
((uchar *)&T) = v;
((uchar *)&T) = v;
j += 3;
byteData >>= 1;
if((T<1900) && (T>1000))byteData |= 0x80;
}
if(byteData == ~byteData) //校验NEC操作码。错误则尝试RC5解码
{
ZIFUC("\r\n 【 NEC通用编码格式:引导码 + 32位编码(16位用户码+操作码正反码) 】\r\n");
ZIFUC("\r\n 用户码(高8位):0x");
JZ(byteData,16,1);
ZIFUC("\r\n 用户码(低8位):0x");
JZ(byteData,16,1);
ZIFUC("\r\n\r\n 操作码正码 :0x");
JZ(byteData,16,1);
ZIFUC("\r\n");
if(byteData == ~byteData)
{
ZIFUC("\r\n\r\n 经对比,16位用户码是正反码,用户码正码:0x");
JZ(byteData,16,1);
}
return;
}
///////////////// 初略分析是否是RC5编码 ////////////////
j=0;
for(i=0;i<20;i++)
{
j++;//最高位丢弃(1个数据3字节);
((uchar *)&T) = v;
((uchar *)&T) = v;
if(T<600 || T>1800)//RC5码前20个脉冲数据600<nn<1800
{
ZIFUC("\r\n 【 解码失败,再试一试或者分析波形数据 】");
return;
}
}
///////////////// 将波形数据绘成图像 ////////////////
ZIFUC("\r\n 【 RC5编码发射波形 】 发射顺序:(低位)<--(高位)\r\n");
ZIFUC("\r\n___");
j=0;
for(i=0;i<26;i++)
{
j++;//最高位丢弃(1个数据3字节);
((uchar *)&T) = v;
((uchar *)&T) = v;
if (T>2000) break;
if(i%2 != 1)//如果i是偶数
{
if(T<1000)ZIFUC("▉");
else ZIFUC("▉▉");
}
else
{
if(T<950)ZIFUC("__");
else ZIFUC("____");
}
}
ZIFUC("_____________");
ZIFUC("\r\n┊┊┊┊┊┊┊┊┊┊┊┊┊┊┊\r\n");
IR_RC5();//RC5解码
ZIFUC("\r\n┃起始位┃空┃ 系统位 ┃ 数据位 ┃\r\n");
ZIFUC("\r\n\r\n 【 RC5通用编码格式:14位编码 】\r\n");
ZIFUC("\r\n 起始位(2位):0x");
JZ(byteData,16,1);
ZIFUC(" 二进制: ");
JZ(byteData,2,2);
ZIFUC("\r\n 控制位(1位):");
if(byteData)ZIFUC(" 1");
else
ZIFUC(" 0");
ZIFUC("\r\n 系统位(5位):0x");
JZ(byteData,16,1);
ZIFUC(" 二进制: ");
JZ(byteData,2,5);
ZIFUC("\r\n 数据位(6位):0x");
JZ(byteData,16,1);
ZIFUC(" 二进制:");
JZ(byteData,2,6);
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:根据收集的脉冲数据进行RC5解码
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void IR_RC5()
{
bitB_v,BV;
uchar x;
uchar n;
uintt;
BV = 1; //BV=1时检测(接收端)低电平时间,BV=0时检测(接收端)高电平时间。
x= 0;
t= 0;
byteData=byteData=byteData=byteData=0;
for(n=0;n<14;n++) //14位位码解码
{
x++; //最高位丢弃(1个数据3字节);
((uchar *)&t) = v;
((uchar *)&t) = v;
/*┈┈┈ 确认位码值 ┈┈┈*/
if(BV)
{
if(t < 950)
{
B_v=1;
x+=3;
} //BV=1时,如果t<950uS,下次还是检测(接收端)低电平时间,且跳过高电平时间。
else
{
B_v=1;
BV=0;
}
} //BV=1时,如果t>950uS,下次检测(接收端)高电平时间
else
{
if(t < 950)
{
B_v=0;
x+=3;
}
else
{
B_v=0;
BV=1;
}
}
/*┈┈┈ 装载位码值 ┈┈┈*/
if(n < 2)
{
byteData >>= 1;
if(B_v)
byteData |= 0x02;
}
else if (n==2)
byteData = B_v;
else if (n<8)
{
byteData >>= 1;
if (B_v)
byteData |= 0x10;
}
else if (n<15)
{
byteData >>= 1;
if(B_v)
byteData |= 0x20;
}
/*┈┈┈ 发射位码值 ┈┈┈*/
ZIFUC(" ");
if(B_v)ZIFUC("1");
else ZIFUC("0");
}
}
void SYSCLK_Init(void)
{
int i = 0;
// 内部高频使能,内部高频输出(不分频)
OSCICN |= 0x83; // Set internal oscillator to run
// at its maximum frequency
CLKSEL = 0x00; // Select the internal osc. as
// the SYSCLK source
CLKMUL= 0x00; // Select internal oscillator as
// input to clock multiplie
for (i = 0; i < 3000; i++); //延时等待振荡器起振防止读标志位错误
RSTSRC= 0x04; // Enable missing clock detector
}
void UART0_Init(void)
{
SCON0 = 0x10; // SCON0: 8-bit variable bit rate
// level of STOP bit is ignored
// RX enabled
// ninth bits are zeros
// clear RI0 and TI0 bits
if (SYSCLK/BAUDRATE/2/256 < 1) {
TH1 = -(SYSCLK/BAUDRATE/2);
CKCON &= ~0x0B; // T1M = 1; SCA1:0 = xx
CKCON |=0x08;
} else if (SYSCLK/BAUDRATE/2/256 < 4) {
TH1 = -(SYSCLK/BAUDRATE/2/4);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 01
CKCON |=0x01;
} else if (SYSCLK/BAUDRATE/2/256 < 12) {
TH1 = -(SYSCLK/BAUDRATE/2/12);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 00
} else {
TH1 = -(SYSCLK/BAUDRATE/2/48);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 10
CKCON |=0x02;
}
TL1 = TH1; // Init Timer1
TMOD &= ~0xf0; // TMOD: timer 1 in 8-bit autoreload
TMOD |=0x20;
TR1 = 1; // START Timer1
TI0 = 1; // Indicate TX0 ready
}
main()
{
PCA0MD = 0x00; // Disable watchdog timer
SYSCLK_Init();
port_init(); //端口初始化
UART0_Init(); //
PCA0_Init(); //PCA初始化
LED1 = 0;
LED2 = 1;
YS10ms(10);
CR =1; //启动PCA0计数器工作
EA = 1;
while (1)
{
if ( vt == 1)
{
LED2=0;
vt = 0;
ChuanKou(); //串口显示
YS10ms(200);
//YS10ms(200);
//YS10ms(200); //6秒后重新开始
PCA0_Init();
CR=1;
EA=1;
LED2=1;
}
}
}
页:
[1]