硬汉嵌入式论坛

 找回密码
 立即注册
查看: 48|回复: 1
收起左侧

FPGA的串口发送数据请教

[复制链接]

3

主题

2

回帖

11

积分

新手上路

积分
11
发表于 昨天 09:06 | 显示全部楼层 |阅读模式
请教大神,下面这段代码,想着每间隔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

回复

使用道具 举报

0

主题

53

回帖

53

积分

初级会员

积分
53
发表于 昨天 13:36 | 显示全部楼层
这是ai的回复你可以看看
回复.png
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-1-8 21:38 , Processed in 0.043977 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表