差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
数码管模块 [2017/06/01 10:38]
anran [硬件说明]
数码管模块 [2022/07/20 10:27] (当前版本)
zhijun [小结]
行 1: 行 1:
-======STEP FPGA驱动基于74HC595的数码管模块======+## STEP FPGA驱动基于74HC595的数码管模块
  
 本节将和大家一起使用FPGA驱动底板上的6位数码管实现动态显示。 本节将和大家一起使用FPGA驱动底板上的6位数码管实现动态显示。
  
  
-====硬件说明==== +### 硬件说明 
--------+
 在前面之前的入门教程中[[4. 数码管显示| 数码管独立显示 ]]章节已为大家介绍了数码管独立显示的相关内容,关于独立显示这里就不在赘述。我们的底板上有6位数码管,根据驱动方法不同,有以下比较: 在前面之前的入门教程中[[4. 数码管显示| 数码管独立显示 ]]章节已为大家介绍了数码管独立显示的相关内容,关于独立显示这里就不在赘述。我们的底板上有6位数码管,根据驱动方法不同,有以下比较:
 \\ \\
行 37: 行 37:
 \\ \\
  
-====Verilog代码==== +### Verilog代码 
-------+
 <code verilog> <code verilog>
  
行 44: 行 44:
 // >>>>>>>>>>>>>>>>>>>>>>>>>​ COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<​ // >>>>>>>>>>>>>>>>>>>>>>>>>​ COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<​
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
-// Module: ​Array_KeyBoard+// Module:Segment_scan ​
 //  // 
 // Author: Step // Author: Step
 //  // 
-// Description: ​Array_KeyBoard+// Description: ​Display with Segment tube 
 +//  
 +// Web: www.stepfpga.com
 //  // 
-// Web: www.stepfapga.com 
-// 
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
 // Code Revision History : // Code Revision History :
行 58: 行 58:
 // V1.0     ​|2015/​11/​11 ​  ​|Initial ver // V1.0     ​|2015/​11/​11 ​  ​|Initial ver
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
-module ​Array_KeyBoard #+module ​Segment_scan
 ( (
- parameter NUM_FOR_200HZ = 60000 //​定义计数器cnt的计数范围,例化时可更改 +input clk_in,​ //​系统时钟 
-+input rst_n_in,​ //​系统复位,低有效 
-+input [3:0] seg_data_1, //SEG1 数码管要显示的数据 
- input clk_in,​ //​系统时钟 +input [3:0] seg_data_2, //SEG2 数码管要显示的数据 
- input rst_n_in,​ //​系统复位,低有效 +input [3:0] seg_data_3,​ //​SEG3 数码管要显示的数据 
- input [3:0] col, //矩阵按键列接口 +input [3:​0] seg_data_4,​ //​SEG4 数码管要显示的数据 
- output reg [3:0] row, //矩阵按键行接口 +input [3:​0] seg_data_5,​ //​SEG5 数码管要显示的数据 
- output reg [15:0] key_out //消抖后信号+input [3:​0] seg_data_6,​ //​SEG6 数码管要显示的数据 
 +input [5:​0] seg_data_en,​ //​各位数码管数据显示使能,[MSB~LSB]=[SEG6~SEG1] 
 +input [5:​0] seg_dot_en,​ //​各位数码管小数点显示使能,[MSB~LSB]=[SEG6~SEG1] 
 +output reg rclk_out,​ //​74HC595的RCK管脚 
 +output reg sclk_out,​ //​74HC595的SCK管脚 
 +output reg sdio_out //74HC595SER管脚
 ); );
-/* 
-因使用4x4矩阵按键,通过扫描方法实现,所以这里使用状态机实现,共分为4种状态 
-在其中的某一状态时间里,对应的4个按键相当于独立按键,可按独立按键的周期采样法采样 
-周期采样时每隔20ms采样一次,对应这里状态机每隔20ms循环一次,每个状态对应5ms时间 
-对矩阵按键实现原理不明白的,请去了解矩阵按键实现原理 
-*/  
- localparam STATE0 = 2'b00; 
- localparam STATE1 = 2'b01; 
- localparam STATE2 = 2'b10; 
- localparam STATE3 = 2'b11; 
  
- //计数分频实现5ms周期信号clk_200hz +parameter CLK_DIV_PERIOD = 600; //​分频系数 
- reg [15:0] cnt+ 
- reg clk_200hz+localparam IDLE = 3'​d0;​ 
- always@(posedge clk_in or negedge rst_n_in) begin +localparam MAIN = 3'​d1;​ 
- if(!rst_n_in) begin //​复位时计数器cnt清零,clk_200hz信号起始电平为低电平 +localparam WRITE = 3'​d2;​ 
- cnt <= 16'​d0;​ + 
- clk_200hz ​<= 1'​b0;​ +localparam LOW = 1'​b0;​ 
- end else begin +localparam HIGH = 1'​b1;​ 
- if(cnt >= ((NUM_FOR_200HZ>>​1) ​- 1)) begin //​数字逻辑中右移1位相当于除2 + 
- cnt <= 16'd0+//创建码管的字库,字库数据依段码顺序有关 
- clk_200hz <= ~clk_200hz;​ //​clk_200hz信号取反 +//​这里字库数据[MSB~LSB]={DP,​G,​F,​E,​D,​C,​B,​A} 
- end ​else begin +reg[7:0] seg [15:0];  
- cnt <= cnt + 1'b1; +initial begin 
- clk_200hz <= clk_200hz;​ +    seg[0] = 8'​h3f; ​  // ​ 0 
- end +    seg[1] = 8'​h06; ​  // ​ 1 
- end+    seg[2] = 8'​h5b; ​  // ​ 2 
 +    seg[3] = 8'​h4f; ​  // ​ 3 
 +    seg[4] = 8'​h66; ​  // ​ 4 
 +    seg[5] = 8'​h6d; ​  // ​ 5 
 +    seg[6] = 8'​h7d; ​  // ​ 6 
 +    seg[7] = 8'​h07; ​  // ​ 7 
 +    seg[8] = 8'​h7f; ​  // ​ 8 
 +    seg[9] = 8'​h6f; ​  // ​ 9 
 + seg[10] = 8'​h77; ​  // ​ A 
 +    seg[11] = 8'​h7c; ​  // ​ b 
 +    seg[12] = 8'​h39; ​  // ​ C 
 +    seg[13] = 8'​h5e; ​  // ​ d 
 +    seg[14] = 8'​h79; ​  // ​ E 
 +    seg[15] = 8'​h71; ​  // ​ F 
 +end  
 +  
 +//计数器对系统时钟信号进行计数 
 +reg[9:0] cnt=0
 +always@(posedge clk_in or negedge rst_n_in) begin 
 + if(!rst_n_in) begin 
 + cnt <= 1'​b0;​ 
 + end else begin 
 + if(cnt>​=(CLK_DIV_PERIOD-1)) cnt <= 1'b0
 + else cnt <= cnt + 1'b1;
  end  end
 +end
  
- reg [1:​0] c_state;​ +//根据计数器计数的周期产生分频的脉冲信号 
- //状态机根据clk_200hz信号在4个状态间循环,每个状态对矩阵按键的行接口单行有效 +reg clk_div; ​ 
- always@(posedge ​clk_200hz ​or negedge rst_n_in) begin +always@(posedge ​clk_in ​or negedge rst_n_in) begin 
- if(!rst_n_in) begin + if(!rst_n_in) begin 
- c_state ​<= STATE0; + clk_div ​<= 1'b0
- row <= 4'b1110+ end else begin 
- end else begin + if(cnt==(CLK_DIV_PERIOD-1)) clk_div ​<= 1'b1
- case(c_state) + else clk_div ​<= 1'b0;
- STATE0: begin c_state <STATE1; row <4'​b1101;​ end //​状态c_state跳转及对应状态下矩阵按键的row输出 +
- STATE1: begin c_state ​<= STATE2; row <= 4'b1011end +
- STATE2: begin c_state ​<= STATE3; row <= 4'b0111end +
- STATE3: begin c_state <= STATE0; row <= 4'​b1110;​ end +
- default:​begin c_state <= STATE0; row <= 4'​b1110;​ end +
- endcase +
- end+
  end  end
-  +end 
- //因为每个状态中单行有效,通过对列接口电平状态采样得到对应4个按键状态,依次循环 + 
- always@(negedge clk_200hz ​or negedge rst_n_in) begin +//使用状态机完成数码管扫描和74HC595时序实现 
- if(!rst_n_in) begin +reg [15:​0] data_reg;​ 
- key_out ​<= 16'hffff+reg [2:​0] cnt_main;​ 
- end else begin +reg [5:​0] cnt_write;​ 
- case(c_state+reg [2:0] state = IDLE; 
- STATE0:key_out[3:0] <= col; //采集当前状态的数据赋值给对应寄存器位 +always@(posedge clk_in ​or negedge rst_n_in) begin 
- STATE1:key_out[7:4] <= col+ if(!rst_n_in) begin //​复位状态下,各寄存器置初值 
- STATE2:key_out[11:8] <= col+ state ​<= IDLE; 
- STATE3:key_out[15:12] <= col+ cnt_main <= 3'd0
- default:key_out ​<= 16'hffff+ cnt_write <= 6'​d0;​ 
- endcase + sdio_out <= 1'​b0;​ 
- end+ sclk_out <= LOW; 
 + rclk_out <= LOW; 
 + end else begin 
 + case(state) 
 + IDLE:​begin //​IDLE作为第一个状态,相当于软复位 
 + state <= MAIN; 
 + cnt_main <= 3'​d0;​ 
 + cnt_write <= 6'​d0;​ 
 + sdio_out <= 1'​b0;​ 
 + sclk_out <= LOW; 
 + rclk_out <= LOW; 
 + end 
 + MAIN:begin 
 + if(cnt_main >= 3'd5) cnt_main <= 1'​b0;​ 
 + else cnt_main <= cnt_main + 1'​b1;​ 
 + case(cnt_main) 
 + //​对6位数码管逐位扫描 
 + 3'​d0: begin  
 + state ​<= WRITE; //在配置完发给74HC595的数据同时跳转至WRITE状态,完成串行时序 
 + data_reg <= {seg[seg_data_1]|(seg_dot_en[0]?​8'​h80:​8'​h00),​seg_data_en[0]?​8'​hfe:​8'​hff};​ 
 + //​data_reg[15:​8]为段选,data_reg[7:​0]为位选 
 + //​seg[seg_data_1] ​ 是根据端口输入获取相应字库数据 
 + //​seg_dot_en[0]?​8'​h80:​8'​h00 ​ 是根据小数点显示使能信号 控制SEG1数码管的小数点DP段的电平 
 + //​seg_data_en[0]?​8'​hfe:​8'​hff ​ 是根据数据显示使能信号 控制SEG1数码管的位选引脚的电平 
 + end 
 + 3'​d1: begin  
 + state <= WRITE; 
 + data_reg <= {seg[seg_data_2]|(seg_dot_en[1]?​8'​h80:8'​h00),​seg_data_en[1]?​8'​hfd:​8'​hff};​  
 + end 
 + 3'​d2:​ begin  
 + state ​<= WRITE
 + data_reg <= {seg[seg_data_3]|(seg_dot_en[2]?​8'​h80:8'​h00),​seg_data_en[2]?​8'​hfb:8'hff};  
 + end 
 + 3'​d3:​ begin  
 + state <= WRITE; 
 + data_reg <= {seg[seg_data_4]|(seg_dot_en[3]?​8'​h80:​8'​h00),​seg_data_en[3]?​8'​hf7:​8'​hff};​  
 + end 
 + 3'​d4:​ begin  
 + state ​<= WRITE; 
 + data_reg <= {seg[seg_data_5]|(seg_dot_en[4]?​8'​h80:​8'​h00),​seg_data_en[4]?​8'​hef:​8'​hff};​ 
 + end 
 + 3'​d5:​ begin  
 + state <= WRITE; 
 + data_reg <= {seg[seg_data_6]|(seg_dot_en[5]?​8'​h80:​8'​h00),​seg_data_en[5]?​8'​hdf:​8'​hff};​  
 + end 
 + default:​ state <= IDLE; 
 + endcase 
 + end 
 + WRITE:begin 
 + if(clk_div) begin //​74HC595的串行时钟有速度要求,需要按照分频后的节拍 
 + if(cnt_write >= 6'd33) cnt_write <= 1'​b0;​ 
 + else cnt_write <= cnt_write + 1'​b1;​ 
 + case(cnt_write) 
 + //​74HC595是串行转并行的芯片,3路输入可产生8路输出,而且可以级联使用 
 + //​74HC595的时序实现,参考74HC595的芯片手册 
 + 6'​d0: ​ begin sclk_out <= LOW; sdio_out <= data_reg[15]; end //​SCK下降沿时SER更新数据 
 + 6'​d1 begin sclk_out <= HIGH; end //​SCK上升沿时SER数据稳定 
 + 6'​d2: ​ begin sclk_out <= LOW; sdio_out <= data_reg[14];​ end 
 + 6'​d3: ​ begin sclk_out <= HIGH; end 
 + 6'​d4: ​ begin sclk_out <= LOW; sdio_out <= data_reg[13];​ end 
 + 6'​d5: ​ begin sclk_out <= HIGH; end 
 + 6'​d6: ​ begin sclk_out <= LOW; sdio_out <= data_reg[12]; end 
 + 6'​d7: ​ begin sclk_out ​<= HIGHend 
 + 6'​d8 begin sclk_out ​<= LOW; sdio_out <= data_reg[11];​ end 
 + 6'​d9: ​ begin sclk_out <= HIGH; end 
 + 6'​d10:​ begin sclk_out <= LOW; sdio_out <= data_reg[10];​ end 
 + 6'​d11:​ begin sclk_out <= HIGH; end 
 + 6'​d12:​ begin sclk_out <= LOW; sdio_out <= data_reg[9];​ end 
 + 6'​d13:​ begin sclk_out <= HIGH; end 
 + 6'​d14:​ begin sclk_out <= LOW; sdio_out <= data_reg[8];​ end 
 + 6'​d15:​ begin sclk_out <= HIGH; end 
 + 6'​d16:​ begin sclk_out <= LOW; sdio_out <= data_reg[7];​ end 
 + 6'​d17:​ begin sclk_out <= HIGH; end 
 + 6'​d18:​ begin sclk_out <= LOW; sdio_out <= data_reg[6];​ end 
 + 6'​d19:​ begin sclk_out <= HIGH; end 
 + 6'​d20:​ begin sclk_out <= LOW; sdio_out <= data_reg[5];​ end 
 + 6'​d21:​ begin sclk_out <= HIGH; end 
 + 6'​d22:​ begin sclk_out <= LOW; sdio_out <= data_reg[4];​ end 
 + 6'​d23:​ begin sclk_out <= HIGH; end 
 + 6'​d24:​ begin sclk_out <= LOW; sdio_out <= data_reg[3];​ end 
 + 6'​d25:​ begin sclk_out <= HIGH; end 
 + 6'​d26:​ begin sclk_out <= LOW; sdio_out <= data_reg[2];​ end 
 + 6'​d27:​ begin sclk_out <= HIGH; end 
 + 6'​d28:​ begin sclk_out <= LOW; sdio_out <= data_reg[1];​ end 
 + 6'​d29:​ begin sclk_out <= HIGH; end 
 + 6'​d30:​ begin sclk_out <= LOW; sdio_out <= data_reg[0];​ end 
 + 6'​d31:​ begin sclk_out <= HIGH; end 
 + 6'​d32:​ begin rclk_out <= HIGH; end //​当16位数据传送完成后RCK拉高,输出生效 
 + 6'd33: begin rclk_out <= LOWstate <= MAIN; end 
 + default:​ state <= IDLE; 
 + endcase 
 + end else begin 
 + sclk_out <= sclk_out; 
 + sdio_out <= sdio_out; 
 + rclk_out <= rclk_out; 
 + cnt_write <= cnt_write;​ 
 + state <= state; 
 + end 
 + end 
 + default: state <= IDLE; 
 + endcase
  end  end
 +end
  
 endmodule endmodule
行 136: 行 249:
 \\  ​ \\  ​
 \\  ​ \\  ​
-====引脚分配==== + 
-------- + 
-综合(synthesize)完成之后一定配置FPGA引脚到应的外设,这样下载FPGA程序后才能达到我们想要的效果+### 小结 
 + 
 +本节主为大家讲解了数码管显示的相关原理及软件大家掌握同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试
 \\ \\
-我们使用PCLK充当程序中clk_in,使用按键KEY1充当rst_n_in,col和row的引脚按照高低顺序分频,key_out可以分配给LED灯、三色灯、PMOD等FPGA控制输出的引脚上,通过观察或示波器测量检验设计+如果你对Diamond软件的使用不了解,请参考这里:[[lattice_fpga|Diamond的使用]]。 
 + 
 +### 相关资料 
 \\ \\
-{{ :step_baseboard_v2.2_引脚分配.jpg?​1200 |}}+使用[[STEP-MXO2第二代]]的数码管扫描程序 ​后续会有下载连接 ​ 待更新
 \\ \\
-====小结==== +使用[[STEP-MAX10]]数码管扫描序:  后续会有下连接 ​ 待更新
------- +
-本节主要为大家讲解了矩阵按键工作原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流,生成FPGA配置文件加测试。+
 \\ \\
-如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 
- 
-====相关资料==== 
------- 
-后期会有链接到云盘 
-