【FPGA零基础学习之旅#13】串口发送模块设计与验证

这篇具有很好参考价值的文章主要介绍了【FPGA零基础学习之旅#13】串口发送模块设计与验证。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🎉欢迎来到FPGA专栏~串口发送模块


  • ☆* o(≧▽≦)o *☆~我是小夏与酒🍹
  • 博客主页:小夏与酒的博客
  • 🎈该系列文章专栏:FPGA学习之旅
  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️
    【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

一、效果演示

1.1 演示

🥝发送测试:
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

🥝issp调试测试:
数据调试:
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信
调试数据发送:
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

1.2 串口发送模块完整代码(可直接使用)

【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

🥝模块端口介绍:

信号名称 功能描述
Clk 系统时钟50MHz
Rst_n 系统复位信号
data_byte 待传输的8bit数据
send_en 发送使能信号
baud_set 波特率设置信号
uart_tx 串口信号输出
Tx_Done 发送结束信号,输出一个时钟周期高电平
uart_state 发送状态,处于发送状态时为1

🥝baud_set值与波特率对应关系:

baud_set 波特率
000 9600
001 19200
010 38400
011 57600
100 115200

uart_byte_tx.v:

//
//模块名称:串口发送模块
//
module uart_byte_tx(
	input 		Clk,
	input 		Rst_n,
	input [7:0]	data_byte,
	input 		send_en,
	input [2:0]	baud_set,
	
	output reg uart_tx,
	output reg Tx_Done,
	output reg uart_state
);

	reg bps_clk;//波特率时钟
	
	reg [15:0]div_cnt;//分频计数器
		
	reg [15:0]bps_DR;//分频计数最大值
	
	reg [3:0]bps_cnt;//波特率计数时钟
		
	//定义数据的起始位和停止位
	localparam START_BIT = 1'b0;
	localparam STOP_BIT  = 1'b1;
	
	reg [7:0]r_data_byte;//数据寄存器
	
//--------<uart状态模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			uart_state <= 1'b0;
		else if(send_en)
			uart_state <= 1'b1;
		else if(bps_cnt == 4'd11)//bps_cnt计数达到11次,即发送结束
			uart_state <= 1'b0;
		else
			uart_state <= uart_state;
	end

//--------<使能分频计数模块>-------	
	assign en_cnt = uart_state;
	
//--------<寄存待发送的数据,使数据保持稳定>--------
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			r_data_byte <= 8'd0;
		else if(send_en)
			r_data_byte <= data_byte;
		else
			r_data_byte <= r_data_byte;
	end
	
//--------<波特率查找表>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_DR <= 16'd5207;
		else begin
			case(baud_set)
				0:bps_DR <= 16'd5207;
				1:bps_DR <= 16'd2603;
				2:bps_DR <= 16'd1301;
				3:bps_DR <= 16'd867;
				4:bps_DR <= 16'd433;
				default:bps_DR <= 16'd5207;
			endcase
		end	
	end
	
//--------<Div_Cnt模块>--------	
//得到不同计数周期的计数器
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			div_cnt <= 16'd0;
		else if(en_cnt)begin
			if(div_cnt == bps_DR)
				div_cnt <= 16'd0;
			else
				div_cnt <= div_cnt + 1'b1;
		end
		else
			div_cnt <= 16'd0;
	end
//--------<bps_clk信号的产生>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_clk <= 1'b0;
		else if(div_cnt == 16'd1)
			bps_clk <= 1'b1;
		else
			bps_clk <= 1'b0;
	end
	
//--------<bps_cnt计数模块>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_cnt <= 4'd0;
		else if(bps_cnt == 4'd11)//clr信号
			bps_cnt <= 4'd0;
		else if(bps_clk)
			bps_cnt <= bps_cnt + 1'b1;
		else
			bps_cnt <= bps_cnt;
	end

//--------<Tx_Done模块>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			Tx_Done <= 1'b0;
		else if(bps_cnt == 4'd11)
			Tx_Done <= 1'b1;
		else
			Tx_Done <= 1'b0;
	end
	
//--------<数据位输出模块-10选1多路器>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			uart_tx <= 1'b1;
		else begin
			case(bps_cnt)
				0:uart_tx <= 1'b1;
				1:uart_tx <= START_BIT;
				2:uart_tx <= r_data_byte[0];
				3:uart_tx <= r_data_byte[1];
				4:uart_tx <= r_data_byte[2];
				5:uart_tx <= r_data_byte[3];
				6:uart_tx <= r_data_byte[4];
				7:uart_tx <= r_data_byte[5];
				8:uart_tx <= r_data_byte[6];
				9:uart_tx <= r_data_byte[7];
				10:uart_tx <= STOP_BIT;
				default:uart_tx <= 1'b1;
			endcase
		end
	end
	
endmodule

二、串口发送时序

串口发送一个字节数据的时序图参考如下:
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

根据上图,一个字节想要成功发送完成,需要计数11次波特率时钟的高电平;而且一个完整的字节发送需要10位数据位,包括1个起始位8个数据位1个停止位

需要注意,在串口未发送数据时(波特率时钟未使能时),串口输出高电平;在第一个波特率时钟高电平到来时,开始发送起始位。

🥝波特率计算:

baud_set 波特率bps 周期 分频计数值 50M系统时钟计数值
0 9600 104167ns 104167/System_clk_period 5208-1
1 19200 52083ns 52083/System_clk_period 2604-1
2 38400 26041ns 26041/System_clk_period 1302-1
3 57600 17361ns 17361/System_clk_period 868-1
4 115200 8680ns 8680/System_clk_period 434-1

三、模块设计与代码详解

根据小梅哥FPGA设计的电路图进行代码编写:
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信
代码理解主要参考前文中代码的模块注释串口发送时序图

在此展示简单的测试激励文件:

uart_byte_tx_tb.v:

`timescale 1ns/1ns
`define clock_period 20

module uart_byte_tx_tb;

	reg Clk;
	reg Rst_n;
	reg [7:0]data_byte;
	reg send_en;
	reg [2:0]baud_set;
	
	wire uart_tx;
	wire Tx_Done;
	wire uart_state;
	
	uart_byte_tx Uuart_byte_tx(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.data_byte(data_byte),
		.send_en(send_en),
		.baud_set(baud_set),	
		.uart_tx(uart_tx),
		.Tx_Done(Tx_Done),
		.uart_state(uart_state)
	);
	
	initial Clk = 1;
	always#(`clock_period / 2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		data_byte = 8'd0;
		send_en = 1'b0;
		baud_set = 3'd4;
		#(`clock_period * 20 + 1);
		Rst_n = 1'b1;
		#(`clock_period * 50);
		data_byte = 8'haa;
		send_en = 1'b1;
		#(`clock_period * 1);
		send_en = 1'b0;
		
		@(posedge Tx_Done)
		
		#(`clock_period * 5000);
		data_byte = 8'hff;
		send_en = 1'b1;
		#(`clock_period * 1);
		send_en = 1'b0;
		
		@(posedge Tx_Done)
		#(`clock_period * 5000);
		
		$stop;
	end

endmodule

仿真结果:

【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

Tx_Done信号的正确输出:

【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

四、按键控制串口发送数据

先看整体的RTL视图来理解设计思路:
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信
按键信号经过KeyFilter按键消抖模块之后的有效信号用来控制串口发送模块的发送使能;HEX8模块74HC595模块用来驱动三线制数码管显示数据;issp模块用来从电脑端调试数据;uart_byte_tx模块用来将调试数据通过串口发送给电脑。

🔸按键消抖模块的详细讲解:【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)。

🔸HEX8模块的详细讲解:【FPGA零基础学习之旅#11】数码管动态扫描。

🔸74HC595模块的详细讲解:【FPGA零基础学习之旅#12】三线制数码管驱动(74HC595)串行移位寄存器驱动。

🔸issp ip核的创建和使用包含在文章【FPGA零基础学习之旅#11】数码管动态扫描中。

在此给出顶层模块,其余模块见文末:

uart_byte_tx_top.v:

module uart_byte_tx_top(
	input 			Clk,		//50M
	input 			Rst_n,
	input 			key_in,
	output 			SH_CP,		//shift clock
	output 			ST_CP,		//latch data clock
	output 			DS,			//shift serial data
	output 			uart_tx,
	output			led
);

	wire [7:0] sel;//数码管位选(选择当前要显示的数码管)
	wire [7:0] seg;//数码管段选(当前要显示的内容)	

	wire  [7:0] data_byte;
	
	wire key_flag;
	wire key_state;
	
	issp issp(
		.probe(),
		.source(data_byte)
	);
	
	KeyFilter KeyFilter(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	//通过按键状态使能串口发送模块,按键按下时,串口发送模块使能
	assign send_en = key_flag & (!key_state);
	
	uart_byte_tx uart_byte_tx(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.data_byte(data_byte),
		.send_en(send_en),
		.baud_set(3'd0),
		.uart_tx(uart_tx),
		.Tx_Done(),
		.uart_state(led)
	);

	//由于串口目前只发送一个字节数据,只占用2个数码管,所以其余数码管显示0
	HEX8 HEX8(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.En(1'b1),
		.disp_data({24'h0,data_byte}),
		.sel(sel),
		.seg(seg)
	);

	m74HC595_Driver m74HC595_Driver(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.Data({seg,sel}),
		.S_EN(1'b1),
		.SH_CP(SH_CP),
		.ST_CP(ST_CP),
		.DS(DS)
	);

endmodule

程序配置完成之后的数码管显示和led的点亮:
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

使用issp更改数据,数码管显示数据并通过按键发送:
🥝修改为11:
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

🥝修改为AF:
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信
【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

本案例的其余模块在此部分列出:

KeyFilter.v:

//
//模块:按键消抖模块
//key_state:输出消抖之后按键的状态
//key_flag:按键消抖结束时产生一个时钟周期的高电平脉冲
//
module KeyFilter(
	input 		Clk,
	input	 	Rst_n,
	input 		key_in,
	output reg 	key_flag,
	output reg 	key_state
);

	//按键的四个状态
	localparam
		IDLE 		= 4'b0001,
		FILTER1 	= 4'b0010,
		DOWN 		= 4'b0100,
		FILTER2 	= 4'b1000;

	//状态寄存器
	reg [3:0] curr_st;
	
	//边沿检测输出上升沿或下降沿
	wire pedge;
	wire nedge;
	
	//计数寄存器
	reg [19:0]cnt;
	
	//使能计数寄存器
	reg en_cnt;
	
	//计数满标志信号
	reg cnt_full;//计数满寄存器
	
//------<边沿检测电路的实现>------
	//边沿检测电路寄存器
	reg key_tmp0;
	reg key_tmp1;
	
	//边沿检测
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			key_tmp0 <= 1'b0;
			key_tmp1 <= 1'b0;
		end
		else begin
			key_tmp0 <= key_in;
			key_tmp1 <= key_tmp0;
		end	
	end
		
	assign nedge = (!key_tmp0) & (key_tmp1);
	assign pedge = (key_tmp0)  & (!key_tmp1);

//------<状态机主程序>------	
	//状态机主程序
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			curr_st <= IDLE;
			en_cnt <= 1'b0;
			key_flag <= 1'b0;
			key_state <= 1'b1;
		end
		else begin
			case(curr_st)
				IDLE:begin
					key_flag <= 1'b0;
					if(nedge)begin
						curr_st <= FILTER1;
						en_cnt <= 1'b1;
					end
					else
						curr_st <= IDLE;
				end
				
				FILTER1:begin
					if(cnt_full)begin
						key_flag <= 1'b1;
						key_state <= 1'b0;
						curr_st <= DOWN;
						en_cnt <= 1'b0;
					end	
					else if(pedge)begin
						curr_st <= IDLE;
						en_cnt <= 1'b0;
					end
					else
						curr_st <= FILTER1;
				end
				
				DOWN:begin
					key_flag <= 1'b0;
					if(pedge)begin
						curr_st <= FILTER2;
						en_cnt <= 1'b1;
					end
					else
						curr_st <= DOWN;
				end
				
				FILTER2:begin
					if(cnt_full)begin
						key_flag <= 1'b1;
						key_state <= 1'b1;
						curr_st <= IDLE;
						en_cnt <= 1'b0;
					end	
					else if(nedge)begin
						curr_st <= DOWN;
						en_cnt <= 1'b0;
					end
					else
						curr_st <= FILTER2;
				end
				
				default:begin
					curr_st <= IDLE;
					en_cnt <= 1'b0;
					key_flag <= 1'b0;
					key_state <= 1'b1;
				end
			endcase
		end
	end
	
//------<20ms计数器>------		
	//20ms计数器
	//Clk 50_000_000Hz
	//一个时钟周期为20ns
	//需要计数20_000_000 / 20 = 1_000_000次
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 20'd0;
		else if(en_cnt)
			cnt <= cnt + 1'b1;
		else
			cnt <= 20'd0;
	end
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt_full <= 1'b0;
		else if(cnt == 999_999)
			cnt_full <= 1'b1;
		else
			cnt_full <= 1'b0;
	end
	
endmodule

HEX8.v:

module HEX8(
		input 					Clk,			//50M
		input 					Rst_n,			//复位
		input 					En,				//数码管显示使能
		input 		[31:0]		disp_data,		//8 × 4 = 32(8个数码管,数据格式为hex,总共输32位)
		output reg 	[7:0]		seg, 			//数码管段选
		output 		[7:0]		sel	 			//数码管位选(数码管选择)
);
	reg [7:0]sel_r;

//----------<分频器>----------
	reg [14:0]divider_cnt;//25000-1
	
	reg clk_1K;
	
	reg [3:0]data_tmp;//待显示数据缓存
	
	//1KHz分频计数器
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			divider_cnt <= 15'd0;
		else if(!En)
			divider_cnt <= 15'd0;
		else if(divider_cnt == 24999)
			divider_cnt <= 15'd0;
		else
			divider_cnt <= divider_cnt + 1'b1;
	end
	
	//1KHz扫描时钟
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			clk_1K <= 1'b0;
		else if(divider_cnt == 24999)
			clk_1K <= ~clk_1K;
		else
			clk_1K <= clk_1K;
	end
	
//----------<6位循环移位寄存器>-----------	
	always@(posedge clk_1K or negedge Rst_n)begin
		if(!Rst_n)
			sel_r <= 8'b0000_0001;
		else if(sel_r == 8'b1000_0000)
			sel_r <= 8'b0000_0001;
		else
			sel_r <= sel_r << 1;
	end	

//----------<6选1多路器>----------		
	always@(*)begin
		case(sel_r)
			8'b0000_0001:data_tmp = disp_data[3:0];
			8'b0000_0010:data_tmp = disp_data[7:4];
			8'b0000_0100:data_tmp = disp_data[11:8];
			8'b0000_1000:data_tmp = disp_data[15:12];
			8'b0001_0000:data_tmp = disp_data[19:16];
			8'b0010_0000:data_tmp = disp_data[23:20];
			8'b0100_0000:data_tmp = disp_data[27:24];
			8'b1000_0000:data_tmp = disp_data[31:28];
			default:data_tmp = 4'b0000;
		endcase
	end

//----------<LUT>----------		
	always@(*)begin
		case(data_tmp)
			4'h0:seg = 8'hc0;
			4'h1:seg = 8'hf9;
			4'h2:seg = 8'ha4;
			4'h3:seg = 8'hb0;
			4'h4:seg = 8'h99;
			4'h5:seg = 8'h92;
			4'h6:seg = 8'h82;
			4'h7:seg = 8'hf8;
			4'h8:seg = 8'h80;
			4'h9:seg = 8'h90;
			4'ha:seg = 8'h88;
			4'hb:seg = 8'h83;
			4'hc:seg = 8'hc6;
			4'hd:seg = 8'ha1;
			4'he:seg = 8'h86;
			4'hf:seg = 8'h8e;
		endcase
	end
		
//----------<2选1多路器>----------		
	assign sel = (En)?(sel_r):8'b1111_1111;
		
endmodule

m74HC595_Driver.v:

module m74HC595_Driver(
		Clk,
		Rst_n,
		Data,
		S_EN,
		SH_CP,
		ST_CP,
		DS
	);

	parameter DATA_WIDTH = 16;

	input 		Clk;
	input 		Rst_n;
	input 		[DATA_WIDTH-1 : 0] Data;	//data to send
	input 		S_EN;						//send en
	output reg 	SH_CP;						//shift clock
	output reg 	ST_CP;						//latch data clock
	output reg 	DS;							//shift serial data
	
	parameter CNT_MAX = 4;
		
	reg [15:0] divider_cnt;//分频计数器
	wire sck_pluse;
	
	reg [4:0]SHCP_EDGE_CNT;//SH_CP EDGE counter
	
	reg [15:0]r_data;
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			r_data <= 16'd0;
		else if(S_EN)
			r_data <= Data;
		else
			r_data <= r_data;
	end
		
	//clock divide
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			divider_cnt <= 16'd0;
		else if(divider_cnt == CNT_MAX)
			divider_cnt <= 16'd0;
		else
			divider_cnt <= divider_cnt + 1'b1;
	end
	
	assign sck_pluse = (divider_cnt == CNT_MAX);
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			SHCP_EDGE_CNT <= 5'd0;
		else if(sck_pluse)begin
			if(SHCP_EDGE_CNT ==  5'd31)
				SHCP_EDGE_CNT <= 5'd0;
			else
				SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'b1;
		end
		else
			SHCP_EDGE_CNT <= SHCP_EDGE_CNT;
	end	
		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			SH_CP <= 1'b0;
			ST_CP <= 1'b0;
			DS <= 1'b0;	
		end
		else begin
			case(SHCP_EDGE_CNT)
				5'd0: begin SH_CP <= 1'b0; ST_CP <= 1'b1; DS <= r_data[15]; end
				5'd1: begin SH_CP <= 1'b1; ST_CP <= 1'b0;end
				5'd2: begin SH_CP <= 1'b0; DS <= r_data[14];end
				5'd3: begin SH_CP <= 1'b1; end
				5'd4: begin SH_CP <= 1'b0; DS <= r_data[13];end
				5'd5: begin SH_CP <= 1'b1; end
				5'd6: begin SH_CP <= 1'b0; DS <= r_data[12];end
				5'd7: begin SH_CP <= 1'b1; end
				5'd8: begin SH_CP <= 1'b0; DS <= r_data[11];end
				5'd9: begin SH_CP <= 1'b1; end
				5'd10:begin SH_CP <= 1'b0; DS <= r_data[10];end
				5'd11:begin SH_CP <= 1'b1; end
				5'd12:begin SH_CP <= 1'b0; DS <= r_data[9];end
				5'd13:begin SH_CP <= 1'b1; end
				5'd14:begin SH_CP <= 1'b0; DS <= r_data[8];end
				5'd15:begin SH_CP <= 1'b1; end
				5'd16:begin SH_CP <= 1'b0; DS <= r_data[7];end
				5'd17:begin SH_CP <= 1'b1; end
				5'd18:begin SH_CP <= 1'b0; DS <= r_data[6];end
				5'd19:begin SH_CP <= 1'b1; end
				5'd20:begin SH_CP <= 1'b0; DS <= r_data[5];end
				5'd21:begin SH_CP <= 1'b1; end
				5'd22:begin SH_CP <= 1'b0; DS <= r_data[4];end
				5'd23:begin SH_CP <= 1'b1; end
				5'd24:begin SH_CP <= 1'b0; DS <= r_data[3];end
				5'd25:begin SH_CP <= 1'b1; end
				5'd26:begin SH_CP <= 1'b0; DS <= r_data[2];end
				5'd27:begin SH_CP <= 1'b1; end
				5'd28:begin SH_CP <= 1'b0; DS <= r_data[1];end
				5'd29:begin SH_CP <= 1'b1; end
				5'd30:begin SH_CP <= 1'b0; DS <= r_data[0];end
				5'd31:begin SH_CP <= 1'b1; end
				default:begin SH_CP <= 1'b0;ST_CP <= 1'b0;DS <= 1'b0;	end
			endcase	
		end
	end

endmodule

【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

🧸结尾文章来源地址https://www.toymoban.com/news/detail-707040.html


  • ❤️ 感谢您的支持和鼓励! 😊🙏
  • 📜您可能感兴趣的内容:
  • 【FPGA零基础学习之旅#11】数码管动态扫描
  • 【Python】串口通信-与FPGA、蓝牙模块实现串口通信(Python+FPGA)
  • 【Arduino TinyGo】【最新】使用Go语言编写Arduino-环境搭建和点亮LED灯
  • 【全网首发开源教程】【Labview机器人仿真与控制】Labview与Solidworks多路支配关系-四足爬行机器人仿真与控制
    【FPGA零基础学习之旅#13】串口发送模块设计与验证,FPGA学习之旅,fpga开发,学习,串口发送,Verilog HDL,串口通信

到了这里,关于【FPGA零基础学习之旅#13】串口发送模块设计与验证的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FPGA初步学习之串口发送模块【单字节和字符串的发送】

    UART 在发送或接收过程中的一帧数据由4部分组成,起始位、数据位、奇偶校验位和停止位,如图所示。其中,起始位标志着一帧数据的开始,停止位标志着一帧数据的结束,数据位是一帧数据中的有效数据。 通常用的串口数据帧格式是:8位数据位,无校验位,1位停止位。

    2024年02月14日
    浏览(45)
  • FPGA学习笔记(三)——串口通信之发送数据(调试过程)

    本学习笔记主要参考小梅哥B站教学视频,网址如下: https://www.bilibili.com/video/BV1va411c7Dz?p=1 使用的编译器为Vivado,HDL语言为verilog 一、串口通信之发送数据 原理 设计代码 测试代码 仿真结果 发现Send_en拉高之前,uart_tx就置为0了,不符合常理。 转到第二个发送信号处,发现Send

    2023年04月09日
    浏览(43)
  • FPGA_学习_13_方差计算小模块

    测距器件APD的性能与器件本身的温度、施加在APD的偏置电压息息相关。 在不同的温度下,APD的偏压对测距性能的影响非常大。 要确定一个合适的APD的偏压Vopt,首先你要知道当前温度下,APD的击穿电压Vbr,一般来讲,Vopt = Vbr – ΔV,ΔV基本是个固定的值。如果要使用算法找到

    2024年02月12日
    浏览(30)
  • 【FPGA零基础学习之旅#9】状态机基础知识

    🎉欢迎来到FPGA专栏~状态机基础知识 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🔸 Hello状态机例程 : RTL视图: 状态

    2024年02月16日
    浏览(46)
  • 【FPGA零基础学习之旅#11】数码管动态扫描

    🎉欢迎来到FPGA专栏~数码管动态扫描 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🥝 Spirit_V2开发板按键控制数码管:

    2024年02月11日
    浏览(40)
  • FPGA基础设计(八):串口访问ROM

    将ROM中的数据读取出来,通过串口发送到上位机。 1、按键消抖模块 2、ROM控制器模块 3、创建ROM IP核模块 4、串口发送模块 前面已经设计好了串口发送模块和按键消抖模块,还剩ROM IP的创建和控制ROM模块的设计。 读ROM控制模块设计 : 1、 address :读地址端口 2、 q :读数据端

    2024年02月03日
    浏览(64)
  • 【FPGA零基础学习之旅#6】ip核基础知识之计数器

    🎉欢迎来到FPGA专栏~ip核基础知识之计数器 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ LPM_COUNTER IP核 的RTL视图: IP核

    2024年02月09日
    浏览(46)
  • 【FPGA零基础学习之旅#8】阻塞赋值与非阻塞赋值讲解

    🎉欢迎来到FPGA专栏~阻塞赋值与非阻塞赋值 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 阻塞赋值 ,操作符为 “ = ”

    2024年02月10日
    浏览(44)
  • 【FPGA零基础学习之旅#5】产生非等占空比信号

    🎉欢迎来到FPGA专栏~产生非等占空比信号 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 我们通过LED的亮灭来展现等占空

    2024年02月05日
    浏览(53)
  • FPGA基础设计(八):串口收发之RAM存储

    实现上位机通过串口发送数据到FPGA,FPGA接收到数据后将其存储在RAM的一段连续空间中,然后通过按键触发读出RAM数据,再通过串口发送到上位机。 1、串口接收模块; 2、按键消抖模块 3、创建RAM IP核模块 4、RAM IP核控制模块; 5、串口发送模块。 前面已经设计好了串口发送模

    2024年02月03日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包