原创 UART学习

2010-7-18 12:59 2373 6 7 分类: FPGA/CPLD

      很多东西看懂了和自己来做那是两回事。串口通讯的协议比较简单。接收端RX一旦检测到一个下降沿就开始接收数据,数据的位数,有无奇偶校验,都是可以自己设定的(帧格式),最后是停止位。TX负责发送数据。


        这个程序主要包括三部分:发送模块,接受模块和波特率产生模块。


       在接受模块:


607ab40c-349b-4123-9dea-40903c89521f.jpg    


 


        rs232_rx是数据接受端直接与要通讯的机器的TX端相连(中间有时当然需要做电平转换)。


always @ (posedge clk or negedge rst_n) begin
 if(!rst_n) begin
  rs232_rx0 <= 1'b0;
  rs232_rx1 <= 1'b0;
  rs232_rx2 <= 1'b0;
  rs232_rx3 <= 1'b0;
  end
 else begin
  rs232_rx0 <= rs232_rx;
  rs232_rx1 <= rs232_rx0;
  rs232_rx2 <= rs232_rx1;
  rs232_rx3 <= rs232_rx2;
  end
end


assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & (~rs232_rx1) & (~rs232_rx0);


          这是在检测起始信号,其实就是一个下降沿检测电路,定义这么多寄存器的目的在于避免误操作,在某一时刻rs232_rx上的电平变成0时,rs232_rx0中的数据会立即变成0,rs232_rx1中的数据会过一个时钟周期之后才变成0,rs232_rx2中的数据会过两个时钟周期之后才变成0,rs232_rx3中的数据会过三个时钟周期之后才变成0。也就是说如果是一个干扰,那它的低电平时间应该很短,在rs232_rx2还没有变成低电平时rs232_rx0又变成了高电平,最后运算的时候取反则下降沿标志位neg_rs232_rx还是不会置1。通俗的讲以下降沿的那时刻为基准则rs232_rx3和rs232_rx2是下降沿前2个系统时钟周期内rs232_rx上的电平信号,rs232_rx1和rs232_rx0是下降沿后2个系统时钟周期内rs232_rx上的电平信号,如果系统时钟是50MHz那么两个系统时钟周期则是40ns,只有下降沿后低电平维持至少40ns才会被认为是起始信号。


         当检测到下降沿后,rx_int信号和bps_start信号置一,rx_int一边输出到发送数据模块,一边作为内部信号用作开始发送数据的信号。bps_start 是输出给波特率产生模块告诉它现在开始启动计数器开始计数。先说一下波特率产生器模块,这个模块其实比较简单,类似一个采样时钟产生器。



35fb612b-163a-49e8-af18-a98e117729bf.jpg 


ce99b12c-0f6f-4bea-b4ef-aa577a85de0f.jpg


     它只有一个输入信号bps_start一个输出信号clk_bps。bps_start 用于启动里面的计数器,里面需要注意的是两个参数的设置假设我们现在用的是9600的波特率即一秒钟传输9600bit数据,传输一位的时间是1/9600s=104.16us,假设50MHz(20ns)的系统时钟,那么计104.16us需要104.16/0.02=5208个数。这个模块完成两个逻辑当bps_start启动信号来了以后马上开始计数,当计数计到一半时发出一个clk_bps信号即采样信号,告诉接受模块或者是发送模块(接受模块在这一时刻读取RX上的数据,发送模块在这一时刻把数据发送到TX),当启动信号有的时候它计数到了以后就会清零。



else if(rx_int) begin //准备接受数据
        if(clk_bps) begin //当检测脉冲来的时候,来一次收一次数据
               num <= num +1'b1;
               case(num)
                             4'd1:rx_temp_data[0] <= rs232_rx; //锁存第一位数据
                             4'd2:rx_temp_data[1] <= rs232_rx;
                             4'd3:rx_temp_data[2] <= rs232_rx;
                             4'd4:rx_temp_data[3] <= rs232_rx;
                             4'd5:rx_temp_data[4] <= rs232_rx;
                             4'd6:rx_temp_data[5] <= rs232_rx;
                             4'd7:rx_temp_data[6] <= rs232_rx;
                             4'd8:rx_temp_data[7] <= rs232_rx;
                            default: ;
             endcase
       end
   else if(num == 4'd12) begin   //一帧数据节后完成
     num <= 4'd0;    //计数器清零
     rx_data_r <= rx_temp_data; //把接受的数据给数据接受寄存器保存


         这是接受模块中数据接受部分的代码,当rx_int 有效时就开始检测波特率发生器的采样信号来一个clk_bps 就把num加一。注意这里的num值是从1开始的,也就是说第一位起始位不读,从数据位开始读。在num == 4'd12的时候,num清零,并且在还会把rx_int 赋0,bps_start赋0。rx_int赋0表示一帧数据已经接收完成两个作用一是告诉发射模块你现在可以把我接受的数据发射出去,2是自己内部判断条件不成立不用接受数据,等待下一个起始位。bps_start赋0则是告诉波特率发生器现在不用工作。在此当中有两点不是很懂:1, num <= num +1'b1 ;  case(num) 我觉得跟c不一样,它是并行的,来一个时钟条件满足num加一,但case(num)里面的值应该是没有加以前的值,同样的道理滞后一拍(这点未验证)。2, num的值为什么要到12后才停止,1个起始位,8个数据位,无奇偶校验,1个停止位都算上也才11位数据?等会再去查查。


        最后一个模块是发送模块,


3a2ec6ce-d960-4df2-9807-7062e67e4bb8.jpg   


          rx_int 是接受模块发出的信号,整个工程实现的功能就是上位机发一个数据这边接受然后把接受的数据再发回给上位机。当rx_int由1变为0时(也是下降沿检测),检测到了以后,就给中间的控制信号,(在这部分定义一个寄存器tx_en)  neg_tx_int 下降沿标志位有效则tx_en 置1, bps_start置1,并且把接受模块的数据给发送模块。波特率发生器开始计数,下面的发送模块开始发送数据,大体过程和接受一样。当num==4'd12时,tx_en赋0,停止发送,bps_start赋0,波特率模块停止计数。


        具体的发送数据部分判断tx_en为高时,来一个采样信号clk_bps,num加1,发相应的数据,还要注意他的起始位和结束位。


        在整个工程中,波特率发生器其实只有一个,但是只是在顶层例化的时候把它例化了两遍,于是就有了连个,一个跟发送模块相连,一个跟接受模块,它们是单独的,只是在例化的时候把引脚重新命一个名字,相连的模块名字一样就好。


         把别人的程序抄一遍,搞懂是最基础的,下一步就是在此基础上发展完善。准备把他的功能完善,写成一个通用模块,就那这个工程开刀,把仿真,时序分析,时序约束整个设计流程完成。Go   on!


 


 


 


 


 


 


 


 


 


 


PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户380721 2011-5-13 10:24

我也学习这个串口实验,但是看了特权同学的这个程序后有点疑惑,他这个只用了波特率频率的两倍频,没有使用波特率本身这个频率,我看了下那个串口通信协议,不是说要过采样,然后回到原来的那个波特率频率吗,他这个怎么没有?
相关推荐阅读
用户220339 2010-09-14 22:36
近来打算
             其实6月份开始接触FPGA,跟着别人做一下这个,做一下那个...
用户220339 2010-09-14 11:31
基于IP核复用技术的SOC芯片
             为适应产品尽快上市的要求,现在ASIC设计越来越多地采用预先验证好的IP核(如存储器,视频编码解码器等)。      IP核通常分为三种形式:硬核(Hard Core),软核...
用户220339 2010-09-13 19:23
可编程逻辑器件与专用集成电路
           早期电子系统硬件设计采用分立元件,随着集成电路的出现和应用,人们选用功能固定的标准集成电路(例如各种逻辑门,编码器,译码器,触发器,和计数器等)构成硬件系统,后来,又以微处理器为...
用户220339 2010-09-11 22:36
组合逻辑电路(一)
         典型的中规模集成组合逻辑电路如编码器,译码器,数据选择器,数据分配器,数值比较器,算术/逻辑运算单元。         对于一个逻辑电路,其输出状态在任何时刻只取决于同一时刻的输入状...
用户220339 2010-09-09 16:00
LPC2103上的PWM,AD,UART模块
         电源的程序主要是PWM驱动MOS管,然后通过采样反馈电压与设定电压比较在通过相应的换算来调整PWM的占空比,从而达到稳定输出。        显然PWM模块要,AD模块要,为了方面到...
用户220339 2010-09-06 22:08
开始写程序(lpc2103的几个文件)
           搬到谢老师办公室,感觉不错,只是希望效率更高一点。关于比赛的所有都已经结束。8月25号省电子竞赛测试完成,9月1号SOPC竞赛测试完成,不管怎么样,都完整的走完了整个过程。3号把...
EE直播间
更多
我要评论
1
6
关闭 站长推荐上一条 /3 下一条