1 /**********************************************
2
3 工程名:可调时钟
4 模块名: clock
5
6 -----------------------------------------------
7 IO说明:
8 clk: 50MHZ时钟
9 key_in[3:0]: 四位独立按键
10 seg_out[7:0]: 七段数码管段选
11 seg_en[7:0]: 八个数码管位选
12 -----------------------------------------------
13 操作说明:
14 key[0] :set键 调时/选位
15 key[1] :inc键 增加
16 key[2] :sub键 减小
17 key[3] :ok键 确认
18
19 1. 默认为计时状态,此时点下set键,进入调时状态
20 2. 此时秒位闪烁,此时点下 inc/sub键,即可调时
21 3:长按inc/sub键,进行快速调时,每秒加减10次
22 4:再点下set键,即可更换调时位
23 5:调完后按下ok键,恢复计时
24
25 ------------------------------------------------
26
27 时间:2012年6月24日
28 作者:刘文武
29
30 ***********************************************/
31 module clock(
32 clk,
33 key_in,
34 seg_out,
35 seg_en
36 );
37
38
39 input clk;
40 input [3:0] key_in;
41 output [7:0] seg_out;
42 output [7:0] seg_en;
43
44 //时间寄存器
45 reg [5:0] min,sec;
46 reg [4:0] hour;
47
48 //a时 b分 c秒
49 //1十位 2个位
50 reg [31:0] a1,a2,b1,b2,c1,c2;
51
52
53 reg clk_1khz ; //用于数码管扫描
54 reg clk_10hz; //用于更新时间数据
55 reg clk_1_2hz; //用于数码管闪烁
56
57 reg [7:0] seg_out ; //数码管段选
58 reg [7:0] seg_en; //数码管位选
59
60 reg state; //状态位,计时为0,调时为1
61 reg [7:0]en_buf; //en缓冲
62 reg [2:0] set_pos; //调时位:{时,分,秒}
63 reg [3:0] key_buf; //读键缓冲
64
65
66 //寄存器初始化
67 //----------------------------------------
68 initial
69 begin
70 count <= 24'b1 ;
71 set_pos <=3'b001;
72 en_buf <= 8'b1111_1110;
73 seg_out <= 8'b1111_1111 ;
74 end
75
76 //分频
77 //------------------------------------------
78 reg [24:0] count ;
79
80 always @ (posedge clk )
81 begin
82
83 if( count == 25000000 ) count <= 1 ;
84 else count <= count + 1'b1;
85
86 if(count % 12500000 == 0 ) clk_1_2hz <= ~ clk_1_2hz; //1_2HZ
87 if(count % 2500000 == 0 ) clk_10hz <= ~ clk_10hz; //10HZ
88 if(count % 25000 == 0 ) clk_1khz <= ~ clk_1khz; //1kHZ
89
90 end
91
92
93 //数码管扫描
94 //------------------------------------------
95 always @ (posedge clk_1khz)
96 begin
97
98 // 计算时间位
99 a1<=hour/10;
100 a2<=hour%10;
101 b1<=min/10;
102 b2<=min%10;
103 c1<=sec/10;
104 c2<=sec%10;
105 //动态扫描
106 seg_en<=en_buf;
107 case (en_buf)
108 //在调时状态下,该调试位为真,且1/2Hz时钟到来时,该数码管灭,实现闪烁效果
109 8'b1111_1110 : seg_out <= (state && set_pos[0]&& clk_1_2hz) ? 8'b1111_1111:zimu(a1);
110 8'b1111_1101 : seg_out <= (state && set_pos[0] && clk_1_2hz) ? 8'b1111_1111: zimu(a2);
111 8'b1111_1011 : seg_out <= 8'b1011_1111; //显示"-"
112 8'b1111_0111 : seg_out <= (state && set_pos[1] && clk_1_2hz) ? 8'b1111_1111:zimu(b1);
113 8'b1110_1111 : seg_out <= (state && set_pos[1] && clk_1_2hz) ? 8'b1111_1111:zimu(b2);
114 8'b1101_1111 : seg_out <= 8'b1011_1111; //显示"-"
115 8'b1011_1111 : seg_out <= (state && set_pos[2] && clk_1_2hz) ? 8'b1111_1111:zimu(c1);
116 8'b0111_1111 : seg_out <= (state && set_pos[2] && clk_1_2hz) ? 8'b1111_1111:zimu(c2);
117 default : en_buf <= 8'b1111_1110;
118 endcase
119 //位选寄存器环形移位
120 if(en_buf == 8'b0111_1111) en_buf <= 8'b1111_1110;
121 else en_buf <= ~( ( ~en_buf ) << 1 );
122
123 end
124
125
126 //按键消抖
127 //-----------------------------------------------
128 reg [19:0] key_count;
129
130 always @ (posedge clk)
131 begin
132 if(key_in != 4'b1111) //判断是否有键按下
133 begin
134 key_count <= key_count+1'b1;//当检测到有键按下,计数器加1
135 key_buf <= 4'b1111;//此时延时尚未达到,所以输出为高
136
137 if(key_count>=20'd1000000)
138 begin
139 key_count<=20'd1000001;//当达到延时200us(50MHZ)时,锁存key-count值
140 key_buf <= key_in; //此时延时达到200us,输出为低
141 end
142 end
143 else
144 begin
145 key_buf <= 4'b1111; //当没有键按下时, 输出为高
146 key_count <= 1'b0; //计数器清0
147 end
148
149 end
150
151 //模式选择
152 //---------------------------------------------------
153 reg [3:0] count2;
154
155 always @ (posedge clk_10hz)
156 begin
157
158 if(state == 0)
159 begin
160 //计时状态下,检测到set键按下,转为调时模式
161 if(key_buf[0]==0) state <= 1'b1;
162
163
164 if(count2==4'd9)
165 begin
166 count2<=4'b0;
167 //0.1s * 10 = 1s
168 timerun(sec,min,hour);
169 end
170 else count2<=count2+1'b1;
171 end
172 else timeset(sec,min,hour,set_pos,key_buf);
173 end
174
175
176 //取字模函数
177 //---------------------------------------------------
178
179 function [7:0] zimu;
180 input [3:0]num;
181 begin
182 case(num)
183 4'b0000: zimu = 8'b1100_0000; // "0"
184 4'b0001: zimu = 8'b1111_1001; // "1"
185 4'b0010: zimu = 8'b1010_0100; // "2"
186 4'b0011: zimu = 8'b1011_0000; // "3"
187 4'b0100: zimu = 8'b1001_1001; // "4"
188 4'b0101: zimu = 8'b1001_0010; // "5"
189 4'b0110: zimu = 8'b1000_0010; // "6"
190 4'b0111: zimu = 8'b1111_1000; // "7"
191 4'b1000: zimu = 8'b1000_0000; // "8"
192 4'b1001: zimu = 8'b1001_0000; // "9"
193 default : zimu = 8'bx; //不确定
194 endcase
195 end
196
197 endfunction
198
199 //计时任务
200 //------------------------------------------------
201 task timerun;
202 inout [5:0] sec,min;
203 inout [4:0] hour;
204 begin
205 if(sec==6'd59)
206 begin
207 sec<=6'b0;
208 if(min==6'd59)
209 begin
210 min<=6'b0;
211 if(hour == 5'd23)
212 hour<=5'b0;
213 else
214 hour<=hour+1'b1;
215 end
216 else
217 min<=min+1'b1;
218 end
219 else
220 sec<=sec+1'b1;
221 end
222 endtask
223
224
225 //调时任务
226 //------------------------------------------------
227 task timeset;
228
229 inout [5:0] sec,min;
230 inout [4:0] hour;
231 inout [2:0] set_pos;
232 input [3:0] key_buf;
233
234 begin
235
236 if(key_buf[0]==0)//按下set键,调试位左移,时<-分<-秒
237 begin
238 if(set_pos==3'b100) set_pos<=3'b001;
239 else set_pos<=set_pos<<1;
240 end
241 else if (key_buf[1]==0)//按下inc键,调试位+
242 begin
243
244 case(set_pos)
245 3'b100: begin if(sec==6'd59) sec<=6'd0; else sec<= sec+1'b1; end //秒+
246 3'b010: begin if(min==6'd59) min<=6'd0; else min<= min+1'b1; end //分+
247 3'b001: begin if(hour==5'd23) hour<=5'd0; else hour<= hour+1'b1; end //时+
248 default:;
249 endcase
250 end
251 else if (key_buf[2]==0)//按下sub键,调试位-
252 begin
253 case(set_pos)
254 3'b100: begin if(sec==6'd00) sec<=6'd59; else sec<= sec-1'b1; end //秒-
255 3'b010: begin if(min==6'd00) min<=6'd59; else min<= min-1'b1; end //分-
256 3'b001: begin if(hour==5'd00) hour<=5'd23; else hour<= hour-1'b1; end //时-
257 default:;
258 endcase
259 end
260 else if (key_buf[3]==0)//按下ok键,退出调时模式
261 state<= 1'b0;
262
263 end
264 endtask
265
266
267 //-----------------------------------------------
268
269 endmodule