15、 Uart串口通信

1.波特率的计算

波特率:简而言之,串口传输的波特率即为每秒钟传输二进制的位数

子:统时钟50M(为串口提供时钟的时钟频率),波特率115200/9600

系统时钟 50M

钟周期为                  1/50_000_000 = 20ns             

计一个数需要           1/50_000_000 = 20ns

一个周期计数           1s/20ns = 50_000_000个数

波特率 9600             1s传输9600个bit          

传输1bit需要            1/9600 s        

传输1bit需要            计数(1/9600)/(1/50_000_000) = 50_000_000/9600 = 5208

波特率 115200         1s传输115200个bit      

传输1bit需要            1/11520 s

传输1bit需要            计数(1/115200)/(1/50_000_000) = 50_000_000/115200 = 434

2.串口的传输格式 

起始位永远低电平,停止位永远高电平

由基础知识知50M系统时钟—波特率为115200条件下传输1bit需要计数个数为434。那么1Byte(串口传输格式为:1bit起始位+8bit数据位+1bit停止位)是不是循环计数10次434就可以传输完毕。

直接上图:图中描述了1Byte数据传输的示意图,重点都在图里!!!。

3.什么时候去采样串口线上的数据呢?

(如何保证串口传输接收来的数据是正确的?)

观察上图,Buad_Flag信号(通道2)表示了传输1Bit传输的间隔,每遇到1个Buad_Flag=1的信号,数据线上切换1次数据,所以两个Buad_Flag=1之间的数据是稳定的数据,根据抽样定理是不是应该在两个Buad_Flag=1信号的中间去采样数据呢,其实就是在1bit数据持续期间的中间点采样,才能得到最稳定的数据。见下图,重点都在图里!!!

图中序号①-⑩分别为10bit数据的采样点,采样点处提取数据为0101_0101(0x55),低位在前。

收发波特率一致:

收发波特率不一致,导致RX端不能正常接收: 

4.波特率计数器

module baudgen
(
    input clk,
    input rst_n,
    input work_en,

    output reg [3:0] bit_cnt,
    output bit_flag
);
    parameter BAUD_CNT_MAX = 50_000_000/9600;
    parameter CNT_SAMP_MAX = BAUD_CNT_MAX/2;
    reg [12:0] cnt;

    always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
          cnt <= 0;
      else 
          cnt <= work_en ? ((cnt == BAUD_CNT_MAX-1) ? 0 : cnt + 1) : 0;
    end

    assign bit_flag = (cnt == CNT_SAMP_MAX - 1) ? 1 : 0;

    always@(posedge clk or negedge rst_n)begin
      if(!rst_n)
          bit_cnt <= 0;
      else if(bit_flag ==1 && bit_cnt == 4'd9)
          bit_cnt <= 0;
      else if(bit_flag ==1 && work_en == 1)
          bit_cnt <= bit_cnt + 1;
    end
endmodule

5.RX接受模块

  1. rx_reg2数据之前用寄存器打两拍使输入数据进行同步消除亚稳态,rx_reg3比rx_reg2延后一拍。
  2. 检测第一个下降沿((~rx_reg2) && (rx_reg3) && (~work_en))后work_en拉高(波特计数器在此期间才进行计数),当9个数据(含起始位)传输完成后work_en拉低(使得波特计数器停止计数并清零,以保证下次数据到来时从零开始计数)。
  3. 波特率计数器(在work_en)为高电平时开始进行计数),9600bps使用50Mhz(20ns)时钟计数需要计5208≈[(1/9600)/20ns],波特率计数器计数到中间值时bit_flag产生一个时钟的高电平。
  4. bit_flag产生高电平时bit_cnt加1,以计数有几位(一个比特8位)数据到来,数据到来时先来低位,后来高位,要将低位进行右移。8位数据(有用数据,不含起始位)均传输完成后拉高一个时钟的高电平。
  5. 输出完整的8位有效数据。
  6. 输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
module uart_rx
(
	input wire 			clk,
	input wire 			rst_n,
	input wire 			bit_flag,
	input wire [3:0]	bit_cnt,
	input wire 			rx,

	output reg  	 	work_en,
	output reg [7:0] 	data_out,
	output reg 		 	data_finish
);
	reg reg1,reg2,reg3; //sync reg
	reg start_nedge;    //start 
	reg [7:0] rx_data;  //rx data
	reg rx_finish;      //rx finish
	
	//sync 
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		begin
		  reg1 <= 0;
		  reg2 <= 0;
		  reg3 <= 0;
		end
	  else 
		begin
		  reg1 <= rx;
		  reg2 <= reg1;
		  reg3 <= reg2;
		end
	end
	//start negedge in (~work_en) state
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		start_nedge <= 0;
	  else if((~work_en) && (reg3 && (~reg2)))
		start_nedge <= 1;
	  else 
		start_nedge <= 0;  
	end
	// create work_en signal in start_nedge and finish in (bit_cnt==9 && bit_flag==1)
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		work_en <= 0;
	  else if(start_nedge)
		work_en <= 1;
	  else if(bit_cnt == 4'd9 && bit_flag == 1)
		work_en <= 0;
	end
	//receive rx data in (1<=bit_cnt<=8 && bit_flag==1)
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		rx_data <= 0;
	  else if(bit_cnt >=4'd1 && bit_cnt <= 4'd8 && bit_flag == 1)
		rx_data <= {reg3,rx_data[7:1]};
	end
	//receive rx finish in (bit_cnt==9 && bit_flag==1)
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		rx_finish <= 0;
	  else if(bit_cnt == 4'd9 && bit_flag == 1)
		rx_finish <= 1;
	  else 
		rx_finish <= 0;
	end
	//data out from rx_data when rx_finish
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		data_out <= 0;
	  else if(rx_finish)
		data_out <= rx_data;
	end
	//data_finish from rx_finish
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		data_finish <= 0;
	  else
		data_finish <= rx_finish;
	end

endmodule 

6.TX发送模块

module uart_tx
(
	input wire 			clk,
	input wire 			rst_n,
	input wire 			bit_flag,
	input wire [3:0]	bit_cnt,
	input wire [7:0]	data_in,
	input wire 			data_start,

	output reg 			work_en,
	output reg 			tx,
	output reg 			data_finish
);
	//send data work_en
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		work_en <= 0;
	  else if(data_start)
		work_en <= 1;
	  else if(bit_cnt == 4'd9 && bit_flag == 1)
		work_en <=0;
	end
	//data_in to tx by bit_cnt when bit_flag
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		  tx <= 1;
	  else if(bit_flag)
		  case(bit_cnt)
			0:tx  <= 0;
			1:tx <= data_in[0];
			2:tx <= data_in[1];
			3:tx <= data_in[2];
			4:tx <= data_in[3];
			5:tx <= data_in[4];
			6:tx <= data_in[5];
			7:tx <= data_in[6];
			8:tx <= data_in[7];
			9:tx <= 1;
			default:tx <= 1;
		  endcase
	end
	//data finish out 
	always@(posedge clk or negedge rst_n)begin
	  if(!rst_n)
		data_finish <= 0;
	  else if(bit_cnt==4'd9 && bit_flag == 1)
		data_finish <= 1;
	  else 
		data_finish <= 0;
	end
endmodule

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值