串口大揭秘

  这两天一直在研究串口rs232,正好身边有一块xilinx的板子,可以在板子上调试。

  虽然之前也写过很多版本的串口,但是隔了这么久,自己的编码水平和风格都变了很多,重新再写串口肯定有新发现,事实也证明了这一点。

  于是在网上看了串口协议和代码,收获不大,但是却发现了一段有意思的代码。

  reg [3:0] cnt;

  always @ (posedge clk) cnt <= cnt + 1'b1;

  wire pulse = (cnt == 15);

  这段代码其实就是每隔15个数产生一个高脉冲,那么我怎样应用到串口程序里面呢?

  parameter

    CLK = 50_000_000,

    BPS = 115200,

    BPS_CNT = CLK / BPS - 1,

    TX_CNT = CLK / BPS - 1,

    RX_CNT = CLK / BPS / 2 - 1;

  reg [9:0] cnt;

  always @ (posedge clk)

    if (rst) cnt <= 10'd0;

    else if (cnt == BPS_CNT) cnt <= 10'd0;

    else cnt <= cnt + 1'b1;

  wire tx_en = (cnt == TX_CNT);

  wire rx_en = (cnt == RX_CNT);

  以上代码是产生周期性的高脉冲,其高脉冲的周期和波特率发送1bit数据的时间是“几乎”相等的,这时候大家可以想一想,只要上位机按115200波特率发过来数据,那么在1bit数据持续时间里肯定有高脉冲,大家再仔细想一想,实际上我将1bit数据的持续时间分割成了BPS_CNT份,而我通过调整RX_CNT的值,就可以在其中一份时间中产生高脉冲,然后接收数据(建议选取靠近中间的时间份)。

  而我以前写串口的思想是产生和波特率发送1bit数据时间“几乎”相等的时钟发送数据,或者产生比这个时钟频率快16、32、64以至于128倍的时钟,用这个快时钟分别计数16、32、64及128,在计数最大值的一半接收数据。

  那么这两种结构的优缺点就显而易见了。首先新方法的分割次数多,115200波特率的分割次数是434,而老方法一般用128倍时钟分割都很少,无疑新方法更准确;其次,新方法只需要产生和波特率对应的周期性高脉冲就可以,而老方法是产生比波特率对应频率快的时钟,然后计数选择接收数据,这更能看出新方法的简易。

  但是在上板调试的时候却出现了问题,问题体现在串口调试助手以1BYTE/ms的速率发送接收数据时,出现周期性错误,难道是新方法的问题?

  经过仔细分析之后,其实出现的这个问题是新旧方法都不会避免的问题,那这个问题是什么呢?

  新旧方法都是采用晶振时钟通过计数进行分频,但是这种方法产生的时钟是有误差的,因为计数值不是整数,那么实际上分频的时钟和上位机发送1bit数据的时间是有略微差距的,这样当发送数据量大的时候,就会出现发送和接收不一致,甚至少发送1BYTE。其实这个问题的实质就是两端不同步了,找到这个问题,我们应该怎样解决呢?

  解决的方法就是在接收和发送每个数据的开始时同步高脉冲信号。同步之后,产生最大的误差也就是发送1BYTE所用时间的差。而原来是不断累加这个小小的误差,直到产生一个大误差的时候就发生错误了。

  那么我要总结一下:

  1.无论是产生高脉冲信号还是计数,需要明白二者和波特率的关系;

  2.产生的高脉冲信号或者计数,一定要和接收数据或者发送数据的开始同步。

  掌握以上两点,串口驱动就可以轻松写出来了。

 

 

 

 

 

 

 

 

 

 

posted @ 2013-11-08 23:55  巴索罗米·熊  阅读(739)  评论(0编辑  收藏  举报