51单片机串口程序在接收了数据后就不能正常发送了,帮忙看下代码有没有问题

51单片机串口程序在接收了数据后就不能正常发送了,帮忙看下代码有没有问题,第1张

while(!RI),决定了它每收到一个字节,发出“It's ok!”中的一个字符,而且,RI会导致中断,中断后RI又=0,很可能,即使收到一个字节,也等不到RI=1,也就不发出下一个字符

//////////////////////////////////////////////////////////////////////////////////////////////////

//E51Proc

//Easy 51Pro编程器主程序,负责通讯,管理编程 *** 作

///////////////////////////////////////////////////////////////////////////////////////////////////

#include <E51Proh>

BYTE ComBuf[18];//串口通讯数据缓存,发送和接收都使用

UINT nAddress;//ROM中地址计数

UINT nTimeOut;//超时计数

ProWork pw;//编程器一般 *** 作

void Delay_us(BYTE nUs)//微秒级延时<255us

{

TH0=0;

TL0=0;

TR0=1;

while(TL0<nUs)//利用T0做定时计数器,循环采样,直到达到定时值

{

}

TR0=0;

}

void Delay_ms(UINT nMs)//豪秒级的延时<65535ms

{

UINT n=0;

TR0=1;

while(n<nMs)////利用T0做定时计数器,循环采样,直到达到定时值

{

TH0=0;

TL0=20;

while(TH0<4)

{

}

n++;

}

TR0=0;

}

BOOL WaitComm()//等待上位机的命令,18字节

{

BYTE n=0;

RI=0;

while(!RI){}//等待第一个字节

ComBuf[n]=SBUF;

RI=0;

n++;

for(n;n<=17;n++)

{

nTimeOut=0;

while(!RI)

{

nTimeOut++;

if(nTimeOut>10000)//后17个字节都有超时限制

return 0;

}

ComBuf[n]=SBUF;

RI=0;

}

return 1;

}

BOOL WaitResp()//等待上位机回应,1字节,有超时限制

{

nTimeOut=0;

RI=0;

while(!RI)

{

nTimeOut++;

if(nTimeOut>50000)

{

return 0;

}

}

RI=0;

ComBuf[0]=SBUF;

return 1;

}

BOOL WaitData()//写器件时等待上位机数据,18字节,有超时限制

{

BYTE n;

RI=0;

for(n=0;n<=17;n++)

{

nTimeOut=0;

while(!RI)

{

nTimeOut++;

if(nTimeOut>10000)

{

return 0;

}

}

RI=0;

ComBuf[n]=SBUF;

}

return 1;

}

void SendData()//发送数据或回应 *** 作完成,18字节

{

BYTE n=0;

for(n;n<=17;n++)

{

TI=0;

SBUF=ComBuf[n];

while(!TI){}

TI=0;

}

}

void SendResp()//回应上位机1个字节,在写器件函数中使用

{

TI=0;

SBUF=ComBuf[0];

while(!TI){}

TI=0;

}

void SetVpp5V()//设置Vpp为5v

{

P3_4=0;

P3_3=0;

}

void SetVpp0V()//设置Vpp为0v

{

P3_3=0;

P3_4=1;

}

void SetVpp12V()//设置Vpp为12v

{

P3_4=0;

P3_3=1;

}

void RstPro()//编程器复位

{

pwfpProOver();//直接编程结束

SendData();//通知上位机,表示编程器就绪,可以直接用此函数因为协议号(ComBuf[0])还没被修改,下同

}

void ReadSign()//读特征字

{

pwfpReadSign();

SendData();//通知上位机,送出读出器件特征字

}

void Erase()//擦除器件

{

pwfpErase();

SendData();//通知上位机,擦除了器件

}

void Write()//写器件

{

BYTE n;

pwfpInitPro();//编程前的准备工作

SendData();//回应上位机表示进入写器件状态,可以发来数据

while(1)

{

if(WaitData())//如果等待数据成功

{

if(ComBuf[0]==0x07)//判断是否继续写

{

for(n=2;n<=17;n++)//ComBuf[2~17]为待写入数据块

{

if(!pwfpWrite(ComBuf[n]))//<<<<<<<<<<<<<<<<<<<调用写该器件一个单元的函数

{

pwfpProOver();//出错了就结束编程

ComBuf[0]=0xff;

SendResp();//回应上位机一个字节,表示写数据出错了

WaitData();//等待上位机的回应后就结束

return;

}

nAddress++;//下一个单元

}

ComBuf[0]=1;//回应上位机一个字节,表示数据块顺利完成,请求继续

SendResp();

}

else if(ComBuf[0]==0x00)//写器件结束

break;

else//可能是通讯出错了

{

pwfpProOver();

return;

}

}

else//等待数据失败

{

pwfpProOver();

return;

}

}

pwfpProOver();//编程结束后的工作

Delay_ms(50);//延时等待上位机写线程结束

ComBuf[0]=0;//通知上位机编程器进入就绪状态

SendData();

}

void Read()//读器件

{

BYTE n;

pwfpInitPro();//先设置成编程状态

SendData();//回应上位机表示进入读状态

while(1)

{

if(WaitResp())//等待上位机回应1个字节

{

if(ComBuf[0]==0)//ComBuf[0]==0表示读结束

{

break;

}

else if(ComBuf[0]==0xff)//0xff表示重发

{

nAddress=nAddress-0x0010;

}

for(n=2;n<=17;n++)//ComBuf[2~17]保存读出的数据块

{

ComBuf[n]=pwfpRead();//<<<<<<<<<<<<<<<<<<<调用写该器件一个单元的函数

nAddress++;//下一个单元

}

ComBuf[0]=6;//向上位机发送读出的数据块

SendData();

}

else

break;//等待回应失败

}

pwfpProOver();// *** 作结束设置为运行状态

ComBuf[0]=0;//通知上位机编程器进入就绪状态

SendData();

}

void Lock()//写锁定位

{

pwfpLock();

SendData();

}

///////////////////////////////////////////////////////////////////////////////////////////////////

//所支持的FID,请在这里继续添加

///////////////////////////////////////////////////////////////////////////////////////////////////

extern void PreparePro00();//FID=00:AT89C51编程器

extern void PreparePro01();//FID=01:AT89C2051编程器

extern void PreparePro02();//FID=02:AT89S51编程器

void main()

{

SP=0x60;

SetVpp5V();//先初始化Vpp为5v

SCON=0x00;

TCON=0x00;

//PCON=0x00;//波特率2

IE=0x00;

//TMOD: GATE|C/!T|M1|M0|GATE|C/!T|M1|M0

// 0 0 1 0 0 0 0 1

TMOD=0x21;//T0用于延时程序

TH1=0xff;

TL1=0xff;//波特率288002,注意PCON

//SCON: SM0|SM1|SM2|REN|TB8|RB8|TI|RI

// 0 1 0 1 0 0 0 0

SCON=0x50;

TR1=1;

Delay_ms(1000);//延时1秒后编程器自举

ComBuf[0]=0;

SendData();

while(1)//串口通讯采用查询方式

{

if(!WaitComm())//如果超时,通讯出错

{

Delay_ms(500);

ComBuf[0]=0;//让编程器复位,使编程器就绪

}

switch(ComBuf[1])//根据FID设置(ProWork)pw中的函数指针

{

case 0://at89c51编程器

PreparePro00();

break;

case 1://at89c2051编程器

PreparePro01();

break;

case 2://at89s51编程器

PreparePro02();

break;

//case 3:支持新器件时,请继续向下添加

// break;

//case 4:

// break;

default:

ComBuf[0]=0xff;

ComBuf[1]=0xff;//表示无效的 *** 作

break;

}

switch(ComBuf[0])//根据 *** 作ID跳到不同的 *** 作函数

{

case 0x00:

RstPro();//编程器复位

break;

case 0x01:

ReadSign();//读特征字

break;

case 0x02:

Erase();//擦除器件

break;

case 0x03:

Write();//写器件

break;

case 0x04:

Read();//读器件

break;

case 0x05:

Lock();//写锁定位

break;

default:

SendData();

break;

}

}

}

我用的新唐芯片,8051内核,跟51差不多,望采纳

void UART_Initial (void)

{

P02_Quasi_Mode; //Setting UART pin as Quasi mode for transmit

P16_Quasi_Mode; //Setting UART pin as Quasi mode for transmit

SCON_1 = 0x50; //UART1 Mode1,REN_1=1,TI_1=1

T3CON = 0x08; //T3PS2=0,T3PS1=0,T3PS0=0(Prescale=1), UART1 in MODE 1

clr_BRCK;

RH3 = HIBYTE(65536 - (1000000/u32Baudrate)-1); /16 MHz /

RL3 = LOBYTE(65536 - (1000000/u32Baudrate)-1); /16 MHz /

set_TR3; //Trigger Timer3

}

以上是初始化的

void Send_Data_To_UART1(UINT8 c)

{

TI_1 = 0;

SBUF_1 = c;

while(TI_1==0);

}

这个是发送

void UART_isr (void) interrupt 4 //串行中断服务程序

{

if (RI_1==1)

{ / if reception occur /

clr_RI_1; / clear reception flag for next reception /

Receive_Date[c] = SBUF_1;

if (Receive_Date[0] == First_Date)

{

c++;

}

else if(Receive_Date_Size > 0 && Receive_Date_Size < 4)

{

c++;

}

else if(Receive_Date[c] == Last_Date && Receive_Date_Size ==4)

{

c = 0;

Flag_Receive_One = 1;

}

else

{

c = 0;

}

}

}

接收

串口的收发可以用查询和中断两个办法来实现。

1、查询方法更适合于半双工机制,编写的思路简单,程序结构简单,在全双工通信中易出问题。

2、中断方法则更高效。你的程序把两种方法混搭使用,容易出错。

以你的程序为例,一旦收到首个23H字符,就停止在中断服务中for循环里面等待5个剩余字符。假设传感器只发了3个字符,你的程序就停止在for循环里面。

以你的程序为例改进,在中断服务接收中,每次接收中断只收1个字符,完成后退出。

void uart_interrupt(void) interrupt 4 using 0

{

static unsigned char i=0;

unsigned char buf;

if(RI==1)

{

buf=SBUF;

switch(i)

{

case 0:

if(buf==0x23)i=1;

break;

case 1:

case 2:

case 3:

case 4:

case 5:

buffer[i-1]=buf;

i++;

if(buf==0x23)

i=1;

if(i==5)

{

do_something_here(buffer);

i=0;

}

break;

default: i=0;break;

}

RI = 0; //RI清零

}

if(TI==1) TI=0; //TI清零

}

这样改符合你的思维习惯吗?实际串口协议解析与协议密切相关,用状态机做比较好。程序中i把它变成状态机的状态,思考一下,改改程序更佳。

/串口2收到一个字符中断子函数 /

void uart2_get_char(void) interrupt 8

{

……

……

}//这里,好像,多了一个(右)大括号。

}

可靠的接受程序!!从LZ 的display(a1a10)看出来这程序就不咋样,如果显示函数 还是 用 延时做的,可靠的接受程序给LZ 也是 白瞎……

以下是 UART 驱动程序

/10位异步收发串口通讯驱动——火柴天堂作品-20130119/

/源程序硬件环境:52单片机,110592MHz晶振,定时器1作为波特率发生器,通讯波特率9600 bit/s/

//

#define UART_H

#include"REG52h" //包含52头文件

#include"UARTh" //包含串口头文件

#define th1 0xfa //651us at 110592MHz Fosc for 8bit auto reload mode

static uchar UART_DataR; //串口接收数据寄存器

static uchar bdata Flag=0; //标志位 寄存器

sbit UART_ReFlag=Flag^0; //串口接收标志位 0:无数据 1:新数据

sbit UART_SendFlag=Flag^1; //串口发送标志位 0:空闲中 1:发送中

void UART()interrupt 4 //串口中断函数

{

if(RI) //若串口接收完成

{

RI=0; //清 串口接收溢出位

UART_DataR=SBUF; //将串口收到的数据存进 UART_DataR

UART_ReFlag=TRUE; //串口接收标志位 置位(有新数据)

}

if(TI) //若串口发送完成

{

TI=0; //清 串口发送溢出位

UART_SendFlag=FALSE; //清串口发送标志位(空闲中)

}

}

void UART_Init() //串口初始化函数

{

SCON=0x50; //选择通讯方式:10位异步收发,串口中断使能

PCON=0x80; //波特率倍频

TMOD&=0x0f; //定时器1控制位清0

TMOD|=0x20; //定时器1工作模式2(8位自重装,做波特率发生器)

TH1=th1; //定时器初值

TL1=th1; //定时器初值

TR1=1; //开始计时

ES=1; //允许串口中断

EA=1; //允许系统中断

}

bit UART_SendByte(uchar send_data) //串口发送字节函数,发送内容send_data,返回值:0 *** 作失败,1 *** 作成功

{

if(!UART_SendFlag) //若串口空闲中,则

{

SBUF=send_data; //将发送内容 送到 串口寄存器

UART_SendFlag=TRUE; //置位串口发送标志位(进入忙态)

return TRUE; //返回1, *** 作成功

}

return FALSE; //否则,返回0, *** 作失败

}

uchar ASCII_ToHex(uchar ascii_data) //ASCII 转 Hex 函数

{

uchar hex_data=0; //定义 Hex变量存储转换结果

if(ascii_data>='0' && ascii_data<='9') hex_data=ascii_data-'0'; //若 转换内容为 字符'0-9',则转成对应数字0-9

else if(ascii_data>='a' && ascii_data<='f') hex_data=ascii_data-'a'+10; //若 转换内容为 字符'a-f',则转成数字10-15

else if(ascii_data>='A' && ascii_data<='F') hex_data=ascii_data-'A'+10; //若 转换内容为 字符'A-F',则转成数字10-15

return hex_data; //返回转换结果,非以上字符,不在Hex(0-F)范围内,默认0

}

bit UART_ReadByte(uchar p_data,bit data_mode) //串口读字节函数,返回值0 无数据,1 有数据,将data_mode模式(ASCII_Mode或HEX_Mode)转成Hex结果存到p_data指向地址

{

if(!UART_ReFlag) return FALSE; //若无新数据,则返回 0(无数据)

UART_ReFlag=FALSE; //否则,清 串口接收标志位

if(data_mode==HEX_Mode) p_data=UART_DataR; //Hex模式,将串口接收结果存到p_data指向地址

if(data_mode==ASCII_Mode) p_data=ASCII_ToHex(UART_DataR); //ASCII模式,将串口接收结果转成Hex后,存到p_data指向地址

return TRUE; //返回 1(有数据)

}

#include <REG52H>

#define uchar unsigned char

#define uint unsigned int

sbit ring=P3^7;

sbit CASE1=P2^0;

sbit CASE2=P2^1;

sbit CASE3=P2^2;

sbit CASE4=P2^3;

uchar se=0,re=0;

uchar temp=0;

void wait(uint cnt)

{

while(--cnt);

}

//串口发送程序

void send(uchar se)

{

SBUF=se; //发送数据

while(TI == 0);

TI = 0;

}

//串口接收程序

uchar receive(void)

{

re=SBUF; //接收数据

while(RI==0);

RI=0;

return re;

}

//串口初始化

void sinti(void)

{

SCON = 0x50;

TMOD |= 0x20;

TH1 = 0xFD;

TR1 = 1;

EA = 1;

ES = 1;

}

void delay(int cnt)

{

while(--cnt);

}

//主程序

int main (void)

{

int i;

sinti(); //串口初始化程序

ring=1;

while(1)

{

while (1)

{

if(CASE1==0)

{

send('a');

ring=0;

break;

}

if(CASE2==0)

{

send('b');

ring=0;

break;

}

if(CASE3==0)

{

send('c');

ring=0;

break;

}

if(CASE4==0)

{

send('d');

ring=0;

break;

}

}

if(ring==0)

{

wait(60000);

ring=1;

}

for(i=0;i<10000;i++);

}

}

//串口中断程序

void UART_SER (void) interrupt 4 //串行中断服务程序

{

if(RI) //判断是接收中断产生

{

RI=0; //标志位清零

temp=SBUF;

}

if(TI) //如果是发送标志位,清零

TI=0;

}

以上就是关于51单片机串口程序在接收了数据后就不能正常发送了,帮忙看下代码有没有问题全部的内容,包括:51单片机串口程序在接收了数据后就不能正常发送了,帮忙看下代码有没有问题、51单片机串口通信、编写单片机串口收发数据的完整程序(C语言编写)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9285491.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-26
下一篇 2023-04-26

发表评论

登录后才能评论

评论列表(0条)

保存