- 建议先去看下我的另外一篇博客,详细分享了我开关版本的设计理念。本博客只附上了改进说明。另一篇博客地址:https://blog.csdn.net/qq_42181309/article/details/90175698
- 因为开关IO口太多,这是介于我第一次写的开关版本的改进按钮版,一共用了5个按钮,两个按钮用来调位置(即时分秒位),两个按钮用来调大小(即9~0)。一个按钮用来复位。
- 既然是按钮首先要使用消抖电路,基于自动机的理念,设置了消抖电路。
-
module Eli_jlt( input clk, input sw, output reg et ); parameter N=24; parameter[2:0] s0=3'b000, s1=3'b001, s2=3'b010, s3=3'b011, s4=3'b100, s5=3'b101, s6=3'b110, s7=3'b111; reg[2:0] state;//state_next; reg[2:0] state_next; reg [N-1:0] st_tick; wire tick; always @(posedge clk) if(st_tick<10**6) st_tick<=st_tick+1; else st_tick<=0; always @(posedge clk) state<=state_next; assign tick=(st_tick==0)? 1'b1:0'b0; always @(*) case(state) s0: begin et=0; if(sw) begin state_next=s1;//当前状态为0检测状态为1,并等待它稳定20~30ms end end s1: if(~sw) state_next=s0; else if(tick) state_next=s2; s2: if(~sw) state_next=s0; else if(tick) state_next=s3; s3: if(~sw) state_next=s0; else if(tick) state_next=s4; s4: begin et=1; if(~sw) state_next=s5;//当前状态为1检测状态为0,并等待它稳定20~30ms end s5: if(sw) state_next=s4; else if(tick) state_next=s6; s6: if(sw) state_next=s4; else if(tick) state_next=s7; default: if(sw) state_next=s4; else if(tick) state_next=s0; endcase endmodule
-
主要改进模块为output_reset。
module output_reset(
input clk,
input butt1,
input butt2,
input butt3,
input butt4,
input [3:0] second_l,
input [3:0] second_h,
input [3:0]minute_l,
input [3:0]minute_h,
input [3:0]hour_l,
input [3:0]hour_h,
output reg [3:0] second_l_r,
output reg [3:0] second_h_r,
output reg [3:0]minute_l_r,
output reg [3:0]minute_h_r,
output reg [3:0]hour_l_r,
output reg [3:0]hour_h_r
);
wire et1,et2,et3,et4;
wire le1,le2,le3,le4;
reg [3:0] second_l1;
reg [3:0] second_h1;
reg [3:0]minute_l1;
reg [3:0]minute_h1;
reg [3:0]hour_l1;
reg [3:0]hour_h1;
reg [3:0] second_ll;
reg [3:0] second_hh;
reg [3:0]minute_ll;
reg [3:0]minute_hh;
reg [3:0]hour_ll;
reg [3:0]hour_hh;
reg [3:0] pos;//表示位置
Eli_jlt one(.clk(clk),.sw(butt1),.et(et1));
Eli_jlt two(.clk(clk),.sw(butt2),.et(et2));
Eli_jlt three(.clk(clk),.sw(butt3),.et(et3));
Eli_jlt four(.clk(clk),.sw(butt4),.et(et4));//消除抖动
trans tone(.clk(clk),.le(le1),.et(et1));
trans ttwo(.clk(clk),.le(le2),.et(et2));
trans tthree(.clk(clk),.le(le3),.et(et3));
trans tfour(.clk(clk),.le(le4),.et(et4));
always @(posedge clk)
if(le3)
begin
if(pos==5)
pos=5;
else
pos=pos+1;
end
else if(le4)
begin
if(pos==0)
pos=0;
else
pos=pos-1;
end
always @(posedge clk)
begin
second_h1<=second_h;
second_hh<=second_h1;
second_l1<=second_l;
second_ll<=second_l1;
minute_h1<=minute_h;
minute_hh<=minute_h1;
minute_l1<=minute_l;
minute_ll<=minute_l1;
hour_h1<=hour_h;
hour_hh<=hour_h1;
hour_l1<=hour_l;
hour_ll<=hour_l1;
end
always @(posedge clk)
case(pos)
5:
if(le1)
if(hour_l1<4)
if(hour_hh<2)
hour_h_r<=hour_hh+1;
else
hour_h_r<=2;
else
if(hour_hh<1)
hour_h_r<=hour_hh+1;
else
hour_h_r<=1;
else if(le2)
if(hour_hh>0)
hour_h_r<=hour_hh-1;
else
hour_h_r<=0;
4:
if(le1)
begin
if(hour_hh==2)
if(hour_ll<3)
hour_l_r<=hour_ll+1;
else
hour_l_r<=3;
else
if(hour_ll<9)
hour_l_r<=hour_ll+1;
else
hour_l_r<=9;
end
else if(le2)
if(hour_ll>0)
hour_l_r<=hour_ll-1;
else
hour_l_r<=0;
3:
if(le1)
if(minute_hh<5)
minute_h_r<=minute_hh+1;
else
minute_h_r<=5;
else if(le2)
if(minute_hh>0)
minute_h_r<=minute_hh-1;
else
minute_h_r<=0;
2:
if(le1)
if(minute_ll<9)
minute_l_r<=minute_ll+1;
else
minute_l_r<=9;
else if(le2)
if(minute_ll>0)
minute_l_r<=minute_ll-1;
else
minute_l_r<=0;
1:
if(le1)
if(second_hh<5)
second_h_r<=second_hh+1;
else
second_h_r<=5;
else if(le2)
if(second_hh>0)
second_h_r<=second_hh-1;
else
second_h_r<=0;
default:
if(le1)
if(second_ll<9)
second_l_r<=second_ll+1;
else
second_l_r<=9;
else if(le2)
if(second_ll>0)
second_l_r<=second_ll-1;
else
second_l_r<=0;
endcase
endmodule
4.现在来解析output_reset,首先从trans说起,它的目的是把按钮信号的沿信号,转换成电平信号,为什么这么做呢,因为你希望两个按钮同时控制一个信号,比如数字的加减你是没办法同时检测两个posedge 沿信号的,但是你可以同时检测两个电平信号,
module trans(
input clk,
input et,
output reg le
);
reg sync_et;
always @(posedge clk)
sync_et<=et;
always @(*)
if((et==1)&(sync_et==0))
le=1;
else
le=0;
endmodule
5.然后剩下的就是非法判断,我用一个always块干掉了这件事,注意pos是另外两个按钮控制的位置即时分秒位
always @(posedge clk)
case(pos)
5:
if(le1)
if(hour_l1<4)
if(hour_hh<2)
hour_h_r<=hour_hh+1;
else
hour_h_r<=2;
else
if(hour_hh<1)
hour_h_r<=hour_hh+1;
else
hour_h_r<=1;
else if(le2)
if(hour_hh>0)
hour_h_r<=hour_hh-1;
else
hour_h_r<=0;
4:
if(le1)
begin
if(hour_hh==2)
if(hour_ll<3)
hour_l_r<=hour_ll+1;
else
hour_l_r<=3;
else
if(hour_ll<9)
hour_l_r<=hour_ll+1;
else
hour_l_r<=9;
end
else if(le2)
if(hour_ll>0)
hour_l_r<=hour_ll-1;
else
hour_l_r<=0;
3:
if(le1)
if(minute_hh<5)
minute_h_r<=minute_hh+1;
else
minute_h_r<=5;
else if(le2)
if(minute_hh>0)
minute_h_r<=minute_hh-1;
else
minute_h_r<=0;
2:
if(le1)
if(minute_ll<9)
minute_l_r<=minute_ll+1;
else
minute_l_r<=9;
else if(le2)
if(minute_ll>0)
minute_l_r<=minute_ll-1;
else
minute_l_r<=0;
1:
if(le1)
if(second_hh<5)
second_h_r<=second_hh+1;
else
second_h_r<=5;
else if(le2)
if(second_hh>0)
second_h_r<=second_hh-1;
else
second_h_r<=0;
default:
if(le1)
if(second_ll<9)
second_l_r<=second_ll+1;
else
second_l_r<=9;
else if(le2)
if(second_ll>0)
second_l_r<=second_ll-1;
else
second_l_r<=0;
endcase
5.总模块和未解决的问题
module top(
input clk,
input reset,
input butt1,
input butt2,
input butt3,
input butt4,
output [6:0] seeg,
output [7:0] sctl,
output seeg_p
);
wire [6:0]decode_hh;
wire [6:0]decode_hl;
wire [6:0]decode_mh;
wire [6:0]decode_ml;
wire [6:0]decode_sh;
wire [6:0]decode_sl;
wire [3:0] second_l;
wire [3:0] second_h;
wire [3:0]minute_l;
wire [3:0]minute_h;
wire [3:0]hour_l;
wire [3:0]hour_h;
wire [3:0] second_l_r;
wire [3:0] second_h_r;
wire [3:0]minute_l_r;
wire [3:0]minute_h_r;
wire [3:0]hour_l_r;
wire [3:0]hour_h_r;
wire [3:0] second_ll;
wire [3:0] second_hh;
wire [3:0]minute_ll;
wire [3:0]minute_hh;
wire [3:0]hour_ll;
wire [3:0]hour_hh;
output_reset output_reset(.clk(clk),.butt1(butt1),.butt2(butt2),.butt3(butt3),.butt4(butt4),.second_l_r(second_l_r),.second_h_r(second_h_r),.minute_l_r(minute_l_r),.minute_h_r(minute_h_r),.hour_l_r(hour_l_r),.hour_h_r(hour_h_r),.hour_h(hour_h),.hour_l(hour_l),.minute_h(minute_h),.minute_l(minute_l),.second_h(second_h),.second_l(second_l));
output_r_cal r_cal(.clk(clk),.second_l_r(second_l_r),.second_h_r(second_h_r),.minute_l_r(minute_l_r),.minute_h_r(minute_h_r),.hour_l_r(hour_l_r),.hour_h_r(hour_h_r),.second_ll(second_ll),.second_hh(second_hh),.minute_ll(minute_ll),.minute_hh(minute_hh),.hour_ll(hour_ll),.hour_hh(hour_hh));
cnt cnt(.reset(reset),.clk(clk),.second_ll(second_ll),.second_hh(second_hh),.minute_ll(minute_ll),.minute_hh(minute_hh),.hour_ll(hour_ll),.hour_hh(hour_hh),.hour_h(hour_h),.hour_l(hour_l),.minute_h(minute_h),.minute_l(minute_l),.second_h(second_h),.second_l(second_l));
decode h_h(.v(hour_h),.seegs(decode_hh));
decode h_l(.v(hour_l),.seegs(decode_hl));
decode m_h(.v(minute_h),.seegs(decode_mh));
decode m_l(.v(minute_l),.seegs(decode_ml));
decode s_h(.v(second_h),.seegs(decode_sh));
decode s_l(.v(second_l),.seegs(decode_sl));
seegctl(.decode_hh(decode_hh),.decode_hl(decode_hl),.decode_mh(decode_mh),.decode_ml(decode_ml),.decode_sh(decode_sh),.decode_sl(decode_sl),.clk(clk),.seeg(seeg),.sctl(sctl),.seeg_p(seeg_p));
endmodule
注意r_cal我原先的想法是对按钮进行纠正,但是output_reset做了这件事情之后,它纯粹变成了触发器,注意到outputreset的输入信号,是cnt的信号,我希望复位的时候是当前的时间值,但实际却综合出了原先调的时间值,研究了好久没解决,但相比于上次开关来说,体验好了很多,也希望有大神能帮我找出错误。个人设计,诸多不良之处,请多指教!
6.演示及补充,
出了output_reset及top,其它模块和开关版均一样,r_cal就改成触发器打一拍。
演示视频地址:https://www.bilibili.com/video/av53854057?pop_share=1