安德鲁

[原创].七段数码管驱动,Verilog版本

0
阅读(2888)

我以前在艾米电子写的驱动。贴在博客之目的:一、时常记记,以防忘记;二、分享给大家。也许是工作比较忙之缘故吧,新近的博文啰嗦的话语少了许多,直接贴上代码,大家有什么不明白的,留言即可。

版本1


顶层例化文件

module seg7x8(
	  input        CLOCK_50,                // 板载50MHz时钟
	  input        Q_KEY,                   // 板载按键RST
	  output [7:0] SEG7_SEG,                // 七段数码管 段脚             
	  output [2:0] SEG7_SEL                 // 七段数码管 待译位脚
	);
	 
	// 显示效果:
	// -------------------------
	// |1 |2.|3 |4 |  |B |C |D |
	// -------------------------
	seg7x8_drive u0(
	  .i_clk            (CLOCK_50),
	  .i_rst_n          (Q_KEY),
	   
	  .i_turn_off       (8'b0000_1000),     // 熄灭位[2进制][此处取第3位
	  .i_dp             (8'b0100_0000),     // 小数点位[2进制][此处取第6位
	  .i_data           (32'h1234_ABCD),    // 欲显数据[16进制]
	   
	  .o_seg(SEG7_SEG),
	  .o_sel(SEG7_SEL)
	);
	 
	endmodule

驱动文件

module seg7x8_drive(
	  input         i_clk,
	  input         i_rst_n,
	   
	  input  [7:0]  i_turn_off,             // 熄灭位[2进制
	  input  [7:0]  i_dp,                   // 小数点位[2进制
	  input  [31:0] i_data,                 // 欲显数据[16进制  
	   
	  output [7:0]  o_seg,                  // 段脚
	  output [2:0]  o_sel                   // 使用74HC138译出位脚
	);
	 
	//++++++++++++++++++++++++++++++++++++++
	// 分频部分 开始
	//++++++++++++++++++++++++++++++++++++++
	reg [16:0] cnt;                         // 计数子
	 
	always @ (posedge i_clk, negedge i_rst_n)
	  if (!i_rst_n)
	    cnt <= 0;
	  else
	    cnt <= cnt + 1'b1;
	 
	wire seg7_clk = cnt[16];                // (2^17/50M = 2.6114)ms
	//--------------------------------------
	// 分频部分 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 动态扫描, 生成seg7_addr 开始
	//++++++++++++++++++++++++++++++++++++++
	reg [2:0]  seg7_addr;                   // 第几个seg7
	 
	always @ (posedge seg7_clk, negedge i_rst_n)
	  if (!i_rst_n)
	    seg7_addr <= 0;
	  else
	    seg7_addr <= seg7_addr + 1'b1;     
	//--------------------------------------
	// 动态扫描, 生成seg7_addr 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据seg7_addr, 译出位码 开始
	//++++++++++++++++++++++++++++++++++++++
	reg [2:0] o_sel_r;                      // 位选码寄存器
	 
	// 开发板上SEG7的方向是低位在左,高位在右
	// 但是实际上我们看数的方向是高位在左,低位在右
	// 故此处将第0位对应DIG[7],第7位对应DIG[0]
	always
	  case (seg7_addr)
	    0 : o_sel_r = 3'b111;               // SEG7[7]
	    1 : o_sel_r = 3'b110;               // SEG7[6]
	    2 : o_sel_r = 3'b101;               // SEG7[5]
	    3 : o_sel_r = 3'b100;               // SEG7[4] 
	    4 : o_sel_r = 3'b011;               // SEG7[3]
	    5 : o_sel_r = 3'b010;               // SEG7[2]
	    6 : o_sel_r = 3'b001;               // SEG7[1]
	    7 : o_sel_r = 3'b000;               // SEG7[0]
	  endcase
	//--------------------------------------
	// 根据seg7_addr, 译出位码 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据seg7_addr, 选择熄灭码 开始
	//++++++++++++++++++++++++++++++++++++++
	reg turn_off_r;                         // 熄灭码
	 
	always
	  case (seg7_addr)
	    0 : turn_off_r = i_turn_off[0];
	    1 : turn_off_r = i_turn_off[1];
	    2 : turn_off_r = i_turn_off[2];
	    3 : turn_off_r = i_turn_off[3];
	    4 : turn_off_r = i_turn_off[4];
	    5 : turn_off_r = i_turn_off[5];
	    6 : turn_off_r = i_turn_off[6];
	    7 : turn_off_r = i_turn_off[7];
	  endcase
	//--------------------------------------
	// 根据seg7_addr, 选择熄灭码 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据seg7_addr, 选择小数点码 开始
	//++++++++++++++++++++++++++++++++++++++
	reg dp_r;                               // 小数点码
	 
	always
	  case (seg7_addr)
	    0 : dp_r = i_dp[0];
	    1 : dp_r = i_dp[1];
	    2 : dp_r = i_dp[2];
	    3 : dp_r = i_dp[3];
	    4 : dp_r = i_dp[4];
	    5 : dp_r = i_dp[5];
	    6 : dp_r = i_dp[6];
	    7 : dp_r = i_dp[7];
	  endcase
	//--------------------------------------
	// 根据seg7_addr, 选择小数点码 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据seg7_addr, 选择待译段码 开始
	//++++++++++++++++++++++++++++++++++++++
	reg [3:0] seg_data_r;                   // 待译段码
	 
	always
	  case (seg7_addr)
	    0 : seg_data_r = i_data[3:0];
	    1 : seg_data_r = i_data[7:4];
	    2 : seg_data_r = i_data[11:8];
	    3 : seg_data_r = i_data[15:12];
	    4 : seg_data_r = i_data[19:16];
	    5 : seg_data_r = i_data[23:20];
	    6 : seg_data_r = i_data[27:24];
	    7 : seg_data_r = i_data[31:28];
	  endcase
	//--------------------------------------
	// 根据seg7_addr, 选择待译段码 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据熄灭码/小数点码/待译段码
	// 译出段码,开始
	//++++++++++++++++++++++++++++++++++++++
	reg [7:0] o_seg_r;                      // 段码寄存器
	 
	/*
	 *     0
	 *  -------
	 *  |     |
	 * 5|  6  |1
	 *  -------
	 *  |     |
	 * 4|     |2
	 *  ------- . 7
	 *    3
	 */
	  
	// 共阳
	always @ (posedge i_clk, negedge i_rst_n)
	  if (!i_rst_n)
	    o_seg_r <= 8'hFF;                   // 送熄灭码
	  else
	    if(turn_off_r)                      // 送熄灭码
	      o_seg_r <= 8'hFF;
	    else
	      if(!dp_r)
	        case(seg_data_r)                // 无小数点
	          4'h0 : o_seg_r <= 8'hC0;
	          4'h1 : o_seg_r <= 8'hF9;
	          4'h2 : o_seg_r <= 8'hA4;
	          4'h3 : o_seg_r <= 8'hB0;
	          4'h4 : o_seg_r <= 8'h99;
	          4'h5 : o_seg_r <= 8'h92;
	          4'h6 : o_seg_r <= 8'h82;
	          4'h7 : o_seg_r <= 8'hF8;
	          4'h8 : o_seg_r <= 8'h80;
	          4'h9 : o_seg_r <= 8'h90;
	          4'hA : o_seg_r <= 8'h88;
	          4'hB : o_seg_r <= 8'h83;
	          4'hC : o_seg_r <= 8'hC6;
	          4'hD : o_seg_r <= 8'hA1;
	          4'hE : o_seg_r <= 8'h86;
	          4'hF : o_seg_r <= 8'h8E;
	        endcase
	      else
	        case(seg_data_r)                // 加小数点
	          4'h0 : o_seg_r <= 8'hC0 ^ 8'h80;
	          4'h1 : o_seg_r <= 8'hF9 ^ 8'h80;
	          4'h2 : o_seg_r <= 8'hA4 ^ 8'h80;
	          4'h3 : o_seg_r <= 8'hB0 ^ 8'h80;
	          4'h4 : o_seg_r <= 8'h99 ^ 8'h80;
	          4'h5 : o_seg_r <= 8'h92 ^ 8'h80;
	          4'h6 : o_seg_r <= 8'h82 ^ 8'h80;
	          4'h7 : o_seg_r <= 8'hF8 ^ 8'h80;
	          4'h8 : o_seg_r <= 8'h80 ^ 8'h80;
	          4'h9 : o_seg_r <= 8'h90 ^ 8'h80;
	          4'hA : o_seg_r <= 8'h88 ^ 8'h80;
	          4'hB : o_seg_r <= 8'h83 ^ 8'h80;
	          4'hC : o_seg_r <= 8'hC6 ^ 8'h80;
	          4'hD : o_seg_r <= 8'hA1 ^ 8'h80;
	          4'hE : o_seg_r <= 8'h86 ^ 8'h80;
	          4'hF : o_seg_r <= 8'h8E ^ 8'h80;
	        endcase
	//--------------------------------------
	// 根据熄灭码/小数点码/待译段码
	// 译出段码,结束
	//--------------------------------------
	 
	assign o_sel = o_sel_r;                 // 寄存器输出位选码
	assign o_seg = o_seg_r;                 // 寄存器输出段码
	 
	endmodule

版本2

顶层例化文件

module seg7x8(
	  input        CLOCK_50,                // 板载50MHz时钟
	  input  [1:1] KEY,                     // KEY[1]
	  output [7:0] SEG7_SEG,                // 七段数码管 段脚             
          output [7:0] SEG7_DIG                 // 七段数码管 位脚
	);
	 
	// 显示效果:
	// -------------------------
	// |1 |2.|3 |4 |  |B |C |D |
	// -------------------------
	seg7x8_drive u0(
	  .i_clk            (CLOCK_50),
	  .i_rst_n          (KEY),
	   
	  .i_turn_off       (8'b0000_1000),     // 熄灭位[2进制][此处取第3位
	  .i_dp             (8'b0100_0000),     // 小数点位[2进制][此处取第6位
	  .i_data           (32'h1234_ABCD),    // 欲显数据[16进制]
	   
	  .o_seg            (SEG7_SEG),
	  .o_dig            (SEG7_DIG)
	);
	 
	endmodule

驱动文件

module seg7x8_drive(
	  input         i_clk,
	  input         i_rst_n,
	   
	  input  [7:0]  i_turn_off,             // 熄灭位[2进制
	  input  [7:0]  i_dp,                   // 小数点位[2进制
	  input  [31:0] i_data,                 // 欲显数据[16进制  
	   
	  output [7:0]  o_seg,                  // 段脚
	  output [7:0]  o_dig                   // 位脚
	);
	 
	//++++++++++++++++++++++++++++++++++++++
	// 分频部分 开始
	//++++++++++++++++++++++++++++++++++++++
	reg [16:0] cnt;                         // 计数子
	 
	always @ (posedge i_clk, negedge i_rst_n)
	  if (!i_rst_n)
	    cnt <= 0;
	  else
	    cnt <= cnt + 1'b1;
	 
	wire seg7_clk = cnt[16];                // (2^17/50M = 2.6114)ms
	//--------------------------------------
	// 分频部分 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 动态扫描, 生成seg7_addr 开始
	//++++++++++++++++++++++++++++++++++++++
	reg [2:0]  seg7_addr;                   // 第几个seg7
	 
	always @ (posedge seg7_clk, negedge i_rst_n)
	  if (!i_rst_n)
	    seg7_addr <= 0;
	  else
	    seg7_addr <= seg7_addr + 1'b1;     
	//--------------------------------------
	// 动态扫描, 生成seg7_addr 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据seg7_addr, 译出位码 开始
	//++++++++++++++++++++++++++++++++++++++
	reg [7:0] o_dig_r;                      // 位码寄存器
	 
	// 开发板上SEG7的方向是低位在左,高位在右
	// 但是实际上我们看数的方向是高位在左,低位在右
	// 故此处将第0位对应DIG[7],第7位对应DIG[0]
	always
	  case (seg7_addr)
	    0 : o_dig_r = 8'b0000_0001;
	    1 : o_dig_r = 8'b0000_0010;
	    2 : o_dig_r = 8'b0000_0100;
	    3 : o_dig_r = 8'b0000_1000;
	    4 : o_dig_r = 8'b0001_0000;
	    5 : o_dig_r = 8'b0010_0000;
	    6 : o_dig_r = 8'b0100_0000;
	    7 : o_dig_r = 8'b1000_0000;
	  endcase
	//--------------------------------------
	// 根据seg7_addr, 译出位码 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据seg7_addr, 选择熄灭码 开始
	//++++++++++++++++++++++++++++++++++++++
	reg turn_off_r;                         // 熄灭码
	 
	always
	  case (seg7_addr)
	    0 : turn_off_r = i_turn_off[0];
	    1 : turn_off_r = i_turn_off[1];
	    2 : turn_off_r = i_turn_off[2];
	    3 : turn_off_r = i_turn_off[3];
	    4 : turn_off_r = i_turn_off[4];
	    5 : turn_off_r = i_turn_off[5];
	    6 : turn_off_r = i_turn_off[6];
	    7 : turn_off_r = i_turn_off[7];
	  endcase
	//--------------------------------------
	// 根据seg7_addr, 选择熄灭码 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据seg7_addr, 选择小数点码 开始
	//++++++++++++++++++++++++++++++++++++++
	reg dp_r;                               // 小数点码
	 
	always
	  case (seg7_addr)
	    0 : dp_r = i_dp[0];
	    1 : dp_r = i_dp[1];
	    2 : dp_r = i_dp[2];
	    3 : dp_r = i_dp[3];
	    4 : dp_r = i_dp[4];
	    5 : dp_r = i_dp[5];
	    6 : dp_r = i_dp[6];
	    7 : dp_r = i_dp[7];
	  endcase
	//--------------------------------------
	// 根据seg7_addr, 选择小数点码 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据seg7_addr, 选择待译段码 开始
	//++++++++++++++++++++++++++++++++++++++
	reg [3:0] seg_data_r;                   // 待译段码
	 
	always
	  case (seg7_addr)
	    0 : seg_data_r = i_data[3:0];
	    1 : seg_data_r = i_data[7:4];
	    2 : seg_data_r = i_data[11:8];
	    3 : seg_data_r = i_data[15:12];
	    4 : seg_data_r = i_data[19:16];
	    5 : seg_data_r = i_data[23:20];
	    6 : seg_data_r = i_data[27:24];
	    7 : seg_data_r = i_data[31:28];
	  endcase
	//--------------------------------------
	// 根据seg7_addr, 选择待译段码 结束
	//--------------------------------------
	 
	 
	//++++++++++++++++++++++++++++++++++++++
	// 根据熄灭码/小数点码/待译段码
	// 译出段码,开始
	//++++++++++++++++++++++++++++++++++++++
	reg [7:0] o_seg_r;                      // 段码寄存器
	 
	/*
	 *     0
	 *  -------
	 *  |     |
	 * 5|  6  |1
	 *  -------
	 *  |     |
	 * 4|     |2
	 *  ------- . 7
	 *    3
	 */
	  
	// 共阳
	always @ (posedge i_clk, negedge i_rst_n)
	  if (!i_rst_n)
	    o_seg_r <= 8'hFF;                   // 送熄灭码
	  else
	    if(turn_off_r)                      // 送熄灭码
	      o_seg_r <= 8'hFF;
	    else
	      if(!dp_r)
	        case(seg_data_r)                // 无小数点
	          4'h0 : o_seg_r <= 8'hC0;
	          4'h1 : o_seg_r <= 8'hF9;
	          4'h2 : o_seg_r <= 8'hA4;
	          4'h3 : o_seg_r <= 8'hB0;
	          4'h4 : o_seg_r <= 8'h99;
	          4'h5 : o_seg_r <= 8'h92;
	          4'h6 : o_seg_r <= 8'h82;
	          4'h7 : o_seg_r <= 8'hF8;
	          4'h8 : o_seg_r <= 8'h80;
	          4'h9 : o_seg_r <= 8'h90;
	          4'hA : o_seg_r <= 8'h88;
	          4'hB : o_seg_r <= 8'h83;
	          4'hC : o_seg_r <= 8'hC6;
	          4'hD : o_seg_r <= 8'hA1;
	          4'hE : o_seg_r <= 8'h86;
	          4'hF : o_seg_r <= 8'h8E;
	        endcase
	      else
	        case(seg_data_r)                // 加小数点
	          4'h0 : o_seg_r <= 8'hC0 ^ 8'h80;
	          4'h1 : o_seg_r <= 8'hF9 ^ 8'h80;
	          4'h2 : o_seg_r <= 8'hA4 ^ 8'h80;
	          4'h3 : o_seg_r <= 8'hB0 ^ 8'h80;
	          4'h4 : o_seg_r <= 8'h99 ^ 8'h80;
	          4'h5 : o_seg_r <= 8'h92 ^ 8'h80;
	          4'h6 : o_seg_r <= 8'h82 ^ 8'h80;
	          4'h7 : o_seg_r <= 8'hF8 ^ 8'h80;
	          4'h8 : o_seg_r <= 8'h80 ^ 8'h80;
	          4'h9 : o_seg_r <= 8'h90 ^ 8'h80;
	          4'hA : o_seg_r <= 8'h88 ^ 8'h80;
	          4'hB : o_seg_r <= 8'h83 ^ 8'h80;
	          4'hC : o_seg_r <= 8'hC6 ^ 8'h80;
	          4'hD : o_seg_r <= 8'hA1 ^ 8'h80;
	          4'hE : o_seg_r <= 8'h86 ^ 8'h80;
	          4'hF : o_seg_r <= 8'h8E ^ 8'h80;
	        endcase
	//--------------------------------------
	// 根据熄灭码/小数点码/待译段码
	// 译出段码,结束
	//--------------------------------------
	 
	/*
	 *        | c[1]
	 * b[in] -|
	 *        | e[out]
	 */
	assign o_dig = ~o_dig_r;                 // 寄存器输出位码
	assign o_seg = o_seg_r;                 // 寄存器输出段码
	 
	endmodule