目录

串行化数据

Verilog描述并仿真


上篇博文讲到了如何产生波特率?(RS232 波特率时钟产生方法?

下面的内容是构建一个异步发送器:

我们正在构建一个具有固定参数的“异步发送器”:8个数据位,2个停止位,无奇偶校验。

RS-232 Transmitter_状态机

它的工作方式如下:

发送器在FPGA内部获取一个8位数据并将其串行化(从“TxD_start”信号置位时开始)。
在发生传输时断言“忙”信号(在此期间忽略“TxD_start”信号)。

串行化数据


要查看起始位,8个数据位和停止位,状态机似乎是合适的。

reg [3:0] state;

// the state machine starts when "TxD_start" is asserted, but advances when "BaudTick" is asserted (115200 times a second)
always @(posedge clk)
case(state)
  4'b0000: if(TxD_start) state <= 4'b0100;
  4'b0100: if(BaudTick) state <= 4'b1000; // start
  4'b1000: if(BaudTick) state <= 4'b1001; // bit 0
  4'b1001: if(BaudTick) state <= 4'b1010; // bit 1
  4'b1010: if(BaudTick) state <= 4'b1011; // bit 2
  4'b1011: if(BaudTick) state <= 4'b1100; // bit 3
  4'b1100: if(BaudTick) state <= 4'b1101; // bit 4
  4'b1101: if(BaudTick) state <= 4'b1110; // bit 5
  4'b1110: if(BaudTick) state <= 4'b1111; // bit 6
  4'b1111: if(BaudTick) state <= 4'b0001; // bit 7
  4'b0001: if(BaudTick) state <= 4'b0010; // stop1
  4'b0010: if(BaudTick) state <= 4'b0000; // stop2
  default: if(BaudTick) state <= 4'b0000;
endcase

现在,我们只需要生成“TxD”输出。

reg muxbit;

always @(state[2:0])
case(state[2:0])
  0: muxbit <= TxD_data[0];
  1: muxbit <= TxD_data[1];
  2: muxbit <= TxD_data[2];
  3: muxbit <= TxD_data[3];
  4: muxbit <= TxD_data[4];
  5: muxbit <= TxD_data[5];
  6: muxbit <= TxD_data[6];
  7: muxbit <= TxD_data[7];
endcase

// combine start, data, and stop bits together
assign TxD = (state<4) | (state[3] & muxbit);


Verilog描述并仿真

Verilog描述:

由于参考链接(https://www.fpga4fun.com/SerialInterface3.html)上的完整代码过于复杂,我自己改成简单的形式,并仿真:

module ays_transmitter(
	input clk,
	input TxD_start,
	input [7:0] TxD_data,
	output TxD,
	output TxD_busy

    );
	
	reg [3:0] TxD_state = 0;
	wire TxD_ready = (TxD_state==0);
	assign TxD_busy = ~TxD_ready;
	
	
	//Generate Baud Clock
	wire BitTick;
	
	BaudGen u_BaudGen(
	.clk(clk),
	.enable(TxD_busy), //generate baud clk only when transmiter data
	.BaudTick(BitTick)
	);

	reg [7:0] TxD_shift = 0;
	always @(posedge clk) begin
		if(TxD_ready & TxD_start)
			TxD_shift <= TxD_data;
		else
			if(TxD_state[3] & BitTick)
				TxD_shift <= (TxD_shift >> 1);

		case(TxD_state)
			4'b0000: if(TxD_start) TxD_state <= 4'b0100;
			4'b0100: if(BitTick) TxD_state <= 4'b1000;  // start bit
			4'b1000: if(BitTick) TxD_state <= 4'b1001;  // bit 0
			4'b1001: if(BitTick) TxD_state <= 4'b1010;  // bit 1
			4'b1010: if(BitTick) TxD_state <= 4'b1011;  // bit 2
			4'b1011: if(BitTick) TxD_state <= 4'b1100;  // bit 3
			4'b1100: if(BitTick) TxD_state <= 4'b1101;  // bit 4
			4'b1101: if(BitTick) TxD_state <= 4'b1110;  // bit 5
			4'b1110: if(BitTick) TxD_state <= 4'b1111;  // bit 6
			4'b1111: if(BitTick) TxD_state <= 4'b0010;  // bit 7
			4'b0010: if(BitTick) TxD_state <= 4'b0011;  // stop1
			4'b0011: if(BitTick) TxD_state <= 4'b0000;  // stop2
			default: if(BitTick) TxD_state <= 4'b0000;
		endcase
	end
	
	
	assign TxD = (TxD_state<4) | (TxD_state[3] & TxD_shift[0]);  // put together the start, data and stop bits
	
	
	
endmodule

BaudGen模块:

module BaudGen( input clk, input enable, output BaudTick ); parameter ClkFrequency = 25000000; // 25MHz parameter Baud = 115200; parameter Ratio = ClkFrequency/Baud; parameter BaudGeneratorAccWidth = 16; parameter BaudGeneratorInc = (1<<BaudGeneratorAccWidth)/Ratio; reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc = 0; always @(posedge clk) if(enable) BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc; else BaudGeneratorAcc <= BaudGeneratorInc; assign BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth]; endmodule

测试模块:

`timescale 1ns / 1ps
//
// Create Date: 2019/05/26 16:06:48
// Design Name: 
// Module Name: ays_transmitter_tb
//


module ays_transmitter_tb(

    );
	
	reg clk;
	reg TxD_start;
	reg [7:0] TxD_data;
	wire TxD;
	wire TxD_busy;
	
	initial begin
		clk = 0;
		forever
			#20 clk = ~clk;
	
	end
	
	initial begin
		TxD_start = 0;
		TxD_data = 8'b10010101;
		#50
		TxD_start = 1;

	end
	
	
	ays_transmitter u_ays_transmitter(
	.clk(clk),
	.TxD_start(TxD_start),
	.TxD_data(TxD_data),
	.TxD(TxD),
	.TxD_busy(TxD_busy)
	
	);

	
endmodule

仿真波形图:

RS-232 Transmitter_串行化_02

RS-232 Transmitter_html_03

从上图可以看出,每一个波特时钟发送一bit数据:从低到高位发送10101001,之后发送两个结束位1.

下面这幅图是显示下一次发送前的空闲期,TxD_busy为低。之后又进入了下一帧数据的发送。

 

RS-232 Transmitter_串行化_04

 

参考链接:

https://www.fpga4fun.com/SerialInterface3.html