蓝桥杯FPGA赛道第三次模拟题代码

  论坛元老 | 2025-4-18 08:44:18 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1730|帖子 1730|积分 5190

一、顶层代码

  1. module test#(
  2.     parameter  SYS_CLK_FREQ = 26'd50_000_000,  // 系统时钟频率50MHz
  3.     parameter  BAUD_RATE = 9600,               // 串口波特率
  4.     parameter  CHECK_BIT = "None"              // 校验位类型(None表示无校验)
  5. )(
  6.     input  wire       sys_clk,    // 系统时钟输入
  7.     input  wire       sys_rst,    // 系统复位(低电平有效)
  8.     input  wire [3:0] key_in,     // 按键输入
  9.     output wire [7:0] sel,        // 数码管位选信号
  10.     output wire [7:0] seg,        // 数码管段选信号
  11.     output reg  [7:0] led,        // LED指示灯
  12.     output wire       tx          // 串口发送线
  13. );
  14. // ========== 状态定义 ==========
  15. localparam STOP  = 3'd0;  // 停止状态
  16. localparam START = 3'd1;  // 启动状态
  17. // ========== 信号定义 ==========
  18. wire [3:0]  key_data;      // 按键消抖后的数据
  19. reg  [31:0] data;          // 数码管显示数据(8位BCD码)
  20. reg  [3:0]  status_count;  // 当前状态(START/STOP)
  21. reg  [7:0]  data_count;    // 计数器值
  22. reg  [3:0]  tx_len;        // 串口发送数据长度
  23. wire        start_send;    // 发送启动信号
  24. reg         start_send_char;  // 字符发送启动标志
  25. reg         start_send_status; // 状态发送启动标志
  26. wire        tx_done;       // 发送完成标志
  27. reg  [7:0]  char_idx;      // 当前发送字符索引
  28. reg  [7:0]  tx_buffer[0:255]; // 发送缓冲区(存储ASCII字符)
  29. reg         tx_done0;      // 发送完成信号打拍(同步用)
  30. reg         tx_done1;      // 发送完成信号打拍(同步用)
  31. wire        send_next;     // 发送下一个字符的触发信号
  32. // ========== 模块实例化 ==========
  33. // 数码管显示模块
  34. seg seg_inst(
  35.     .clk      (sys_clk),
  36.     .rst      (sys_rst),
  37.     .seg      (seg),
  38.     .sel      (sel),
  39.     .dsp_data (data)  // 显示数据输入
  40. );
  41. // 按键消抖模块
  42. key key_inst(
  43.     .sys_clk  (sys_clk),
  44.     .sys_rst  (sys_rst),
  45.     .key_in   (key_in),
  46.     .key_data (key_data)  // 消抖后的按键数据
  47. );
  48. // 串口发送模块
  49. uart_tx#(
  50.     .CLOCK    (SYS_CLK_FREQ),
  51.     .BUAD     (BAUD_RATE),
  52.     .CHECK_BIT(CHECK_BIT)
  53. ) uart_tx_list(
  54.     .clk         (sys_clk),
  55.     .rst         (sys_rst),
  56.     .tx_data     (tx_buffer[char_idx]),  // 当前发送字符
  57.     .tx_data_vld (start_send),           // 发送使能
  58.     .ready       (tx_done),              // 发送完成标志
  59.     .tx          (tx)                    // 串口输出
  60. );
  61. // ========== LED控制逻辑 ==========
  62. always @(posedge sys_clk or negedge sys_rst) begin
  63.     if (!sys_rst)
  64.         led <= 8'b1111_1111;  // 复位时LED全灭
  65.     else if (status_count == START)
  66.         led <= 8'b1111_1110;  // START状态时点亮最低位LED
  67.     else
  68.         led <= 8'b1111_1111;  // 其他状态LED全灭
  69. end
  70. // ========== 数码管显示数据处理 ==========
  71. always @(posedge sys_clk or negedge sys_rst) begin
  72.     if (sys_rst == 1'b0)
  73.         // 复位时显示" 0"(11表示不显示)
  74.         data <= {4'd10, 4'd11, 4'd11, 4'd11, 4'd11, 4'd11, 4'd11, 4'd0};
  75.     else begin
  76.         // 动态更新显示数据(BCD码转换)
  77.         data[11:8] <= (data_count > 99) ? (data_count / 100) : 4'd11;  // 百位
  78.         data[7:4]  <= (data_count > 9)  ? (data_count % 100 / 10) : 4'd11;  // 十位
  79.         data[3:0]  <= data_count % 10;  // 个位
  80.     end
  81. end
  82. // ========== 按键处理逻辑 ==========
  83. always @(posedge sys_clk or negedge sys_rst) begin
  84.     if (sys_rst == 1'b0) begin
  85.         data_count <= 8'b0;        // 计数器清零
  86.         status_count <= START;     // 初始状态为START
  87.         start_send_char <= 0;      // 发送标志清零
  88.     end else begin
  89.         case (key_data)  // 根据按键值更新状态
  90.             4'b0001: begin  // 按键1:切换START/STOP状态
  91.                 if (status_count == START)
  92.                     status_count <= STOP;
  93.                 else if (status_count == STOP)
  94.                     status_count <= START;
  95.             end
  96.             4'b0010: begin  // 按键2:计数器加1(仅在START状态)
  97.                 if (status_count == START)
  98.                     data_count <= data_count + 8'd1;
  99.             end
  100.             4'b0100: begin  // 按键3:计数器减1(仅在STOP状态且值>0)
  101.                 if ((status_count == STOP) && (data_count > 0))
  102.                     data_count <= data_count - 1;
  103.             end
  104.             4'b1000: begin  // 按键4:触发串口发送
  105.                 start_send_char <= 1;
  106.             end
  107.             default: start_send_char <= 0;  // 无按键时清零
  108.         endcase
  109.     end
  110. end
  111. // ========== 发送缓冲区初始化 ==========
  112. always @(posedge sys_clk or negedge sys_rst) begin
  113.     if (!sys_rst) begin
  114.         // 初始化发送缓冲区内容为"COUNT:"
  115.         tx_buffer[0] <= "C";
  116.         tx_buffer[1] <= "O";
  117.         tx_buffer[2] <= "U";
  118.         tx_buffer[3] <= "N";
  119.         tx_buffer[4] <= "T";
  120.         tx_buffer[5] <= ":";
  121.     end
  122. end
  123. // ========== 串口发送数据格式化 ==========
  124. always @(posedge sys_clk or negedge sys_rst) begin
  125.     if (!sys_rst) begin
  126.         tx_len <= 7;  // 默认发送长度("COUNT:X")
  127.     end else begin
  128.         // 根据计数器值动态生成ASCII字符
  129.         if (data_count > 99) begin  // 3位数
  130.             tx_len <= 9;
  131.             tx_buffer[6] <= data_count / 100 + 8'h30;    // 百位ASCII
  132.             tx_buffer[7] <= data_count % 100 / 10 + 8'h30; // 十位ASCII
  133.             tx_buffer[8] <= data_count % 10 + 8'h30;      // 个位ASCII
  134.         end else if (data_count > 9) begin  // 2位数
  135.             tx_len <= 8;
  136.             tx_buffer[6] <= data_count / 10 + 8'h30;     // 十位ASCII
  137.             tx_buffer[7] <= data_count % 10 + 8'h30;      // 个位ASCII
  138.         end else begin  // 1位数
  139.             tx_len <= 7;
  140.             tx_buffer[6] <= data_count + 8'h30;           // 个位ASCII
  141.         end
  142.     end
  143. end
  144. // ========== 串口发送完成检测 ==========
  145. always @(posedge sys_clk or negedge sys_rst) begin
  146.     if (!sys_rst) begin
  147.         tx_done0 <= 0;
  148.         tx_done1 <= 0;
  149.     end else begin
  150.         tx_done0 <= tx_done;  // 打拍同步
  151.         tx_done1 <= tx_done0; // 用于边沿检测
  152.     end
  153. end
  154. // 发送完成信号的上升沿检测
  155. assign send_next = ~tx_done1 && tx_done0;
  156. // 发送使能信号(按键触发或状态机触发)
  157. assign start_send = start_send_char || start_send_status;
  158. // ========== 串口发送状态机 ==========
  159. always @(posedge sys_clk or negedge sys_rst) begin
  160.     if (!sys_rst) begin
  161.         char_idx <= 0;
  162.         start_send_status <= 0;
  163.     end else begin
  164.         if (start_send) begin  // 发送使能有效
  165.             if (char_idx < tx_len - 1) begin  // 未发送完所有字符
  166.                 start_send_status <= 1;
  167.                 if (send_next)  // 检测到发送完成上升沿
  168.                     char_idx <= char_idx + 1;  // 发送下一个字符
  169.             end else begin
  170.                 start_send_status <= 0;  // 发送完成
  171.             end
  172.         end else
  173.             char_idx <= 0;  // 发送结束或未启动时复位索引
  174.     end
  175. end
  176. endmodule
复制代码
二、数码管模块 

  1. // 数码管驱动模块
  2. // 功能:实现8位数码管的动态扫描显示
  3. module seg
  4. (
  5.     input      wire        clk,        // 系统时钟输入(假设50MHz)
  6.     input      wire        rst,        // 异步复位信号,低电平有效
  7.     input      wire [31:0] dsp_data,   // 显示数据输入,32位分为8个4位BCD码
  8.     output     reg  [7:0]  seg,        // 段选信号输出,控制显示内容
  9.     output     reg  [7:0]  sel         // 位选信号输出,控制数码管选择
  10. );
  11. // ===== 数码管段码定义(共阴极数码管)=====
  12. // 格式:DP g f e d c b a (高位到低位)
  13. localparam [7:0] DIGIT0 = 8'b1100_0000; // 数字0的段码(C0)
  14. localparam [7:0] DIGIT1 = 8'b1111_1001; // 数字1的段码(F9)
  15. localparam [7:0] DIGIT2 = 8'b1010_0100; // 数字2的段码(A4)
  16. localparam [7:0] DIGIT3 = 8'b1011_0000; // 数字3的段码(B0)
  17. localparam [7:0] DIGIT4 = 8'b1001_1001; // 数字4的段码(99)
  18. localparam [7:0] DIGIT5 = 8'b1001_0010; // 数字5的段码(92)
  19. localparam [7:0] DIGIT6 = 8'b1000_0010; // 数字6的段码(82)
  20. localparam [7:0] DIGIT7 = 8'b1111_1000; // 数字7的段码(F8)
  21. localparam [7:0] DIGIT8 = 8'b1000_0000; // 数字8的段码(80)
  22. localparam [7:0] DIGIT9 = 8'b1001_0000; // 数字9的段码(90)
  23. localparam [7:0] DIGITX = 8'b1011_1111; // 特殊符号"X"的段码
  24. localparam [7:0] DIGOFF = 8'b1111_1111; // 关闭显示的段码(FF)
  25. localparam [7:0] DIGITC = 8'hC6;        // 特殊字符"C"的段码
  26. // 1ms计数器的最大值(50MHz时钟下,50000个周期=1ms)
  27. localparam DSP_COUNT = 20'd50000;
  28. // ===== 内部寄存器定义 =====
  29. reg [19:0] dsp_count;  // 1ms计数器
  30. reg [3:0]  bits;       // 当前扫描的数码管编号(0-7)
  31. reg [3:0]  bcd;        // 当前数码管对应的BCD码
  32. // ===== 1ms定时计数器 =====
  33. always @(posedge clk or negedge rst) begin
  34.     if(!rst) begin
  35.         dsp_count <= 20'd0;  // 复位时清零计数器
  36.     end else begin
  37.         if (dsp_count == DSP_COUNT-1) begin
  38.             dsp_count <= 20'd0;  // 计数到1ms时归零
  39.         end else begin
  40.             dsp_count <= dsp_count + 20'd1;  // 计数器递增
  41.         end
  42.     end
  43. end
  44. // ===== 位选控制逻辑 =====
  45. always @(posedge clk or negedge rst) begin
  46.     if(!rst) begin
  47.         sel <= 8'b1111_1111;  // 复位时关闭所有数码管
  48.         bits <= 4'd0;         // 复位时从第0位数码管开始
  49.     end else begin
  50.         if(dsp_count == DSP_COUNT-1) begin  // 每1ms更新一次
  51.             if(bits == 4'd8) begin
  52.                 bits <= 4'd0;  // 扫描完8位数码管后归零
  53.             end else begin
  54.                 bits <= bits + 4'd1;  // 指向下一个数码管
  55.             end
  56.             
  57.             // 根据当前数码管编号选择对应的位选信号和BCD码
  58.             case(bits)
  59.                 4'd0: begin sel <= 8'b1111_1110; bcd <= dsp_data[31:28]; end  // 第1位数码管
  60.                 4'd1: begin sel <= 8'b1111_1101; bcd <= dsp_data[27:24]; end  // 第2位数码管
  61.                 4'd2: begin sel <= 8'b1111_1011; bcd <= dsp_data[23:20]; end  // 第3位数码管
  62.                 4'd3: begin sel <= 8'b1111_0111; bcd <= dsp_data[19:16]; end  // 第4位数码管
  63.                 4'd4: begin sel <= 8'b1110_1111; bcd <= dsp_data[15:12]; end  // 第5位数码管
  64.                 4'd5: begin sel <= 8'b1101_1111; bcd <= dsp_data[11:8];  end  // 第6位数码管
  65.                 4'd6: begin sel <= 8'b1011_1111; bcd <= dsp_data[7:4];   end  // 第7位数码管
  66.                 4'd7: begin sel <= 8'b0111_1111; bcd <= dsp_data[3:0];   end  // 第8位数码管
  67.                 default: sel <= 8'b1111_1111;  // 默认关闭所有数码管
  68.             endcase
  69.         end
  70.     end
  71. end
  72. // ===== 段选控制逻辑 =====
  73. always @(posedge clk or negedge rst) begin
  74.     if(!rst) begin
  75.         seg <= DIGOFF;  // 复位时关闭显示
  76.     end else begin
  77.         // 根据BCD码选择对应的段码
  78.         case(bcd)
  79.             4'd0:  seg <= DIGIT0;  // 显示数字0
  80.             4'd1:  seg <= DIGIT1;  // 显示数字1
  81.             4'd2:  seg <= DIGIT2;  // 显示数字2
  82.             4'd3:  seg <= DIGIT3;  // 显示数字3
  83.             4'd4:  seg <= DIGIT4;  // 显示数字4
  84.             4'd5:  seg <= DIGIT5;  // 显示数字5
  85.             4'd6:  seg <= DIGIT6;  // 显示数字6
  86.             4'd7:  seg <= DIGIT7;  // 显示数字7
  87.             4'd8:  seg <= DIGIT8;  // 显示数字8
  88.             4'd9:  seg <= DIGIT9;  // 显示数字9
  89.             4'd10: seg <= DIGITC;  // 显示特殊字符"C"
  90.             default: seg <= DIGOFF; // 其他值关闭显示
  91.         endcase
  92.     end
  93. end
  94. endmodule
复制代码
 三、按键驱动模块

 
  1. module key(
  2.     input   wire                sys_clk,
  3.     input   wire                sys_rst,
  4.     input   wire    [3:0]       key_in,
  5.          output reg      [3:0]                  key_data
  6. );
  7. //按键键值定义
  8. localparam  KEY_VAL_S1 =4'b0001;
  9. localparam  KEY_VAL_S2 =4'b0010;
  10. localparam  KEY_VAL_S3 =4'b0100;
  11. localparam  KEY_VAL_S4=4'b1000;
  12. localparam  KEY_VAL_NL=4'b1111;
  13. localparam  KEY_COUNT_MAX =20'd500000;
  14. //按键状态定义
  15. localparam  IDLE      =3'd0;
  16. localparam  PRESS     =3'd1;
  17. localparam  RELEASE   =3'd2;
  18. //按键扫描计数器,每隔0.01秒扫描一次按键
  19. reg [19:0]   key_count;
  20. //寄存器的定义用来存储不同的状态
  21. reg [2:0]    key_status;
  22. //按键计数更新
  23. always@(posedge sys_clk or negedge sys_rst) begin
  24.     if(sys_rst==1'b0)
  25.         key_count <=0;
  26.         else begin
  27.              if(key_count == KEY_COUNT_MAX-1)begin
  28.                 key_count <= 0;
  29.             end else
  30.                 key_count = key_count + 1;   
  31.         end
  32.     end
  33. //按键状态更新
  34. always@(posedge sys_clk or negedge sys_rst)begin
  35.     if(sys_rst==1'b0)begin//复位
  36.         key_data <= KEY_VAL_NL;
  37.                   key_status<=IDLE;
  38.          end else begin
  39.     if(key_data == KEY_VAL_NL) begin
  40.                         if(key_count==KEY_COUNT_MAX-1)begin
  41.                                 if(key_status==IDLE)begin//当前没有按键时,并且按键扫描时间到,进行判断
  42.                                    if(key_in!=4'b1111)//当按键键不等于1111
  43.                                                 key_status<=PRESS;//按键处于按下状态
  44.                                    end  else if(key_status==PRESS)begin//在有按键按下,赋予键值
  45.                                                         case(key_in)
  46.                                                                 4'b1110: begin key_data <=KEY_VAL_S1; key_status <=RELEASE; end
  47.                                                                 4'b1101: begin key_data <=KEY_VAL_S2; key_status <=RELEASE; end
  48.                                                                 4'b1011: begin key_data <=KEY_VAL_S3; key_status <=RELEASE; end
  49.                                                                 4'b0111: begin key_data <=KEY_VAL_S4; key_status <=RELEASE; end
  50.                                                                 default: begin key_data <=KEY_VAL_NL; key_status <=IDLE;    end
  51.                                                         endcase
  52.                                         end else begin
  53.                                                         if(key_in == 4'b1111)
  54.                                                                         key_status <=IDLE;
  55.                                                         end
  56.                                                 end
  57.                                         end else
  58.                                              key_data <=KEY_VAL_NL;
  59.                                 end
  60.                         end
  61. endmodule
复制代码
四、串口驱动模块 

  1. // UART发送模块
  2. // 功能:实现UART串口数据发送,支持可配置波特率和校验位
  3. module uart_tx #(
  4.     parameter CLOCK = 26'd50_000_000,  // 系统时钟频率(默认50MHz)
  5.     parameter BUAD = 9600,            // 波特率(默认9600)
  6.     parameter CHECK_BIT = "None"      // 校验位类型:"None"/"Odd"/"Even"
  7. )(
  8.     input           clk,         // 系统时钟
  9.     input           rst,         // 异步复位,低电平有效
  10.     input   [7:0]   tx_data,     // 待发送数据(8位)
  11.     input           tx_data_vld, // 数据有效信号(高电平有效)
  12.     output  wire    ready,       // 发送就绪信号(高电平表示可以接收新数据)
  13.     output  reg     tx           // 串行数据输出
  14. );
  15. // ===== 参数定义 =====
  16. parameter MAX_1bit = CLOCK/BUAD;  // 每bit所需的时钟周期数
  17. // 状态定义(独热码编码)
  18. localparam IDLE   = 5'b00001,  // 空闲状态
  19.            START  = 5'b00010,  // 起始位
  20.            DATA   = 5'b00100,  // 数据位
  21.            CHECK  = 5'b01000,  // 校验位
  22.            STOP   = 5'b10000;  // 停止位
  23. // ===== 寄存器定义 =====
  24. reg [4:0] cstate;      // 当前状态
  25. reg [4:0] nstate;      // 下一状态
  26. reg [19:0] cnt_baud;   // 波特率计数器
  27. reg [2:0] cnt_bit;     // 位计数器(计数当前发送的bit数)
  28. reg [3:0] bit_max;     // 各状态需要计数的最大bit数
  29. reg [7:0] tx_data_r;   // 发送数据寄存器
  30. // ===== 状态转移条件 =====
  31. wire IDLE_START;   // 空闲→起始位
  32. wire START_DATA;   // 起始位→数据位
  33. wire DATA_CHECK;   // 数据位→校验位
  34. wire DATA_STOP;    // 数据位→停止位(无校验时)
  35. wire CHECK_STOP;   // 校验位→停止位
  36. wire STOP_IDLE;    // 停止位→空闲
  37. // ===== 计数器控制信号 =====
  38. wire add_cnt_baud; // 波特率计数器递增使能
  39. wire end_cnt_baud; // 波特率计数器结束(达到1bit时间)
  40. wire add_cnt_bit;  // 位计数器递增使能
  41. wire end_cnt_bit;  // 位计数器结束(达到当前状态所需bit数)
  42. // ===== 校验位计算 =====
  43. wire check_val;    // 校验位值
  44. // ==============================================
  45. // 波特率计数器(控制每个bit的持续时间)
  46. // ==============================================
  47. always @(posedge clk or negedge rst) begin
  48.     if(!rst) begin
  49.         cnt_baud <= 'd0;
  50.     end else if(add_cnt_baud) begin
  51.         if(end_cnt_baud) begin
  52.             cnt_baud <= 'd0;  // 计数器归零
  53.         end else begin
  54.             cnt_baud <= cnt_baud + 1'd1;  // 计数器递增
  55.         end
  56.     end
  57. end
  58. assign add_cnt_baud = (cstate != IDLE);  // 非空闲状态下计数
  59. assign end_cnt_baud = (add_cnt_baud && (cnt_baud == MAX_1bit - 1'd1));  // 达到1bit时间
  60. // ==============================================
  61. // 位计数器(计数当前状态已发送的bit数)
  62. // ==============================================
  63. always @(posedge clk or negedge rst) begin
  64.     if(!rst) begin
  65.         cnt_bit <= 'd0;
  66.     end else if(add_cnt_bit) begin
  67.         if(end_cnt_bit) begin
  68.             cnt_bit <= 'd0;  // 计数器归零
  69.         end else begin
  70.             cnt_bit <= cnt_bit + 1'd1;  // 计数器递增
  71.         end
  72.     end
  73. end
  74. assign add_cnt_bit = end_cnt_baud;  // 每bit时间结束时递增
  75. assign end_cnt_bit = (add_cnt_bit && (cnt_bit == bit_max - 1'd1));  // 达到当前状态所需bit数
  76. // ==============================================
  77. // 各状态需要计数的bit数
  78. // ==============================================
  79. always @(*) begin
  80.     case (cstate)
  81.         IDLE  : bit_max = 'd0;   // 空闲状态不计数
  82.         START : bit_max = 'd1;   // 起始位(1bit)
  83.         DATA  : bit_max = 'd8;   // 数据位(8bit)
  84.         CHECK : bit_max = 'd1;   // 校验位(1bit)
  85.         STOP  : bit_max = 'd1;   // 停止位(1bit)
  86.         default: bit_max = 'd0;
  87.     endcase
  88. end
  89. // ==============================================
  90. // 状态转移条件
  91. // ==============================================
  92. assign IDLE_START = (cstate == IDLE) && tx_data_vld;  // 空闲时收到有效数据
  93. assign START_DATA = (cstate == START) && end_cnt_bit; // 起始位发送完成
  94. assign DATA_STOP  = (cstate == DATA) && end_cnt_bit && (CHECK_BIT == "None"); // 无校验时直接到停止位
  95. assign DATA_CHECK = (cstate == DATA) && end_cnt_bit && (CHECK_BIT != "None"); // 有校验时到校验位
  96. assign CHECK_STOP = (cstate == CHECK) && end_cnt_bit; // 校验位发送完成
  97. assign STOP_IDLE  = (cstate == STOP) && end_cnt_bit;  // 停止位发送完成
  98. // ==============================================
  99. // 状态寄存器
  100. // ==============================================
  101. always @(posedge clk or negedge rst) begin
  102.     if(!rst) begin
  103.         cstate <= IDLE;  // 复位到空闲状态
  104.     end else begin
  105.         cstate <= nstate; // 状态更新
  106.     end
  107. end
  108. // ==============================================
  109. // 状态转移逻辑(有限状态机)
  110. // ==============================================
  111. always @(*) begin
  112.     case(cstate)
  113.         IDLE: begin
  114.             if (IDLE_START) nstate = START;  // 收到数据,进入起始位
  115.             else nstate = cstate;            // 保持空闲
  116.         end
  117.         START: begin
  118.             if (START_DATA) nstate = DATA;   // 起始位完成,进入数据位
  119.             else nstate = cstate;            // 保持起始位
  120.         end
  121.         DATA: begin
  122.             if (DATA_CHECK) nstate = CHECK;  // 有校验时进入校验位
  123.             else if (DATA_STOP) nstate = STOP; // 无校验时直接到停止位
  124.             else nstate = cstate;            // 保持数据位
  125.         end
  126.         CHECK: begin
  127.             if (CHECK_STOP) nstate = STOP;  // 校验位完成,进入停止位
  128.             else nstate = cstate;           // 保持校验位
  129.         end
  130.         STOP: begin
  131.             if (STOP_IDLE) nstate = IDLE;  // 停止位完成,回到空闲
  132.             else nstate = cstate;          // 保持停止位
  133.         end
  134.         default: nstate = cstate;          // 默认保持当前状态
  135.     endcase
  136. end
  137. // ==============================================
  138. // 发送数据寄存器(锁存输入数据)
  139. // ==============================================
  140. always @(posedge clk or negedge rst) begin
  141.     if (!rst) begin
  142.         tx_data_r <= 'd0;  // 复位清零
  143.     end else if (tx_data_vld) begin
  144.         tx_data_r <= tx_data;  // 锁存有效数据
  145.     end
  146. end
  147. // ==============================================
  148. // 校验位计算
  149. // ==============================================
  150. // 奇校验:1的个数为奇数时校验位=0
  151. // 偶校验:1的个数为偶数时校验位=0
  152. assign check_val = (CHECK_BIT == "Odd") ? ~^tx_data_r : ^tx_data_r;
  153. // ==============================================
  154. // 串行数据输出
  155. // ==============================================
  156. always @(*) begin
  157.     case (cstate)
  158.         IDLE  : tx = 1'b1;               // 空闲时保持高电平
  159.         START : tx = 1'b0;               // 起始位(低电平)
  160.         DATA  : tx = tx_data_r[cnt_bit]; // 数据位(LSB first)
  161.         CHECK : tx = check_val;          // 校验位
  162.         STOP  : tx = 1'b1;               // 停止位(高电平)
  163.         default: tx = 1'b1;
  164.     endcase
  165. end
  166. // ==============================================
  167. // 就绪信号(空闲时可接收新数据)
  168. // ==============================================
  169. assign ready = (cstate == IDLE);
  170. endmodule
复制代码
五、管脚束缚


声明: 本代码借鉴网络资料,如有侵权请联系作者删除,如有错误请在批评区或者私信作者改正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表