所用序列槽為RS232,
波特率設定為5種速率可調,其中預設為115200bps,
在csdn上見多了采用Moore類型狀态機編寫的序列槽單位元組發送子產品和多位元組發送子產品,部落客偏要自己寫一份Mealy類型的狀态機,用來實作單位元組發送和多位元組發送。
另外,根據我自己的個人情況,我認為Mealy型狀态機要比Moore型狀态機友善的多!!
代碼及最終的測試結果如下:
歡迎大家進行借鑒和讨論,其中,多位元組發送子產品部落客根據實際需求命名為資料回報子產品,使用者可根據自己想法進行更改。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/08/17 14:33:07
// Design Name:
// Module Name: uart_tx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
// 序列槽單位元組發送
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_tx(
input clk, //50Mhz
input rst_n,
input [3:0]bps_set, //波特率設定
input [7:0]byte, //待發送資料
input byte_en, //待發送資料使能
output tx, //序列槽發送引腳
output tx_done //序列槽單位元組發送完畢
);
reg st;
reg byte_en_r1;
reg byte_en_r2;
reg [7:0]byte_r;
reg [9:0]data;
reg bps_clk_r1;
reg bps_clk_r2;
reg tx_r;
reg [3:0]bit_cnt;
reg tx_done_r;
wire bps_clk;
//資料發送
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
st<=1'b0;
byte_en_r1<=1'b1;
byte_en_r2<=1'b1;
byte_r<=8'd0;
data<=10'd0;
bps_clk_r1<=1'b1;
bps_clk_r2<=1'b1;
tx_r<=1'b1; //序列槽發送引腳常高,
bit_cnt<=4'd0;
tx_done_r<=1'b0;
end
else begin
byte_en_r1<=byte_en;
byte_en_r2<=byte_en_r1;
byte_r<=byte;
bps_clk_r1<=bps_clk;
bps_clk_r2<=bps_clk_r1;
case(st)
1'b0:begin
if(byte_en_r1==1'b1 && byte_en_r2==1'b0)begin //單位元組發送使能
st<=8'd1;
data<={1'b1,byte_r,1'b0}; //起始位低電平,停止位高電平,中間8位是待發送位元組,
end
else begin
st<=8'd0;
data<=10'd0;
tx_done_r<=1'b0;
end
end
8'd1:begin
if(bps_clk_r1==1'b1 && bps_clk_r2==1'b0)begin //序列槽時鐘上升沿到來,更新序列槽發送引腳上的資料,
if(bit_cnt>=4'd10)begin //判斷序列槽是否發送完10bits資料,
st<=1'b0;
bit_cnt<=4'd0;
tx_r<=1'b1;
data<=10'd0;
tx_done_r<=1'b1;
end
else begin
st<=1'b1;
bit_cnt<=bit_cnt+1'b1;
tx_r<=data[0];
data<={1'b0,data[9:1]};
tx_done_r<=1'b0;
end
end
else begin
st<=st;
bit_cnt<=bit_cnt;
tx_r<=tx_r;
data<=data;
tx_done_r<=tx_done_r;
end
end
endcase
end
end
assign tx =tx_r; //序列槽發送引腳
assign tx_done =tx_done_r; //序列槽單位元組發送完畢
//時鐘分頻,生成序列槽時鐘,
bps_div bps_div(
.clk_in(clk),
.rst_n(rst_n && st), //序列槽工作時,st==1'b1,即隻有在序列槽工作時才産生分頻,
.bps_set(bps_set),
.clk_out(bps_clk)
);
endmodule
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/08/17 18:54:08
// Design Name:
// Module Name: Data_Feedback
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
// 資料回報子產品
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module Data_Feedback(
input clk,
input rst_n,
input [15:0]frame_cnt, //回報目前圖像幀數,也是目前子產品的多位元組發送資料,
input frame_en, //序列槽多位元組發送使能,
input tx_done, //序列槽單位元組發送完畢,
output [7:0]tx_byte, //序列槽單位元組待發送資料,
output tx_en //序列槽單位元組待發送資料使能,
);
reg [1:0]st;
reg frame_r1;
reg frame_r2;
reg [15:0]frame_cnt_r;
reg [31:0]data;
reg [7:0]tx_byte_r;
reg tx_en_r;
reg tx_done_r1;
reg tx_done_r2;
reg [7:0]byte_cnt;
//将多位元組資料逐個發送
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
st<=2'd0;
frame_r1<=1'b1;
frame_r2<=1'b1;
frame_cnt_r<=16'd0;
data<=32'd0;
tx_byte_r<=8'd0;
tx_en_r<=1'b0;
tx_done_r1<=1'b1;
tx_done_r2<=1'b1;
byte_cnt<=8'd0;
end
else begin
frame_r1<=frame_en;
frame_r2<=frame_r1;
frame_cnt_r<=frame_cnt;
tx_done_r1<=tx_done;
tx_done_r2<=tx_done_r1;
case(st)
2'd0:begin
if(frame_r1==1'b1 && frame_r2==1'b0)begin //檢測到序列槽多位元組發送使能信号,
st<=2'd1;
data<={8'hFE,frame_cnt_r[7:0],frame_cnt_r[15:8],8'hEF}; //将待發送資料鎖存,其中EF是幀頭,FE是幀尾,
end
else begin
st<=2'd0;
data<=32'd0;
end
end
2'd1:begin
st<=2'd2;
tx_byte_r<=data[7:0]; //更新待發送的單位元組資料,
tx_en_r<=1'b1; //單位元組發送使能,
data<={{8{1'b0}},data[31:8]}; //進行一個資料的移位,
end
2'd2:begin
tx_en_r<=1'b0;
if(tx_done_r1==1'b1 && tx_done_r2==1'b0)begin //檢測到單位元組發送完畢後進行下一個位元組發送,直至多位元組發送完畢。
if(byte_cnt>=8'd3)begin
st<=8'd0;
byte_cnt<=8'd0;
end
else begin
st<=8'd1;
byte_cnt<=byte_cnt+1'b1;
end
end
else begin
st<=st;
byte_cnt<=byte_cnt;
end
end
default:st<=2'd0;
endcase
end
end
assign tx_byte =tx_byte_r;
assign tx_en =tx_en_r;
endmodule
以下是采用50Mhz時鐘進行時鐘累加,最終實作序列槽每秒發送一次資料,每次發送的有效資料進行累加。