小梅哥和你一起深入学习FPGA之数码管动态扫描(上)
时间:02-18
来源:互联网
点击:
关键代码解读
因为数码管属于低速设备,其正常的扫描频率为500~10KHz,扫描频率太快,会导致系统功耗增加,显示效果变暗。扫描频率太慢,会有明显的闪烁感。本实验通过调试观察,选择以1KHz作为扫描频率,实际显示效果非常好。
因此本实验首先就需要产生一个1KHz的扫描时钟,该时钟由系统时钟分频得到。产生1KHz扫描时钟的代码如下:
parameter system_clk = 50_000_000;
localparam cnt1_MAX = system_clk/1000/2-1;
//1KHz时钟分频计数器
always@(posedge Clk)
begin
if(!Rst_n)cnt1
else if(cnt1==cnt1_MAX)cnt1
else cnt1
end
//得到1KHz时钟
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)clk_1K
else if(cnt1==cnt1_MAX)
clk_1K
else ;
其中,定义了一个全局参数system_clk,该参数为Clk的频率,不同的时钟频率,只需要更改该参数,就可改变分频计数器的最大计数值,以保证1KHz分频的精准性。
在驱动中,数码管的位选以扫描时钟的速率进行切换,因为只有6位数码管,因此当位选计数到6-1后必须清零从头开始计数。相关代码如下:
//位选信号控制
always@(posedge clk_1K or negedge Rst_n)
if(!Rst_n)sel_r
else if(sel_r == 3'd5)
sel_r
else
sel_r
每个数码管需要显示的内容都不相同,由Data中相应的位指定,Data中各位与数码管的位对应关系如下:
Data位Data[23:20]Data[19:16]Data[15:12]Data[11:8]Data[7:4]Data[3:0]
数码管位数码管0数码管1数码管2数码管3数码管4数码管5
因此需要从Data中将每个数码管被选中时需要显示的数据提取出来,提取数据的代码如下所示:
//根据不同的数码管位选择不同的待显示数据
always@(*)
if(!Rst_n)
disp_data
else
begin
case(sel_r)
0:disp_data
1:disp_data
2:disp_data
3:disp_data
4:disp_data
5:disp_data
default :disp_data
endcase
end
因为提取出来的数据还是BCD码的形式,还需要将BCD码对应的数据翻译成为数码管显示对应字符时应该点亮或熄灭的对应的LED的控制信号,因此必须还有一个BCD码译码的过程,该过程代码如下图所示:
//数据译码,将待显示数据翻译为符合数码管显示的编码
always@(*)
if(!Rst_n)
seg_r
else
begin
case(disp_data)
4'd0: seg_r
4'd1: seg_r
4'd2: seg_r
4'd3: seg_r
4'd4: seg_r
4'd5: seg_r
4'd6: seg_r
4'd7: seg_r
4'd8: seg_r
4'd9: seg_r
4'd10: seg_r
4'd11: seg_r
4'd12: seg_r
4'd13: seg_r
4'd14: seg_r
4'd15: seg_r
default : seg_r
endcase
end
最后,需要将位选和段选信号输出:
assign Dig_Led_seg = seg_r;
assign Dig_Led_sel = sel_r;
控制部分相对简单,只需要根据对应的 按键信息,给待显示的数据加上一个对应的值,该部分代码如下所示:
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Dig_Led_Data
else if(Key_Flag)
begin
case(Key_Value)
4'b0001:Dig_Led_Data
4'b0010:Dig_Led_Data
4'b0100:Dig_Led_Data
4'b1000:Dig_Led_Data
default:Dig_Led_Data
endcase
end
因为数码管属于低速设备,其正常的扫描频率为500~10KHz,扫描频率太快,会导致系统功耗增加,显示效果变暗。扫描频率太慢,会有明显的闪烁感。本实验通过调试观察,选择以1KHz作为扫描频率,实际显示效果非常好。
因此本实验首先就需要产生一个1KHz的扫描时钟,该时钟由系统时钟分频得到。产生1KHz扫描时钟的代码如下:
parameter system_clk = 50_000_000;
localparam cnt1_MAX = system_clk/1000/2-1;
//1KHz时钟分频计数器
always@(posedge Clk)
begin
if(!Rst_n)cnt1
else if(cnt1==cnt1_MAX)cnt1
else cnt1
end
//得到1KHz时钟
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)clk_1K
else if(cnt1==cnt1_MAX)
clk_1K
else ;
其中,定义了一个全局参数system_clk,该参数为Clk的频率,不同的时钟频率,只需要更改该参数,就可改变分频计数器的最大计数值,以保证1KHz分频的精准性。
在驱动中,数码管的位选以扫描时钟的速率进行切换,因为只有6位数码管,因此当位选计数到6-1后必须清零从头开始计数。相关代码如下:
//位选信号控制
always@(posedge clk_1K or negedge Rst_n)
if(!Rst_n)sel_r
else if(sel_r == 3'd5)
sel_r
else
sel_r
每个数码管需要显示的内容都不相同,由Data中相应的位指定,Data中各位与数码管的位对应关系如下:
Data位Data[23:20]Data[19:16]Data[15:12]Data[11:8]Data[7:4]Data[3:0]
数码管位数码管0数码管1数码管2数码管3数码管4数码管5
因此需要从Data中将每个数码管被选中时需要显示的数据提取出来,提取数据的代码如下所示:
//根据不同的数码管位选择不同的待显示数据
always@(*)
if(!Rst_n)
disp_data
else
begin
case(sel_r)
0:disp_data
1:disp_data
2:disp_data
3:disp_data
4:disp_data
5:disp_data
default :disp_data
endcase
end
因为提取出来的数据还是BCD码的形式,还需要将BCD码对应的数据翻译成为数码管显示对应字符时应该点亮或熄灭的对应的LED的控制信号,因此必须还有一个BCD码译码的过程,该过程代码如下图所示:
//数据译码,将待显示数据翻译为符合数码管显示的编码
always@(*)
if(!Rst_n)
seg_r
else
begin
case(disp_data)
4'd0: seg_r
4'd1: seg_r
4'd2: seg_r
4'd3: seg_r
4'd4: seg_r
4'd5: seg_r
4'd6: seg_r
4'd7: seg_r
4'd8: seg_r
4'd9: seg_r
4'd10: seg_r
4'd11: seg_r
4'd12: seg_r
4'd13: seg_r
4'd14: seg_r
4'd15: seg_r
default : seg_r
endcase
end
最后,需要将位选和段选信号输出:
assign Dig_Led_seg = seg_r;
assign Dig_Led_sel = sel_r;
控制部分相对简单,只需要根据对应的 按键信息,给待显示的数据加上一个对应的值,该部分代码如下所示:
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Dig_Led_Data
else if(Key_Flag)
begin
case(Key_Value)
4'b0001:Dig_Led_Data
4'b0010:Dig_Led_Data
4'b0100:Dig_Led_Data
4'b1000:Dig_Led_Data
default:Dig_Led_Data
endcase
end
电子 单片机 ARM FPGA 电路 电路图 二极管 发光二极管 三极管 LED 电阻 电流 相关文章:
- 基于ARM的嵌入式系统中从串配置FPGA的实现(06-09)
- 周立功:如何兼顾学习ARM与FPGA(05-23)
- 初学者如何学习FPGA(08-06)
- 为何、如何学习FPGA(05-23)
- 学习FPGA绝佳网站推荐!!!(05-23)
- 我的FPGA学习历程(05-23)