问题概述如下:我要用51单片机采样外部的红外信号数据,用定时器0定时26us进行采样,然后将采样的数值存入数组,但现在发现采样出来的数值和理论值差距有点大,比如说理论值是0.56ms,采样出来的值有可能只有0.30ms,这个问题出在哪里?
代码如下:#include<reg52.h>
#include<intrins.h>
typedef unsigned int uint;
typedef unsigned char uchar;
sbit Txd_Port = P1^0; //发射脚
sbit remotein = P3^2; //遥控信号输入口
sbit Txd_key = P1^1; //发射键
sbit Txd_key1 = P1^2; //发射键2
sbit scl = P3^6; //I2C时钟信号线
sbit sda = P3^7; //I2C数据线
unsigned short data count1 = 0;
uchar idata remotedata[80]; //存脉冲宽度数据用 数组较大,放在idata里 ,只能用指针读写
uchar int_flag = 0; // 红外接收中断是否产生
uchar Time1_Flag = 0;
sbit test0 = P0^0;
sbit test1 = P0^1;
sbit test2 = P0^2;
sbit test3 = P0^3;
sbit test4 = P0^4;
sbit test5 = P0^5;
sbit test6 = P0^6;
sbit test7 = P0^7;
/***************************************
延时2个_nop_
***************************************/
void flash(void)
{
_nop_();
_nop_();
}
/**************************************
Delay_1ms 延时1MS
**************************************/
void Delay_1ms(uint i)
{
uint x, j;
for(j=0; j<i; j++)
for(x=0; x<=148; x++)
;
}
/********************************************************************
* 名称 : x24c02_init()
* 功能 : 24c02初始化子程序
* 输入 : 无
* 输出 : 无
***********************************************************************/
void x24c02_init(void)
{
scl = 1;
flash();
sda = 1;
flash();
}
/********************************************************************
* 名称 : start(void)
* 功能 : 启动I2C总线
* 输入 : 无
* 输出 : 无
***********************************************************************/
void start(void)
{
scl = 1;
flash();
sda = 1;
flash();
sda = 0;
flash();
scl = 0;
flash();
}
/********************************************************************
* 名称 : stop()
* 功能 : 停止I2C总线
* 输入 : 无
* 输出 : 无
***********************************************************************/
void stop()
{
scl = 0;
flash();
sda = 0;
flash();
scl = 1;
flash();
sda = 1;
flash();
}
/********************************************************************
* 名称 : writex()
* 功能 : 写一个字节
* 输入 : j(需要写入的值)
* 输出 : 无
***********************************************************************/
void writex(uchar j)
{
uchar i,temp;
temp = j;
for(i=0; i<8; i++)
{
scl = 0;
flash();
sda = (bit)(temp & 0x80);
flash();
scl = 1;
flash();
temp = temp << 1;
}
scl = 0;
flash();
}
/********************************************************************
* 名称 : readx()
* 功能 : 读一个字节
* 输入 : 无
* 输出 : 读出的值
***********************************************************************/
uchar readx(void)
{
uchar i, j, k = 0;
for(i=0; i<8; i++)
{
scl = 1;
flash();
if(sda == 1)
{
j = 1;
}
else j = 0;
k = (k << 1) | j;
scl = 0;
flash();
}
return(k);
}
/********************************************************************
* 名称 : ack()
* 功能 : I2C总线时钟
* 输入 : 无
* 输出 : 无
***********************************************************************/
void ack(void)
{
scl = 1;
flash();
flash();
scl = 0;
flash();
}
/********************************************************************
* 名称 : x24c02_read()
* 功能 : 从24c02中读出值
* 输入 : address(要在这个地址读取值)
* 输出 : 从24c02中读出的值
***********************************************************************/
uchar x24c02_read(uchar address)
{
uchar i;
start();
writex(0xa0);
ack();
writex(address);
ack();
start();
writex(0xa1);
ack();
i = readx();
sda = 1; //no ack
ack();
stop();
return(i);
}
/********************************************************************
* 名称 : x24c02_write()
* 功能 : 想24c02中写入数据
* 输入 : address(地址) , info(值)
* 输出 : 无
***********************************************************************/
void x24c02_write(uchar address, uchar info)
{
start();
writex(0xa0);
ack();
writex(address);
ack();
writex(info);
ack();
stop();
}
/**************************************
函数名称:矩阵键盘
用法:矩阵端口接P2口
***************************************/
int Detect_key_down(void)
{
uchar temp = 0x00;
P2 = 0xfe;
temp = P2;
switch (temp) {
case 0xee: return 0;
case 0xde: return 1;
case 0xbe: return 2;
case 0x7e: return 3;
default: break;
}
P2 = 0xfd;
temp = P2;
switch (temp) {
case 0xed: return 4;
case 0xdd: return 5;
case 0xbd: return 6;
case 0x7d: return 7;
default: break;
}
P2 = 0Xfb;
temp = P2;
switch (temp) {
case 0xeb: return 8;
case 0xdb: return 9;
case 0xbb: return 10;
case 0x7b: return 11;
default: break;
}
P2 = 0Xf7;
temp = P2;
switch (temp) {
case 0xe7: return 12;
case 0xd7: return 13;
case 0xb7: return 14;
case 0x77: return 15;
default: break;
}
return 16;
} //end KEY
/**************************************
函数功能:红外线产生中断函数
用法:红外线接收口接P3^2
****************************************/
void IR_RexFlag() interrupt 0
{
EX0 = 0;
int_flag = 1;
TR0 = 1;
count1 = 0; //开定时器0 26us
}
void Time0_init()
{
TH0 = 0Xe7; //38KHz载波 26us
TL0 = 0Xe7;
ET0 = 1; //开中断
}
void Time0_26us() interrupt 1
{
Txd_Port = 1;
TR1 = 1;
count1++;
test4 = 0;
}
void Time1_init()
{
TH1 = 0Xf9; //8us
TL1 = 0Xf9;
//ET1 = 1;
}
void Time1_9us() interrupt 3
{
TR1 = 0; //关定时器
Txd_Port = Time1_Flag;
test3 = 0;
}
void TR0_Count(unsigned short count) //26us*count,有信号
{
Time1_Flag = 0;
count1 = 0;
TR0 = 1;
while(count1<count);
TR0 = 0;
}
void TR0_Count1(unsigned short count)
{ //26*count,无信号
Time1_Flag = 1;
count1 = 0;
TR0 = 1;
while(count1<count);
TR0 = 0;
}
void Com_Init(void) //串口打印初始化
{
TMOD = 0x20;
PCON = 0x00;
SCON = 0x50;
TH1 = 0xFd;
TL1 = 0xFd;
TR1 = 1;
}
int main(void)
{
uchar count_flag = 0;
uchar IR_First = 0; //红外线接收开启中断标志
uchar key_again = 0; //按第二个按键的其实条件
char n_elements = 80;
uint data1 = 0; //记录数组里面的数据
uchar *P = 0; //将idata的数组存到E2PROM里面
//uchar sec = 0; //数组元素
uchar last_in = 0; // 默认输入为低电平
uchar key_value; //存放按键值
// uchar close_T0 = 0;
uchar key_down_flag = 0; //按键抬起的标记(按键已经按下过了)
uchar *pArray = 0; //接收指针
unsigned short *pArray1 = 0;
uchar *PTex = 0; //发射指针
unsigned short *PTex1 = 0;
uchar *PE = &remotedata[0]; //数组存入E2PROM的指针
uchar up_down = 0; //标记红外线的9MS低电平,4.5MS高电平的引导码
uchar Key_down = 1;
uchar i = 0;
uchar j = 0;
uchar k = 0;
unsigned short remoteout = 0;
//for(i=0;i<80;i++) //清空数组内存
//{
// remotedata[i] = 0x00;
//}
x24c02_init(); //初始化I2C总线
test0 = 1;
test1 = 1;
test2 = 1;
test3 = 1;
test4 = 1;
test5 = 1;
test6 = 1;
test7 = 1;
EA = 1;
TMOD = 0X22; //8位自动重装
IT0 = 1; //脉冲触发方式,负跳变有效
Time0_init();
Time1_init();
while(1)
{
key_value = Detect_key_down();
if (key_value == 16)
{ // 没有按键按下,或者按键已经UP
if (key_down_flag == 1)
{ // 按键1抬起
P = &remotedata[0];
for(i=0;i<80;i++) //数组写入E2PROM
{
x24c02_write(i,*P);
P++;
Delay_1ms(5); //每一次写数据后要进入E2PROM内部写周期,最大时长为5ms
}
key_down_flag = 0;
IR_First = 0;
//TR1 = 0;
// if(close_T0 == 0)
// {
// TR0 = 0; // 关定时器0
// TR1 = 0;
// close_T0 = 1;
// }
//PTex = &remotedata[0];
//PTex1 = (unsigned short*)&remotedata[0];
}
if(key_down_flag == 2)
{ //如果按键2抬起
P = &remotedata[0];
for(i=80;i<160;i++) //数组写入E2PROM
{
x24c02_write(i,*P);
P++;
Delay_1ms(5);
test0 = 0; //每一次写数据后要进入E2PROM内部,写周期最大时长为5ms
}
key_down_flag = 0;
//int_flag = 0; //红外线标志
//last_in = 0; //高低电平翻转标志
//up_down = 0; //9ms,4.5ms判断标志
//pArray = &remotedata[0];
//pArray1 = (unsigned short*)&remotedata[0];
//TR0 = 0; //一次接收完成以后定时器关闭
//TR1 = 0;
}
if(Txd_key == 0)
{
PE = &remotedata[0];
Com_Init();
while(Txd_key ==0);
for(i=0;i<80;i++)
{
*PE= x24c02_read(i);
SBUF = *PE;
while(!TI)
{
;
}
TI = 0;
// Delay_1ms(5);
PE++;
}
}
if(Txd_key1 == 0)
{
PE = &remotedata[0];
Com_Init();
while(Txd_key1 ==0 );
for(i=0;i<80;i++)
{
*PE = x24c02_read(80+i);
SBUF = *PE;
while(!TI)
{
;
}
TI = 0;
Delay_1ms(5);
PE++;
}
}
/* if(Txd_key == 0) //发射0键按下
{
PE = &remotedata[0];
for(i=0;i<80;i++)
{
*PE++ = x24c02_read(i);
// remotedata[i] = x24c02_read(i);
}
ET1 = 1; //开启定时器1中断 接收的时候不用定时器1;
PTex = &remotedata[0];
PTex1 = (unsigned short*)&remotedata[0];
data1 = (*PTex1);
TR0_Count(data1); //9MS低电平
PTex1++;
data1 = (*PTex1); //4.5MS高电平
TR0_Count1(data1);
PTex1++;
PTex = (uchar*)PTex1;
test0 = 0;
for(j=0;j<n_elements-4;j++)
{
data1 = (*PTex);
TR0_Count(data1); //发信号
PTex++;
data1 = (*PTex);
TR0_Count1(data1); //不发信号
PTex++;
test1 = 0;
if(*PTex == 0)
{
Txd_Port = 1;
test2 = 0;
}
}
TR0_Count1(200); //两组数据之间50ms的时间间隔
}
if(Txd_key1 == 0) //发射键1按下
{
PE = &remotedata[0];
for(i=0;i<80;i++)
{
*PE++ = x24c02_read(i+80);
// remotedata[i] = x24c02_read(i);
}
// ET1 = 1; //开启定时器1中断 接收的时候不用定时器1;
PTex = &remotedata[0];
PTex1 = (unsigned short*)&remotedata[0];
data1 = (*PTex1);
TR0_Count(data1); //9MS低电平
PTex1++;
data1 = (*PTex1); //4.5MS高电平
TR0_Count1(data1);
PTex1++;
PTex = (uchar*)PTex1;
test0 = 0;
for(j=0;j<n_elements-4;j++)
{
data1 = (*PTex);
TR0_Count(data1); //发信号
PTex++;
data1 = (*PTex);
TR0_Count1(data1); //不发信号
PTex++;
test1 = 0;
if(*PTex == 0)
{
Txd_Port = 1;
test2 = 0;
}
}
TR0_Count1(200); //两组数据之间50ms的时间间隔
} */
//key_down_flag = 0;
IE0 = 0; //当按键还没有按下的时候不能产生中断
}
else //接受模块
{
if (key_value == 0)
{
if(IR_First == 0) //每次红外线到来时就开一次中断
{
pArray = &remotedata[0];
pArray1 = (unsigned short*)&remotedata[0];
EX0 = 1; //开外中断0;
IR_First++;
}
if (key_down_flag == 0)
{
key_down_flag = 1;
}
if (int_flag == 1) // 有数据传送
{
if (remotein == 0) //如果是低电平
{
if (last_in == 1) //等待它翻转成高电平
{
if (up_down == 1) //如果是第一次 4.5MS
{
*pArray1++ = count1;
pArray = (unsigned char*)pArray1;
count1 = 0;
up_down++;
}
else
{
*pArray++ = count1;
count1 = 0;
}
last_in = 0;
}
}
else
{
if (last_in == 0)
{
// 9MS
if (up_down == 0)
{
*pArray1++ = count1;
//pArray = (unsigned char*)pArray1;
count1 = 0;
up_down++;
}
else
{
*pArray++ = count1;
count1 = 0;
}
last_in = 1;
}
}
}
}
if (key_value == 1)
{
if(IR_First == 0)
{
int_flag = 0; //红外线标志
last_in = 0; //高低电平翻转标志
up_down = 0; //9ms,4.5ms判断标志
pArray = &remotedata[0];
pArray1 = (unsigned short*)&remotedata[0];
//TR0 = 0; //一次接收完成以后定时器关闭
test1 = 0;
//TR0 = 0;
//TR1 = 0;
EX0 = 1;
Time0_init();
//Time1_init();
IR_First ++;
}
if (key_down_flag == 0)
{
key_down_flag = 2;
test2 = 0;
}
if (int_flag == 1) // 有数据传送
{
if (remotein == 0) //如果是低电平
{
if (last_in == 1) //等待它翻转成高电平
{
if (up_down == 1) //如果是第一次 4.5MS
{
*pArray1++ = count1;
pArray = (unsigned char*)pArray1;
test3 = 0;
count1 = 0;
up_down++;
}
else
{
*pArray++ = count1;
count1 = 0;
test7 = 0;
}
last_in = 0;
}
}
else
{
if (last_in == 0)
{
// 9MS
if (up_down == 0)
{
*pArray1++ = count1;
// pArray = (unsigned char*)pArray1;
count1 = 0;
up_down++;
test5 = 0;
}
else
{
*pArray++ = count1;
count1 = 0;
test6 = 0;
}
last_in = 1;
}
}
}
}
}
}
return 0;
}
|