好久不见,我又回来开新坑了。老挖坑人了。
这学期开始接触数电了,感觉比模电好玩多了模电是什么废物玩意,而且因为数电极强的逻辑性以及又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
江大佬牛逼
波形发生器整活
懒得整