发一发学习EDA实验课上的一些实验。
-------应读者要求加一下Pin脚绑定,注意仅适用这个设备
1.编写Verilog程序,实现8位数码动态扫描显示电路。在此基础上,用8位数码管实现电子表功能。
module scan(clk,seg8,bt);//顶层模块名,最好要和项目名同个
input clk;
output [7:0]seg8;
output [7:0]bt;
reg[7:0]seg8;
reg[7:0]bt;
reg[2:0]cnt8;
reg[3:0]a;
always@(cnt8)//时序逻辑用非阻塞语句赋值
begin
case(cnt8)//bt代表着数码管,通过cnt的计数实现不断对每位对于数码管进行动态扫描
//高频率(4096Hz)下,人眼看不出频闪。
3'b000:begin bt<=8'b00000001;a<=1;end
3'b001:begin bt<=8'b00000010;a<=3;end
3'b010:begin bt<=8'b00000100;a<=5;end
3'b011:begin bt<=8'b00001000;a<=7;end
3'b100:begin bt<=8'b00010000;a<=9;end
3'b101:begin bt<=8'b00100000;a<=10;end
3'b110:begin bt<=8'b01000000;a<=11;end
3'b111:begin bt<=8'b10000000;a<=12;end
default begin bt<=8'b00000000;end
endcase
end
always@(posedge clk) cnt8<=cnt8+1'b1;cnt从0加到8后溢出会自动归零重新计算,所以不需要归零语句
always@(a)
begin
case(a)//每扫描一次bt的时候,实时更新对应位的数码管的值a,并输出
0:seg8<=8'b00111111;
1:seg8<=8'b00000110;
2:seg8<=8'b01011011;
3:seg8<=8'b01001111;
4:seg8<=8'b01100110;
5:seg8<=8'b01101101;
6:seg8<=8'b01111101;
7:seg8<=8'b00000111;
8:seg8<=8'b01111111;
9:seg8<=8'b01101111;
10:seg8<=8'b01110111;
11:seg8<=8'b01111110;
12:seg8<=8'b00111001;
13:seg8<=8'b01011110;
14:seg8<=8'b01111001;
15:seg8<=8'b01110001;
default :seg8<=8'b00111111;
endcase
end
endmodule
2.
- 修改程序,继续使用实验箱左下角主板上“标准时钟信号源”模块的4096Hz时钟源,实现全部数码管显示相同的数字(从“1”至“8”循环显示),每组数字显示的时间为1秒。(提交代码及实验现象照片或截图)
module scan(rst,clk,seg8,bt);
input clk;
input rst;
output [7:0]seg8;
output [7:0]bt;
reg[7:0]seg8;
reg[7:0]bt;
reg[2:0]cnt8;
reg[2:0]a;
wire clk2;
cnt10 t1(rst,clk,clk2);//例化模块,将4096hz大小的频率clk分频成1hz大小clk2,即1s,
always@(posedge clk2 or negedge rst)begin//每隔一秒改变a的值
if(!rst)a<=0;
else a<=a+1;
end
//值得注意的是,同一个变量并不能在不同的always和assign里赋值,
//也就是说,它只能在一个always或者assign里赋值
always@(cnt8)
begin
case(cnt8)//依然像第一个实验一样在clk下直接不断扫描,但是不再赋值a值
3'b000:begin bt<=8'b00000001;end
3'b001:begin bt<=8'b00000010;end
3'b010:begin bt<=8'b00000100;end
3'b011:begin bt<=8'b00001000;end
3'b100:begin bt<=8'b00010000;end
3'b101:begin bt<=8'b00100000;end
3'b110:begin bt<=8'b01000000;end
3'b111:begin bt<=8'b10000000;end
default begin bt<=8'b00000000;end
endcase
end
always@(posedge clk) cnt8<=cnt8+1'b1;//cnt8,每次clk上升,cnt计数一次。
always@(a)
begin
case(a)
0:seg8<=8'b00111111;
1:seg8<=8'b00000110;
2:seg8<=8'b01011011;
3:seg8<=8'b01001111;
4:seg8<=8'b01100110;
5:seg8<=8'b01101101;
6:seg8<=8'b01111101;
7:seg8<=8'b00000111;
8:seg8<=8'b01111111;
default :seg8<=8'b00111111;
endcase
end
endmodule
module cnt10(rst,clk,clk2);//分频用的模块,是占空比位为50%的时钟分频形式,只适合偶数分频。
parameter all=2048;//原频率4096,那么为了达到占空比50%,就计数到一半的时候就翻转一次
input rst;
input clk;
output clk2;
reg[11:0] sum;//4096是2的12次方,所以位宽为12;
reg clk2;
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
sum<=0;clk2<=0;
end
else if(sum==all-1)begin sum<=0;clk2<=~clk2;end
//all-1的原因是因为all是从零开始的。计数到2047就满2048次了。
//只会在sum==2048的时候翻转,4098的时候不翻转。
//如果sum=4098的时候还翻转,那么时钟速度就是2hz即0.5s了!
else begin
sum<=sum+1'b1;
end
end
endmodule
话了一个很丑的图来看看为什么4096的时候不反转。从图里很明显看得出2048翻转的话,两次翻转加起来刚好是4096次。
3.使用实验箱左下角主板上“标准时钟信号源”模块的4096Hz时钟和8位数码管实现电子钟的功能,即左数第1和2位数码管显示小时值,第4和5位显示分钟值,第7和8位显示秒值,第3和6位显示“-”作为分隔线.
module scan(rst,clk,seg8,bt);
input clk;
input rst;
output [7:0]seg8;
output [7:0]bt;
reg[7:0]seg8;
reg[7:0]bt;
reg[5:0]timer[2:0];//6位的3字节寄存器数组,保存时分秒,xx:xx:xx,
reg[2:0]cnt8;
reg[3:0]a;
reg[2:0]i;
wire clk2;
cnt10 t1(.rst(rst),.clk(clk),.clk2(clk2));//分频模块,分频到1Hz,输出clk2
always@(posedge clk) cnt8<=cnt8+1'b1;//cnt8,每次clk上升,cnt计数一次。
always@(posedge clk2 or negedge rst)//计算时分秒
begin
if(!rst)
begin
for(i=0;i<3;i=i+1)begin timer[i]<=0;end
end
else if(timer[0]==59)begin timer[0]<=0;timer[1]=timer[1]+1;end
else if(timer[1]==59)begin timer[1]<=0;timer[2]=timer[2]+1; if(timer[2]==24)begin for(i=0;i<3;i=i+1)begin timer[i]<=0;end
//分钟到时钟这一段和分钟本身的变换肯定存在问题,会导致时和分的变换之间的误差明显,但我不想改。
end
end
else if(timer[2]==24)begin for(i=0;i<3;i=i+1)begin timer[i]<=0;end
end
else timer[0]=timer[0]+1;
end
always@(posedge cnt8 or negedge rst)
begin
if(!rst)begin bt<=8'b00000000;a<=0; end
case(cnt8)//从上到下是时分秒,具体要看引脚绑定吧,看看那边是正方向,
3'b000:begin bt<=8'b00000001;a<=timer[2]/10;end
3'b001:begin bt<=8'b00000010;a<=timer[2]%10;end
3'b010:begin bt<=8'b00000100;a<=10;end
3'b011:begin bt<=8'b00001000;a<=timer[1]/10;end
3'b100:begin bt<=8'b00010000;a<=timer[1]%10;end
3'b101:begin bt<=8'b00100000;a<=10;end
3'b110:begin bt<=8'b01000000;a<=timer[0]/10;end
3'b111:begin bt<=8'b10000000;a<=timer[0]%10;end
default begin bt<=8'b00000000;end
endcase
end
always@(a)
begin
case(a)
0:seg8<=8'b00111111;
1:seg8<=8'b00000110;
2:seg8<=8'b01011011;
3:seg8<=8'b01001111;
4:seg8<=8'b01100110;
5:seg8<=8'b01101101;
6:seg8<=8'b01111101;
7:seg8<=8'b00000111;
8:seg8<=8'b01111111;
9:seg8<=8'b01101111;
default :seg8<=8'b01000000;
endcase
end
endmodule
module cnt10(rst,clk,clk2);
parameter all=2048;
input rst;
input clk;
output clk2;
reg[11:0] sum;
reg clk2;
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
sum<=0;clk2<=0;
end
else if(sum==all-1)begin sum<=0;clk2<=~clk2;end
else begin
sum<=sum+1'b1;
end
end
endmodule