好久不见,我又回来开新坑了。老挖坑人了。
这学期开始接触数电了,感觉比模电好玩多了模电是什么废物玩意,而且因为数电极强的逻辑性以及又fpga这种可编程器件的存在,所以我觉得数电比模电更容易上手,而事实也是现在数电的发展远比模电强大。
闲话不多说,接下来我来介绍一下我设计的电子钟模块,它通过输入一个1Hz的时钟信号来达到计秒的功能,并且具有校准时、分、秒以及清零的功能。具体的实现方法是在内部设置了两套存储器,一套用于存储时钟信号计算的秒数,另一套用于存储用户自定义的校准时间,然后将两套存储相加即可输出最后的时分秒信号。
原理非常简单,算是我学习Verillog以来做的第一个模块了吧,接下来贴出代码:(添加了代码注释)
module clock( input clk,h_ad,m_ad,s_ad,res, //输入clk为1Hz output reg[5:0]h, output reg[5:0]m, output reg[5:0]s ); reg[5:0]h1; reg[5:0]m1; reg[5:0]s1; reg[5:0]h2; reg[5:0]m2; reg[5:0]s2; reg[6:0]m_tmp; //寄存器定义 initial begin //赋初值 h=0; m=0; s=0; h1=0; h2=0; m1=0; m2=0; s1=0; s2=0; end always @(posedge clk,negedge res)begin //按秒增加时间 s1=s1+1; if(s1==60)begin //满60秒进一分 s1=0; m1=m1+1; end if(m1==60)begin //满60分进一小时 m1=0; h1=h1+1; end if(h1==24) //满24小时重置 h1=0; if(!res)begin //异步复位 s1=0; m1=0; h1=0; end end always @(posedge h_ad,negedge res)begin //校时 时增加 h2=h2+1; if(h2==24) //满24小时重置 h2=0; if(!res) //异步复位 h2=0; end always @(posedge m_ad,negedge res)begin //校时 分增加 m2=m2+1; if(m2==60) //满60分重置 m2=0; if(!res) //异步复位 m2=0; end always @(posedge s_ad,negedge res)begin //校时 秒位置0 s2=s1; if(!res) //异步复位 s2=0; end always @(h1,h2,m1,m2,s1,s2)begin h=h1+h2; //最终小时数为计时小时+矫时小时 m_tmp=m1+m2; //最终分钟数为计时分钟+矫时分钟 if(s1>=s2) //处理秒数置0矫时 s=s1-s2; else begin s=s1+60-s2; if(m_tmp==0)begin //矫时秒数超前分钟数减1 h=h-1; m_tmp=59; end else m_tmp=m_tmp-1; end if(m_tmp>=60)begin //分钟数满60进一小时 m_tmp=m_tmp-60; h=h+1; end m=m_tmp[5:0]; if(h>=24) //小时数限制在24小时内 h=h-24; end endmodule
同时与这个模块配套的还有一个动态显示模块,这个模块的作用是利用动态显示的方法在数码管上“同时”显示多位数字。这与你现在眼前的显示器类似:通过高速刷新,使各个数字轮流显示,每个仅显示几毫秒。由于人具有视觉暂留,所以在人眼中数码管上的数字就是同时点亮的。
以下是6位动态显示模块的代码:(由于使用的数码管接口自带译码电路,所以这里的模块直接输出了数字,对于其他某些情况还需要自己编写译码模块)
module show_dig_6( input [3:0]dig1,[3:0]dig2,[3:0]dig3,[3:0]dig4,[3:0]dig5,[3:0]dig6, //待显示的6位数字 input clk, //时钟通常在1000Hz左右 output reg[3:0]dig, //输出数字 output reg[6:1]ch //输出数码管有效信号 ); reg [2:0]counter; initial begin dig=0; ch=6'b111111; counter=0; end always @(posedge clk) begin counter=counter+1; //每周期计数器加1 if(counter==6) //计满6清零 counter=0; case(counter) 0:begin //对于每个状态 dig=dig1; //输出该位对应的数字 ch=6'b011111; //将对应位值为有效,其他无效 end //下同 1:begin dig=dig2; ch=6'b101111; end 2:begin dig=dig3; ch=6'b110111; end 3:begin dig=dig4; ch=6'b111011; end 4:begin dig=dig5; ch=6'b111101; end 5:begin dig=dig6; ch=6'b111110; end default:begin dig=0; ch=6'b111111; end endcase end endmodule
然后将上面编写的两个模块整合进一个主模块中,将程序烧入FPGA里就完成了:
module Sinon( input clk,clock_clk,h_ad,m_ad,s_ad,res, output[3:0]dig, output[1:6]ch ); wire [3:0]dig_out; wire [1:6]ch_out; wire [5:0]h_out; wire [5:0]m_out; wire [5:0]s_out; reg [5:0]h; reg [5:0]m; reg [5:0]s; reg [3:0]dig1;reg [3:0]dig2;reg [3:0]dig3;reg [3:0]dig4;reg [3:0]dig5;reg[3:0]dig6; always @(clock_clk,h_ad,m_ad,s_ad)begin h=h_out; m=m_out; s=s_out; dig1=h/10; //获取小时数十位,下同 dig2=h%10; //获取小时数个位,下同 dig3=m/10; dig4=m%10; dig5=s/10; dig6=s%10; end assign dig=dig_out; assign ch=ch_out; clock clock_0(clock_clk,h_ad,m_ad,s_ad,res,h_out,m_out,s_out); //数字钟模块 show_dig_6 show_dig(dig1,dig2,dig3,dig4,dig5,dig6,clk,dig_out,ch_out); //动态显示模块 endmodule
江大佬牛逼
波形发生器整活
懒得整