?? 77e516.txt
字號:
C51編程:請教:W77E516芯片,為何我的串口只能一次接收1個字節?
串口0使用定時器1做波特率發生器,串口采用中斷方式接收,但是用串口調試助手只能一
次發一個字節,如果發兩個以上就會有問題,下面是我的程序:
void InitSeriesPort(void)
{
ES = 0;//使串口0不能中斷
IP |= 0x10;//將串口0設為高優先級
T2CON = 0x00;//串行口0使用定時器1做波特率發生器
TL1 = 0xFD; //11.0592MHz :9600
TH1 = 0xFD;//TH1 = 0xdc;//TH1 = 0xFF;
}
void SeriesPort (void) interrupt 4 using 2
{
if(RI)
{
ReceiveData[g_zi]=SBUF;
En4850=1; TI=0;SBUF=ReceiveData[g_zi]; while(TI==0);TI=0;En4850=0;
}
RI=0;
}
void main()
{ TMOD=0x22; /*定時器1為工作模式2(8位自動重裝),0為模式2(8位自動重裝) */
SCON=0x40;//串行口工作于10位異步模式1
PCON=0;
InitSeriesPort();
//SM2=0;
ET1=0;//定時器1中斷
ES = 1;//EA = 1;
TR1=1;//啟動定時器1
SendData();
RI=0;REN=1;
PT0=1;
EA=1;
}
各位大俠,幫我分析分析吧!
大家幫幫忙吧!謝謝了。 [kenn654321] 2006-7-21 17:08:17
你的本來就一次只能接受發送一個阿 [lk@422] 2006-7-21 17:10:40
請問:但是我如果用串口調試助手一次發一串數據,它只能接收到第一個,后面就亂了。 [kenn654321] 2006-7-21 17:18:58
樓主,能不能幫我看看我的程序為什么會不能接收一串數據?實在不知道該怎么辦了! [kenn654321] 2006-7-21 17:29:18
你的程序發了一次數據,但沒有發中斷處理 [yunwei] 2006-7-21 19:00:30
主程序沒有等待,不知道運行到哪去了
我有串口中斷處理啊,你說的是定時器1的中斷處理嗎?這個不要也可以啊。能講的再清楚點嗎? [kenn654321] 2006-7-22 11:48:39
好像這里錯了! [space005] 2006-7-22 12:31:23
“while(TI==0);TI=0;En4850=0;”應該該成“while(TI==1);TI=0;En4850=0;”
這里沒錯,我總感覺時序上有問題。 [kenn654321] 2006-7-22 13:54:31
大概跑飛了 [ssaassa] 2006-7-22 16:18:29
主程序么sjmp $,串口中斷reti后會跑飛俄大概~~~
開了timer1,要寫中斷處理,不然可能也會跑飛~~~
我已經把定時器1的中斷給關了,可是還是只能用串口調試助手1個字節1個字節發送 [kenn654321] 2006-7-22 17:21:54
這里沒有問題 [liuhuiwang] 2006-7-22 17:43:24
if(RI)改while(RI), RI=0放在while的第一行再送資料, 不過在中斷內等發送完在離開不太好啊! [C.C.] 2006-7-22 17:57:13
你看看你的程序的問題 [liuhuiwang] 2006-7-22 18:03:05
void SeriesPort (void) interrupt 4 using 2{ if(RI)
{ ReceiveData[g_zi]=SBUF; En4850=1;
TI=0;SBUF=ReceiveData[g_zi]; while(TI==0);TI=0;En4850=0; }
RI=0;}
非常明顯的錯誤
應該為:
void SeriesPort (void) interrupt 4 using 2
{
if(RI)
{ ReceiveData[g_zi]=SBUF;
}
RI = 0;
En4850=1;
TI=0;
SBUF=ReceiveData[g_zi];
while(TI==0);
TI=0;
En4850=0;
}
這里我改了,但是好象還是不能用串口調試助手一次發一串數據,我看了一下,好象單片機串口接收的數據不能正常存到receivedata數組中。 [kenn654321] 2006-7-22 18:19:36
g_zi沒加1 [C.C.] 2006-7-22 18:33:07
把1 加上也不行,我郁悶壞了 [kenn654321] 2006-7-22 18:36:22
你把最後測試的程序貼上來, 最好是完整的 [C.C.] 2006-7-22 18:44:46
請看里面 [kenn654321] 2006-7-22 18:57:35
void SeriesPort (void) interrupt 4 using 0
{ ES=0;
if(RI)
{
ReceiveData[g_zi]=SBUF;
{En4850=1; TI=0;SBUF=ReceiveData[g_zi]; whil(TI==0);TI=0;En4850=0; }
g_zi++;
if(g_zi>=30)g_zi=0;
RI=0;
}
}
else TI=0;
ES=1;
}
這個程序主要是想單片機串口接收到什么數據,讓它把接收到的數據發出來,但是我用軟
件調試時發現receivedata的數組里總是0,接硬件后用串口調試助手1個字節一個字節個單
片機的串口發數據,單片機可以準確無誤的給我返回我剛發的數據,可是發2個以上的字節
就出現亂碼,{En4850=1; TI=0;SBUF=ReceiveData[g_zi]; while
(TI==0);TI=0;En4850=0; } 我以前這樣在中斷中用過,所以這里應該沒錯。數組我是這樣
定義的:
static unsigned char g_zi,ReceiveData[40];
我的所有程序在下面:
#include <reg52.h>
sbit BT_SND =P1^5;
sbit BT_REC =P1^4;
sbit En4851 = P1^1; //UART1 enabel H---SEND,L---RECEIVE
sbit En4850 = P3^2; //UART0 enabel
#define F_TM F0
#define TIMER0_ENABLE TL0=TH0; TR0=1;
#define TIMER0_DISABLE TR0=0;
#define OSCU 1 //1 11.0592 0 22.1184
static unsigned char idata g_zi,ReceiveData[40];
bit ReceiveFinish;
sbit ACC0= ACC^0;
sbit ACC1= ACC^1;
sbit ACC2= ACC^2;
sbit ACC3= ACC^3;
sbit ACC4= ACC^4;
sbit ACC5= ACC^5;
sbit ACC6= ACC^6;
sbit ACC7= ACC^7;
void IntTimer0() interrupt 1
{
F_TM=1;
}
//發送一個字符
void PSendChar(unsigned char inch)
{
ACC=inch;
F_TM=0;
BT_SND=0; //start bit
TIMER0_ENABLE; //啟動
while(!F_TM);
BT_SND=ACC0; //先送出低位
F_TM=0;
while(!F_TM);
BT_SND=ACC1;
F_TM=0;
while(!F_TM);
BT_SND=ACC2;
F_TM=0;
while(!F_TM);
BT_SND=ACC3;
F_TM=0;
while(!F_TM);
BT_SND=ACC4;
F_TM=0;
while(!F_TM);
BT_SND=ACC5;
F_TM=0;
while(!F_TM);
BT_SND=ACC6;
F_TM=0;
while(!F_TM);
BT_SND=ACC7;
F_TM=0;
while(!F_TM);
BT_SND=1;
F_TM=0;
while(!F_TM);
TIMER0_DISABLE; //停止timer
}
//接收一個字符
unsigned char PGetChar()
{
TL0=TH0;
TIMER0_ENABLE;
F_TM=0;
while(!F_TM); //等過起始位
ACC0=BT_REC;
F_TM=0;
while(!F_TM);
ACC1=BT_REC;
F_TM=0;
while(!F_TM);
ACC2=BT_REC;
F_TM=0;
while(!F_TM);
ACC3=BT_REC;
F_TM=0;
while(!F_TM);
ACC4=BT_REC;
F_TM=0;
while(!F_TM);
ACC5=BT_REC;
F_TM=0;
while(!F_TM);
ACC6=BT_REC;
F_TM=0;
while(!F_TM);
ACC7=BT_REC;
F_TM=0;
while(!F_TM)
{
if(BT_REC)
{
break;
}
}
TIMER0_DISABLE; //停止timer
return ACC;
}
//檢查是不是有起始位
bit StartBitOn()
{
return (BT_REC==0);
}
/*上面為模擬串口程序*/
/*下面為串口與主機的無線通訊程序*/
void SeriesPort (void) interrupt 4 using 0
{ ES=0;
if(RI)
{
ReceiveData[g_zi]=SBUF;
{En4850=1; TI=0;SBUF=ReceiveData[g_zi]; whil(TI==0);TI=0;En4850=0; }
g_zi++;
if(g_zi==1) {if(ReceiveData[0]!=0xFE) g_zi=0; }
if(g_zi==2) { if(ReceiveData[1]!=0xF8) g_zi=0;}
if(g_zi==3) { if(ReceiveData[2]>36) g_zi=0;}
if(g_zi==(ReceiveData[2]+2)) {ReceiveFinish=1;g_zi=0; }
RI=0;
}
else TI=0;
ES=1;
}
/*
void Timer1 (void) interrupt 3 using 1
//void Timer1 (void) interrupt 3 using 2
{
#if OSCU
{ TH1 = 0xff; //time=50ms, Fosc=11.0592MHz
TL1 = 0xdc;
}
#else
{
TH1 = 0x4B; //time=25ms, Fosc=22.1184MHz
TL1 = 0xFF;
}
#endif
}
*/
void InitSeriesPort(void)
{
ES = 0;//使串口0不能中斷
PS = 0;//將串口0設為低優先級
RCLK=0;TCLK=0;//串行口0使用定時器1做波特率發生器
#if OSCU
{ TL1 = 0xFD; //11.0592MHz :9600
TH1 = 0xFD;//TH1 = 0xdc;//TH1 = 0xFF;
}
#else
{
TL1 = 0xFA; //22.1184MHz :9600
TH1 = 0xFA;//TH1 = 0xFF;
}
#endif
}
void SendData(void)
{
unsigned char idata i;
unsigned char zd[2];
ES = 0;
En4850=1; //允許發送
TI=0;
for(i=0;i<2;i++)
{
zd[i]=0x50+i;
SBUF=zd[i];
while(TI==0);
TI=0;
}
ES = 1; En4850=0;//允許接收
}
void main()
{
unsigned char gch,i;
ReceiveFinish=0;
TMOD=0x22; /*定時器1為工作模式2(8位自動重裝),0為模式2(8位自動重裝) */
SCON=0x40;//串行口0工作于10位異步模式1
PCON=0;
InitSeriesPort();
ET1= 0;//關定時器1中斷
TR1=1;//啟動定時器1
SendData();
RI=0;REN=1;
PT0=1;
TR0=0; //在發送或接收才開始使用
TF0=0;
TH0=(256-96); //9600bps 就是 1000000/9600=104.167微秒 執行的 timer是
104.167*11.0592/12= 96
TL0=TH0;
ET0=1;
EA=1;
PSendChar(0x55);
PSendChar(0x66);
PSendChar(0x77);
PSendChar(0x88);
g_zi=0;
while(1)
{
if(ReceiveFinish)
{ReceiveFinish=0;
for(i=0;i<=(ReceiveData[2]+2);i++)
{En4850=1; TI=0;SBUF=ReceiveData[g_zi]; while(TI==0); TI=0;En4850=0; }
}
if(StartBitOn())
{
gch=PGetChar();
PSendChar(gch);
}
}
}
忘了問你該不會是485吧? 如果是那當然不行, 因為485為half duplex [C.C.] 2006-7-22 19:05:30
我用的是半雙工的485,請問:那我怎么用串口調試助手一次發一串數據呢? [kenn654321] 2006-7-22 19:11:14
半雙工不可以收發同時, 你必須改成全部收完再發送, 只是收多少算收完就必須有協議才行 [C.C.] 2006-7-22 19:17:57
這個我有協議,在程序里也可以看到,當receivefished=1時結束。 [kenn654321] 2006-7-22 19:33:48
請教:如果我程序里的方法不行,怎樣才能把它改成全部收完呢? [kenn654321] 2006-7-22 19:37:55
不要在串口中斷發送資料, 將主程序改一下(你怎麼兩個地方都有發送啊?) [C.C.] 2006-7-22 19:57:27
if(ReceiveFinish)
{ReceiveFinish=0;
for(i=0;i<=(ReceiveData[2]+2);i++)
{En4850=1; TI=0;SBUF=ReceiveData[i]; while(TI==0); TI=0;En4850=0; }
}
好的,我現在就試試。 [kenn654321] 2006-7-22 20:00:47
把串口中斷的 else TI=0; 和 ES=0, ES=1 拿掉 [C.C.] 2006-7-22 20:07:07
請C.C.看里面 [kenn654321] 2006-7-22 20:13:03
我把中斷中的發送數據刪除掉只在后面發,但是軟件調試時receivedata的數組里一直都是
0,好象存不進去,請問你以前遇到過這種情況嗎?你可以把我的程序用軟件調試一下。
#include <reg52.h>
sbit BT_SND =P1^5;
sbit BT_REC =P1^4;
sbit En4851 = P1^1; //UART1 enabel H---SEND,L---RECEIVE
sbit En4850 = P3^2; //UART0 enabel
#define F_TM F0
#define TIMER0_ENABLE TL0=TH0; TR0=1;
#define TIMER0_DISABLE TR0=0;
#define OSCU 1 //1 11.0592 0 22.1184
static unsigned char idata g_zi,ReceiveData[40];
bit ReceiveFinish;
sbit ACC0= ACC^0;
sbit ACC1= ACC^1;
sbit ACC2= ACC^2;
sbit ACC3= ACC^3;
sbit ACC4= ACC^4;
sbit ACC5= ACC^5;
sbit ACC6= ACC^6;
sbit ACC7= ACC^7;
void IntTimer0() interrupt 1
{
F_TM=1;
}
//發送一個字符
void PSendChar(unsigned char inch)
{
ACC=inch;
F_TM=0;
BT_SND=0; //start bit
TIMER0_ENABLE; //啟動
while(!F_TM);
BT_SND=ACC0; //先送出低位
F_TM=0;
while(!F_TM);
BT_SND=ACC1;
F_TM=0;
while(!F_TM);
BT_SND=ACC2;
F_TM=0;
while(!F_TM);
BT_SND=ACC3;
F_TM=0;
while(!F_TM);
BT_SND=ACC4;
F_TM=0;
while(!F_TM);
BT_SND=ACC5;
F_TM=0;
while(!F_TM);
BT_SND=ACC6;
F_TM=0;
while(!F_TM);
BT_SND=ACC7;
F_TM=0;
while(!F_TM);
BT_SND=1;
F_TM=0;
while(!F_TM);
TIMER0_DISABLE; //停止timer
}
//接收一個字符
unsigned char PGetChar()
{
TL0=TH0;
TIMER0_ENABLE;
F_TM=0;
while(!F_TM); //等過起始位
ACC0=BT_REC;
F_TM=0;
while(!F_TM);
ACC1=BT_REC;
F_TM=0;
while(!F_TM);
ACC2=BT_REC;
F_TM=0;
while(!F_TM);
ACC3=BT_REC;
F_TM=0;
while(!F_TM);
ACC4=BT_REC;
F_TM=0;
while(!F_TM);
ACC5=BT_REC;
F_TM=0;
while(!F_TM);
ACC6=BT_REC;
F_TM=0;
while(!F_TM);
ACC7=BT_REC;
F_TM=0;
while(!F_TM)
{
if(BT_REC)
{
break;
}
}
TIMER0_DISABLE; //停止timer
return ACC;
}
//檢查是不是有起始位
bit StartBitOn()
{
return (BT_REC==0);
}
/*上面為模擬串口程序*/
/*下面為串口與主機的無線通訊程序*/
void SeriesPort (void) interrupt 4 using 0
{ ES=0;
if(RI)
{
ReceiveData[g_zi]=SBUF;
//{En4850=1; TI=0;SBUF=ReceiveData[g_zi]; while(TI==0);
TI=0;En4850=0; }
g_zi++;
if(g_zi==1) { if(ReceiveData[0]!=0xFE) g_zi=0; }
if(g_zi==2) { if(ReceiveData[1]!=0xF8) g_zi=0;}
if(g_zi==3) { if(ReceiveData[2]>36) g_zi=0;}
if(g_zi==(ReceiveData[2]+2)) { ReceiveFinish=1;
g_zi=0; }
RI=0;
}
else TI=0;
ES=1;
}
void InitSeriesPort(void)
{
ES = 0;//使串口0不能中斷
PS = 0;//將串口0設為低優先級
RCLK=0;TCLK=0;//串行口0使用定時器1做波特率發生器
#if OSCU
{ TL1 = 0xFD; //11.0592MHz :9600
TH1 = 0xFD;//TH1 = 0xdc;//TH1 = 0xFF;
}
#else
{
TL1 = 0xFA; //22.1184MHz :9600
TH1 = 0xFA;//TH1 = 0xFF;
}
#endif
}
void SendData(void)
{
unsigned char idata i;
unsigned char zd[2];
ES = 0;
En4850=1; //允許發送
TI=0;
for(i=0;i<2;i++)
{
zd[i]=0x50+i;
SBUF=zd[i];
while(TI==0);
TI=0;
}
ES = 1; En4850=0;//允許接收
}
void main()
{
unsigned char gch,i;
ReceiveFinish=0;
TMOD=0x22; /*定時器1為工作模式2(8位自動重裝),0為模式2(8位自動重裝) */
SCON=0x40;//串行口0工作于10位異步模式1
PCON=0;
InitSeriesPort();
ET1= 0;//關定時器1中斷
TR1=1;//啟動定時器1
SendData();
RI=0;REN=1;
PT0=1;
TR0=0; //在發送或接收才開始使用
TF0=0;
TH0=(256-96); //9600bps 就是 1000000/9600=104.167微秒 執行的 timer是
104.167*11.0592/12= 96
TL0=TH0;
ET0=1;
EA=1;
PSendChar(0x55);
PSendChar(0x66);
PSendChar(0x77);
PSendChar(0x88);
g_zi=0;ReceiveData[0]=1;ReceiveData[2]=0x55;
while(1)
{
if(ReceiveFinish)
{ReceiveFinish=0;
for(i=0;i<=(ReceiveData[2]+2);i++)
{En4850=1; TI=0;SBUF=ReceiveData[g_zi]; while(TI==0); TI=0;En4850=0; }
}
if(StartBitOn())
{
gch=PGetChar();
PSendChar(gch);
}
}
}
我測試可以啊! 我送 FE F8 01 會回送資料(必須先把else ti=0 才可以) [C.C.] 2006-7-22 20:23:13
主程序不是要改成 SBUF=ReceiveData[i]; [C.C.] 2006-7-22 20:26:01
對,主程序里把g_zi改為i后,再把中斷里發送的數據去掉后就好了,我發現中斷里發送數據會干擾接收到的數據,非常感謝你能給我這么多指點!謝謝! [kenn654321] 2006-7-22 20:37:30
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -