1、利用数码管动态显示原理设计一个自加器,要求写出详细钓代码和画出模块框图?
`timescale 1ns / 1ps
//数码管静态显示:"4444"
//自动地址增加模式
module smg(
input wire sysclk ,//系统时钟---50Mhz
input wire rst_n ,//系统复位----低电平0有效
output reg CLK ,//TM1620的时钟
output reg STB ,//片选信号线
output reg DIN //串行数据输入-----TM1620
);
//内部信号声明
parameter delay = 9'd500 ;//传输一个bit所需时间
parameter data = 8'b0110_0110 ;//段选的二进制值----数字"4"
parameter data_cmd1 = 8'b00_0000_10 ;//设置显示模式-----显示模式命令设置_无关项_显示模式(6位8段数码管)
parameter data_cmd2 = 8'b01_00_0_0_00 ;//设置数据命令---数据命令设置_无关项_普通模式_自动地址增加_写数据到显示寄存器
parameter data_addr = 8'b11_00_0000 ;//设置显示地址(起始地址)----地址命令设置_无关项_显示地址(OOh)
parameter data_cmd3 = 8'b10_00_1_100 ;//设置显示控制命令---显示控制命令设置_无关项_显示开_设置脉冲宽度。
parameter delay_cnt = 9'd1000 ;//1000个传输周期记一次数
parameter num_0 = 8'b0011_1111 ;//设置显示数据--0-9
parameter num_1 = 8'b0000_0110 ;
parameter num_2 = 8'b0101_1011 ;
parameter num_3 = 8'b0100_1111 ;
parameter num_4 = 8'b0110_0110 ;
parameter num_5 = 8'b0110_1101 ;
parameter num_6 = 8'b0111_1101 ;
parameter num_7 = 8'b0000_0111 ;
parameter num_8 = 8'b0111_1111 ;
parameter num_9 = 8'b0110_1111 ;
//状态编码--格雷码(相邻两个状态只有一个位在变化.2的n次方>=状态个数)
localparam IDLE = 3'b000;//空闲状态--不工作
localparam Cmd1 = 3'b001;//设置显示模式
localparam Cmd2 = 3'b011;//设置数据命令
localparam Cmd3 = 3'b010;//设置显示地址
localparam DATA_W = 3'b110;//传输显示数据---段选
localparam Cmd4 = 3'b111;//设置显示控制命令
//状态寄存器
reg [2:0] c_state,n_state ;//现态、次态
//内部寄存器
reg [8:0] cnt_clk ;//周期计数器
reg [3:0] cnt_bit ;//bit位计数器---记录传输了几位数据
reg [3:0] cnt_byte ;//字节计数器----记录传输了几个字节的数据
reg [7:0] data_reg ;//数据缓存器
reg [13:0] data_dy ;//要显示的4位十进制数字
reg [9:0] cnt_cycle ;//传输数据周期计数---1000个周期约1s改变一次动态数据。
reg [7:0] digit_1,digit_2,digit_3,digit_4;//存储各个位数字
//-------------------三段式状态机--------------//
//第一段:描述总状态的跳转,时序逻辑,给现态赋值
always@(posedge sysclk)begin
if(!rst_n) //复位拉低
c_state <= IDLE;//赋初始值
else
c_state <= n_state;
end
//第二段:描述各个状态之间的跳转,组合逻辑,给次态赋值
always @(*)
begin
if(!rst_n) //复位拉低
n_state = IDLE ;//赋初始值
else
begin
case (c_state)
IDLE :begin
n_state = Cmd1;
end
Cmd1 :begin
if(cnt_bit == 4'd8 && cnt_clk == delay - 1'd1)//8位数据传输完成+1bit结束信号
n_state = Cmd2;
else
n_state = c_state;//n_state = Cmd1-----保持
end
Cmd2 :begin
if(cnt_bit == 4'd8 && cnt_clk == delay - 1'd1)//8位数据传输完成+1bit结束信号
n_state = Cmd3;
else
n_state = c_state;//n_state = Cmd2-----保持
end
Cmd3 :begin
if(cnt_bit == 4'd8 && cnt_clk == delay - 1'd1)//8位数据传输完成+1bit结束信号
n_state = DATA_W;
else
n_state = c_state;//n_state = Cmd3-----保持
end
DATA_W:begin
if(cnt_bit == 4'd8 && cnt_clk == delay - 1'd1 && cnt_byte == 4'd7)//8个字节的数据传输完成
n_state = Cmd4;
else
n_state = c_state;//n_state = DATA_W-----保持
end
Cmd4 :begin
if(cnt_bit == 4'd8 && cnt_clk == delay - 1'd1)//8位数据传输完成+1bit结束信号
n_state = IDLE;
else
n_state = c_state;//n_state = Cmd4-----保持
end
default: n_state = IDLE ;//赋初始值
endcase
end
end
//第三段:描述各个状态下的动作,时序逻辑,给动作赋值
//cnt_bit、cnt_clk
always @(posedge sysclk)
begin
if(!rst_n)begin
cnt_bit <= 4'd0;
cnt_clk <= 9'd0;
end
else
begin
case (c_state)
if(cnt_clk == delay - 1)begin//计满传输1bit所需时间
cnt_clk <= 9'd0;
if(cnt_bit == 4'd8)//计满9bit
cnt_bit <= 4'd0;
else
cnt_bit <= cnt_bit + 1'd1;
end
else
cnt_clk <= cnt_clk + 1'd1;
end
default:
begin
cnt_bit <= 4'd0;
cnt_clk <= 9'd0;
end
endcase
end
end
//cnt_byte ----- 字节计数器
always @(posedge sysclk)
begin
if(!rst_n)
cnt_byte <= 4'd0;
else if(c_state == DATA_W)begin//在写数据状态时
if(cnt_bit == 4'd8 && cnt_clk == delay - 1'd1)begin
if(cnt_byte == 4'd7)//计满8个字节
cnt_byte <= 4'd0;
else
cnt_byte <= cnt_byte + 1'd1;//计满9bit,cnt_byte+1
end
else
cnt_byte <= cnt_byte;
end
else //不在写数据状态时
cnt_byte <= 4'd0;//不工作
end
//CLK
always @(posedge sysclk)
begin
if(!rst_n)
CLK<= 1'b1;//赋初始值
else
begin
case (c_state)
if(cnt_clk == 9'd0 )begin
if(cnt_bit == 4'd8)
CLK <= 1'b1;
else
CLK <= 1'b0;
end
else if(cnt_clk == delay / 2'd2 )
CLK <= 1'b1;
else
CLK <= CLK;
end
default: CLK<= 1'b1;
endcase
end
end
//STB----片选信号---低电平有效
always @(posedge sysclk)
begin
if(!rst_n)
STB <= 1'b1;//赋初始值
else
begin
case (c_state)
if(cnt_clk == 9'd0 && cnt_bit == 4'd0)
STB <= 1'b0;
else if(cnt_clk == delay - 1'd1 && cnt_bit == 4'd7)
STB <= 1'b1;
else
STB <= STB;
end
Cmd3 :begin
if(cnt_clk == 9'd0 && cnt_bit == 4'd0)
STB <= 1'b0;
else
STB <= STB;
end
DATA_W:begin
if(cnt_clk == delay - 1'd1 && cnt_bit == 4'd7 && cnt_byte == 4'd7)
STB <= 1'b1;
else
STB <= STB;
end
default: STB <= 1'b1;
endcase
end
end
//data_reg----数据缓存
always @(posedge sysclk)
begin
if(!rst_n)
data_reg <= 8'd0;
else
begin
case (c_state)
Cmd1 :data_reg <= data_cmd1;//设置显示模式
Cmd2 :data_reg <= data_cmd2;//设置数据命令
Cmd3 :data_reg <= data_addr;//设置显示地址
DATA_W:
begin
case (cnt_byte)
4'd0: data_reg <= digit_1; //传输第一位
4'd1: data_reg <= digit_2;
4'd2: data_reg <= digit_3;
4'd3: data_reg <= digit_4;
default: data_reg <= 8'd0;
endcase
end
Cmd4 :data_reg <= data_cmd3;//设置显示控制命令
default: data_reg <= 8'd0;
endcase
end
end
//DIN----串行数据输入
always @(posedge sysclk)
begin
if(!rst_n)
DIN <= 1'b1;
else if(cnt_clk == delay / 2'd2)begin
case (c_state)
if(cnt_bit <= 4'd7)
DIN <= data_reg[cnt_bit];//将并行数据转换为串行数据
else if(cnt_bit == 4'd8)
DIN <= 1'b1;
else
DIN <= DIN;
end
default: DIN <= 1'b1;
endcase
end
else
DIN <= DIN;
end
//周期计数器
always @(posedge sysclk)
begin
if(!rst_n)
cnt_cycle <= 10'd0;
else if (c_state == Cmd4 && cnt_bit == 4'd8 && cnt_clk == delay - 1'd1)//CMD4结束时计数
if (cnt_cycle == delay_cnt - 1'd1)
cnt_cycle <= 10'd0;
else
cnt_cycle <= cnt_cycle + 1;
else
cnt_cycle <= cnt_cycle;
end
//将计数器转化为四位数据
always @(*)
begin
if(!rst_n)
begin
digit_1 = 8'd0;
digit_2 = 8'd0;
digit_3 = 8'd0;
digit_4 = 8'd0;
end
else
begin
case(data_dy % 10)//个位
14'd0: digit_1 = num_0;
14'd1: digit_1 = num_1;
14'd2: digit_1 = num_2;
14'd3: digit_1 = num_3;
14'd4: digit_1 = num_4;
14'd5: digit_1 = num_5;
14'd6: digit_1 = num_6;
14'd7: digit_1 = num_7;
14'd8: digit_1 = num_8;
14'd9: digit_1 = num_9;
default: digit_1 = 8'b0;
endcase
case((data_dy / 10) % 10)//十位
14'd0: digit_2 = num_0;
14'd1: digit_2 = num_1;
14'd2: digit_2 = num_2;
14'd3: digit_2 = num_3;
14'd4: digit_2 = num_4;
14'd5: digit_2 = num_5;
14'd6: digit_2 = num_6;
14'd7: digit_2 = num_7;
14'd8: digit_2 = num_8;
14'd9: digit_2 = num_9;
default: digit_2 = 8'b0;
endcase
case((data_dy / 100) % 10)//百位
14'd0: digit_3 = num_0;
14'd1: digit_3 = num_1;
14'd2: digit_3 = num_2;
14'd3: digit_3 = num_3;
14'd4: digit_3 = num_4;
14'd5: digit_3 = num_5;
14'd6: digit_3 = num_6;
14'd7: digit_3 = num_7;
14'd8: digit_3 = num_8;
14'd9: digit_3 = num_9;
default: digit_3 = 8'b0;
endcase
case((data_dy / 1000) % 10)//千位
14'd0: digit_4 = num_0;
14'd1: digit_4 = num_1;
14'd2: digit_4 = num_2;
14'd3: digit_4 = num_3;
14'd4: digit_4 = num_4;
14'd5: digit_4 = num_5;
14'd6: digit_4 = num_6;
14'd7: digit_4 = num_7;
14'd8: digit_4 = num_8;
14'd9: digit_4 = num_9;
default: digit_4 = 8'b0;
endcase
end
end
//动态数据
always @(posedge sysclk)
begin
if(!rst_n)
data_dy <= 14'd0;
else if (c_state == Cmd4 && cnt_bit == 4'd8 && cnt_clk == delay - 1'd1 && cnt_cycle == delay_cnt - 1'd1)
if(data_dy == 14'd9999)
data_dy <= 14'd0;
else
data_dy <= data_dy + 1;
else
data_dy <= data_dy;
end
endmodule2、请画出简易数码管秒表数据模块钓时字图?
评论 0