概述:上位机(PC机)向MCU发送指令,MCU串口接收指令并根据列表发送响应。
全局变量声明
#include
BYTE ComBuf[18];//串口通讯数据缓存,发送和接收都使用
UINT nAddress;//ROM中地址计数
UINT nTimeOut;//超时计数
ProWork pw;//编程器一般操作
1 定时器延时
1.1 微秒级
void Delay_us(BYTE nUs)//微秒级延时<255us
{
TH0=0;
TL0=0;
TR0=1;
while(TL0 TR0=0; } 分析: 定时器初始值归零,自增1次约1us。 打开定时器中断,BYTE有效值为0~255,因此TL 最后关闭定时器中断。 1.2 毫秒级 void Delay_ms(UINT nMs) //毫秒级的延时<65535ms { UINT n=0; TR0=1; while(n { TH0=0; TL0=20; while(TH0<4); n++; } TR0=0; } TH自增1,即TL自增255,故TH自增4次约1ms,其他同微秒级。 2 等待上位机命令 BOOL WaitComm() //等待上位机的命令,18字节 { BYTE n=0; RI=0; //*****1****** while(!RI){} //等待第一个字节 ComBuf[n]=SBUF; RI=0; n++; //*****2****** for(n;n<=17;n++) { nTimeOut=0; while(!RI) { nTimeOut++; if(nTimeOut>10000) return 0; //后17个字节都有超时限制 } ComBuf[n]=SBUF; RI=0; } return 1; } **1** 上位机发送第一个字节,接收中断,接收字符存入ComBuf数组;软件置零,继续接收下一字节。 **2** 下一字节要若在超时计数nTimeOut自增超过1W,则返回0,不再接收;未超时,则把剩下17字节依次存入ComBuf数组。 3 等待上位机回应 BOOL WaitResp()//等待上位机回应,1字节,有超时限制 { nTimeOut=0; RI=0; while(!RI) { nTimeOut++; if(nTimeOut>50000) { return 0; } } RI=0; ComBuf[0]=SBUF; return 1; } 上位机在5Wus内回应,存入ComBuf。 4 写器件等待上位机,与等待上位机命令有区别 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; } 所有18字节均有超时限制 6 把Com数组内容发送到上位机,回应操作完成 void SendData() //发送数据或回应操作完成,18字节 { BYTE n=0; for(n;n<=17;n++) { TI=0; SBUF=ComBuf[n]; while(!TI){} TI=0; } } 7 写器件对上位机回应 void SendResp()//回应上位机1个字节,在写器件函数中使用 { TI=0; SBUF=ComBuf[0]; while(!TI){} TI=0; } 8 读特征字 void ReadSign() //读特征字 { pw.fpReadSign(); SendData(); //通知上位机,送出读出器件特征字 } 读取PW特殊寄存器 附一:源码 //Easy 51Pro编程器主程序,负责通讯,管理编程操作 /////////////////////////////////////////////////////////////////////////////////////////////////// #include BYTE ComBuf[18];//串口通讯数据缓存,发送和接收都使用 UINT nAddress;//ROM中地址计数 UINT nTimeOut;//超时计数 ProWork pw;//编程器一般操作 void Delay_us(BYTE nUs)//微秒级延时<255us { TH0=0; TL0=0; TR0=1; while(TL0 { } TR0=0; } void Delay_ms(UINT nMs)//豪秒级的延时<65535ms { UINT n=0; TR0=1; while(n { 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()//编程器复位 { pw.fpProOver();//直接编程结束 SendData();//通知上位机,表示编程器就绪,可以直接用此函数因为协议号(ComBuf[0])还没被修改,下同 } void ReadSign()//读特征字 { pw.fpReadSign(); SendData();//通知上位机,送出读出器件特征字 } void Erase()//擦除器件 { pw.fpErase(); SendData();//通知上位机,擦除了器件 } void Write()//写器件 { BYTE n; pw.fpInitPro();//编程前的准备工作 SendData();//回应上位机表示进入写器件状态,可以发来数据 while(1) { if(WaitData())//如果等待数据成功 { if(ComBuf[0]==0x07)//判断是否继续写 { for(n=2;n<=17;n++)//ComBuf[2~17]为待写入数据块 { if(!pw.fpWrite(ComBuf[n]))//<<<<<<<<<<<<<<<<<<<调用写该器件一个单元的函数 { pw.fpProOver();//出错了就结束编程 ComBuf[0]=0xff; SendResp();//回应上位机一个字节,表示写数据出错了 WaitData();//等待上位机的回应后就结束 return; } nAddress++;//下一个单元 } ComBuf[0]=1;//回应上位机一个字节,表示数据块顺利完成,请求继续 SendResp(); } else if(ComBuf[0]==0x00)//写器件结束 break; else//可能是通讯出错了 { pw.fpProOver(); return; } } else//等待数据失败 { pw.fpProOver(); return; } } pw.fpProOver();//编程结束后的工作 Delay_ms(50);//延时等待上位机写线程结束 ComBuf[0]=0;//通知上位机编程器进入就绪状态 SendData(); } void Read()//读器件 { BYTE n; pw.fpInitPro();//先设置成编程状态 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]=pw.fpRead();//<<<<<<<<<<<<<<<<<<<调用写该器件一个单元的函数 nAddress++;//下一个单元 } ComBuf[0]=6;//向上位机发送读出的数据块 SendData(); } else break;//等待回应失败 } pw.fpProOver();//操作结束设置为运行状态 ComBuf[0]=0;//通知上位机编程器进入就绪状态 SendData(); } void Lock()//写锁定位 { pw.fpLock(); 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;//波特率28800*2,注意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; } } }
上一篇:(C51学习五)单片机与PC通过串口通信
下一篇:51单片机与PC进行串口通信
推荐阅读最新更新时间:2024-03-16 16:08