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