51单片机串口通信

51单片机串口通信,第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;

}

}

}

串口通讯参考程序如下:

来源:深入浅出AVR单片机

#include<reg51h>

unsigned char UART_RX; //定义串口接收数据变量

unsigned char RX_flag; //定义穿行接收标记

/

函数名:UART串口初始化函数

调  用:UART_init();

参  数:无

返回值:无

结  果:启动UART串口接收中断,允许串口接收,启动T/C1产生波特率(占用)

备  注:振荡晶体为12MHz,PC串口端设置 [ 4800,8,无,1,无 ]

//

void UART_init (void){

EA = 1; //允许总中断(如不使用中断,可用//屏蔽)

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

TMOD = 0x20; //定时器T/C1工作方式2

SCON = 0x50; //串口工作方式1,允许串口接收(SCON = 0x40 时禁止串口接收)

TH1 = 0xF3; //定时器初值高8位设置

TL1 = 0xF3; //定时器初值低8位设置

PCON = 0x80; //波特率倍频(屏蔽本句波特率为2400)

TR1 = 1; //定时器启动

}

//

/

函数名:UART串口接收中断处理函数

调  用:[SBUF收到数据后中断处理]

参  数:无

返回值:无

结  果:UART串口接收到数据时产生中断,用户对数据进行处理(并发送回去)

备  注:过长的处理程序会影响后面数据的接收

//

void UART_R (void) interrupt 4  using 1{ //切换寄存器组到1

RI = 0;   //令接收中断标志位为0(软件清零)

UART_RX = SBUF; //将接收到的数据送入变量 UART_data

RX_flag=1;  //标记接收

//用户函数内容(用户可使用UART_data做数据处理)

//SBUF = UART_data; //将接收的数据发送回去(删除//即生效)

//while(TI == 0); //检查发送中断标志位

//TI = 0;  //令发送中断标志位为0(软件清零)

}

//

/

函数名:UART串口发送函数

调  用:UART_T ();

参  数:需要UART串口发送的数据(8位/1字节)

返回值:无

结  果:将参数中的数据发送给UART串口,确认发送完成后退出,采用非中断方式

备  注:

//

void UART_T (unsigned char UART_data){ //定义串口发送数据变量

ES=0;    //禁止穿行中断

SBUF = UART_data; //将接收的数据发送回去

while(TI == 0);  //检查发送中断标志位

TI = 0;   //令发送中断标志位为0(软件清零)

ES=1;   //打开穿行中断

}

/

函数名:UART串口发送字符串函数

调  用:UART_S ();

参  数:需要UART串口发送的数据(8位/1字节)

返回值:无

结  果:将参数中的数据发送给UART串口,确认发送完成后退出,采用非中断方式

备  注:

//

void UART_S(unsigned char str)

{

while(1)

{

if(str=='\0') break;

UART_T(str++);

}

}

/

函数名:主函数

调  用:main();

参  数:

返回值:无

结  果:

备  注:

//

void main()

{

unsigned char Buf_data[]={"      welcome to MCU world     \n\r"};

UART_init();

UART_S(Buf_data);

while(1){

if(RX_flag==1)

{

UART_T(UART_RX);

RX_flag=0;

}

}

}

祝愿楼主马到功成

HERE: AJMP HERE

SINT: MOV P1,R0

JB RI,RECV

JB TI,SEND

AJMP HERE

中断里面直接用这种方式直接跳到主程序,我以前还是真没试过,不过估计能行吧。 我一直用RETI 返回堆栈地址位置的。

但下面这地方肯定有错的,就是执行MOV SBUF,A 后没有等待!!

正确的顺序是: CLR TI ;清发送标记

MOV SBUF,A ;发送

JNB TI,$ ; 这里是如果TI没有被置1就等待,因为送数可能还没有完成。。就去执行别的动作,可能会有问题。

接收也一样要等待:

MOV A,SBUF

JNB RI,$ ;等待接收完成标志。

另外:

CPL P17 有问题,我猜你是用P17来观察接收次数,

但由于CPL P17取反命令是读一下P17再取反输出的,如果你的p17外接电路不科学,不合理,可能会出现你每次不管发1,还是发0,p17都是低电平,比如你将p17直接接在npn三管基极就会一直是0V或07V , P17的读入值会总为0,CPL 输出会总是为1

你可以用内部(非P口的位地址过度一下),比如: CPL 01H

MOV C,01H

MOV P17,C

你先试验吧。。。

以上就是关于51单片机串口通信全部的内容,包括:51单片机串口通信、51单片机和计算机之间实现串口通信的电路图、51单片机串口通信(汇编)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存