問題概述如下:我要用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;
}
|