以下内容为北邮2020级数字电视大学实验报告。蜂鸣器模块没有报错,但时间不灵。删除后,其他代码可以正常运行。整个报告缺乏模拟代码和图片,将粘贴在个人发布的资源中。
目录
一、 任务要求的任务要求
1. 实验目的
2. 实验中使用的仪器和部件
3. 实验内容
二、 系统设计
设计思路
总体框图
分块设计
三、 模拟波形及波形分析
display模块
segment 模块
button模块
view1模块(通风)
view2模块(风暖)
view同上解读3模块(强暖)
view同上解读4模块(干动画)
view_open模块(开机动画)
时钟分频模块
sound模块
四、 源程序
1.顶层模块
2.button模块
3.segment模块
4.display模块
5.开机动画
6. view1模块
7. view2模块
8. view3模块
9. view4模块
10. 声音模块
11. 时钟分频模块(课堂教程代码)
12. 按钮抖动模块(课堂教程代码)
五、 功能描述和资源利用
功能说明
资源利用
六、 故障及问题分析
七、 总结和结论
- 进一步掌握Verilog和Quartus II软件的使用
- 掌握状态机的工作原理和设计方法
- 计算机
- MAX EPM1270T144C5
简要设计思路如下:
- 通过整体控制拨码开关SW6控制整个虚拟浴霸的开关。如果关闭,所有按钮和功能都将失效;如果打开,则通过旗帜变量start记录浴霸从关到开的状态,我暂时称之为开启状态start = 1.启动动画,这种状态持续2s,此后start = 进入按键检测状态。
- 打开状态后,进入按钮检测状态,设计切换变量switch,通过变量的变化对应case相应的状态变化在句子中。简介:按键-按键抖动产生脉冲-检测脉冲-switch状态变化。由于主题要求在不同状态之间切换,并通过两次按下相同的按钮打开和关闭状态,我想到了一个解决方案:和switch的
,如果不同,则切换,如果相同,则关闭并延迟(设计done,延迟已经完成了变量,但需要更多的重复)和其他操作。工艺设计图如下:比较上一种状态
本设计包括:顶层模块:bath_heater,按键检测模块button,蜂鸣器模块sound,数码管模块segment,动画展示模块display,启动动画模块view_open,通风动画模块view1.风暖动画模块view2.强暖动画模块view3,干燥动画模块view4。
可以在模拟图片中看到,检测到on1之后,显示开机动画,switch1010是待机状态,1000是通风状态,0100是强暖状态,0010是风暖状态,0001是干燥状态。在仿真图中可以看到switch状态变化、绿色列信号、红色列信号和行信号都发生了变化(后续动画模块模拟分析中会显示波形图)。
并且在testbench在写作中,我会lighten(点亮信号)赋值为1-0-1-0,因此可以观察到,启动动画后,light的第六位即led对应1-0-1-0的变化。
该仿真模拟了延时状态下的数码管变化,可以看见,在delay = 4以及 delay = 2的情况下数码管均有不同状态的显示,并且当延时完成时,输出变量done处产生了两个脉冲表示延时完成。
在顶层模块的模块例化以及参数传递下,当segment模块中的done = 1后,该变量传入button模块中,作为条件判断改变switch状态值,使点阵停止,进入待机状态。
其中lighten对应的是灯是否点亮,其对应控制脉冲为pulse[4],在图片中可以看到第一次脉冲产生后,lighten为1,再次产生脉冲(即第二次按下按键)lighten变为0。
通过行扫描在点阵上显示动画,观察第一个行扫描信号与最后一个行扫描信号之间的绿色列信号,易看出点阵动画为题目所需,行扫描信号为0有效,绿色列信号为1有效。
Seg信号一直有效,即所有数码管都处于同一状态,segnum从0100-1111-0100-1111,完成全八点亮到default值控制数码管全灭的过程,完成四帧闪烁。
Light信号的变化可以看书十六个led灯也为有规律的四帧闪烁。
将pulse设置为四位宽的窄脉冲,检验到脉冲,则产生不同频率的时钟信号赋值给beep蜂鸣器,产生频率不同的一段声音。
module bath_heater( input clk,//输入选择1MHz的时钟 input on,//为sw6键状态,是否工作 input rst,//设置为按键0 input BTN7,BTN6,BTN5,BTN4,BTN3,//分别实现换气、风暖、强暖、干燥功能 output beep,//蜂鸣器 output [15:0]light,//LED6为照明灯 output [7:0] col_r,//红色列 output [7:0] col_g,//绿色列 output [7:0] row,//行 output [7:0] Seg, //选择哪个数码管输出,低电平有效 output [7:0] Seg_pin//数码管受控端,高电平有效 ); wire [7:0]seg;//选择八个数码管哪一个输出端 wire [3:0]segpin;//选择数码管引脚端 wire done ;//计时完成 wire [2:0]delay ;//是否进行延迟,延迟几秒 wire lighten;//灯是否亮 wire [3:0] switch;//选择播放哪个动画,全1则处于待机状态.对应按键6543 wire start; wire pulse7,pulse6,pulse5,pulse4,pulse3; //按键消抖 debounce #(.N(5)) de1( .clk(clk), .rst(!rst), .key({!BTN7,!BTN6,!BTN5,!BTN4,!BTN3}), .key_pulse({pulse7,pulse6,pulse5,pulse4,pulse3}) ); //声音模块 sound so( .rst(rst), .on(on), .clk(clk), .pulse3(pulse3),.pulse4(pulse4),.pulse5(pulse5),.pulse6(pulse6),.pulse7(pulse7), .beep(beep) ); //按键检测 button b1( .clk(clk), .on(on), .pulse3(pulse3),.pulse4(pulse4),.pulse5(pulse5),.pulse6(pulse6),.pulse7(pulse7), .lighten(lighten), .switch(switch), .delay(delay), .done(done) ); //数码管模块 segment s1( .on(on), .seg(seg), .start(start), .delay(delay), .clk(clk), .segpin(segpin), .done(done), .Seg(Seg), .Seg_pin(Seg_pin) ); //动画、功能展示模块 display di( .clk(clk), .on(on), .lighten(lighten), .switch(switch), .start(start), .light(light), .col_r(col_r), .col_g(col_g), .row(row), .segpin(segpin), .seg(seg) ); endmodule |
module button ( input clk, input on,//是否开启,作为判断最优先条件 input pulse3,pulse4,pulse5,pulse6,pulse7, input done,//由segment模块输出的变量done表示延时是否完成 output reg lighten,//控制灯是否点亮变量 output reg [3:0] switch,//切换变量 output reg [2:0] delay//记录延时时间,若为0则为default值全灭 ); initial begin lighten <= 0; switch <= 4'b1111; delay <= 0; end always@(posedge clk)begin //检测功能按键 if(on)begin//跟当前状态比较,若输出下一状态与当前状态相同,则进入待机/关闭 if(pulse7)begin if(lighten) lighten <= 0; else lighten <= 1; end else if(pulse3)begin if(switch == 4'b0001) switch <= 4'b1111;//进入待机状态 else switch <= 4'b0001; end else if(pulse4)begin //延时4s if(switch == 4'b0010) delay <= 4; else switch <= 4'b0010; end else if(pulse5)begin //延时2s if(switch == 4'b0100) delay <= 2; else switch <= 4'b0100; end else if(pulse6)begin if(switch == 4'b1000) switch <= 4'b1111;//进入待机状态 else switch <= 4'b1000; end else if(done)begin delay <= 0; switch <= 4'b1111;//进入待机状态 end end else begin//关机则重置 switch <= 4'b1111; lighten <= 0; delay <= 0; end end endmodule |
module segment( input on, input start,//开机动画是否开启 input clk, input [2:0]delay, input [3:0]segpin, input [7:0]seg, output reg done,//接受button模块传来的延时信号delay,将是否完成延时输出 output reg [7:0]Seg, output reg [7:0]Seg_pin ); reg [3:0]segnum = 4'b1111;//segnum控制数码管的显示 reg [19:0] delaycnt = 0; initial begin done <= 0; end always@(segnum)begin case(segnum) 4'd1: Seg_pin = 8'b0000_0110; 4'd2: Seg_pin = 8'b0101_1011; 4'd3: Seg_pin = 8'b0100_1111; 4'd4: Seg_pin = 8'b0110_0110; 4'd8: Seg_pin = 8'b0111_1111;//全8闪烁,不需要小数点 default: Seg_pin = 8'b0000_0000;//全灭 endcase end always@(negedge clk)begin //数码管控制模块 if(on)begin if(start)begin segnum <= segpin; Seg <= seg; end else if(delay != 0)begin //不为0则 if(segnum != 0)begin Seg <= 8'b1111_0111; if(delaycnt == 1000000)begin //延时到1s delaycnt <= 0; if(segnum == 1)begin segnum <= 0;done <= 1; end else segnum <= segnum-1; end else delaycnt <= delaycnt + 1; end else begin segnum <= delay;done <= 0; end end else begin//若不是开机动画,且不需要延时(待机动画) Seg <= 8'b1111_1111; done <= 0; delaycnt <= 0; segnum <= 0; end end//若关机 else begin segnum <= 4'b1111;//为default值 Seg <= 8'b1111_1111; end end endmodule |
module display( input clk, input on, input lighten, input [3:0]switch, output start, output reg [15:0]light,//LED6为照明灯 output reg [7:0] col_r,//红色列 output reg [7:0] col_g,//绿色列 output reg [7:0] row,//行 output [3:0]segpin, output [7:0]seg ); wire [7:0] col_go,col_ro,row_open; wire [15:0]light_rec1; //换气、风暖、强暖、干燥功能动画存储变量 wire [7:0] col_g1,col_r1;//记录第一个动画绿色列信号 wire [7:0] col_g2,col_r2;//记录第二个动画绿色、红色列信号 wire [7:0] col_g3,col_r3;//记录第三个动画绿色列信号 wire [7:0] col_g4,col_r4;//记录第四个动画绿色列信号 wire [7:0] row1,row2,row3,row4;//记录行信号 //开机动画 view_open open( .on(on), .clk(clk), .col_r(col_ro), .col_g(col_go), .light(light_rec1), .segnum(segpin), .Seg(seg), .row(row_open), .start(start) ); //换气动画 view1 v1( .clk(clk), .col_r(col_r1), .col(col_g1), .row(row1) ); //风暖 view2 v2( .clk(clk), .col_r(col_r2), .col_g(col_g2), .row(row2) ); //强暖 view3 v3( .clk(clk), .col_r(col_r3), .col_g(col_g3), .row(row3) ); //干燥 view4 v4( .clk(clk), .col_g(col_g4), .col_r(col_r4), .row(row4) ); always@(posedge clk)//此处通过检测按键,利用条件判断输出哪个动画 begin if(on)begin//若开机 if(start)begin //通过是否 col_r <= col_ro; col_g <= col_go; light <= light_rec1; row <= row_open; end else begin//功能动画 if(lighten) light <= 16'b0000_0000_0100_0000; else light <= 16'b0000_0000_0000_0000; case (switch)//利用switch的改变检测按键变化,从而进行相应赋值显示相应动画 4'b1111:begin col_g <= 8'b0000_0000;col_r <= 8'b0000_0000;row <= 8'b1111_1111; end 4'b0001:begin col_g <= col_g4;col_r <= col_r4;row <= row4; end 4'b0010:begin col_g <= col_g3;col_r <= col_r3;row <= row3; end 4'b0100:begin col_g <= col_g2;col_r <= col_r2;row <= row2; end 4'b1000:begin col_g <= col_g1;col_r <= col_r1;row <= row1; end endcase end end else begin//若关机 light <= 16'b0000_0000_0000_0000; col_g <= 8'b0000_0000; col_r <= 8'b0000_0000; row <= 8'b1111_1111; end end endmodule |
module view_open( input clk, input on, output reg [7:0] col_r, output reg [7:0] col_g, output reg [15:0]light, output reg [3:0] segnum,//数码管受控端 output reg [7:0] Seg, //选择哪个数码管输出 output reg [7:0] row, output reg start );//开机动画 reg flag = 1; reg [2:0]cnt = 0; reg [18:0]period = 0;//记录周期,当达到0.5s时切换下一周期 //开关打开后,点阵全红、全绿交替全亮以2Hz闪烁,八个数码管亮“8”、16个发光二极同时亮以2Hz频率闪烁 //2s后,即红绿交替闪烁两次进入待机状态,点阵、数码管和二极管全灭 initial begin start <= 1; end always @(posedge clk)begin if(start)begin case(flag) 2'd1:begin light <= 16'b1111_1111_1111_1111; col_r <= 8'b1111_1111; col_g <= 8'b0000_0000; row <= 8'b0000_0000; segnum <= 4'd8; Seg <= 8'b0000_0000; end
2'd0: begin light <= 16'b0000_0000_0000_0000; col_g <= 8'b1111_1111; col_r <= 8'b0000_0000; row <= 8'b0000_0000; segnum <= 4'b1111;//default全灭 Seg <= 8'b0000_0000; end endcase end else begin light <= 16'b0000_0000_0000_0000; col_g <= 8'b0000_0000; col_r <= 8'b0000_0000; row <= 8'b1111_1111; segnum <= 0; Seg <= 8'b0000_0000; end end always @(posedge clk)begin//现在需要再次重置start if(on)begin//若开机 if(period == 500000) begin if(cnt == 3)begin//如果完成四次转换,则开机动画结束 start <= 0;//动画结束 end else begin cnt <= cnt + 1;//完成一次转换 flag <= ~flag;//完成帧的转换 period <= 0; end end else begin period <= period+1; end end //若关机 else begin start <= 1; cnt <= 0; period <= 0; flag <= 1; end end endmodule |
module view1 //第一个动画 ( input clk, output reg [7:0] col,//列 output reg [7:0] col_r,//列 output reg [7:0] row//行 ); reg [2:0]cnt = 0;//每一帧画面的行扫描记录,初始值为default,点阵全灭 reg flag = 0;//每一帧画面是否切换 reg [18:0]period = 0;//记录周期,当达到0.5s时切换下一周期 always@(negedge clk) begin if(cnt == 8)cnt <= 0; else cnt<=cnt+1; if(period == 500000) begin //若使用仿真,该数字有点大,可改小为500 flag <= ~flag;//完成帧的转换 period<=0;//此处period=0.5/t,t为时钟的一个周期,暂设为7,则两帧动画无缝衔接,便于在仿真中观测波形 end else begin period<=period+1; end end always@(cnt) begin
//第一帧 if(!flag) case(cnt)//从第七行开始扫描,即最上面一行 3'd0:begin col <= 8'b11100001;col_r <= 8'b00000000;row <= 8'b11111110;end 3'd1:begin col <= 8'b01100011;col_r <= 8'b00000000;row <= 8'b11111101;end 3'd2:begin col <= 8'b00100111;col_r <= 8'b00000000;row <= 8'b11111011;end 3'd3:begin col <= 8'b00011000;col_r <= 8'b00000000;row <= 8'b11110111;end 3'd4:begin col <= 8'b00011000;col_r <= 8'b00000000;row <= 8'b11101111;end 3'd5:begin col <= 8'b11100100;col_r <= 8'b00000000;row <= 8'b11011111;end 3'd6:begin col <= 8'b11000110;col_r <= 8'b00000000;row <= 8'b10111111;end 3'd7:begin col <= 8'b10000111;col_r <= 8'b00000000;row <= 8'b01111111;end default : begin row <= 8'b11111111;col_r <= 8'b00000000;col <= 8'b00000000;//点阵全灭 end endcase else case(cnt) 3'd0:begin col <= 8'b00010000;col_r <= 8'b00000000;row <= 8'b11111110;end 3'd1:begin col <= 8'b00011000;col_r <= 8'b00000000;row <= 8'b11111101;end 3'd2:begin col <= 8'b00010000;col_r <= 8'b00000000;row <= 8'b11111011;end 3'd3:begin col <= 8'b01011111;col_r <= 8'b00000000;row <= 8'b11110111;end 3'd4:begin col <= 8'b11111010;col_r <= 8'b00000000;row <= 8'b11101111;end 3'd5:begin col <= 8'b00001000;col_r <= 8'b00000000;row <= 8'b11011111;end 3'd6:begin col <= 8'b00011000;col_r <= 8'b00000000;row <= 8'b10111111;end 3'd7:begin col <= 8'b00001000;col_r <= 8'b00000000;row <= 8'b01111111;end default : begin row <= 8'b11111111;col_r <= 8'b00000000;col <= 8'b00000000;//点阵全灭 end endcase end endmodule |
module view2( input clk, output reg [7:0] col_r, output reg [7:0] col_g, output reg [7:0] row ); reg [2:0] cnt = 0;//每一帧画面的行扫描记录,初始值为default,点阵全灭 reg [2:0]flag = 0;//每一帧画面的切换 reg [18:0]period = 0;//记录周期,当达到0.5s时切换下一周期 always@(negedge clk) begin if(cnt == 8) cnt<=0; else cnt<=cnt+1; if(period == 500000) begin//仿真时改为500显示全部图形 period <= 0; flag <= (flag+1)%4; end else period<=period+1; end always@(cnt) begin case(flag) //第一帧动画 3'd0:case(cnt) 3'd0:begin col_g <= 8'b11100000;col_r <= 8'b00000111;row <= 8'b01111111;end 3'd1:begin col_g <= 8'b11000000;col_r <= 8'b00000011;row <= 8'b10111111;end 3'd2:begin col_g <= 8'b10100000;col_r <= 8'b00000101;row <= 8'b11011111;end 3'd3:begin col_g <= 8'b00010000;col_r <= 8'b00001000;row <= 8'b11101111;end 3'd4:begin col_g <= 8'b00001000;col_r <= 8'b00010000;row <= 8'b11110111;end 3'd5:begin col_g <= 8'b00000101;col_r <= 8'b10100000;row <= 8'b11111011;end 3'd6:begin col_g <= 8'b00000011;col_r <= 8'b11000000;row <= 8'b11111101;end 3'd7:begin col_g <= 8'b00000111;col_r <= 8'b11100000;row <= 8'b11111110;end endcase 3'd1:case(cnt) //第二帧动画 3'd0:begin col_g <= 8'b00001000;col_r <= 8'b00000000;row <= 8'b01111111;end 3'd1:begin col_g <= 8'b00011100;col_r <= 8'b00000000;row <= 8'b10111111;end 3'd2:begin col_g <= 8'b00001000;col_r <= 8'b01000000;row <= 8'b11011111;end 3'd3:begin col_g <= 8'b00001000;col_r <= 8'b11110010;row <= 8'b11101111;end 3'd4:begin col_g <= 8'b00010000;col_r <= 8'b01001111;row <= 8'b11110111;end 3'd5:begin col_g <= 8'b00010000;col_r <= 8'b00000010;row <= 8'b11111011;end 3'd6:begin col_g <= 8'b00111000;col_r <= 8'b00000000;row <= 8'b11111101;end 3'd7:begin col_g <= 8'b00010000;col_r <= 8'b00000000;row <= 8'b11111110;end endcase 3'd2:case(cnt) //第三帧动画 3'd0:begin col_r <= 8'b11100000;col_g <= 8'b00000111;row <= 8'b01111111;end 3'd1:begin col_r <= 8'b11000000;col_g <= 8'b00000011;row <= 8'b10111111;end 3'd2:begin col_r <= 8'b10100000;col_g <= 8'b00000101;row <= 8'b11011111;end 3'd3:begin col_r <= 8'b00010000;col_g <= 8'b00001000;row <= 8'b11101111;end 3'd4:begin col_r <= 8'b00001000;col_g <= 8'b00010000;row <= 8'b11110111;end 3'd5:begin col_r <= 8'b00000101;col_g <= 8'b10100000;row <= 8'b11111011;end 3'd6:begin col_r <= 8'b00000011;col_g <= 8'b11000000;row <= 8'b11111101;end 3'd7:begin col_r <= 8'b00000111;col_g <= 8'b11100000;row <= 8'b11111110;end endcase 3'd3:case(cnt) //第四帧动画 3'd0:begin col_r <= 8'b00001000;col_g <= 8'b00000000;row <= 8'b01111111;end 3'd1:begin col_r <= 8'b00011100;col_g <= 8'b00000000;row <= 8'b10111111;end 3'd2:begin col_r <= 8'b00001000;col_g <= 8'b01000000;row <= 8'b11011111;end 3'd3:begin col_r <= 8'b00001000;col_g <= 8'b11110010;row <= 8'b11101111;end 3'd4:begin col_r <= 8'b00010000;col_g <= 8'b01001111;row <= 8'b11110111;end 3'd5:begin col_r <= 8'b00010000;col_g <= 8'b00000010;row <= 8'b11111011;end 3'd6:begin col_r <= 8'b00111000;col_g <= 8'b00000000;row <= 8'b11111101;end 3'd7:begin col_r <= 8'b00010000;col_g <= 8'b00000000;row <= 8'b11111110;end endcase endcase end endmodule |
module view3( input clk, output reg [7:0] col_r, output reg [7:0] col_g, output reg [7:0] row ); reg [2:0] cnt = 0;//每一帧画面的行扫描记录,初始值为default,点阵全灭 reg [2:0]flag = 0;//每一帧画面的切换 reg [18:0]period = 0;//记录周期,当达到0.5s时切换下一周期 always@(negedge clk) begin if(cnt == 8) cnt<=0; else cnt<=cnt+1; if(period == 500000) begin period <= 0; flag <= (flag+1)%4; end else period<=period+1; end always@(cnt) begin case(flag) //第一帧动画 3'd0:case(cnt) 3'd0:begin col_g <= 8'b11100000;col_r <= 8'b11100111;row <= 8'b01111111;end 3'd1:begin col_g <= 8'b11000000;col_r <= 8'b11000011;row <= 8'b10111111;end 3'd2:begin col_g <= 8'b10100000;col_r <= 8'b10100101;row <= 8'b11011111;end 3'd3:begin col_g <= 8'b00010000;col_r <= 8'b00011000;row <= 8'b11101111;end 3'd4:begin col_g <= 8'b00001000;col_r <= 8'b00011000;row <= 8'b11110111;end 3'd5:begin col_g <= 8'b00000101;col_r <= 8'b10100101;row <= 8'b11111011;end 3'd6:begin col_g <= 8'b00000011;col_r <= 8'b11000011;row <= 8'b11111101;end 3'd7:begin col_g <= 8'b00000111;col_r <= 8'b11100111;row <= 8'b11111110;end endcase 3'd1:case(cnt) //第二帧动画 3'd0:begin col_g <= 8'b00001000;col_r <= 8'b00001000;row <= 8'b01111111;end 3'd1:begin col_g <= 8'b00011100;col_r <= 8'b00011100;row <= 8'b10111111;end 3'd2:begin col_g <= 8'b00001000;col_r <= 8'b01001000;row <= 8'b11011111;end 3'd3:begin col_g <= 8'b00001000;col_r <= 8'b11111010;row <= 8'b11101111;end 3'd4:begin col_g <= 8'b00010000;col_r <= 8'b01011111;row <= 8'b11110111;end 3'd5:begin col_g <= 8'b00010000;col_r <= 8'b00010010;row <= 8'b11111011;end 3'd6:begin col_g <= 8'b00111000;col_r <= 8'b00111000;row <= 8'b11111101;end 3'd7:begin col_g <= 8'b00010000;col_r <= 8'b00010000;row <= 8'b11111110;end endcase 3'd2:case(cnt) //第三帧动画 3'd0:begin col_g <= 8'b00000111;col_r <= 8'b11100111;row <= 8'b01111111;end 3'd1:begin col_g <= 8'b00000011;col_r <= 8'b11000011;row <= 8'b10111111;end 3'd2:begin col_g <= 8'b00000101;col_r <= 8'b10100101;row <= 8'b11011111;end 3'd3:begin col_g <= 8'b00001000;col_r <= 8'b00011000;row <= 8'b11101111;end 3'd4:begin col_g <= 8'b00010000;col_r <= 8'b00011000;row <= 8'b11110111;end 3'd5:begin col_g <= 8'b10100000;col_r <= 8'b10100101;row <= 8'b11111011;end 3'd6:begin col_g <= 8'b11000000;col_r <= 8'b11000011;row <= 8'b11111101;end 3'd7:begin col_g <= 8'b11100000;col_r <= 8'b11100111;row <= 8'b11111110;end endcase 3'd3:case(cnt) //第四帧动画 3'd0:begin col_r |