//////////////////////////////////////////////////////////////////////////////////////////////////
//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单片机串口通信(汇编)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)