FPGA学习笔记_UART串口协议以及串口发送端设计1

FPGA学习笔记

1. UART串口协议以及串口发送端设计1

  • 发送单一字节

    1.1 UART介绍
    1.2 串口协议发送端设计

1.1 UART介绍

(1). 概念:
UART: (Universal Asynchronous Receiver/Transmitter)通用异步收发器,是异步串行通信的总称。全双工,发送端:并转串;接收端:串转并。包括RS232,RS449,RS423,RS485(各种异步串行通信口的接口标准和总线标准,电气特性,传输速率,连接特性,接口的机械特性等)。
(2). 特点:
电路结构简单,成本低。
(3). 关键参数:
数据位(data bits): 单个UART数据传输在开始从停止期间发送的数据位数;可选择5, 6, 7, 8(默认)
波特率(baud): 从一个设备发到另一个设备,每秒可以通信的数据比特个数。典型的波特率有300,1200,2400,9600,19200,115200(1s:115200bits;1bit: 8.68us)等;通信设备两端应设置相同的波特率。
【波特率与时钟周期的换算】:
频率(f)=500MHz, 周期(T)=20ns;
波特率B(bps) >> 1s传送Bbit数据>> 1bit数据传输需要(1/B(bps))s=(1000000000/ B(bps))ns
波特率的分频计数值:(1000000000/ B(bps))ns/时钟周期
系统时钟计数值 = 波特率的分频计数值 - 1;
在这里插入图片描述
奇偶校验位: 验证数据的正确性。偶校验(even):传输的数位中1的个数位偶数;奇校验(odd):传送的数位中1的个数位奇数(含字符的各个数位和校验位)。
停止位数 : 在每个字节的数据位发送完成后,发送停止位,标志一次数据传输完成,同时可用来帮助接受信号方硬件同步。可选择位:1(默认),1.5,2位。
RS323:8N1(8个数据位,1个停止位,无奇偶校验位)

1.2 串口协议发送端设计

(1). 串口协议发送端整体框图
在这里插入图片描述
在这里插入图片描述

(2). 串口协议发送端时序图
在这里插入图片描述
START: 低电平
STOP:高电平
DATA:8bits

(3). Verilog 代码


module uart_tx_r0#(
	parameter START = 1'b0,
	parameter STOP = 1'b1
)
(
		input 		clk, //50MHz
		input 		rst_n,
		input			send_en,
		input [2:0] baud_set,
		input [7:0] data_byte,
		
		output reg	rs232_tx,
		output reg	tx_done,
		output reg	uart_state
);
//----define--------------------------------------
	reg [7:0]	reg_data_byte;
	reg [15:0] 	cnt;//divide frequence counter
	reg			baud_clk;
	reg [15:0]	cnt_max;//baud value
	reg [3:0]   cnt_bit;//
	
	
	
//----baud_set--------------------------------------
	always@(*)begin
		case(baud_set)
//			0:	cnt_max <= 16'd20832;
//			1: cnt_max <= 16'd10415;
			0: cnt_max <= 16'd5207;
			1: cnt_max <= 16'd2603;
			2: cnt_max <= 16'd1301;
			3: cnt_max <= 16'd867;
			4: cnt_max <= 16'd433;
//			7: cnt_max <= 16'd194;
			default: cnt_max <= 5207;
		endcase
	end

//----divide frequence counter-->baud clock------------------------	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			cnt <= 0;
		end 
		else if(uart_state)begin
			if(cnt == cnt_max) 
			cnt <= 0;
		else
			cnt <= cnt +16'd1;
		end else
			cnt <= 0;
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			baud_clk <= 1'b0;
		else if(cnt == 16'd1)
			baud_clk <= 1'b1;
		else
			baud_clk <= 1'b0;
	end
//----cnt_bit----------------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt_bit <= 0;
		else if(cnt_bit == 4'd11)
				cnt_bit <= 0;
		else if(baud_clk)
				cnt_bit <= cnt_bit + 4'd1;
		else
				cnt_bit <= cnt_bit;
	end
//----rs232_tx --------------------------------------	
	always@(posedge clk or negedge rst_n)begin // asynchronos transimiter, reg_data_byte is used to keep input data stable 
		if(!rst_n)
			reg_data_byte <= 8'd0;
		else if(send_en)
			reg_data_byte <= data_byte;
		else
			reg_data_byte <= reg_data_byte;
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			rs232_tx <= 0;
		end begin
			case(cnt_bit) //0:initial cnt_bit=0 --> after sending data, rs232_tx always be 0; 
				0: rs232_tx <= 1'b1;
				1: rs232_tx <= START; //0
				2: rs232_tx <= reg_data_byte[0];
				3: rs232_tx <= reg_data_byte[1];
			   4: rs232_tx <= reg_data_byte[2];
				5: rs232_tx <= reg_data_byte[3];
				6: rs232_tx <= reg_data_byte[4];
				7: rs232_tx <= reg_data_byte[5];
				8: rs232_tx <= reg_data_byte[6];
				9: rs232_tx <= reg_data_byte[7];
				10: rs232_tx <= STOP; //1
				default: rs232_tx <= 1;
		endcase
	 end
	end
//----tx_done-----------------------------------------
		always@(posedge clk or negedge rst_n)begin
			if(!rst_n)
				tx_done <= 1'b0;
			else if(cnt_bit == 4'd11)
				tx_done <= 1'b1;
			else
				tx_done <= 1'b0;
		end
		
//----uart_state--------------------------------------
		always@(posedge clk or negedge rst_n)
			if(!rst_n)
				uart_state <= 1'b0;
			else if(send_en)
				uart_state <= 1'b1;
			else if(cnt_bit == 4'd11)
				uart_state <= 0;
			else
				uart_state <= uart_state;

endmodule

//------------------------------------------------
//----testbench-----------------------------------
`timescale 1ns/1ns
`define clk_period 20

module tb_uart_tx_r0;
	reg clk;
	reg rst_n;
	reg send_en;
	reg [2:0] baud_set;
	reg [7:0] data_byte;
	
	wire	rs232_tx;
	wire	tx_done;
	wire	uart_state; 
	
	uart_tx_r0 uut(
		.clk(clk),
		.rst_n(rst_n),
		.send_en(send_en),
		.baud_set(baud_set),
		.tx_done(tx_done),
		.data_byte(data_byte),
		.uart_state(uart_state),
		.rs232_tx(rs232_tx)
	);
	
	initial begin
		clk = 1;
		rst_n = 0;
		send_en = 0;
		baud_set = 3'd4;
		#(`clk_period*20+1);
		rst_n = 1;
		#(`clk_period*50);
		data_byte = 8'haa;//8'b1010_1010
		send_en = 1;
		#`clk_period;
		send_en = 0;
		
		@(posedge tx_done)
		
		#(`clk_period*5000);
		data_byte = 8'h55;//0101_0101
		send_en = 1;
		#`clk_period;
		send_en = 0;
		
		@(posedge tx_done)
		#(`clk_period*5000);
		$stop;
	end
	always begin #(`clk_period/2) clk = ~clk;end
endmodule

(3). Modelsim仿真

在这里插入图片描述

----学习内容来自小梅哥FPGA视频
【注】:个人学习笔记,如有错误,望不吝赐教,这厢有礼了~~~

猜你喜欢

转载自blog.csdn.net/weixin_50722839/article/details/109554050