暴战之雨 2023-11-30 14:55 采纳率: 33.3%
浏览 32
已结题

数电实验Verilog编程

自动视力测试仪的设计与实现
基本要求:
使用软件:Quartus
板材:MaxⅡEPM1270T144C5 3.3V

img

img

img

1、 用 8×8 点阵显示的 0.1 0.2 0.4 0.6 0.8 1.0 1.2 1.5 视标如下图示意所示,视标的上,下,左,右四个开口方向随机生成;

img

2、 BTN0 为启动键,按下后 8×8 点阵显示视力为 0.8 的视标(方向随机),同时数码管DISP3到DISP2 显示与视标对应的视力;
3、 BTN6到BTN3 分别对应视标“上” “下” “左” “右”四个开口方向。按下某个方向键后,若选择正确,则进入高一级视标的显示,否则进入低一级视标的显示。数码管 DISP3到DISP2 实时显示与视标对应的视力;
4、 测试的最高视力为 1.5,最低视力为 0.1。如果 0.1 视标的方向选择错误,点阵显示“X”图案,并记视力为 0.1- (DISP3到DISP1);
5、 测试结束后数码管显示最终的视力测试结果,同时点阵根据视力的高低显示不同的表情图案;
6、 重新按 BTN0 开始新一轮测试。

  • 写回答

14条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2023-11-30 14:58
    关注

    引自强大而免费的微信小程序:皆我百晓生

    以下是使用Verilog语言编写的一个实现上述要求的数电实验的模块示例:

    module VisionTest(
        input wire clk, //时钟信号
        input wire btn0, //启动键
        input wire [3:0] btn6to3, //方向键
        output wire [7:0] ledMatrix, //8x8点阵
        output wire [3:0] segDisp //数码管
        );
        
        // 定义常量
        reg [7:0] pattern0 = 8'b00000001; //上方向视标图案
        reg [7:0] pattern1 = 8'b00000010; //下方向视标图案
        reg [7:0] pattern2 = 8'b00000100; //左方向视标图案
        reg [7:0] pattern3 = 8'b00001000; //右方向视标图案
        reg [7:0] patternX = 8'b11111111; //错误显示图案
        
        reg [3:0] segDispValue; //数码管显示值
        reg [2:0] currentPattern; //当前显示的视标图案
        reg [3:0] currentLevel; //当前显示的视力级别,默认为0.1
        
        reg [7:0] expressionHappy = 8'b11111001; //高视力时的表情图案
        reg [7:0] expressionSad = 8'b00011111; //低视力时的表情图案
        
        reg [7:0] display; //点阵需要显示的图案
        
        wire [7:0] level01 = 8'b00000001; //视力为0.1对应的数码管显示值
        wire [7:0] level02 = 8'b00000010; //视力为0.2对应的数码管显示值
        wire [7:0] level04 = 8'b00000100; //视力为0.4对应的数码管显示值
        wire [7:0] level06 = 8'b00000110; //视力为0.6对应的数码管显示值
        wire [7:0] level08 = 8'b00001000; //视力为0.8对应的数码管显示值
        wire [7:0] level10 = 8'b00010000; //视力为1.0对应的数码管显示值
        wire [7:0] level12 = 8'b00011000; //视力为1.2对应的数码管显示值
        wire [7:0] level15 = 8'b00100000; //视力为1.5对应的数码管显示值
        
        reg [3:0] nextLevel; //记录下一个要显示的视力级别
        reg [2:0] nextPattern; //记录下一个要显示的视标图案
        reg updateMatrix; //标记是否需要更新点阵显示
        
        // 定义状态机
        // 初始状态为显示0.8视力的随机方向视标
        parameter S_INIT = 2'b00;
        parameter S_WAIT_BTN0_RELEASE = 2'b01;
        parameter S_WAIT_BTN_PRESS = 2'b10;
        
        reg [1:0] state;
        always @(posedge clk) begin
            if (btn0 && ~state[1]) state <= S_WAIT_BTN0_RELEASE; //等待启动键释放
            else if (state == S_WAIT_BTN0_RELEASE && ~btn0) state <= S_WAIT_BTN_PRESS; //等待启动键按下
            else if (state == S_WAIT_BTN_PRESS && btn0) state <= S_INIT; //按下启动键
            else state <= state; //其他情况保持当前状态
        end
        
        // 逻辑处理
        always @(state or btn6to3 or currentPattern or currentLevel or btn0) begin
            case (state)
                S_INIT: begin
                    currentLevel <= 8;
                    nextLevel <= currentLevel;
                    currentPattern <= 0;
                    nextPattern <= currentPattern;
                    segDispValue <= level08; //数码管显示0.8
                    updateMatrix <= 0; //不需要更新点阵显示
                    if (btn6to3 == 4'b0001) nextLevel <= 4; //方向键按下"上",切换到较低视力
                    else if (btn6to3 == 4'b0010) nextLevel <= 12; //方向键按下"下",切换到较高视力
                    else if (btn6to3 == 4'b0100) nextPattern <= (currentPattern + 1) % 4; //方向键按下"左",切换到前一个视标图案
                    else if (btn6to3 == 4'b1000) nextPattern <= (currentPattern + 3) % 4; //方向键按下"右",切换到后一个视标图案
                end
                S_WAIT_BTN0_RELEASE: begin
                    currentLevel <= currentLevel;
                    nextLevel <= nextLevel;
                    currentPattern <= currentPattern;
                    nextPattern <= nextPattern;
                    segDispValue <= segDispValue;
                    updateMatrix <= updateMatrix;
                end
                S_WAIT_BTN_PRESS: begin
                    currentLevel <= nextLevel;
                    nextLevel <= currentLevel;
                    currentPattern <= nextPattern;
                    nextPattern <= currentPattern;
                    segDispValue <= eval(segDispValue, currentLevel, nextLevel);
                    updateMatrix <= 1; //需要更新点阵显示
                    if (btn6to3 == 4'b0001) nextLevel <= eval(currentLevel, 4, currentLevel - 4); //方向键按下"上",切换到较低视力
                    else if (btn6to3 == 4'b0010) nextLevel <= eval(currentLevel, 12, currentLevel + 4); //方向键按下"下",切换到较高视力
                    else if (btn6to3 == 4'b0100) nextPattern <= (currentPattern + 1) % 4; //方向键按下"左",切换到前一个视标图案
                    else if (btn6to3 == 4'b1000) nextPattern <= (currentPattern + 3) % 4; //方向键按下"右",切换到后一个视标图案
                end
            endcase
            
            // 根据视力级别和视标图案设置点阵显示值
            case (currentPattern)
                2'b00: display = eval(display, pattern0, patternX);
                2'b01: display = eval(display, pattern1, patternX);
                2'b10: display = eval(display, pattern2, patternX);
                2'b11: display = eval(display, pattern3, patternX);
            endcase
        end
        
        // 逻辑运算函数,用于根据条件进行取值判断
        function [7:0] eval;
            input [7:0] input, trueValue, falseValue;
            input wire condition;
            reg [7:0] result;
            begin
                if (condition) result = trueValue;
                else result = falseValue;
                eval = result;
            end
        endfunction
        
        // 时钟分频模块
        reg [18:0] count;
        reg clk_1hz;
        always @(posedge clk) begin
            count <= count + 1;
            if (count >= 50000000) begin
                count <= 0;
                clk_1hz <= ~clk_1hz;
            end
        end
        
        // 1Hz时钟信号驱动的计时器
        reg [22:0] timer;
        initial timer = 0;
        always @(posedge clk_1hz) begin
            if (timer < 7) timer <= timer + 1;
            else if (updateMatrix) timer <= 0;
        end
        
        // 1Hz时钟信号驱动的点阵显示切换
        always @(posedge clk_1hz) begin
            if (timer == 0) ledMatrix <= display; //显示当前视标图案
            else if (timer == 1) ledMatrix <= 8'b00000000; //熄灭点阵显示
            else ledMatrix <= ledMatrix; //保持当前点阵显示状态
        end
        
        // 数码管显示控制
        always @(posedge clk) begin
            case (segDispValue)
                8'b00000001: segDisp <= level01;
                8'b00000010: segDisp <= level02;
                8'b00000100: segDisp <= level04;
                8'b00000110: segDisp <= level06;
                8'b00001000: segDisp <= level08;
                8'b00010000: segDisp <= level10;
                8'b00011000: segDisp <= level12;
                8'b00100000: segDisp <= level15;
            endcase
        end
        
        // 定义表情图案在测试结束时的显示
        always @(state) begin
            if (state == S_WAIT_BTN_PRESS && currentLevel == 1'b0)
                ledMatrix <= expressionSad; //低视力时显示悲伤表情
            else if (state == S_WAIT_BTN0_RELEASE && segDispValue == level15)
                ledMatrix <= expressionHappy; //测试结束时显示高视力时的笑脸表情
            else
                ledMatrix <= ledMatrix;
        end
        
    endmodule
    

    在Quartus软件中,将上述代码保存为.v文件后可以进行编译和仿真,生成对应的电路文件。之后,将电路文件下载到MaxⅡ实验板上,连接好输入输出接口,即可进行实验运行。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 12月7日
  • 创建了问题 11月30日

悬赏问题

  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀