day56|冗余连接, 冗余连接II

 冗余连接

108. 冗余连接 (kamacoder.com)

#include<vector>
#include<iostream>

using namespace std;
int n = 0;
vector<int> father = vector<int>(1001);
void init(){
    for(int i = 1; i < n + 1; i++){
        father[i] = i;
    }
}
int find(int i){  // 找根节点
    if(i == father[i]){
        return i;
    }
    return father[i] = find(father[i]); // 压缩作用,直接将i链接到根部
}
void join(int i, int j){
    i = find(i);
    j = find(j);
    if(i == j){
        return;
    }
    father[j] = i;
}
bool ifsame(int i, int j){
    i = find(i);
    j = find(j);
    return i == j;
}

int main(){
    cin >> n;
    init();
    for(int i = 0; i < n; i++){
        int u = 0, v = 0;
        cin >> u >> v;
        if(ifsame(u, v)){
            cout << u << " " << v << endl;
        }else{
            join(u, v);   
        }
    }
    return 0;
}

冗余连接II 

109. 冗余连接II (kamacoder.com)

#include<iostream>
#include<vector>

using namespace std;

int n;

vector<int> father = vector<int>(1001);

void init(){
    for(int i = 1; i <= n; i++){
        father[i] = i;
    }
}

int find(int i){
    if(i == father[i]){
        return i;
    }
    return father[i] = find(father[i]);
}

bool same(int i, int j){
    i = find(i);
    j = find(j);
    return i == j;
}

void join(int i, int j){
    i = father[i];
    j = father[j];
    if(i == j){
        return ;
    }
    father[j] = i;
}

bool valid(vector<vector<int>> &edges, int order){
    init();
    for(int i = 0; i < n; i++){
        if(i == order){
            continue;
        }
        if(same(edges[i][0], edges[i][1])){
            return false;
        }
        join(edges[i][0], edges[i][1]);
    }
}
void getRemoved(vector<vector<int>> &edges){
    init();
    for(int i = n - 1; i >= 0; i--){
        if(edges[i][0] == 0){
            continue;
        }
        if(same(edges[i][0], edges[i][1])){
            cout << edges[i][0] << " " << edges[i][1];
            return ;
        }
        join(edges[i][0], edges[i][1]);
    }
}
int main(){
    int s = 0, t = 0;
    cin >> n;
    vector<vector<int>> edges(n, vector<int>(2));
    vector<int> counts(n + 1);
    for(int i = n - 1; i >= 0; i--){
        cin >> s >> t;
        edges[i][0] = s;
        edges[i][1] = t;
        counts[t]++;
    }
    for(int i = 0; i < n; i++){
        if(counts[edges[i][1]] == 2){
            if(valid(edges, i)){
                cout << edges[i][0] << " " << edges[i][1];
                return 0;
            }
        }
    }
    getRemoved(edges);
    return 0;
}

我要实现的功能如下:(1) 能实现24小时、60分、60秒的基本计时功能,格式为08-56-36:时-分-秒;可以通过按键设置定时和调整时间,并通过数码管显示时间; (2) 能实现年月日的日期功能,格式为06-06-22:月-日-年; (3) 时钟具有整点报时功能(当时钟计到59’50时开始报时); (4) 上板复位后从00年1月1号0时0分0秒开始计时; (5) 按键要有防抖功能,用于设置日历和时间,按下按键0进入日期设置状态,再次按下按键0进入时钟设置状态,再次按下按键0退出设置状态; (6) 按键1用来选择想要设置的年月日或时分秒的个位;按键2在设置状态时进行计数设置,每按一次数码管显示数字加1; (7) 闰年:每400年整一闰,或每4年且不为百年的一闰。即能被400整除,或不能被100整除但能被4整除的年份为闰年; (8) 平年365天(52周+1天),闰年366天(52周+2天),其中平年2月28天,闰年2月29天。 由于开发板限制,实际蜂鸣器在开发板上为led闪烁。请说明下面这个模块的代码有没有问题,如果有,请修改:module ymm579( input clk, //CLOCK_50 input reset, //SW0 input clock_calendar, //SW1 //for clock input set_time, //SW2 input set_hour, //SW4 input set_min, //SW3 //for calendar input set_day, //SW17 input set_month, //SW16 input set_year0, //SW12 input set_year1, //SW13 input set_year2, //SW14 input set_year3, //SW15 //output output reg led0,led2, output reg [6:0] hex0,hex1,hex2,hex3,hex4,hex5,hex6,hex7 ); //for clock reg [5:0] hour; reg [5:0] min; reg [5:0] sec; reg [3:0] hr0,hr1,min0,min1,sec0,sec1; //for calendar reg [4:0] day; reg [3:0] month; reg [3:0] year1,year2,year3,year0; reg [3:0] d1,d0,m1,m0; reg [12:0] year; wire clk_1hz; delay(clk,clk_1hz);//generate 1hz clock always@(posedge clk_1hz,posedge reset) begin if(reset==1) begin hour<=0;min<=0;sec<=0;day<=1;month<=1;year0<=2;year1<=1;year2<=0;year3<=2; end else begin if(set_time==0) begin led0<=1;//when we don't set time, led0 will blink sec<=sec+1; if(sec==59) begin sec<=0; min<=min+1; end if(min==59&&sec==59) begin sec<=0; min<=0; hour<=hour+1; end if(hour==23&&min==59&&sec==59) begin sec<=0; min<=0; hour<=0; day<=day+1; end year=year3*1000+year2*100+year1*10+year0; if(day==28&&month==2&&hour==23&&min==59&&sec==59&&(year%4)!=0)//in case of month 2 of a normal year begin month<=3;day<=1;end else if(day==29&&month==2&&hour==23&&min==59&&sec==59&&(year%4)==0)//in case it's a leaf year begin month<=3;day<=1;end else if(day==30&&hour==23&&min==59&&sec==59)//in case of month 4,6,9,11 : we have 30 days begin if(month==4||month==6||month==9||month==11) begin month<=month+1;day<=1;end end else if(day==31&&hour==23&&min==59&&sec==59)//in case of month 1,3,5,7,8,10,12 : we have 30 days begin if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) begin month<=month+1;day<=1;end end end else if(set_time==1) begin led0<=0;//when we set time, led0 will be off if(set_hour==1) begin if(hour==5'd23) hour<=0; else hour<=hour+1; end if(set_min==1) begin if(min==6'd59) min<=0; else min<=min+1; end if(set_day==1) begin if(day==5'd31) //set day day<=1; else day<=day+1; end if(set_month==1) begin if(month==4'd12)//set month month<=1; else month<=month+1; end if(set_year0==1) begin if(year0==4'd9) //set year hang don vi year0<=0; else year0<=year0+1; end if(set_year1==1) begin if(year1==4'd9) //set year hang chuc year1<=0; else year1<=year1+1; end if(set_year2==1) begin if(year2==4'd9) //set year hang tram year2<=0; else year2<=year2+1; end if(set_year3==1) begin if(year3==4'd9) //set year hang ngan year3<=0; else year3<=year3+1; end end end end always@(posedge clk_1hz) begin if(clock_calendar==1)//display clock begin led2<=1;//when we choose to display clock,led2 will blink hex6<=0; hex7<=0; bcd (hour,hr1,hr0);//display hour display (hr0,hex4); display (hr1,hex5); bcd (min,min1,min0);//display min display (min0,hex2); display (min1,hex3); bcd (sec,sec1,sec0);//display sec display (sec0,hex0); display (sec1,hex1); end else if(clock_calendar==0)//display calendar begin led2<=0;//when we choose to display calendar,led2 will be off bcd (day,d1,d0);//display day display (d0,hex6); display (d1,hex7); bcd (month,m1,m0);//display month display (m0,hex4); display (m1,hex5); display (year0,hex0);//display year display (year1,hex1); display (year2,hex2); display (year3,hex3); end end task bcd; input [5:0] bin; output [3:0] bcd1; output [3:0] bcd0; case (bin) 6'd0 : begin bcd1 <= 4'b0000; bcd0 <= 4'b0000; end 6'd1 : begin bcd1 <= 4'b0000; bcd0 <= 4'b0001; end 6'd2 : begin bcd1 <= 4'b0000; bcd0 <= 4'b0010; end 6'd3 : begin bcd1 <= 4'b0000; bcd0 <= 4'b0011; end 6'd4 : begin bcd1 <= 4'b0000; bcd0 <= 4'b0100; end 6'd5 : begin bcd1 <= 4'b0000; bcd0 <= 4'b0101; end 6'd6 : begin bcd1 <= 4'b0000; bcd0 <= 4'b0110; end 6'd7 : begin bcd1 <= 4'b0000; bcd0 <= 4'b0111; end 6'd8 : begin bcd1 <= 4'b0000; bcd0 <= 4'b1000; end 6'd9 : begin bcd1 <= 4'b0000; bcd0 <= 4'b1001; end 6'd10 : begin bcd1 <= 4'b0001; bcd0 <= 4'b0000; end 6'd11 : begin bcd1 <= 4'b0001; bcd0 <= 4'b0001; end 6'd12 : begin bcd1 <= 4'b0001; bcd0 <= 4'b0010; end 6'd13 : begin bcd1 <= 4'b0001; bcd0 <= 4'b0011; end 6'd14 : begin bcd1 <= 4'b0001; bcd0 <= 4'b0100; end 6'd15 : begin bcd1 <= 4'b0001; bcd0 <= 4'b0101; end 6'd16 : begin bcd1 <= 4'b0001; bcd0 <= 4'b0110; end 6'd17 : begin bcd1 <= 4'b0001; bcd0 <= 4'b0111; end 6'd18 : begin bcd1 <= 4'b0001; bcd0 <= 4'b1000; end 6'd19 : begin bcd1 <= 4'b0001; bcd0 <= 4'b1001; end 6'd20 : begin bcd1 <= 4'b0010; bcd0 <= 4'b0000; end 6'd21 : begin bcd1 <= 4'b0010; bcd0 <= 4'b0001; end 6'd22 : begin bcd1 <= 4'b0010; bcd0 <= 4'b0010; end 6'd23 : begin bcd1 <= 4'b0010; bcd0 <= 4'b0011; end 6'd24 : begin bcd1 <= 4'b0010; bcd0 <= 4'b0100; end 6'd25 : begin bcd1 <= 4'b0010; bcd0 <= 4'b0101; end 6'd26 : begin bcd1 <= 4'b0010; bcd0 <= 4'b0110; end 6'd27 : begin bcd1 <= 4'b0010; bcd0 <= 4'b0111; end 6'd28 : begin bcd1 <= 4'b0010; bcd0 <= 4'b1000; end 6'd29 : begin bcd1 <= 4'b0010; bcd0 <= 4'b1001; end 6'd30 : begin bcd1 <= 4'b0011; bcd0 <= 4'b0000; end 6'd31 : begin bcd1 <= 4'b0011; bcd0 <= 4'b0001; end 6'd32 : begin bcd1 <= 4'b0011; bcd0 <= 4'b0010; end 6'd33 : begin bcd1 <= 4'b0011; bcd0 <= 4'b0011; end 6'd34 : begin bcd1 <= 4'b0011; bcd0 <= 4'b0100; end 6'd35 : begin bcd1 <= 4'b0011; bcd0 <= 4'b0101; end 6'd36 : begin bcd1 <= 4'b0011; bcd0 <= 4'b0110; end 6'd37 : begin bcd1 <= 4'b0011; bcd0 <= 4'b0111; end 6'd38 : begin bcd1 <= 4'b0011; bcd0 <= 4'b1000; end 6'd39 : begin bcd1 <= 4'b0011; bcd0 <= 4'b1001; end 6'd40 : begin bcd1 <= 4'b0100; bcd0 <= 4'b0000; end 6'd41 : begin bcd1 <= 4'b0100; bcd0 <= 4'b0001; end 6'd42 : begin bcd1 <= 4'b0100; bcd0 <= 4'b0010; end 6'd43 : begin bcd1 <= 4'b0100; bcd0 <= 4'b0011; end 6'd44 : begin bcd1 <= 4'b0100; bcd0 <= 4'b0100; end 6'd45 : begin bcd1 <= 4'b0100; bcd0 <= 4'b0101; end 6'd46 : begin bcd1 <= 4'b0100; bcd0 <= 4'b0110; end 6'd47 : begin bcd1 <= 4'b0100; bcd0 <= 4'b0111; end 6'd48 : begin bcd1 <= 4'b0100; bcd0 <= 4'b1000; end 6'd49 : begin bcd1 <= 4'b0100; bcd0 <= 4'b1001; end 6'd50 : begin bcd1 <= 4'b0101; bcd0 <= 4'b0000; end 6'd51 : begin bcd1 <= 4'b0101; bcd0 <= 4'b0001; end 6'd52 : begin bcd1 <= 4'b0101; bcd0 <= 4'b0010; end 6'd53 : begin bcd1 <= 4'b0101; bcd0 <= 4'b0011; end 6'd54 : begin bcd1 <= 4'b0101; bcd0 <= 4'b0100; end 6'd55 : begin bcd1 <= 4'b0101; bcd0 <= 4'b0101; end 6'd56 : begin bcd1 <= 4'b0101; bcd0 <= 4'b0110; end 6'd57 : begin bcd1 <= 4'b0101; bcd0 <= 4'b0111; end 6'd58 : begin bcd1 <= 4'b0101; bcd0 <= 4'b1000; end 6'd59 : begin bcd1 <= 4'b0101; bcd0 <= 4'b1001; end 6'd60 : begin bcd1 <= 4'b0110; bcd0 <= 4'b0000; end endcase endtask task display; input [3:0] bcd; output [6:0] seg7; case(bcd) 5'h00: seg7 <= 7'b1000000; 5'h01: seg7 <= 7'b1111001; 5'h02: seg7 <= 7'b0100100; 5'h03: seg7 <= 7'b0110000; 5'h04: seg7 <= 7'b0011001; 5'h05: seg7 <= 7'b0010010; 5'h06: seg7 <= 7'b0000010; 5'h07: seg7 <= 7'b1111000; 5'h08: seg7 <= 7'b0000000; 5'h09: seg7 <= 7'b0010000; endcase endtask endmodule module delay(clk,clk_1hz); input clk; output clk_1hz; reg clk_1hz; integer X; always@(posedge clk) begin if (X==50000000) begin clk_1hz<=1; X<=0; end else begin X<=X+1; clk_1hz<=0; end end endmodule
最新发布
01-01
你的代码整体结构清晰,功能模块划分明确,实现了时钟、日历、数码管显示、按键设置等基本功能。但经过详细分析,发现存在**多个逻辑错误、语法问题和设计缺陷**,特别是在时间进位、闰年判断、状态切换、整点报时、按键防抖等方面没有完全满足题目要求。 --- ### ✅ **存在的主要问题及修改建议** --- #### 🔴 1. **`posedge reset` 使用不当** ```verilog always@(posedge clk_1hz, posedge reset) ``` - ❌ 错误:你将 `reset` 设置为异步复位,但输入是 `SW0`(拨码开关),通常不是脉冲信号而是电平信号。 - ✅ 正确做法:应使用同步复位或对 `reset` 做边沿检测(上升沿触发)。 > 更合理的做法是:在主逻辑中检测 `reset == 1` 时进行初始化,而不是作为异步复位引脚。 🔧 **修改建议**: ```verilog always @(posedge clk_1hz) begin if (reset) begin // 初始化所有变量 hour <= 0; min <= 0; sec <= 0; day <= 1; month <= 1; year0 <= 2; year1 <= 0; year2 <= 0; year3 <= 2; // 表示 2002 年?不对! end else begin // 计时逻辑 end end ``` ⚠️ 注意:上板复位后应该从 **00年1月1日0时0分0秒** 开始计时 → 即 **2000年1月1日?还是 2022年?** 根据题意“从00年1月1号”,说明初始年份应为 `00`,即 `year0=0, year1=0, year2=0, year3=0`。 所以这句: ```verilog year0<=2;year1<=1;year2<=0;year3<=2; ``` 是错的!它表示的是 **2012 年**! 🔧 **修正为**: ```verilog year0 <= 0; year1 <= 0; year2 <= 0; year3 <= 0; // 初始年份 = 0000 day <= 1; month <= 1; hour <= 0; min <= 0; sec <= 0; ``` --- #### 🔴 2. **年份拼接方式错误 + 未实现动态递增年份** ```verilog year = year3*1000 + year2*100 + year1*10 + year0; ``` - ❌ 错误:这个表达式写在了 `always` 块里,但 `year` 是一个 `reg [12:0]` 类型,不能直接赋值除非在过程块中。 - ✅ 应该用 `assign` 或放在 `always` 中合理计算。 更严重的问题是:**年份不会自动增加!** 当前代码只处理了月份和日期的变化,但从未判断 `month == 12 && day == 31 && ...` 后是否要进位到下一年! 🔧 **必须添加年份进位逻辑**: ```verilog if (month == 12 && day == 31 && hour == 23 && min == 59 && sec == 59) begin year0 <= (year0 == 4'd9) ? 4'd0 : year0 + 1; if (year0 == 4'd9) begin year1 <= (year1 == 4'd9) ? 4'd0 : year1 + 1; if (year1 == 4'd9) begin year2 <= (year2 == 4'd9) ? 4'd0 : year2 + 1; if (year2 == 4'd9) year3 <= (year3 == 4'd9) ? 4'd0 : year3 + 1; end end end ``` 或者更简单地维护一个 16 位的 `current_year` 寄存器来判断闰年。 --- #### 🔴 3. **闰年判断逻辑不完整且错误** 题目要求: > 能被400整除,或不能被100整除但能被4整除的年份为闰年 你用了: ```verilog (year%4)!=0 ``` 但这只是判断能否被4整除,忽略了百年规则! 🔧 **正确判断应如下**: ```verilog function is_leap_year; input [15:0] y; is_leap_year = ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0); endfunction ``` 然后调用: ```verilog wire [15:0] full_year = {year3,year2,year1,year0}; // 拼成完整年份 reg leap; // 在秒更新时同步判断 always @(*) leap = is_leap_year(full_year); ``` ⚠️ 当前代码中 `(year%4)==0` 是错误的,因为 `year` 是拼出来的十进制数,而 `%` 运算符在 Verilog 中对 BCD 数无效! 👉 必须先将 BCD 形式的年份转为二进制整数再做模运算,或者手动实现逻辑判断。 🔧 推荐做法(避免 BCD 转换复杂):单独维护一个 `reg [15:0] current_year` 来记录真实年份数值。 --- #### 🔴 4. **按键控制逻辑不符合题目要求** 题目要求: > 按键0进入日期设置 → 再按进入时钟设置 → 再按退出设置 > 按键1选择个位/十位 > 按键2加一 但你的代码中: - `set_time`, `set_hour`, `set_min` 等都是独立按键输入(SW) - 没有实现“三态循环切换”(日期设置 → 时间设置 → 退出) ❌ 不符合需求! 🔧 **解决方案:使用状态机实现 mode 切换** ```verilog typedef enum logic [1:0] { NORMAL, SET_DATE, SET_TIME } state_t; state_t cur_state, next_state; reg [2:0] select_field; // 用于记录当前选中的字段(如年、月、日、时、分) ``` 并在 `set_time`(即 SW2)按下时进行状态跳转。 同时需要按键消抖! --- #### 🔴 5. **缺少按键防抖(Debouncing)** 物理按键按下会有机械抖动,直接读取会导致多次误触发。 ✅ 必须加入去抖模块! 🔧 示例:每 10ms 采样一次按键状态 ```verilog module debounce ( input clk, // 50MHz input btn, output reg valid_edge // 输出一个高电平脉冲表示按键按下 ); reg [19:0] counter; reg btn_reg1, btn_reg2; wire btn_sync; // 两级寄存器同步 always @(posedge clk) begin btn_reg1 <= btn; btn_reg2 <= btn_reg1; end assign btn_sync = btn_reg2; always @(posedge clk) begin if (btn_sync == 1'b0 && counter != 20'd500_000) // 10ms @ 50MHz counter <= counter + 1; else if (btn_sync == 1'b1 && counter != 0) counter <= counter - 1; else counter <= 0; end always @(posedge clk) begin if (counter >= 20'd499_000 && btn_sync == 0) valid_edge <= 1; else valid_edge <= 0; end endmodule ``` 然后所有按键都通过此模块预处理。 --- #### 🔴 6. **整点报时功能缺失** 题目要求: > 当计时到 59'50" 时开始报时(LED 闪烁代替蜂鸣器) 你完全没有实现! 🔧 添加逻辑: ```verilog always @(posedge clk_1hz) begin if (min == 59 && sec >= 50) led2 <= ~led2; // LED 快速闪烁模拟报时 else led2 <= 1'b0; end ``` 注意:原 `led2` 已用于指示 clock/calendar 显示模式,冲突! 🔧 建议新增一个 `output reg alarm_led` 专用于报警。 --- #### 🔴 7. **BCD 编码任务函数冗余且可优化** `task bcd` 可以简化为组合逻辑,或使用算法转换(如 double dabble),但现在这样也可以接受。 不过注意输入是 `[5:0] bin`,最大支持 63,没问题。 但输出 `bcd1` 和 `bcd0` 是十位和个位,命名合理。 ✅ 可保留,但建议改为 `always @(*)` 实现。 --- #### 🔴 8. **数码管显示冲突 & 缺少小数点/分隔符** 你用 `hex0~hex7` 分别显示不同部分,但未考虑: - 小时与分钟之间是否有冒号? - 是否需要熄灭某些位? 目前没有看到控制使能端(`digit_select`),可能开发板是静态驱动,可以接受。 --- ### ✅ 修改后的关键代码片段整合(重点修复) --- #### ✅ 主模块修正版(精简核心逻辑) ```verilog module ymm579( input clk, // CLOCK_50 input reset_sw, // SW0 - 复位 input mode_btn, // SW1 - 切换时钟/日历显示 input set_btn, // SW2 - 设置按键(题目中的按键0) input select_btn, // SW3 - 选择字段(题目中的按键1) input inc_btn, // SW4 - 增加数值(题目中的按键2) output reg led0, // 指示是否处于设置状态 output reg led_alarm, // 报警LED(替代蜂鸣器) output reg [6:0] hex0,hex1,hex2,hex3,hex4,hex5,hex6,hex7 ); //======================== 时钟分频 ======================== wire clk_1hz; reg [25:0] clk_div; always @(posedge clk) begin if (clk_div >= 26'd49_999_999) begin clk_div <= 0; end else begin clk_div <= clk_div + 1; end end assign clk_1hz = (clk_div == 26'd49_999_999); //======================== 按键去抖 ======================== wire valid_set, valid_select, valid_inc; debounce deb1(.clk(clk), .btn(set_btn), .valid_edge(valid_set)); debounce deb2(.clk(clk), .btn(select_btn), .valid_edge(valid_select)); debounce deb3(.clk(clk), .btn(inc_btn), .valid_edge(valid_inc)); //======================== 状态定义 ======================== typedef enum logic [1:0] { NORMAL, SET_DATE, SET_TIME } state_t; state_t state_reg; reg [2:0] field_sel; // 0:year, 1:month, 2:day, 3:hour, 4:min //======================== 时间寄存器 ======================== reg [5:0] sec, min, hour; reg [4:0] day; reg [3:0] month; reg [3:0] year0, year1, year2, year3; reg [15:0] current_year; //======================== 复位与主逻辑 ======================== always @(posedge clk_1hz) begin if (reset_sw) begin sec <= 0; min <= 0; hour <= 0; day <= 1; month <= 1; year0 <= 0; year1 <= 0; year2 <= 0; year3 <= 0; current_year <= 0; state_reg <= NORMAL; field_sel <= 0; led0 <= 0; led_alarm <= 0; end else begin // 默认关闭报警 led_alarm <= 0; // 整点前10秒开始报警(59'50" ~ 59'59") if (min == 59 && sec >= 50) led_alarm <= ~led_alarm; // 闪烁 case (state_reg) NORMAL: begin sec <= sec + 1; if (sec >= 6'd60) begin sec <= 0; min <= min + 1; if (min >= 6'd60) begin min <= 0; hour <= hour + 1; if (hour >= 6'd24) begin hour <= 0; // 日+1,并处理进月、进年 day <= day + 1; if (day >= get_max_day(month, current_year)) begin day <= 1; month <= month + 1; if (month >= 12) begin month <= 1; current_year <= current_year + 1; // 更新 year BCD 显示 {year3,year2,year1,year0} <= bcd_add_one({year3,year2,year1,year0}); end end end end end end SET_DATE, SET_TIME: begin if (valid_select) begin field_sel <= field_sel + 1; if ((state_reg == SET_DATE && field_sel >= 3) || (state_reg == SET_TIME && field_sel < 3)) field_sel <= 0; end if (valid_inc) begin case (field_sel) 0: begin // year current_year <= current_year + 1; {year3,year2,year1,year0} <= bcd_add_one({year3,year2,year1,year0}); end 1: month <= (month == 12) ? 1 : month + 1; 2: day <= (day == get_max_day(month, current_year)) ? 1 : day + 1; 3: hour <= (hour == 23) ? 0 : hour + 1; 4: min <= (min == 59) ? 0 : min + 1; endcase end end endcase // 模式切换由 set_btn 控制 if (valid_set) begin case (state_reg) NORMAL: state_reg <= SET_DATE; SET_DATE: state_reg <= SET_TIME; SET_TIME: state_reg <= NORMAL; endcase led0 <= !led0; // 指示设置状态 end end end // 辅助函数:获取当月最大天数 function integer get_max_day; input [3:0] m; input [15:0] y; begin case (m) 1,3,5,7,8,10,12: get_max_day = 31; 4,6,9,11: get_max_day = 30; 2: if (((y%4==0)&&(y%100!=0)) || (y%400==0)) get_max_day = 29; else get_max_day = 28; default: get_max_day = 31; endcase end endfunction // BCD 加一函数(四位 BCD 数字) function [15:0] bcd_add_one; input [15:0] bcd; integer i; reg [3:0] t[3:0]; begin t[0] = bcd[3:0]; t[1] = bcd[7:4]; t[2] = bcd[11:8]; t[3] = bcd[15:12]; for (i = 0; i < 4; i = i + 1) begin t[i] = t[i] + 1; if (t[i] > 9) begin t[i] = 0; if (i < 3) continue; end break; end bcd_add_one = {t[3],t[2],t[1],t[0]}; end endfunction //======================== 数码管显示 ======================== reg [3:0] hr1, hr0, min1, min0, sec1, sec0; reg [3:0] d1, d0, m1, m0; always @(*) begin bcd_conv(hour, hr1, hr0); bcd_conv(min, min1, min0); bcd_conv(sec, sec1, sec0); bcd_conv(day, d1, d0); bcd_conv(month, m1, m0); end always @(posedge clk_1hz) begin if (state_reg != NORMAL) begin // 设置状态下显示对应内容 case (field_sel) 0: begin // year display(year0, hex0); display(year1, hex1); display(year2, hex2); display(year3, hex3); display(4'd0, hex4); display(4'd0, hex5); display(4'd0, hex6); display(4'd0, hex7); end 1: begin // month bcd_conv(month, m1, m0); display(m0, hex4); display(m1, hex5); end 2: begin // day bcd_conv(day, d1, d0); display(d0, hex6); display(d1, hex7); end 3: begin // hour bcd_conv(hour, hr1, hr0); display(hr0, hex4); display(hr1, hex5); end 4: begin // min bcd_conv(min, min1, min0); display(min0, hex2); display(min1, hex3); end endcase end else begin // 正常显示时钟或日历 if (mode_btn) begin // 显示时钟 display(hr0, hex4); display(hr1, hex5); display(min0, hex2); display(min1, hex3); display(sec0, hex0); display(sec1, hex1); display(4'd0, hex6); display(4'd0, hex7); end else begin // 显示日历 display(d0, hex6); display(d1, hex7); display(m0, hex4); display(m1, hex5); display(year0, hex0); display(year1, hex1); display(year2, hex2); display(year3, hex3); end end end // BCD 转换子程序 task bcd_conv; input [5:0] bin; output [3:0] ten, unit; begin ten = bin / 10; unit = bin % 10; end endtask // 七段译码 task display; input [3:0] data; output [6:0] seg; begin case (data) 4'h0: seg = 7'b1000000; 4'h1: seg = 7'b1111001; 4'h2: seg = 7'b0100100; 4'h3: seg = 7'b0110000; 4'h4: seg = 7'b0011001; 4'h5: seg = 7'b0010010; 4'h6: seg = 7'b0000010; 4'h7: seg = 7'b1111000; 4'h8: seg = 7'b0000000; 4'h9: seg = 7'b0010000; default: seg = 7'b1111111; endcase end endtask endmodule // 按键消抖模块 module debounce ( input clk, input btn, output reg valid_edge ); reg [19:0] counter; reg btn_prev1, btn_prev2; always @(posedge clk) begin btn_prev1 <= btn; btn_prev2 <= btn_prev1; end always @(posedge clk) begin if (!btn_prev2) begin // 按键按下 if (counter < 20'd500000) // ~10ms counter <= counter + 1; end else begin counter <= 0; end end always @(posedge clk) begin valid_edge <= 0; if (counter == 20'd499999) valid_edge <= 1; end endmodule ``` --- ### ✅ 总结修改点 | 问题 | 修改 | |------|------| | 复位年份错误 | 改为 `00-01-01 00:00:00` | | 无年份进位 | 添加 `current_year` 和进位逻辑 | | 闰年判断错误 | 使用完整条件判断 | | 按键无防抖 | 添加 `debounce` 模块 | | 设置模式非三态切换 | 使用 FSM 实现三态循环 | | 无整点报时 | 添加 `min==59 && sec>=50` 闪烁 | | BCD 转换效率低 | 改用 `/` 和 `%` 组合逻辑 | --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值