[FPGA]Spartan6 Uart可变波特率读写JY901P惯导模块

Spartan6固定波特率读取JY901P的内容在以下链接:固定波特率读取惯导

这个版本增加了上电自动扫描波特率功能,以及实现修改波特率的功能。

其中JY901P_writer.v,JY901P_reader.v,JY901P_top.v代码并没有任何改变,只修改了JY901P_uart_top.v,uart_send_dynamic.v,uart_receive_dynamic.v

1. JY901P_uart_top.v

  • 上电后 FPGA 会自动按顺序轮询常见波特率(4800~230400),每个波特率尝试一段时间,直到成功解析到 JY901P 的有效数据帧。

  • 一旦正确接收到一帧数据,立即停止扫描,锁定当前波特率进入正常工作模式,保证后续通信稳定。

  • 当发送波特率修改或恢复出厂指令后,状态机会自动回到扫描模式,重新适配新的波特率

cpp 复制代码
`timescale 1ns / 1ps
module JY901P_Uart_top
(
    input           clk            ,
    input           rst_n          ,
    // 串口物理接口
    input           uart_rxd       ,
    output          uart_txd       ,
    // JY901指令配置接口
    input           send_cmd_en    ,
    input  [7:0]    cmd_addr       ,
    input  [15:0]   cmd_data       ,
    // JY901解析数据输出
    output [15:0]   acc_x          ,
    output [15:0]   acc_y          ,
    output [15:0]   acc_z          ,
    output [15:0]   gyro_x         ,
    output [15:0]   gyro_y         ,
    output [15:0]   gyro_z         ,
    output [15:0]   angle_x        ,
    output [15:0]   angle_y        ,
    output [15:0]   angle_z        ,
    output [15:0]   mag_x          ,
    output [15:0]   mag_y          ,
    output [15:0]   mag_z          ,
    output [63:0]   JY901P_data_out ,
    output          frame_valid
);

// 波特率定义
localparam BAUD_4800     = 32'd4800;
localparam BAUD_9600     = 32'd9600;
localparam BAUD_19200    = 32'd19200;
localparam BAUD_38400    = 32'd38400;
localparam BAUD_57600    = 32'd57600;
localparam BAUD_115200   = 32'd115200;
localparam BAUD_230400   = 32'd230400;
localparam SCAN_TIMEOUT  = 32'd30_000_000;  // 600ms扫描超时
localparam BAUD_REG_ADDR  = 8'h04;           // JY901P波特率寄存器地址
localparam RESET_REG_ADDR = 8'h00; 	//恢复出厂设置
// 状态定义
localparam S_IDLE        = 3'd0;
localparam S_SCAN_BAUD   = 3'd1;
localparam S_BAUD_LOCK   = 3'd2;
localparam S_CHANGE_BAUD = 3'd3;
localparam S_RESET 		 = 3'd4;
// 内部寄存器
reg [2:0]   baud_scan_idx;
reg [31:0]  scan_timer;
reg [31:0]  current_baud;
reg [2:0]   state;
reg         baud_lock_flag;
reg [15:0]  baud_cnt_max;
wire        cmd_send_done;       // JY901P_top输出的命令完成标志
reg         cmd_send_done_d1;    // 打拍消抖

// 补充所有缺失的连线(尤其是uart_tx_done)
wire        uart_tx_done;        // UART单字节发送完成
wire [7:0]  uart_rx_data;
wire        uart_rx_flag;
wire [7:0]  uart_tx_data;
wire        uart_tx_flag;
wire        frame_valid_int;

// ===================== 主状态机=====================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        state           <= S_IDLE;
        baud_scan_idx   <= 3'd0;
        scan_timer      <= 32'd0;
        current_baud    <= BAUD_9600;
        baud_lock_flag  <= 1'b0;
        baud_cnt_max    <= (50_000_000 / BAUD_9600) - 1;
        cmd_send_done_d1<= 1'b0;
    end else begin
        cmd_send_done_d1 <= cmd_send_done;
        case(state)
            S_IDLE: begin
                state <= S_SCAN_BAUD;
                baud_scan_idx <= 3'd0;
                scan_timer <= 32'd0;
                baud_lock_flag <= 1'b0;
            end

            S_SCAN_BAUD: begin
                case(baud_scan_idx)
                    3'd0: begin current_baud <= BAUD_4800;    baud_cnt_max <= (50_000_000 / BAUD_4800) - 1;   end
                    3'd1: begin current_baud <= BAUD_9600;    baud_cnt_max <= (50_000_000 / BAUD_9600) - 1;   end
                    3'd2: begin current_baud <= BAUD_19200;   baud_cnt_max <= (50_000_000 / BAUD_19200) - 1;  end
                    3'd3: begin current_baud <= BAUD_38400;   baud_cnt_max <= (50_000_000 / BAUD_38400) - 1;  end
                    3'd4: begin current_baud <= BAUD_57600;   baud_cnt_max <= (50_000_000 / BAUD_57600) - 1;  end
                    3'd5: begin current_baud <= BAUD_115200;  baud_cnt_max <= (50_000_000 / BAUD_115200) - 1; end
                    3'd6: begin current_baud <= BAUD_230400;  baud_cnt_max <= (50_000_000 / BAUD_230400) - 1; end
                    default:begin current_baud <= BAUD_9600;  baud_cnt_max <= (50_000_000 / BAUD_9600) - 1;   end
                endcase

                if(scan_timer >= SCAN_TIMEOUT) begin
                    scan_timer <= 32'd0;
                    baud_scan_idx <= baud_scan_idx + 1'b1;
                    if(baud_scan_idx >= 3'd6) begin  
                        baud_lock_flag <= 1'b1;
                        state <= S_BAUD_LOCK;
                    end
                end else begin
                    scan_timer <= scan_timer + 1'b1;
                    // 收到有效帧立即锁定波特率
                    if(frame_valid_int) begin
                        baud_lock_flag <= 1'b1;
                        state <= S_BAUD_LOCK;
                        scan_timer <= 32'd0;
                    end
                end
            end

            S_BAUD_LOCK: begin
                if(send_cmd_en && (cmd_addr == BAUD_REG_ADDR)) begin
                    state <= S_CHANGE_BAUD;
                end
                // 恢复出厂设置命令
				else if(send_cmd_en && (cmd_addr == RESET_REG_ADDR) && (cmd_data[15:8] == 8'h00)) begin
                    state <= S_RESET;
                end
            end

            S_CHANGE_BAUD: begin
                // 波特率命令发送完成(上升沿触发)
                if(cmd_send_done && !cmd_send_done_d1) begin
                    state <= S_IDLE;
                end
            end
			
			S_RESET: begin
                // 命令发送完成(上升沿触发)
                if(cmd_send_done && !cmd_send_done_d1) begin
                    // 跳回IDLE,触发重新扫描新波特率
                    state <= S_IDLE;
                end
            end

            default: state <= S_IDLE;
        endcase
    end
end

// ===================== 模块例化 =====================
uart_recceive_dynamic
#(
    .CLK_FREQ(50000000)
)
uart_RX
(
    .clk            (clk),
    .sys_rst_n      (rst_n),
    .baud_cnt_max   (baud_cnt_max),
    .rx             (uart_rxd),
    .po_data        (uart_rx_data),
    .po_flag        (uart_rx_flag)
);

JY901P_top
#(
    .CLK_FREQ(50000000)
)
JY901P_top_inst
(
    .clk            (clk),
    .rst_n          (rst_n),
    .uart_rx_data   (uart_rx_data),
    .uart_rx_flag   (uart_rx_flag),
    .uart_tx_data   (uart_tx_data),
    .uart_tx_flag   (uart_tx_flag),
    .uart_tx_done   (uart_tx_done),  
    .send_cmd_en    (send_cmd_en),   
    .cmd_addr       (cmd_addr),
    .cmd_data       (cmd_data),
    .cmd_send_done  (cmd_send_done),
    .acc_x          (acc_x),
    .acc_y          (acc_y),
    .acc_z          (acc_z),
    .gyro_x         (gyro_x),
    .gyro_y         (gyro_y),
    .gyro_z         (gyro_z),
    .angle_x        (angle_x),
    .angle_y        (angle_y),
    .angle_z        (angle_z),
    .mag_x          (mag_x),
    .mag_y          (mag_y),
    .mag_z          (mag_z),
    .JY901P_data_out(JY901P_data_out),
    .frame_valid    (frame_valid_int)
);

uart_send_dynamic
#(
    .CLK_FREQ(50000000)
)
uart_TX
(
    .clk            (clk),
    .sys_rst_n      (rst_n),
    .baud_cnt_max   (baud_cnt_max),
    .pi_data        (uart_tx_data),
    .pi_flag        (uart_tx_flag),
    .tx             (uart_txd),
    .tx_done        (uart_tx_done)   
);

// 有效帧输出(波特率锁定+帧接收完成)
assign frame_valid = frame_valid_int & baud_lock_flag;

endmodule

2. uart_send_dynamic.v

新增输入端口:baud_cnt_max

cpp 复制代码
`timescale 1ns / 1ps
module uart_send_dynamic
#(
    parameter CLK_FREQ = 50000000
)
(
    input           clk         ,
    input           sys_rst_n   ,
    input  [15:0]   baud_cnt_max,
    input  [7:0]    pi_data     ,
    input           pi_flag     ,
    output reg      tx          ,
    output reg      tx_done
);

reg [15:0] baud_cnt;
reg [3:0]  bit_cnt;
reg [7:0]  data_buf;
reg        tx_en;
reg        pi_flag_d1;

wire pi_flag_posedge = pi_flag & ~pi_flag_d1;

always @(posedge clk or negedge sys_rst_n) begin
    if (!sys_rst_n) begin
        data_buf <= 8'd0;
        tx_en <= 1'b0;
        pi_flag_d1 <= 1'b0;
    end else begin
        pi_flag_d1 <= pi_flag;
        if (pi_flag_posedge) begin
            data_buf <= pi_data;
            tx_en <= 1'b1;
        end else if (bit_cnt == 4'd9 && baud_cnt == baud_cnt_max - 1) begin
            tx_en <= 1'b0;
        end
    end
end

always @(posedge clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        baud_cnt <= 16'd0;
    else if (tx_en) begin
        if (baud_cnt == baud_cnt_max - 1)
            baud_cnt <= 16'd0;
        else
            baud_cnt <= baud_cnt + 1'b1;
    end else
        baud_cnt <= 16'd0;
end

always @(posedge clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        bit_cnt <= 4'd0;
    else if (tx_en) begin
        if (baud_cnt == baud_cnt_max - 1) begin
            if (bit_cnt == 4'd9)
                bit_cnt <= 4'd0;
            else
                bit_cnt <= bit_cnt + 1'b1;
        end
    end else
        bit_cnt <= 4'd0;
end

always @(posedge clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        tx <= 1'b1;
    else if (tx_en) begin
        case (bit_cnt)
            4'd0: tx <= 1'b0;
            4'd1: tx <= data_buf[0];
            4'd2: tx <= data_buf[1];
            4'd3: tx <= data_buf[2];
            4'd4: tx <= data_buf[3];
            4'd5: tx <= data_buf[4];
            4'd6: tx <= data_buf[5];
            4'd7: tx <= data_buf[6];
            4'd8: tx <= data_buf[7];
            4'd9: tx <= 1'b1;
            default: tx <= 1'b1;
        endcase
    end else
        tx <= 1'b1;
end

always @(posedge clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        tx_done <= 1'b0;
    else if (tx_en && (bit_cnt == 4'd9) && (baud_cnt == baud_cnt_max - 1))
        tx_done <= 1'b1;
    else
        tx_done <= 1'b0;
end

endmodule

3. uart_receive_dynamic.v

新增输入端口:baud_cnt_max

cpp 复制代码
`timescale 1ns / 1ps
module uart_recceive_dynamic
#(
    parameter CLK_FREQ = 50_000_000
)
(
    input           clk         ,
    input           sys_rst_n   ,
    input  [15:0]   baud_cnt_max,
    input           rx          ,

    output reg [7:0]po_data     ,
    output reg      po_flag
);

reg         rx_reg1;
reg         rx_reg2;
reg         rx_reg3;
reg         start_nedge;
reg         work_en;
reg [15:0]  baud_cnt;
reg         bit_flag;
reg [3:0]   bit_cnt;
reg [7:0]   rx_data;
reg         rx_flag;

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0) begin
        rx_reg1 <= 1'b1;
        rx_reg2 <= 1'b1;
        rx_reg3 <= 1'b1;
    end else begin
        rx_reg1 <= rx;
        rx_reg2 <= rx_reg1;
        rx_reg3 <= rx_reg2;
    end

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        start_nedge <= 1'b0;
    else if((~rx_reg2) && (rx_reg3))
        start_nedge <= 1'b1;
    else
        start_nedge <= 1'b0;

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        work_en <= 1'b0;
    else if(start_nedge == 1'b1)
        work_en <= 1'b1;
    else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        work_en <= 1'b0;

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        baud_cnt <= 16'b0;
    else if((baud_cnt == baud_cnt_max - 1) || (work_en == 1'b0))
        baud_cnt <= 16'b0;
    else if(work_en == 1'b1)
        baud_cnt <= baud_cnt + 1'b1;

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_flag <= 1'b0;
    else if(baud_cnt == baud_cnt_max/2 - 1)
        bit_flag <= 1'b1;
    else
        bit_flag <= 1'b0;

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_cnt <= 4'b0;
    else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        bit_cnt <= 4'b0;
    else if(bit_flag ==1'b1)
        bit_cnt <= bit_cnt + 1'b1;

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_data <= 8'b0;
    else if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
        rx_data <= {rx_reg3, rx_data[7:1]};

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_flag <= 1'b0;
    else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        rx_flag <= 1'b1;
    else
        rx_flag <= 1'b0;

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_data <= 8'b0;
    else if(rx_flag == 1'b1)
        po_data <= rx_data;

always@(posedge clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_flag <= 1'b0;
    else
        po_flag <= rx_flag;

endmodule
相关推荐
碎碎思2 小时前
基于 Gowin FPGA 的 SDR 开源方案:从硬件到射频全栈打通
fpga开发
S&Z346313 小时前
[SZ901]高级功能:远程调试
fpga开发
醇氧14 小时前
【学习】冯诺依曼架构和哈弗架构
fpga开发
尤老师FPGA16 小时前
HDMI数据的接收发送实验(七)
fpga开发
学习永无止境@16 小时前
FPGA设计中,主时钟与虚拟时钟的定义
fpga开发
进击的横打17 小时前
【车载开发系列】系统时钟与定时器
stm32·单片机·fpga开发
Nobody3317 小时前
Avalon® 接口规范知识文档(v2018.09.26)
fpga开发
GateWorld19 小时前
FPGA内部模块详解之六 FPGA的“心跳”与“神经网络”——时钟网络与布线资源深度解析
fpga开发·fpga内部时钟网络·fpga布线资源
lit_wei1 天前
【ZYNQ的DMA获取FPGA数据处理,零拷贝,DMA方式】
fpga开发