所用串口为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时钟进行时钟累加,最终实现串口每秒发送一次数据,每次发送的有效数据进行累加。
最后
以上就是腼腆小土豆最近收集整理的关于采用FPGA实现串口多字节发送的全部内容,更多相关采用FPGA实现串口多字节发送内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复