[西门子] 单片机串口接收未知长度的字节数据程序实例

[复制链接]
查看108 | 回复0 | 2025-4-13 20:38:07 | 显示全部楼层 |阅读模式

单片机串口通过接收中断来判断接收数据,通常我们接收数据长度是确定的数,可以通过建立数组,将接收的数据不断放入数组中,当达到所要接收的长度,做判断,表示接收完成,再进行下一步的程序。但如果接收的数据并不知道其长度,那怎么判断是否接收完毕呢。通常我们可以做一个空闲等待,即在一定时间内没有接收到数据,我们就可以认为他不在发送。通常空闲等待时间5ms,当然可以更长,传输的数据也更稳定。我以等待5ms没有发过来数据来认定不在发送。
 
在串口中断函数里面,每接收到一个字节,就会把接收到的字节保存到Rx_R[]数组中,Rx_R[]可以事先定义一个较大的数组,足可以放下所要接收的字符串。但如果太大,会报错:segment too large。所以如果定义较大的数组,如Rx_R[255],需要加入code区才可以。在文中,我定义了Rx_R[30],因为所接收的字符串小于30。
unsigned  char flag_R=0;   //接收标志位
unsigned  char flag_T=0;   //发送标志位
unsigned  char flag_Time=0;  //时间计时
unsigned  char Tx_R='R';    //发送字符为R
unsigned  char Rx_R[30];//接收数组,定义要大于接收数         unsigned  char Res_Count;  //默认是0      


在串口中断函数里面,每接收到一个字节,变量Res_Count作为字节计数器+1。每当flag_R1,flag_Time置0,表示接收完毕。
// 串口1 中断服务程序
void UART1(void) interrupt 4
{
if(TI)// 发送完成中断
  {
  TI=0;
  flag_T=1;   //接收完毕标志,接收一个'R' 
  }
if(RI)// 接收完成中断 RI==1,接收完成一个字节
 {
  RI=0;
  Rx_R[Res_Count] = SBUF;
  Res_Count++;
  flag_R=1;   //接收完成标志位置1
  flag_Time=0; //延时计数清零
  }
}

在主函数当中,发现变量flag_Time等于1了,就开始启动延时计数让这个变量1ms加1每当接收到数据后flag_Time又为0,只要一直接收,flag_Time就一直为0。如果串口不停的收数据,永不停顿,那Res_Times也到不了5。直到停顿5ms了未收到数据,认为不在发送,看做一个完整字节串结束。当不在接收后,flag_Time经过5ms,此时flag_Time已经加到5,退出do循环,此时认为接收完毕,执行Res_Count0,准备下一次的接收或下面的程序运行。同时给数组加\0,表示此字节串到此为止。
main()
{
UART1_init();
while(1)
{
  unsigned int   j=0;
  unsigned int   k=0;
   SendDataByUart1('R');
   for(j=0;j<1000;j++)//发完后延迟等待1s,同时等待接收
   {
     Delay1000us();  
   }  
   do{
    flag_Time++; // 延时计数器+1
    Delay1000us(); //延迟1ms     
     }while(flag_Time<5);
// 5ms时间到,flag_Time仍未置0,表示5ms没有收到数据。
//相当于空闲等待5ms。
//下面写所要进行的程序
flag_R=0;// 接收标志清0
Rx_R[Res_Count] ='\0';  
//空闲5ms未收到后,表示结束,加结束符。
Res_Count=0; // 接收数据字节计数器清0
    sendcombytes(Rx_R);//向1口发送
   for(j=0;j<500;j++)//发完后延迟等待0.5s,同时等待接收
    {
    Delay1000us();  
    }
  }
 }


STC15W为案例
每秒向串口助手发送R,向单片机回复字符串,单片机将回复的字符串打印在串口助手上。

#define MAIN_Fosc11059200L
//定义主时钟,注意和下载频率选择一致
#define  uint16   unsigned int  
#define  uint8    unsigned char
#include
 
#include"STC15.H"
#include
#define T_MS   5  //定时时间常量,单位ms
#define T1TMS    (T_MS*MAIN_Fosc/1000)       //1T模式下  
#define T12TMS   (T_MS*MAIN_Fosc/1000/12)    //12T模式下
unsigned  char flag_R=0;   //接收标志位
unsigned  char flag_T=0;   //发送标志位
unsigned  char flag_Time=0;//时间计时
unsigned  char Tx_R='R';  //发送字符为R
unsigned  char Rx_R[30];  //接收数组
//如果定义数字较大的数组,需要加入code区,不然显示segment too large
unsigned  char Res_Count;  //首次默认是0
uint8 temp;
 
 
//**********//串口1初始化*************************/
 
void UART1_init(void)//T2作为UART1波特率发生器
{
 
SCON = 0x50;//8位数据,可变波特率
AUXR |= 0x40;//定时器1时钟为Fosc,即1T  11.0592MHz
AUXR &= 0xFE;//串口1选择定时器1为波特率发生器
TMOD &= 0x0F;//设定定时器1为16位自动重装方式
TL1 = 0xE0;//设定定时初值
TH1 = 0xFE;//设定定时初值
ET1 = 0;//禁止定时器1中断
TR1 = 1;//启动定时器1
//以上设置由STC-ISP生成
ES   = 1;// 开串口1中断
EA   = 1;// 开总中断
}
 

//*********//延迟函数1ms 由STC-ISP生成******************/
void Delay1000us()//@11.0592
{
unsigned char i, j;
 
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
 

//*********口1 发送字符函数********************/
void SendDataByUart1(uint8 dat)
{
 SBUF = dat;   //写数据到UART数据寄存器
 while(TI == 0);  
//在停止位没有发送时,TI为0即一直等待,在函数里循环。
//当TI硬件置1,跳出此循环。
TI = 0;  //清除TI位(该位必须软件清零)
}
//串口1 发送字符串函数
void sendcombytes(unsigned char *ptr)  
//*ptr指向字符串的首地址,printf打印时直到\0停止。
 while(*ptr)  //*ptr 不为空,一直循环
  {
  SendDataByUart1(*ptr++); 
  //TI、RI发送接收中断必须清零,防止出现意外
  }
}
 
 
  
//*********串口1 中断服务程序********************/
void UART1(void) interrupt 4
{ 

if(TI)// 发送完成中断
 {
   TI=0;
   flag_T=1;   //接收完毕标志,接收一个'R' 
 }

if(RI)// 接收完成中断 RI==1,接收完成一个字节
{
RI=0;
Rx_R[Res_Count] = SBUF;
Res_Count++;
flag_R=1;   //接收完成标志位置1
flag_Time=0; //延时计数清零
   }
 }
 
 
//*********写主函数********************/
 
main()
{
 
UART1_init();
 
while(1)
{
  unsigned int   j=0;
  unsigned int   k=0;    
  SendDataByUart1('R');
 for(j=0;j<1000;j++)//发完后延迟等待1s,同时等待接收
 {
 Delay1000us();  
  }
  
   do{
    flag_Time++; // 延时计数器+1
    Delay1000us(); //延迟1ms     
   }while(flag_Time<5);
// 5ms时间到,flag_Time仍未置0,表示5ms没有收到数据。
 //相当于空闲等待5ms。
  flag_R=0;// 接收标志清0
  Rx_R[Res_Count] ='\0';  
//空闲5ms未收到后,表示结束,加结束符。
 Res_Count=0; // 接收数据字节计数器清0
 sendcombytes(Rx_R);//向1口发送

  for(j=0;j<500;j++)//发完后延迟等待0.5s,同时等待接收
  {
  Delay1000us();  
  }
 }
}
 
串口收发如图:可自由输入字符串长度,并打印出来。


 



 


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册哦

x
您需要登录后才可以回帖 登录 | 注册哦

本版积分规则