📄 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 + -