本帖最后由 何立立 于 2015-8-11 16:42 编辑
关于到串口接收,基本上就是“采样”的操作。当你明白“bps”的意义后,对于理解串口的接收,非常的简单。
Rx_module.v 是一个组合模块,主要是包含 detect_module.v , bps_module.v 和 rx_control_module.v,3个功能模块。
detect_module.v 的输入是连结物理引脚rx,它主要检测一帧数据的第0位,也就是起始位,然后产生一个高脉冲经 H2L_Sig 给 rx_control_module.v ,以表示一帧数据接收工作已经开始。
rx_bps_module.v 是产生波特率定时的功能模块。换一句话说,它是配置波特率的模块。
当rx_control_module.v拉高Count_Sig, bps_module.v经BPS_CLK对 rx_control_module.v 产生定时。
rx_control_module.v 是核心控制模块。针对串口的配置主要是1帧11位的数据,重视八位数据位,无视起始位,校验位和结束位。当RX_En_Sig 拉高,这个模块就开始工作,它将采集来自 RX_Pin_In 的数据,当完成一帧数据接收的时候,就会产生一个高脉冲给 RX_Done_Sig。
它到底是如何实现采集的呢?
如上图所示,数据采集都是在“每位数据的中间”进行着。在上图中 RX_Pin_In 输入一帧数据,当 detect_module.v 检测到低电平(起始位),rx_control_module.v 和 rx_bps_module.v 就产生定时(与RX_Pin_In的波特率是一致)。然而rx_bps_module.v 产生的定时是在每个位时间的中间。
在第0位数据,采取忽略的态度,然后接下来的8位数据位都被采集,最后校验位和停止位,却是采取了忽略的操作。有一点你必须好好注意,串口传输数据“从最低位开始,到最高位结束”。
- module detect_module
- (
- CLK, RSTn,
- RX_Pin_In,
- H2L_Sig
- );
- input CLK;
- input RSTn;
- input RX_Pin_In;
- output H2L_Sig;
- /******************************/
- reg H2L_F1;
- reg H2L_F2;
- always @ ( posedge CLK or negedge RSTn )
- if( !RSTn )
- begin
- H2L_F1 <= 1'b1;
- H2L_F2 <= 1'b1;
- end
- else
- begin
- H2L_F1 <= RX_Pin_In;
- H2L_F2 <= H2L_F1;
- end
- /***************************************/
- assign H2L_Sig = H2L_F2 & !H2L_F1;
- /***************************************/
- endmodule
detect_module.v 这个功能模块,读者也非常眼熟了吧,而该功能模块是为了检查电平由高变低。当检测到电平又高变低,在第31行就会输出高脉冲。
- module rx_bps_module
- (
- CLK, RSTn,
- Count_Sig,
- BPS_CLK
- );
- input CLK;
- input RSTn;
- input Count_Sig;
- output BPS_CLK;
- /***************************/
- reg [12:0]Count_BPS;
- always @ ( posedge CLK or negedge RSTn )
- if( !RSTn )
- Count_BPS <= 13'd0;
- else if( Count_BPS == 13'd1250 )
- Count_BPS <= 13'd0;
- else if( Count_Sig ) //Count_Sig为1时候启动计数
- Count_BPS <= Count_BPS + 1'b1;
- else
- Count_BPS <= 13'd0;
- /********************************/
- assign BPS_CLK = ( Count_BPS == 13'd625) ? 1'b1 : 1'b0;
- /*********************************/
- endmodule
9600 bps 传输速度使一位数据的周期是 0.000104166666666667s 。以12Mhz时钟频率要得到上述的定时需要:N = 0.000104166666666667 / ( 1 / 12Mhz ) = 1250
- module rx_control_module
- (
- CLK, RSTn,
- H2L_Sig, RX_Pin_In, BPS_CLK, RX_En_Sig,
- Count_Sig, RX_Data, RX_Done_Sig
- );
- input CLK;
- input RSTn;
- input H2L_Sig;
- input RX_En_Sig;
- input RX_Pin_In;
- input BPS_CLK;
- output Count_Sig;
- output [7:0]RX_Data;
- output RX_Done_Sig;
- /********************************************************/
- reg [3:0]i;
- reg [7:0]rData;
- reg isCount;
- reg isDone;
- always @ ( posedge CLK or negedge RSTn )
- if( !RSTn )
- begin
- i <= 4'd0;
- rData <= 8'd0;
- isCount <= 1'b0;
- isDone <= 1'b0;
- end
- else if( RX_En_Sig )
- case ( i )
- 4'd0 :
- if( H2L_Sig ) begin i <= i + 1'b1; isCount <= 1'b1; end//启动波特率定时模块
- 4'd1 :
- if( BPS_CLK ) begin i <= i + 1'b1; end //起始位可以忽略
- 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8, 4'd9 :
- if( BPS_CLK ) begin i <= i + 1'b1; rData[i - 2] <= RX_Pin_In; end//采集8位数据
- 4'd10 :
- if( BPS_CLK ) begin i <= i + 1'b1; end//校验位
- 4'd11 :
- if( BPS_CLK ) begin i <= i + 1'b1; end//停止位
- 4'd12 :
- begin i <= i + 1'b1; isDone <= 1'b1; isCount <= 1'b0; end
- 4'd13 :
- begin i <= 4'd0; isDone <= 1'b0; end
- endcase
- /********************************************************/
- assign Count_Sig = isCount;
- assign RX_Data = rData;
- assign RX_Done_Sig = isDone;
- /*********************************************************/
- endmodule
RX_En_Sig 如果没有拉高,这个模块是不会工作,isCount 标志寄存器,为了使能 rx_bps_module.v 输出采集定时信号;当 rx_control_module.v 模块被使能,该模块就会处于就绪状态,一旦 detect_module.v 检查到由高变低的电平变化,会使步骤i进入第0位采集,然而 isCount 标志寄存器同时也会被设置为逻辑1, rx_bps_module.v 便会开始产生波特率的定时。
rx_bps_module.v 产生的定时是在“每位数据的中间,第一次的定时采集时第0位数据(起始位),保持忽略态度,定时采集的是八位数据位,每一位数据位会依低位到最高位储存入 rData 寄存器;
最后两位的定时采集(校验位,停留位),同时采取忽略的态度。当进入
- 4'd12 :
- begin i <= i + 1'b1; isDone <= 1'b1; isCount <= 1'b0; end
- 4'd13 :
- begin i <= 4'd0; isDone <= 1'b0; end
[size=14.3999996185303px]endcase,这表示一帧数据的采集工作已经结束。最后会产生一个完成信号的高脉冲,同时间 isCount会被设置为逻辑0,亦即停止rx_bps_module.v 的操作。
顶层模块:
- module rx_module_demo
- (
- CLK, RSTn,
- RX_Pin_In,
- Number_Data
- );
- input CLK;
- input RSTn;
- input RX_Pin_In;
- output [3:0]Number_Data;
- /**********************************/
- wire RX_Done_Sig;
- wire [7:0]RX_Data;
- wire RX_En_Sig;
- rx_module U4
- (
- .CLK( CLK ),
- .RSTn( RSTn ),
- .RX_Pin_In( RX_Pin_In ),
- .RX_En_Sig( RX_En_Sig ),
- .RX_Done_Sig( RX_Done_Sig ),
- .RX_Data( RX_Data )
- );
- /**********************************/
-
- wire [7:0]Output_Data;
- control_module U5
- (
- .CLK( CLK ),
- .RSTn( RSTn ),
- .RX_Done_Sig( RX_Done_Sig ),
- .RX_Data( RX_Data ),
- .RX_En_Sig( RX_En_Sig ),
- .Number_Data( Output_Data )
- );
- /***********************************/
- assign Number_Data = Output_Data[3:0];
- endmodule
RTL级原理图:
自此就完成了串口接收模块了!