数码管实现电子时钟

一.模块设计图

在这里插入图片描述

二.设计思路

2.1计数器设计

  • 设计四个计数器,第一个计50_000_000,表示计满1s;第二个计数器计数秒位;第三个计数器计数分钟位;第四个计数器计数小时位。
  • 计数器+1标志:秒计数器当计满一秒+1,分钟计数器当秒计数器计满60时+1,小时计数器当分钟计数器计满60时+1;所有计数器当计满清零。

2.2时序图

在这里插入图片描述

2.3传输数据

  • time_count模块有三个输出:[4:0]hour、[5:0]min、[5:0]sec。传输给seg_dirver模块。每一位数据如下:
    在这里插入图片描述

2.4余晖效应

  • 计数器计1ms,数码管每隔1ms做位拼接,肉眼无法分辨1ms的数码管位选变化,在视觉上就是数码管全亮的状态。

2.5设定小数点位

  • point_n可以在顶层模块例化模块是直接给它赋值,将数值位设为7位,考察data时(case(data))将小数点位和数值位拼接起来。可以实现小数点固定位亮。
    在这里插入图片描述

在这里插入图片描述

三.代码

  • time_count.v
/**************************************功能介绍***********************************
Date	: 2023年8月2日11:17:33
Author	: Alegg xy.
Version	: 1.0
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module time_count( 
    input				clk		,
    input				rst_n	,
    output      [4:0]   hour    ,
    output	    [5:0]	min	    ,
    output	    [5:0]	sec	    
);								 
//---------<参数定义>--------------------------------------------------------- 
    parameter MAX = 26'd50_000_000;//1s
    parameter MAX_sec = 6'd59;//一分钟60秒
    parameter MAX_min = 6'd59;//1小时60分钟
    parameter MAX_hour = 5'd23;//1天24小时
//---------<内部信号定义>-----------------------------------------------------
    reg			[25:0]	cnt	   	;
    wire				add_cnt	;
    wire				end_cnt	;

    reg			[5:0]	cnt_sec	   	;
    wire				add_cnt_sec	;
    wire				end_cnt_sec	;

    reg			[5:0]	cnt_min	   	;
    wire				add_cnt_min	;
    wire				end_cnt_min	;

    reg			[4:0]	cnt_hour	;
    wire				add_cnt_hour;
    wire				end_cnt_hour;
    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt <= 'd0;
        end 
        else if(add_cnt)begin 
            if(end_cnt)begin 
                cnt <= 'd0;
            end
            else begin 
                cnt <= cnt + 1'd1;
            end 
        end
    end 
    
    assign add_cnt = 1'b1;
    assign end_cnt = add_cnt && cnt == MAX - 1'd1;
    

    //秒计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_sec <= 'd0;
        end 
        else if(add_cnt_sec)begin 
            if(end_cnt_sec)begin 
                cnt_sec <= 'd0;
            end
            else begin 
                cnt_sec <= cnt_sec + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_sec = end_cnt;
    assign end_cnt_sec = add_cnt_sec && cnt_sec == MAX_sec;
    
    //分计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_min <= 'd0;
        end 
        else if(add_cnt_min)begin 
            if(end_cnt_min)begin 
                cnt_min <= 'd0;
            end
            else begin 
                cnt_min <= cnt_min + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_min = end_cnt_sec;
    assign end_cnt_min = add_cnt_min && cnt_min == MAX_min;
    
    //小时计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_hour <= 'd0;
        end 
        else if(add_cnt_hour)begin 
            if(end_cnt_hour)begin 
                cnt_hour <= 'd0;
            end
            else begin 
                cnt_hour <= cnt_hour + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_hour = end_cnt_min;
    assign end_cnt_hour = add_cnt_hour && cnt_hour == MAX_hour;
    
    
    assign hour = cnt_hour;
    assign min = cnt_min;
    assign sec = cnt_sec;
endmodule
  • seg_dirver.v
/**************************************功能介绍***********************************
Date	: 2023年8月2日13:44:09
Author	: Alegg xy.
Version	: 1.0
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module seg_driver( 
    input				clk		,
    input				rst_n	,
    input		[4:0]	hour	,
    input		[5:0]	min		,
    input		[5:0]	sec		,
    input       [5:0]   point_n ,

    output	reg	[5:0]	sel	    ,
    output	reg	[7:0]	seg	    
);								 
//---------<参数定义>--------------------------------------------------------- 
    parameter MAX_1ms = 50_000;//1ms
//---------<内部信号定义>-----------------------------------------------------
    reg [3:0]   data;//存数据
    reg [5:0]   point_n_r;//存小数点位

    reg			[15:0]	cnt_1ms	   	;
    wire				add_cnt_1ms	;
    wire				end_cnt_1ms	;
    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_1ms <= 'd0;
        end 
        else if(add_cnt_1ms)begin 
            if(end_cnt_1ms)begin 
                cnt_1ms <= 'd0;
            end
            else begin 
                cnt_1ms <= cnt_1ms + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_1ms = 1'b1;
    assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == MAX_1ms - 1'd1;
    
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            sel <= 6'b111_110;
        end  
        else if (end_cnt_1ms) begin
             sel <= {sel[4:0],sel[5]};
        end 
    end

    always @(*)begin 
        case (sel)
            6'b111_110:begin data = hour / 10;   point_n_r = point_n[0]; end
            6'b111_101:begin data = hour % 10;   point_n_r = point_n[1]; end
            6'b111_011:begin data = min / 10 ;   point_n_r = point_n[2]; end
            6'b110_111:begin data = min % 10 ;   point_n_r = point_n[3]; end
            6'b101_111:begin data = sec / 10 ;   point_n_r = point_n[4]; end
            6'b011_111:begin data = sec % 10 ;   point_n_r = point_n[5]; end
            default: data = 4'd0;
        endcase
    end
    
    always @(*)begin 
        case (data)
            4'h0:seg = {point_n_r,7'b100_0000};
            4'h1:seg = {point_n_r,7'b111_1001};
            4'h2:seg = {point_n_r,7'b010_0100};
            4'h3:seg = {point_n_r,7'b011_0000};
            4'h4:seg = {point_n_r,7'b001_1001};
            4'h5:seg = {point_n_r,7'b001_0010};
            4'h6:seg = {point_n_r,7'b000_0010};
            4'h7:seg = {point_n_r,7'b111_1000};
            4'h8:seg = {point_n_r,7'b000_0000};
            4'h9:seg = {point_n_r,7'b001_0000};
            default: seg = 8'b1100_0000;
        endcase
    end
    
endmodule

  • top_clock.v
/**************************************功能介绍***********************************
Date	: 2023年8月2日13:58:10
Author	: Alegg xy.
Version	: 1.0
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module top_clock( 
    input				clk		,
    input				rst_n	,
    input       [5:0]   point_n ,
    output		[5:0]	sel 	,
    output		[7:0]	seg	
);								 
//---------<参数定义>--------------------------------------------------------- 
    wire [4:0] hour_link;
    wire [5:0] min_link;
    wire [5:0] sec_link;
//---------<内部信号定义>-----------------------------------------------------
    time_count u_time_count(
        .clk		(clk),
        .rst_n	    (rst_n),
        .hour       (hour_link),
        .min	    (min_link),
        .sec	    (sec_link) 
    );
    
    seg_driver u_seg_dirver(
        .clk		(clk),
        .rst_n	    (rst_n),
        .hour	    (hour_link),
        .min		(min_link),
        .sec		(sec_link),
        .point_n    (6'b110101),
        .sel	    (sel),
        .seg	    (seg)
    );    
    
    
endmodule
eg_dirver(
        .clk		(clk),
        .rst_n	    (rst_n),
        .hour	    (hour_link),
        .min		(min_link),
        .sec		(sec_link),
        .point_n    (6'b110101),
        .sel	    (sel),
        .seg	    (seg)
    );    
    
    
endmodule
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现电子时钟需要以下步骤: 1. 确定使用的数码管型号,并连接到89c52单片机的端口上。 2. 编写程序实现时钟的计时和显示功能。可以使用定时器来计时,并在定时器中断中更新时钟的时间和数码管的显示。 3. 实现时钟的校准功能。可以在程序中加入按键检测,当按下校准键时,时钟停止计时,等待用户输入正确的时间,然后再重新开始计时。 4. 添加其他功能,例如闹钟、定时器等。 下面是一个简单的示例程序,用89c52单片机实现电子时钟的功能: ```c #include <reg52.h> #include <intrins.h> // 数码管引脚定义 #define DIG1 P1 #define DIG2 P1 #define DIG3 P1 #define DIG4 P1 #define SEG P0 // 定时器计数器初值 #define T0RH 0xFF #define T0RL 0x00 // 定义时间结构体 struct Time { unsigned char hour; unsigned char minute; unsigned char second; }; // 初始化定时器 void initTimer() { TMOD |= 0x01; // 定时器0工作在模式1 TH0 = T0RH; // 定时器计数器初值 TL0 = T0RL; TR0 = 1; // 启动定时器0 ET0 = 1; // 允许定时器0中断 EA = 1; // 开启全局中断 } // 定时器0中断服务函数 void timer0() interrupt 1 { static unsigned char count = 0; static struct Time time = {0, 0, 0}; count++; if (count == 20) { // 每1秒更新一次时间 count = 0; time.second++; if (time.second == 60) { time.second = 0; time.minute++; if (time.minute == 60) { time.minute = 0; time.hour++; if (time.hour == 24) { time.hour = 0; } } } } // 显示时间 DIG1 = 0x7F; // 显示小时的十位 SEG = time.hour / 10; _nop_(); DIG1 = 0xFF; DIG2 = 0xBF; // 显示小时的个位 SEG = time.hour % 10; _nop_(); DIG2 = 0xFF; DIG3 = 0xDF; // 显示分钟的十位 SEG = time.minute / 10; _nop_(); DIG3 = 0xFF; DIG4 = 0xEF; // 显示分钟的个位 SEG = time.minute % 10; _nop_(); DIG4 = 0xFF; } // 主函数 void main() { initTimer(); while (1); } ``` 在上面的程序中,数码管的引脚分别连接到单片机的P1和P0端口上,定时器0工作在模式1,每经过50ms就会产生一个中断,因此计数器初值为65536-5000=60536,即0xEE38。在定时器中断服务函数中,每经过20次中断(1秒),就会更新一次时间并显示到数码管上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值