//输入 50MHz 时钟信号
//输出控制红灯
//输出控制小数点
module shen(key,clock,outstate,seg_date,seg_com,L1,L2,L3,L4,p);
input [1:0]key;//key[0]表示投入 5 角的开关,key[1]表示投入 1 元的开关
input clock ;
reg [1:0]currentstate,nextstate;// currentstate 表示现态,nextstate 表示次态
output reg outstate;
output reg p;
output reg L1,L2,L3,L4;//红灯辅助控制电路
output reg [7:0]seg_date;
output reg[3:0] seg_com;
reg outnext;
reg [2:0]x1,x2,x3,x4;
reg [2:0]y1,y2,y3,y4;
reg[31:0]
reg[2:0] scan_led_com;
reg clk_500Hz,clk_scan;
reg i;
reg counter;
reg [2:0]shujv;
reg [1:0] in;
reg [1:0] in_flag;
reg [3:0] count;
//段选
//位选
DCLK_DIV,DCLK_DIV1;
/***主功能实现函数***/
always @(posedge clk_500Hz)
begin
L1=0;
L2=1;
L3=1;
L4=1;
if(currentstate==0)//状态为 S0
begin
if(~in[0])
//投入 5 角,低电平为有效信号
begin
if(~in_flag[0])//in_flag[0]标志位防止低电平期间重复计数
begin
nextstate=1;//次态变成 S1
outnext=0;
//无饮料输出
//第一位数码管应该显示的数据 0
y1=3'b000;
//第二位数码管应该显示的数据 5
y2=3'b101;
//第三位数码管应该显示的数据 0
y3=3'b000;
y4=3'b000;
//第四位数码管应该显示的数据 0
in_flag[0]=1;
end
end
else if (~in[1])
//投入 1 元,低电平为有效信号
begin
if(~in_flag[1])//in_flag[1]标志位防止低电平期间重复计数
begin
nextstate=2;//次态变成 S2
//无饮料输出
outnext=0;
//第一位数码管应该显示的数据 1
y1=3'b001;
//第二位数码管应该显示的数据 0
y2=3'b000;
y3=3'b000;
//第一位数码管应该显示的数据 0
y4=3'b000;
//第一位数码管应该显示的数据 0
in_flag[1]=1;
end
end
else//未投币
begin
nextstate=0;
outnext=0;
y1=3'b000;
y2=3'b000;
y3=3'b000;
y4=3'b000;
in_flag[0]=0;
in_flag[1]=0;
end
//保持 S0 状态
//无饮料输出
//第一位数码管应该显示的数据 0
//第二位数码管应该显示的数据 0
//第三位数码管应该显示的数据 0
//第四位数码管应该显示的数据 0
end
if(currentstate==1)
//状态为 S1
begin
if(~in[0])
begin
if(~in_flag[0])
begin
nextstate=2;//次态变成 S2
outnext=0;
y1=3'b001;
y2=3'b000;
y3=3'b000;
y4=3'b000;
in_flag[0]=1;
end
//无饮料输出
//第一位数码管应该显示的数据 1
//第二位数码管应该显示的数据 0
//第三位数码管应该显示的数据 0
//第四位数码管应该显示的数据 0
end
else if (~in[1])
begin
if(~in_flag[1])
begin
nextstate=0;//次态变成 S0
outnext=1;
y1=3'b001;
y2=3'b101;
y3=3'b000;
y4=3'b000;
in_flag[1]=1;
end
//有饮料输出
//第一位数码管应该显示的数据 1
//第二位数码管应该显示的数据 5
//第三位数码管应该显示的数据 0
//第四位数码管应该显示的数据 0
end
else
begin
nextstate=1;//保持 S1 状态
outnext=0;
y1=3'b000;
y2=3'b101;
y3=3'b000;
y4=3'b000;
in_flag[0]=0;
in_flag[1]=0;
end
//无饮料输出
//第一位数码管应该显示的数据 0
//第二位数码管应该显示的数据 5
//第三位数码管应该显示的数据 0
//第四位数码管应该显示的数据 0
end
if(currentstate==2)
begin
if(~in[0])
begin
if(~in_flag[0])
begin
nextstate=0;//次态变成 S0
outnext=1;
//有饮料输出
y1=3'b001;//第一位数码管应该显示的数据 1
y2=3'b101;//第二位数码管应该显示的数据 5
y3=3'b000;//第三位数码管应该显示的数据 0
y4=3'b000;//第四位数码管应该显示的数据 0
in_flag[0]=1;
end
end
else if(~in[1])
begin
if(~in_flag[1])
begin
nextstate=0;//次态变成 S0
//有饮料输出
outnext=1;
y1=3'b010;//第一位数码管应该显示的数据 2
y2=3'b000;//第二位数码管应该显示的数据 0
y3=3'b000;//第三位数码管应该显示的数据 0
y4=3'b101;//第四位数码管应该显示的数据 5
in_flag[1]=1;
end
end
else
begin
nextstate=2;//保持 S2 状态
outnext=0;//无饮料输出
y1=3'b001;//第一位数码管应该显示的数据 1
y2=3'b000;
y3=3'b000;
y4=3'b000;
in_flag[0]=0;
in_flag[1]=0;
end
//第二位数码管应该显示的数据 0
//第三位数码管应该显示的数据 0
//第四位数码管应该显示的数据 0
end
end
/***消抖程序***/
always @ (posedge clk_500Hz)
begin
if((~key[0]) ||( ~key[1]))
//判断是否有按键按下
begin
if(count==10)
//延时 20ms 消除抖动
begin
的判断
in[0]=key[0];
//此时 key 值为稳定状态复值给 in 进行主函数
in[1]=key[1];
count=0;
end
else
count=count+1;
end
else
begin
in[0]=1;//否则 in 为高电平不能进入主程序
in[1]=1;
end
end
/***扫描数码管**/
always @(posedge clk_scan)
if(scan_led_com<3)
begin
scan_led_com = scan_led_com + 1;//循环扫描 4 位数码管
else scan_led_com = 0;
end
/********状态转换***/
always @(posedge clk_500Hz)
begin
currentstate<=nextstate;
outstate<=outnext;
end
//将前面主程序执行的结果进行状态转换
/**时钟分频 2.5Khz,用来扫描数码管**/
always @(posedge clock)
begin if(DCLK_DIV < 10_000)
begin
DCLK_DIV <= DCLK_DIV+1'b1;
else
DCLK_DIV <= 0;
clk_scan <= ~clk_scan;
end
end
/****分频 500hz,用来检测按键****/
always @(posedge clock)
begin if(DCLK_DIV1 < 50_000)
begin
DCLK_DIV1 <= DCLK_DIV1+1'b1;
else
DCLK_DIV1 <= 0;
clk_500Hz <= ~clk_500Hz;
end
end
/**数码管显示***/
always @(posedge clk_scan)
begin
//2.5KHz
case(scan_led_com) //循环扫描 4 个 LED,共阳极
3'b000: seg_com=8'b00000001; //扫描第一位数码管
3'b001: seg_com=8'b00000010;
3'b010: seg_com=8'b00000100;
3'b011: seg_com=8'b00001000;
default: seg_com=8'b00000000;
endcase
//扫描第三位数码管
//扫描第四位数码管
//扫描第五位数码管
//扫描第二位数码管
case(scan_led_com)//位选
3'b000: begin shujv<=y1;p=0;end
3'b001:begin shujv<=y2;p=1;end
3'b010: begin shujv<=y3;p=0;end
3'b011: begin shujv<=y4;p=1;end
endcase
case(shujv)
//段选
//扫描第一位数码管时把数据赋值给 shujv
//扫描第二位数码管时把数据赋值给 shujv
//扫描第三位数码管时把数据赋值给 shujv
//扫描第四位数码管时把数据赋值给 shujv
3'b000:seg_date=7'b1000000;//显示 0
3'b001:seg_date=7'b1111001;//显示 1
3'b010:seg_date=7'b0100100;//显示 2
3'b101:seg_date=7'b0010010;//显示 5
default: seg_date=7'b0000000;
endcase
end
endmodule