51单片机串口通信

谁有51单片机与电脑串口通信的C程序,最好是中断方式的.
2024-11-17 00:27:21
推荐回答(3个)
回答(1):

//////////////////////////////////////////////////////////////////////////////////////////////////
//E51Pro.c
//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;
}
}
}

回答(2):

// 单片机串行口发送/接收程序,每接收到字节即发送出去
// 和微机相接后键入的字符回显示在屏幕上
// 可用此程序测试
//
#include

#define XTAL 11059200 // CUP 晶振频率
#define baudrate 9600 // 通信波特率

void main(void)
{
unsigned char c;

TMOD = 0x20; // 定时器1工作于8位自动重载模式, 用于产生波特率
TH1=(unsigned char)(256 - (XTAL / (32L * 12L * baudrate)));
TL1=(unsigned char)(256 - (XTAL / (32L * 12L * baudrate))); // 定时器0赋初值

SCON = 0x50;
PCON = 0x00;

TR1 = 1;
IE = 0x00; // 禁止任何中断

while(1)
{
while(RI == 0);
RI = 0;
c = SBUF; // 从缓冲区中把接收的字符放入c中

SBUF = c; // 要发送的字符放入缓冲区
while(TI == 0);
TI = 0;
}
}

回答(3):

  #include
  #include
  unsigned char ch;

  bit read_flag= 0 ;

  void init_serialcom( void ) //串口通信初始设定

  {

  SCON = 0x50 ; //UART为模式1,8位数据,允许接收

  TMOD |= 0x20 ; //定时器1为模式2,8位自动重装

  PCON |= 0x80 ; //SMOD=1;

  TH1 = 0xFD ; //Baud:19200 fosc="11".0592MHz

  IE |= 0x90 ; //Enable Serial Interrupt

  TR1 = 1 ; // timer 1 run

  TI=1;

  }

  //向串口发送一个字符

  void send_char_com( unsigned char ch)

  {

  SBUF=ch;

  while (TI== 0);

  TI= 0 ;

  }

  //串口接收中断函数

  void serial () interrupt 4 using 3

  {

  if (RI)

  {

  RI = 0 ;

  ch=SBUF;

  read_flag= 1 ; //就置位取数标志

  }

  }

  main()

  {

  init_serialcom(); //初始化串口

  while ( 1 )

  {

  if (read_flag) //如果取数标志已置位,就将读到的数从串口发出

  {

  read_flag= 0 ; //取数标志清0

  send_char_com(ch);

  }

  }

  }