|
|
请教大神,下面这段代码,想着每间隔4秒发送01 02 03 04 05 06 07 08 09 0A这些数据,按下面的代码,在串口助手中看到的是01 02 03 04 05 06 07 08 09 0A 0A,初学FPGA,求解惑,谢谢
`timescale 1ns/1ns
////////////////////////////////////////////////////////////////////////
// Module Name : uart_tx
// Description : 每4秒发送01-0A共10个字节,解决多发送01的问题
////////////////////////////////////////////////////////////////////////
module uart_tx
#(
parameter UART_BPS = 'd9600, //串口波特率
parameter CLK_FREQ = 'd50_000_000 //时钟频率
)
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
output reg tx //串转并后的1bit数据
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//localparam define
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS; // 波特率计数最大值
localparam BYTE_GAP_TIME = BAUD_CNT_MAX; // 字节间隔(1位时间)
localparam CNT_5S_MAX = 31'd250_000_000; // 4秒计数最大值(50MHz)
// 状态定义
localparam IDLE = 4'b0000, // 空闲状态
WAIT_START = 4'b0001, // 等待发送开始
SEND_BYTE = 4'b0010, // 发送字节
WAIT_GAP = 4'b0011, // 等待字节间隔
SEND_DONE = 4'b0100; // 发送完成
//reg define
reg [12:0] baud_cnt; // 波特率计数器
reg bit_flag; // 位发送标志
reg [3:0] bit_cnt; // 位计数(0-9:起始位+8数据位+停止位)
reg work_en; // 发送工作使能
reg [7:0] data_array [0:9]; // 发送数据数组(01-0A)
reg [30:0] cnt_1s; // 4秒计数器
reg send_en; // 发送使能信号
reg [3:0] send_cnt; // 发送数据计数(0-9)
reg [7:0] tx_data; // 发送数据寄存器
reg data_valid; // 数据有效标志
reg [3:0] state; // 状态机状态
reg [31:0] gap_cnt; // 字节间隔计数器
// 初始化数据数组(01-0A)
integer i;
initial begin
for(i = 0; i < 10; i = i + 1) begin
data_array[i] = i + 1;
end
end
//********************************************************************//
//************************* 4秒定时器 ************************//
//********************************************************************//
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0) begin
cnt_1s <= 31'd0;
send_en <= 1'b0;
end
else begin
if(cnt_1s < CNT_5S_MAX) begin
cnt_1s <= cnt_1s + 31'd1;
send_en <= 1'b0;
end
else begin
cnt_1s <= 31'd0;
send_en <= 1'b1; // 每4秒产生一个发送使能脉冲
end
end
end
//********************************************************************//
//************************* 发送控制状态机 ************************//
//********************************************************************//
//********************************************************************//
//************************* 发送控制状态机 ************************//
//********************************************************************//
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0) begin
state <= IDLE;
send_cnt <= 4'd0;
data_valid <= 1'b0;
tx_data <= 8'd0;
gap_cnt <= 32'd0;
end
else begin
case(state)
IDLE: begin
data_valid <= 1'b0;
send_cnt <= 4'd0; // 重置计数器
gap_cnt <= 32'd0;
if(send_en) begin
tx_data <= data_array[0]; // 发送第一个字节01
data_valid <= 1'b1;
state <= SEND_BYTE;
end
end
SEND_BYTE: begin
if(bit_flag && bit_cnt == 4'd9) begin
data_valid <= 1'b0;
if(send_cnt == 4'd9) begin
// 已发送10个字节(最后一个字节0A发送完成)
state <= SEND_DONE;
end
else begin
// 等待字节间隔
state <= WAIT_GAP;
end
end
end
WAIT_GAP: begin
if(gap_cnt < BYTE_GAP_TIME - 1) begin
gap_cnt <= gap_cnt + 32'd1;
end
else begin
// 间隔结束,准备发送下一个字节
gap_cnt <= 32'd0;
send_cnt <= send_cnt + 4'd1; // 递增发送计数
// 关键修改:检查是否已经达到10个字节
if(send_cnt + 4'd1 < 10) begin
tx_data <= data_array[send_cnt + 4'd1]; // 取下个数据
data_valid <= 1'b1;
state <= SEND_BYTE;
end
else begin
// 已经发送了10个字节
state <= SEND_DONE;
end
end
end
SEND_DONE: begin
if(send_en == 1'b0) begin
state <= IDLE;
end
end
default: state <= IDLE;
endcase
end
end
//********************************************************************//
//************************* 波特率控制逻辑 ************************//
//********************************************************************//
// work_en: 发送工作使能(数据有效时置1,发送完1字节置0)
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0) begin
work_en <= 1'b0;
end
else if(data_valid == 1'b1) begin
work_en <= 1'b1;
end
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9)) begin
work_en <= 1'b0;
end
end
// baud_cnt: 波特率计数器(0到BAUD_CNT_MAX-1循环)
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0) begin
baud_cnt <= 13'b0;
end
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0)) begin
baud_cnt <= 13'b0;
end
else if(work_en == 1'b1) begin
baud_cnt <= baud_cnt + 1'b1;
end
end
// bit_flag: 位发送标志(波特率计数器到1时置1,仅1个时钟周期)
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0) begin
bit_flag <= 1'b0;
end
else if(baud_cnt == 13'd1) begin
bit_flag <= 1'b1;
end
else begin
bit_flag <= 1'b0;
end
end
// bit_cnt: 位计数(0-9,对应起始位+8数据位+停止位)
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0) begin
bit_cnt <= 4'b0;
end
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9)) begin
bit_cnt <= 4'b0;
end
else if((bit_flag == 1'b1) && (work_en == 1'b1)) begin
bit_cnt <= bit_cnt + 1'b1;
end
end
// tx: UART发送数据(遵循RS232协议:起始位0,停止位1,数据位低位先行)
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0) begin
tx <= 1'b1; // 空闲状态为高电平
end
else if(bit_flag == 1'b1) begin
case(bit_cnt)
0 : tx <= 1'b0; // 起始位
1 : tx <= tx_data[0]; // 数据位0(最低位)
2 : tx <= tx_data[1];
3 : tx <= tx_data[2];
4 : tx <= tx_data[3];
5 : tx <= tx_data[4];
6 : tx <= tx_data[5];
7 : tx <= tx_data[6];
8 : tx <= tx_data[7]; // 数据位7(最高位)
9 : tx <= 1'b1; // 停止位
default : tx <= 1'b1;
endcase
end
end
endmodule
|
|