国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng)

這篇具有很好參考價(jià)值的文章主要介紹了【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

??歡迎來(lái)到FPGA專(zhuān)欄~搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng)


  • ☆* o(≧▽≦)o *☆~我是小夏與酒??
  • ?博客主頁(yè):小夏與酒的博客
  • ??該系列文章專(zhuān)欄:FPGA學(xué)習(xí)之旅
  • 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正??
  • ?? 歡迎大家關(guān)注! ??
    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

一、效果演示

??輸入數(shù)據(jù):
【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

??輸出數(shù)據(jù):
【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

??串口助手分析:
【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM
按下第一次按鍵,F(xiàn)PGA開(kāi)始連續(xù)發(fā)送數(shù)據(jù),按下第二次按鍵,F(xiàn)PGA停止發(fā)送數(shù)據(jù)。

二、基礎(chǔ)知識(shí)

2.1 實(shí)現(xiàn)目標(biāo)

使用按鍵消抖、串口發(fā)送與接收模塊,以及雙端口RAM模塊實(shí)現(xiàn)串口發(fā)送數(shù)據(jù)到FPGA中,F(xiàn)PGA接收到數(shù)據(jù)后將數(shù)據(jù)存儲(chǔ)在雙口RAM中,當(dāng)按下按鍵時(shí)FPGA將RAM中存儲(chǔ)的數(shù)據(jù)再通過(guò)串口發(fā)送出去,再次按下按鍵后,F(xiàn)PGA停止發(fā)送數(shù)據(jù)。

2.2 所需基礎(chǔ)模塊

相關(guān)模塊學(xué)習(xí)文章:
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#10】按鍵消抖模塊設(shè)計(jì)與驗(yàn)證(一段式狀態(tài)機(jī)實(shí)現(xiàn));
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#13】串口發(fā)送模塊設(shè)計(jì)與驗(yàn)證;
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#14】串口發(fā)送字符串;
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#15】串口接收模塊設(shè)計(jì)與驗(yàn)證(工業(yè)環(huán)境);
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#16】嵌入式塊RAM-雙口ram的使用。

三、系統(tǒng)分析

參考小梅哥FPGA設(shè)計(jì)的系統(tǒng)框圖:
【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM
通過(guò)串口發(fā)送數(shù)據(jù)到FPGA中,F(xiàn)PGA接收到數(shù)據(jù)后將數(shù)據(jù)存儲(chǔ)在雙口RAM一段連續(xù)空間中。當(dāng)需要時(shí),按下按鍵S0,則FPGA將RAM中存儲(chǔ)的數(shù)據(jù)通過(guò)串口發(fā)送出去;再次按下S0,則停止數(shù)據(jù)發(fā)送。

進(jìn)行功能劃分:串口接收模塊按鍵消抖模塊、RAM模塊、串口發(fā)送模塊以及控制模塊。

在此給出所需使用的模塊代碼:

按鍵消抖模塊

//
//模塊:按鍵消抖模塊
//key_state:輸出消抖之后按鍵的狀態(tài)
//key_flag:按鍵消抖結(jié)束時(shí)產(chǎn)生一個(gè)時(shí)鐘周期的高電平脈沖
//
module KeyFilter(
	input 		Clk,
	input 		Rst_n,
	input 		key_in,
	output reg 	key_flag,
	output reg 	key_state
);

	//按鍵的四個(gè)狀態(tài)
	localparam
		IDLE 		= 4'b0001,
		FILTER1 	= 4'b0010,
		DOWN 		= 4'b0100,
		FILTER2 	= 4'b1000;

	//狀態(tài)寄存器
	reg [3:0] curr_st;
	
	//邊沿檢測(cè)輸出上升沿或下降沿
	wire pedge;
	wire nedge;
	
	//計(jì)數(shù)寄存器
	reg [19:0]cnt;
	
	//使能計(jì)數(shù)寄存器
	reg en_cnt;
	
	//計(jì)數(shù)滿標(biāo)志信號(hào)
	reg cnt_full;//計(jì)數(shù)滿寄存器
	
//------<邊沿檢測(cè)電路的實(shí)現(xiàn)>------
	//邊沿檢測(cè)電路寄存器
	reg key_tmp0;
	reg key_tmp1;
	
	//邊沿檢測(cè)
	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);

//------<狀態(tài)機(jī)主程序>------	
	//狀態(tài)機(jī)主程序
	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計(jì)數(shù)器>------		
	//20ms計(jì)數(shù)器
	//Clk 50_000_000Hz
	//一個(gè)時(shí)鐘周期為20ns
	//需要計(jì)數(shù)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

串口接收模塊

//
//模塊名稱(chēng):串口接收模塊(工業(yè)環(huán)境)
//
module uart_byte_rx(
	input 					Clk,//50M
	input 					Rst_n,
	input 			[2:0]	baud_set,
	input 					data_rx,
	output 	reg 	[7:0]	data_byte,
	output 	reg			Rx_Done
);

	reg s0_Rx,s1_Rx;//同步寄存器
	
	reg tmp0_Rx,tmp1_Rx;//數(shù)據(jù)寄存器
	
	reg [15:0]bps_DR;//分頻計(jì)數(shù)器計(jì)數(shù)最大值
	reg [15:0]div_cnt;//分頻計(jì)數(shù)器
	reg bps_clk;//波特率時(shí)鐘
	reg [7:0]bps_cnt;
	
	reg uart_state;
	
	reg [2:0] r_data_byte [7:0];
	
	reg [2:0]START_BIT;
	reg [2:0]STOP_BIT;
	
	wire nedge;
	
//--------<同步寄存器處理>--------		
//用于消除亞穩(wěn)態(tài)
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			s0_Rx <= 1'b0;
			s1_Rx <= 1'b0;
		end
		else begin
			s0_Rx <= data_rx;
			s1_Rx <= s0_Rx;
		end
	end
	
//--------<數(shù)據(jù)寄存器處理>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			tmp0_Rx <= 1'b0;
			tmp1_Rx <= 1'b0;
		end
		else begin
			tmp0_Rx <= s1_Rx;
			tmp1_Rx <= tmp0_Rx;
		end
	end
	
//--------<下降沿檢測(cè)>--------	
	assign nedge = !tmp0_Rx & tmp1_Rx;
	
//--------<div_cnt模塊>--------	
//得到不同計(jì)數(shù)周期的計(jì)數(shù)器
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			div_cnt <= 16'd0;
		else if(uart_state)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信號(hào)的產(chǎn)生>--------	
	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_clk計(jì)數(shù)模塊>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_cnt <= 8'd0;
		else if(bps_cnt == 8'd159 || (bps_cnt == 8'd12 && (START_BIT > 2)))
			bps_cnt <= 8'd0;
		else if(bps_clk)
			bps_cnt <= bps_cnt + 1'b1;
		else
			bps_cnt <= bps_cnt;
	end
	
//--------<Rx_Done模塊>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			Rx_Done <= 1'b0;
		else if(bps_cnt == 8'd159)
			Rx_Done <= 1'b1;
		else
			Rx_Done <= 1'b0;
	end	
	
//--------<波特率查找表>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_DR <= 16'd324;
		else begin
			case(baud_set)
				0:bps_DR <= 16'd324;
				1:bps_DR <= 16'd162;
				2:bps_DR <= 16'd80;
				3:bps_DR <= 16'd53;
				4:bps_DR <= 16'd26;
				default:bps_DR <= 16'd324;
			endcase
		end	
	end

//--------<采樣數(shù)據(jù)接收模塊>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			START_BIT <= 3'd0;
			r_data_byte[0] <= 3'd0; 
			r_data_byte[1] <= 3'd0;
			r_data_byte[2] <= 3'd0; 
			r_data_byte[3] <= 3'd0;
			r_data_byte[4] <= 3'd0; 
			r_data_byte[5] <= 3'd0;
			r_data_byte[6] <= 3'd0; 
			r_data_byte[7] <= 3'd0;
			STOP_BIT <= 3'd0;
		end
		else if(bps_clk)begin
			case(bps_cnt)
				0:begin
					START_BIT <= 3'd0;
					r_data_byte[0] <= 3'd0;
					r_data_byte[1] <= 3'd0;
					r_data_byte[2] <= 3'd0;
					r_data_byte[3] <= 3'd0;
					r_data_byte[4] <= 3'd0;
					r_data_byte[5] <= 3'd0;
					r_data_byte[6] <= 3'd0;
					r_data_byte[7] <= 3'd0;
					STOP_BIT <= 3'd0; 
				end
				6,7,8,9,10,11:START_BIT <= START_BIT + s1_Rx;
				22,23,24,25,26,27:r_data_byte[0] <= r_data_byte[0] + s1_Rx;
				38,39,40,41,42,43:r_data_byte[1] <= r_data_byte[1] + s1_Rx;
				54,55,56,57,58,59:r_data_byte[2] <= r_data_byte[2] + s1_Rx;
				70,71,72,73,74,75:r_data_byte[3] <= r_data_byte[3] + s1_Rx;
				86,87,88,89,90,91:r_data_byte[4] <= r_data_byte[4] + s1_Rx;
				102,103,104,105,106,107:r_data_byte[5] <= r_data_byte[5] + s1_Rx;
				118,119,120,121,122,123:r_data_byte[6] <= r_data_byte[6] + s1_Rx;
				134,135,136,137,138,139:r_data_byte[7] <= r_data_byte[7] + s1_Rx;
				150,151,152,153,154,155:STOP_BIT <= STOP_BIT + s1_Rx;
				default:begin
					START_BIT <= START_BIT;
					r_data_byte[0] <= r_data_byte[0];
					r_data_byte[1] <= r_data_byte[1];
					r_data_byte[2] <= r_data_byte[2];
					r_data_byte[3] <= r_data_byte[3];
					r_data_byte[4] <= r_data_byte[4];
					r_data_byte[5] <= r_data_byte[5];
					r_data_byte[6] <= r_data_byte[6];
					r_data_byte[7] <= r_data_byte[7];
					STOP_BIT <= STOP_BIT;
				end
			endcase
		end
	end

//--------<數(shù)據(jù)狀態(tài)判定模塊>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			data_byte <= 8'd0;
		else if(bps_cnt == 8'd159)begin
			data_byte[0] <= r_data_byte[0][2];
			data_byte[1] <= r_data_byte[1][2];
			data_byte[2] <= r_data_byte[2][2];
			data_byte[3] <= r_data_byte[3][2];
			data_byte[4] <= r_data_byte[4][2];
			data_byte[5] <= r_data_byte[5][2];
			data_byte[6] <= r_data_byte[6][2];
			data_byte[7] <= r_data_byte[7][2];
		end
		else
			;
	end

//--------<uart_state模塊>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			uart_state <= 1'b0;
		else if(nedge)
			uart_state <= 1'b1;
		else if(Rx_Done || (bps_cnt == 8'd12 && (START_BIT > 2)))
			uart_state <= 1'b0;
		else
			uart_state <= uart_state;
	end

endmodule

串口發(fā)送模塊

//
//模塊名稱(chēng):串口發(fā)送模塊
//
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;//波特率時(shí)鐘
	
	reg [15:0]div_cnt;//分頻計(jì)數(shù)器
		
	reg [15:0]bps_DR;//分頻計(jì)數(shù)最大值
	
	reg [3:0]bps_cnt;//波特率計(jì)數(shù)時(shí)鐘
		
	//定義數(shù)據(jù)的起始位和停止位
	localparam START_BIT = 1'b0;
	localparam STOP_BIT  = 1'b1;
	
	reg [7:0]r_data_byte;//數(shù)據(jù)寄存器
	
//--------<uart狀態(tài)模塊>--------	
	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計(jì)數(shù)達(dá)到11次,即發(fā)送結(jié)束
			uart_state <= 1'b0;
		else
			uart_state <= uart_state;
	end

//--------<使能分頻計(jì)數(shù)模塊>-------	
//	assign en_cnt = uart_state;
	
//--------<寄存待發(fā)送的數(shù)據(jù),使數(shù)據(jù)保持穩(wěn)定>--------
	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模塊>--------	
//得到不同計(jì)數(shù)周期的計(jì)數(shù)器
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			div_cnt <= 16'd0;
		else if(uart_state)begin	//	assign en_cnt = uart_state;
			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信號(hào)的產(chǎn)生>--------	
	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計(jì)數(shù)模塊>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			bps_cnt <= 4'd0;
		else if(bps_cnt == 4'd11)//clr信號(hào)
			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
	
//--------<數(shù)據(jù)位輸出模塊-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

四、代碼編寫(xiě)

上述已給出按鍵消抖模塊和串口收發(fā)模塊,在本文中主要編寫(xiě)控制模塊頂層模塊。

4.1 控制模塊

為了實(shí)現(xiàn)FPGA將接收到的數(shù)據(jù)存儲(chǔ)到雙口RAM的一段連續(xù)空間中,就需要設(shè)計(jì)一個(gè)可以實(shí)現(xiàn)寫(xiě)地址數(shù)據(jù)自加的控制邏輯,且其控制信號(hào)為串口接收模塊輸出的Rx_Done信號(hào)。每來(lái)一個(gè)Rx_Done就表明接收成功一字節(jié)數(shù),地址數(shù)進(jìn)行加一:

assign wren = Rx_Done;

always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)
		wraddress <= 8'd0;
	else if(Rx_Done)
		wraddress <= wraddress + 1'b1;
	else
		wraddress <= wraddress;
end

當(dāng)按下按鍵S0,F(xiàn)PGA將RAM中存儲(chǔ)的數(shù)據(jù)通過(guò)串口發(fā)送出去。需要實(shí)現(xiàn)按鍵按下即啟動(dòng)連續(xù)讀操作,再次按下可暫停讀操作:

reg do_send;

always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)
		do_send <= 1'd0;
	else if(Key_flag && !Key_state)
		do_send <= ~do_send;
end

always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n) 
		rdaddress <= 8'd0;
	else if(do_send && Tx_Done)
		rdaddress <= rdaddress + 8'd1;
	else
		rdaddress <= rdaddress;
end

在仿真雙端口RAM時(shí)發(fā)現(xiàn)其輸出會(huì)延遲兩個(gè)系統(tǒng)時(shí)鐘周期。這是為了保證數(shù)據(jù)變化穩(wěn)定之后才進(jìn)行數(shù)據(jù)輸出,所以在此將驅(qū)動(dòng)Send_en的信號(hào)接兩級(jí)寄存器進(jìn)行延遲兩拍。當(dāng)按鍵按下后啟動(dòng)一次發(fā)送,然后判斷上一字節(jié)是否發(fā)送結(jié)束,是則進(jìn)行下一字節(jié)發(fā)送否則不進(jìn)行下一次發(fā)送:

reg r0_send_done,r1_send_done;

always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)begin
		r0_send_done <= 1'b0;
		r1_send_done <= 1'b0;
	end
	else begin
		r0_send_done <= (do_send && Tx_Done);
		r1_send_done <= r0_send_done; 
	end
end

always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)
		Send_en <= 1'b0;
	else if(Key_flag && !Key_state)
		Send_en <= 1'b1;
	else if(r1_send_done)
		Send_en <= 1'b1;
	else
		Send_en <= 1'b0;
end

為了保證RAM地址操作的有效性,在寫(xiě)地址和讀地址代碼部分加上范圍限制

//--------<dpram寫(xiě)地址加1>--------	
always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)
		wraddress <= 8'd0;
	else if(Rx_Done)
		wraddress <= wraddress + 1'b1;
	else if(wraddress > 8'd255) //當(dāng)寫(xiě)地址大于配置ip核時(shí)的值時(shí),返回到0地址;
		wraddress <= 8'd0;
	else
		wraddress <= wraddress;
end

//--------<dpram讀地址加1>--------		
always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)
		rdaddress <= 8'd0;
	else if(do_send && Tx_Done)
		rdaddress <= rdaddress + 8'd1;
	else if(rdaddress > 8'd255)	//當(dāng)讀地址大于255時(shí),返回到0地址;
		rdaddress <= 8'd0;
	else
		rdaddress <= rdaddress;
end

完整的控制模塊代碼:system_ctrl.v

module system_ctrl(
	input 				Clk,
	input 				Rst_n,
	input 				Key_flag,
	input 				Key_state,
	input 				Rx_Done,
	input 				Tx_Done,
	output 				wren,
	output reg			Send_en,
	output reg [7:0]	rdaddress,
	output reg [7:0]	wraddress
);

	assign wren = Rx_Done;
	
	reg do_send;
	
	reg r0_send_done;
	reg r1_send_done;

//--------<dpram寫(xiě)地址加1>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			wraddress <= 8'd0;
		else if(Rx_Done)
			wraddress <= wraddress + 1'b1;
		else if(wraddress > 8'd255) //當(dāng)寫(xiě)地址大于配置ip核時(shí)的值時(shí),返回到0地址;
			wraddress <= 8'd0;
		else
			wraddress <= wraddress;
	end

//--------<翻轉(zhuǎn)標(biāo)志信號(hào)>--------
//按下一次按鍵開(kāi)始連續(xù)發(fā)送數(shù)據(jù),再按一次按鍵停止發(fā)送;
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			do_send <= 1'b0;
		else if(Key_flag && !Key_state)
			do_send <= ~do_send;
	end

//--------<dpram讀地址加1>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			rdaddress <= 8'd0;
		else if(do_send && Tx_Done)
			rdaddress <= rdaddress + 8'd1;
		else if(rdaddress > 8'd255)	//當(dāng)讀地址大于255時(shí),返回到0地址;
			rdaddress <= 8'd0;
		else
			rdaddress <= rdaddress;
	end

//--------<RAM的兩拍延遲>--------	
//雙端口RAM的輸出延遲兩個(gè)系統(tǒng)時(shí)鐘周期;
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)begin
			r0_send_done <= 1'b0;
			r1_send_done <= 1'b1;
		end
		else begin
			r0_send_done <= (do_send && Tx_Done);
			r1_send_done <= r0_send_done;
		end
	end

//--------<按鍵控制與連續(xù)讀操作>--------	
//Send_en由按鍵信號(hào)和r1_send_done信號(hào)同時(shí)控制;
//r1_send_done信號(hào)使得串口連續(xù)讀取dpram的數(shù)據(jù);
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			Send_en <= 1'b0;
		else if(Key_flag && !Key_state)
			Send_en <= 1'b1;
		else if(r1_send_done)
			Send_en <= 1'b1;
		else
			Send_en <= 1'b0;
	end

endmodule

控制模塊的RTL視圖:

【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

4.2 頂層模塊

串口接收模塊、按鍵消抖模塊、RAM模塊、串口發(fā)送模塊以及控制模塊例化到頂層模塊中。

uart_system_top.v:

module uart_system_top(
	input 	Clk,
	input 	Rst_n,
	input		key_in,
	input 	uart_rx,
	output 	uart_tx
);
	
	wire [7:0]rx_data;
	wire [7:0]tx_data;
	wire Key_flag;
	wire Key_state;
	wire Rx_Done;
	wire Tx_Done;
	wire wren;
	wire Send_en;
	wire [7:0]rdaddress;
	wire [7:0]wraddress;
	
	uart_byte_rx uart_byte_rx(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.baud_set(3'd0),
		.data_rx(uart_rx),
		.data_byte(rx_data),
		.Rx_Done(Rx_Done)
	);
	
	dpram dpram(
		.clock(Clk),
		.data(rx_data),
		.rdaddress(rdaddress),
		.wraddress(wraddress),
		.wren(wren),
		.q(tx_data)
	);
		
	KeyFilter KeyFilter(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(Key_flag),
		.key_state(Key_state)
	);

	uart_byte_tx uart_byte_tx(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.data_byte(tx_data),
		.send_en(Send_en),
		.baud_set(3'd0),
		.uart_tx(uart_tx),
		.Tx_Done(Tx_Done),
		.uart_state()
	);

	system_ctrl system_ctrl(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.Key_flag(Key_flag),
		.Key_state(Key_state),
		.Rx_Done(Rx_Done),
		.Tx_Done(Tx_Done),
		.wren(wren),
		.Send_en(Send_en),
		.rdaddress(rdaddress),
		.wraddress(wraddress)
	);

endmodule

頂層模塊的RTL視圖:

【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

五、仿真測(cè)試激勵(lì)文件

5.1 key_model

key_model仿真模型用于有按鍵控制信號(hào)的項(xiàng)目進(jìn)行仿真測(cè)試,模擬實(shí)際情況中的按鍵抖動(dòng)。 在仿真時(shí)將該模型也添加到工程中使用。

key_model.v:

`timescale 1ns/1ns

module key_model(press,key);
	
	input press;
	output reg key;
	
	reg [15:0]myrand;
	
	initial begin
		key = 1'b1;		
	end
	
	always@(posedge press)
		press_key;
		
	task press_key;
		begin
			repeat(50)begin
				myrand = {$random}%65536;//0~65535;
				#myrand key = ~key;			
			end
			key = 0;
			#25000000;
			
			repeat(50)begin
				myrand = {$random}%65536;//0~65535;
				#myrand key = ~key;			
			end
			key = 1;
			#25000000;		
		end	
	endtask

endmodule

5.2 testbench編寫(xiě)

完整的仿真測(cè)試激勵(lì)文件:

uart_system_top_tb.v:

`timescale 1ns/1ns
`define clock_period 20

module uart_system_top_tb;
	
	reg Clk;
	reg Rst_n;
	wire Key_in;
	wire uart_rx;
	wire uart_tx;
	
	reg [7:0]data_byte_t;
	reg send_en;
	wire [2:0]baud_set;
	wire Tx_Done;
	reg press;
	
	assign baud_set = 3'd0;
	
	uart_system_top uart_system_top(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(Key_in),
		.uart_rx(uart_tx),
		.uart_tx(uart_rx)
	);
	
	uart_byte_tx uart_byte_tx(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.data_byte(data_byte_t),
		.send_en(send_en),
		.baud_set(baud_set),
		.uart_tx(uart_tx),
		.Tx_Done(Tx_Done),
		.uart_state()
	);
	
	key_model key_model(
		.press(press),
		.key(Key_in)
	);
	
	initial Clk = 1;
	always#(`clock_period / 2) Clk = ~Clk;

	initial begin
		Rst_n = 1'b0;
		press = 0;
		data_byte_t = 8'd0;
		send_en = 1'd0;
		#(`clock_period*20 + 1 );
		Rst_n = 1'b1;
		#(`clock_period*50);
		
		data_byte_t = 8'haa;
		send_en = 1'd1;
		#`clock_period;
		send_en = 1'd0;		
		@(posedge Tx_Done)
		
		#(`clock_period*5000);
		
		data_byte_t = 8'h55;
		send_en = 1'd1;
		#`clock_period;
		send_en = 1'd0;
		@(posedge Tx_Done)
		
		#(`clock_period*5000);
		
		data_byte_t = 8'h33;
		send_en = 1'd1;
		#`clock_period;
		send_en = 1'd0;		
		@(posedge Tx_Done)
		
		#(`clock_period*5000);
		
		data_byte_t = 8'haf;
		send_en = 1'd1;
		#`clock_period;
		send_en = 1'd0;
		@(posedge Tx_Done)
		
		#(`clock_period*5000);
		
		press = 1;
		#(`clock_period*3)
		press = 0;
		
		#(`clock_period*2000000)
		
		$stop;
	end

endmodule

5.3 仿真結(jié)果

【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

六、板級(jí)驗(yàn)證

??輸入數(shù)據(jù)儲(chǔ)存到雙口RAM中:
【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

??輸出RAM中的數(shù)據(jù):
【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

??結(jié)尾文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-713679.html


  • ?? 感謝您的支持和鼓勵(lì)! ????
  • ??您可能感興趣的內(nèi)容:
  • 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#14】串口發(fā)送字符串
  • 【Python】串口通信-與FPGA、藍(lán)牙模塊實(shí)現(xiàn)串口通信(Python+FPGA)
  • 【Arduino TinyGo】【最新】使用Go語(yǔ)言編寫(xiě)Arduino-環(huán)境搭建和點(diǎn)亮LED燈
  • 【全網(wǎng)首發(fā)開(kāi)源教程】【Labview機(jī)器人仿真與控制】Labview與Solidworks多路支配關(guān)系-四足爬行機(jī)器人仿真與控制
    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng),FPGA學(xué)習(xí)之旅,1024程序員節(jié),fpga開(kāi)發(fā),學(xué)習(xí),Verilog HDL,串口收發(fā),雙口RAM

到了這里,關(guān)于【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#9】狀態(tài)機(jī)基礎(chǔ)知識(shí)

    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#9】狀態(tài)機(jī)基礎(chǔ)知識(shí)

    ??歡迎來(lái)到FPGA專(zhuān)欄~狀態(tài)機(jī)基礎(chǔ)知識(shí) ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏與酒 ?? ? 博客主頁(yè): 小夏與酒的博客 ??該系列 文章專(zhuān)欄: FPGA學(xué)習(xí)之旅 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正?? ?? 歡迎大家關(guān)注! ?? ?? Hello狀態(tài)機(jī)例程 : RTL視圖: 狀態(tài)

    2024年02月16日
    瀏覽(17)
  • 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#11】數(shù)碼管動(dòng)態(tài)掃描

    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#11】數(shù)碼管動(dòng)態(tài)掃描

    ??歡迎來(lái)到FPGA專(zhuān)欄~數(shù)碼管動(dòng)態(tài)掃描 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏與酒 ?? ? 博客主頁(yè): 小夏與酒的博客 ??該系列 文章專(zhuān)欄: FPGA學(xué)習(xí)之旅 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正?? ?? 歡迎大家關(guān)注! ?? ?? Spirit_V2開(kāi)發(fā)板按鍵控制數(shù)碼管:

    2024年02月11日
    瀏覽(19)
  • 【FPGA + 串口】功能完備的串口測(cè)試模塊,三種模式:自發(fā)自收、交叉收發(fā)、內(nèi)源

    【FPGA + 串口】功能完備的串口測(cè)試模塊,三種模式:自發(fā)自收、交叉收發(fā)、內(nèi)源 將 mode設(shè)置為0,是自發(fā)自收; 將 mode設(shè)置為1,是交叉收發(fā); 將 mode設(shè)置為2,是內(nèi)源;外部串口直接看數(shù)據(jù)即可; 通過(guò)三種模式的測(cè)量,可以精確的測(cè)量串口是否通,出故障,也可以判斷出 是

    2024年02月15日
    瀏覽(22)
  • 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#7】BCD計(jì)數(shù)器設(shè)計(jì)

    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#7】BCD計(jì)數(shù)器設(shè)計(jì)

    ??歡迎來(lái)到FPGA專(zhuān)欄~BCD計(jì)數(shù)器設(shè)計(jì) ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏與酒 ?? ? 博客主頁(yè): 小夏與酒的博客 ??該系列 文章專(zhuān)欄: FPGA學(xué)習(xí)之旅 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正?? ?? 歡迎大家關(guān)注! ?? 頂層模塊中的BCD模塊級(jí)聯(lián): Verilog實(shí)現(xiàn)

    2024年02月08日
    瀏覽(24)
  • 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#6】ip核基礎(chǔ)知識(shí)之計(jì)數(shù)器

    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#6】ip核基礎(chǔ)知識(shí)之計(jì)數(shù)器

    ??歡迎來(lái)到FPGA專(zhuān)欄~ip核基礎(chǔ)知識(shí)之計(jì)數(shù)器 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏與酒 ?? ? 博客主頁(yè): 小夏與酒的博客 ??該系列 文章專(zhuān)欄: FPGA學(xué)習(xí)之旅 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正?? ?? 歡迎大家關(guān)注! ?? LPM_COUNTER IP核 的RTL視圖: IP核

    2024年02月09日
    瀏覽(18)
  • 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#8】阻塞賦值與非阻塞賦值講解

    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#8】阻塞賦值與非阻塞賦值講解

    ??歡迎來(lái)到FPGA專(zhuān)欄~阻塞賦值與非阻塞賦值 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏與酒 ?? ? 博客主頁(yè): 小夏與酒的博客 ??該系列 文章專(zhuān)欄: FPGA學(xué)習(xí)之旅 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正?? ?? 歡迎大家關(guān)注! ?? 阻塞賦值 ,操作符為 “ = ”

    2024年02月10日
    瀏覽(19)
  • 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#5】產(chǎn)生非等占空比信號(hào)

    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#5】產(chǎn)生非等占空比信號(hào)

    ??歡迎來(lái)到FPGA專(zhuān)欄~產(chǎn)生非等占空比信號(hào) ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏與酒 ?? ? 博客主頁(yè): 小夏與酒的博客 ??該系列 文章專(zhuān)欄: FPGA學(xué)習(xí)之旅 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正?? ?? 歡迎大家關(guān)注! ?? 我們通過(guò)LED的亮滅來(lái)展現(xiàn)等占空

    2024年02月05日
    瀏覽(21)
  • 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#10】按鍵消抖模塊設(shè)計(jì)與驗(yàn)證(一段式狀態(tài)機(jī)實(shí)現(xiàn))

    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#10】按鍵消抖模塊設(shè)計(jì)與驗(yàn)證(一段式狀態(tài)機(jī)實(shí)現(xiàn))

    ??歡迎來(lái)到FPGA專(zhuān)欄~按鍵消抖模塊設(shè)計(jì)與驗(yàn)證 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏與酒 ?? ? 博客主頁(yè): 小夏與酒的博客 ??該系列 文章專(zhuān)欄: FPGA學(xué)習(xí)之旅 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正?? ?? 歡迎大家關(guān)注! ?? ?? 模塊設(shè)計(jì): ?? 按鍵消

    2024年02月12日
    瀏覽(24)
  • STM32系列——串口收發(fā)數(shù)據(jù)基礎(chǔ)

    STM32系列——串口收發(fā)數(shù)據(jù)基礎(chǔ)

    串行接口相關(guān)知識(shí) 兩種通信方式:并行通信與串行通信,并行通信傳輸速度快但是占用的引腳資源多,串行通信傳輸速度慢但是占用的引腳資源少。 三種模式:?jiǎn)喂ぁ腚p工、全雙工 異步串行通信:通信雙方在沒(méi)有同步時(shí)鐘的前提下,將一個(gè)字符(包括特定的附加位)按位進(jìn)

    2024年02月11日
    瀏覽(23)
  • 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#12】三線制數(shù)碼管驅(qū)動(dòng)(74HC595)串行移位寄存器驅(qū)動(dòng)

    【FPGA零基礎(chǔ)學(xué)習(xí)之旅#12】三線制數(shù)碼管驅(qū)動(dòng)(74HC595)串行移位寄存器驅(qū)動(dòng)

    ??歡迎來(lái)到FPGA專(zhuān)欄~三線制數(shù)碼管驅(qū)動(dòng) ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏與酒 ?? ? 博客主頁(yè): 小夏與酒的博客 ??該系列 文章專(zhuān)欄: FPGA學(xué)習(xí)之旅 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正?? ?? 歡迎大家關(guān)注! ?? ?? ISSP調(diào)試演示: 程序配置完成:

    2024年02月09日
    瀏覽(27)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包