原理
数字时钟:我这里实现的是数码管显示,外加设置时间功能和闹钟功能,闹钟就是蜂鸣器,没有其他的功能。
状态机:这里就不具体介绍了,上一篇已经介绍过了。
实现
设计:
1)按键消抖模块
2)控制模块(实现状态机,产生数码管显示数据,输出蜂鸣器信号,主要模块)
3)数码管驱动模块
4)蜂鸣器驱动模块
按键消抖就不粘贴复制了,上一篇博客很清楚了,
驱动
控制模块
别看代码多,大部分粘贴复制再改下信号名
我认为逻辑还是比较清晰了
分三个功能,正常显示时间(时间计数器),设置时间(再定义一组寄存器,结构和时间计数器一样,就是加1条件不太一样,基本是用按键控制的),设置闹钟(同设置时间一样)
module control(
input clk ,
input rst_n ,
input [2:0] key ,
output [23:0] time_data ,
output alarm_clk_flag ,
output [5:0] shan_shuo
);
localparam TIME_1S = 50_000_000;
localparam IDLE = 3'b001;
localparam SET_TIME = 3'b010;
localparam SET_ALARM = 3'b100;
wire idle2set_time;
wire idle2set_alarm;
wire set_time2idle;
wire set_alarm2idle;
reg [2:0] state_c;
reg [2:0] state_n;
reg [5:0] shanshuo_r;//闪烁标志,选中位0/1不停变换
reg set_time_flag;//设置时间标志
reg set_alarm_flag;//设置闹钟标志
reg [23:0] time_data_r;
reg [25:0] cnt_1s;//1s计数器
wire add_cnt_1s;
wire end_cnt_1s;
reg [3:0] cnt0;//s个位计数器
wire add_cnt0;
wire end_cnt0;
reg [3:0] cnt1;//s十位计数器
wire add_cnt1;
wire end_cnt1;
reg [3:0] cnt2;//m个位计数器
wire add_cnt2;
wire end_cnt2;
reg [3:0] cnt3;//m十位计数器
wire add_cnt3;
wire end_cnt3;
reg [3:0] cnt4;//h个位计数器
wire add_cnt4;
wire end_cnt4;
reg [3:0] cnt5;//h十位计数器
wire add_cnt5;
wire end_cnt5;
//设置时间寄存器
reg [3:0] set_time_cnt0;//s个位计数器
reg [3:0] set_time_cnt1;//s十位计数器
reg [3:0] set_time_cnt2;//m个位计数器
reg [3:0] set_time_cnt3;//m十位计数器
reg [3:0] set_time_cnt4;//h个位计数器
reg [3:0] set_time_cnt5;//h十位计数器
reg [2:0] key_sel_time;//设置时间片选记录
wire add_key_sel_time;
wire end_key_sel_time;
reg [2:0] key_sel_alarm;//设置闹钟片选记录
wire add_key_sel_alarm;
wire end_key_sel_alarm;
//设置闹钟寄存器
reg [23:0] alarm;//保存闹钟数据
reg [3:0] set_alarm_cnt0;//s个位计数器
reg [3:0] set_alarm_cnt1;//s十位计数器
reg [3:0] set_alarm_cnt2;//m个位计数器
reg [3:0] set_alarm_cnt3;//m十位计数器
reg [3:0] set_alarm_cnt4;//h个位计数器
reg [3:0] set_alarm_cnt5;//h十位计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
always @(*) begin
case(state_c)
IDLE:begin
if(idle2set_time)begin
state_n <= SET_TIME;
end
else if(idle2set_alarm)begin
state_n <= SET_ALARM;
end
else begin
state_n <= state_c;
end
end
SET_TIME:begin
if(set_time2idle)begin
state_n <= IDLE;
end
else begin
state_n <= state_c;
end
end
SET_ALARM:begin
if(set_alarm2idle)begin
state_n <= IDLE;
end
else begin
state_n <= state_c;
end
end
default:state_n = state_c;
endcase
end
assign idle2set_time = (state_c == IDLE) && (set_time_flag);
assign idle2set_alarm = (state_c == IDLE) && (set_alarm_flag);
assign set_time2idle = (state_c == SET_TIME) && (!set_time_flag);
assign set_alarm2idle = (state_c == SET_ALARM)&& (!set_alarm_flag);
//1s计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_1s <= 26'b0;
end
else if(add_cnt_1s)begin
if(end_cnt_1s)begin
cnt_1s <= 26'b0;
end
else begin
cnt_1s <= cnt_1s + 1'b1;
end
end
end
assign add_cnt_1s = 1'b1;
assign end_cnt_1s = add_cnt_1s && (cnt_1s == TIME_1S - 1);
//s个位计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0 <= 4'b0;
end
else if(add_cnt0)begin
if(end_cnt0)begin
cnt0 <= 4'b0;
end
else begin
cnt0 <= cnt0 + 1'b1;
end
end
else if(set_time2idle)begin
cnt0 <= set_time_cnt0;
end
end
assign add_cnt0 = end_cnt_1s;
assign end_cnt0 = add_cnt0 && (cnt0 == 10 - 1);
//s十位计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1 <= 4'b0;
end
else if(add_cnt1)begin
if(end_cnt1)begin
cnt1 <= 4'b0;
end
else begin
cnt1 <= cnt1 + 1'b1;
end
end
else if(set_time2idle)begin
cnt1 <= set_time_cnt1;
end
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && (cnt1 == 6 - 1);
//m个位计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt2 <= 4'b0;
end
else if(add_cnt2)begin
if(end_cnt2)begin
cnt2 <= 4'b0;
end
else begin
cnt2 <= cnt2 + 1'b1;
end
end
else if(set_time2idle)begin
cnt2 <= set_time_cnt2;
end
end
assign add_cnt2 = end_cnt1;
assign end_cnt2 = add_cnt2 && (cnt2 == 10 - 1);
//m十位计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt3 <= 4'b0;
end
else if(add_cnt3)begin
if(end_cnt3)begin
cnt3 <= 4'b0;
end
else begin
cnt3 <= cnt3 + 1'b1;
end
end
else if(set_time2idle)begin
cnt3 <= set_time_cnt3;
end
end
assign add_cnt3 = end_cnt2;
assign end_cnt3 = add_cnt3 &&