2022寒假在家练 基于iCE40UP5K的FPGA学习平台,利用PWM制作一个音乐播放器(项目2)
基于iCE40UP5k的FPGA学习平台,利用PWM制作一个音乐播放器。总共包含三首曲子,通过含有代码消抖的按键进行切换,同时正在播放的曲目名称会在SPI OLED屏上显示。
标签
嵌入式系统
FPGA
数字逻辑
PWM
蜂鸣器
OLED显示
Undefined_User
更新2022-03-03
992

2022寒假在家一起练——基于iCE40UP5K的FPGA学习平台,利用PWM制作一个音乐播放器(项目2)

1 项目需求及功能

  1. 利用PWM驱动蜂鸣器以播放歌曲
  2. 将正在播放的曲目名称通过SPI OLED显示
  3. 用含有软件消抖的按键切换歌曲
  4. 呼吸灯指示按键的触发

2 整体功能框图

整体功能框图由图一所示。

Frox216XFK20do-wSYT4L88pUEaa

图一整体功能框图

 

3 操作说明

板卡资源的操作与说明由下图所示(图二)。

FgX9EHoCCTKuNOp-li9QVjC8Znxr

图二:操作与说明

 

4 代码与实现思路

依据功能逐项介绍如何实现。

4.1 利用PWM驱动蜂鸣器以播放歌曲

扩展板上的蜂鸣器属于无源蜂鸣器,其内部不带震荡源,且直流信号无法令发生。用一定频率交流信号(如方波)去驱动它,可使其发出特定频率的声音。

通过歌曲简谱,将歌曲转换为单音音符的排列;每个单音音符通过在单位时间250ms内,以一定频率的方波驱动蜂鸣器实现。

每个音符的频率右下表所示(表一)。

FhIkBR8ln9a53RibhiDuVMBK6rR5

表一:不同音符对应的频率

 

根据频率和音符的关系,将音符对应的频率值取出来,根据频率值算出分频比。由表一所示的音符频率,建立音符库模块module key_lib。代码如下:

module key_lib (
  
  input   wire              clk,
  input   wire              rst,
  input   wire    [4:0]     key_num,
  
  output  reg     [23:0]    divnum
);
  
  reg             [10:0]    freq;
  
  always @ * begin
    case (key_num)
	  5'd0    : freq =    11'd1  ;
		
      5'd1    : freq =    11'd262;
      5'd2    : freq =    11'd294;
      5'd3    : freq =    11'd330;
      5'd4    : freq =    11'd349;
      5'd5    : freq =    11'd392;
      5'd6    : freq =    11'd440;
      5'd7    : freq =    11'd494;
      
      5'd8    : freq =    11'd523;
      5'd9    : freq =    11'd587;
      5'd10   : freq =    11'd659;
      5'd11   : freq =    11'd699;
      5'd12   : freq =    11'd784;
      5'd13   : freq =    11'd880;
      5'd14   : freq =    11'd988;
      
      5'd15   : freq =    11'd1050;
      5'd16   : freq =    11'd1175;
      5'd17   : freq =    11'd1319;
      5'd18   : freq =    11'd1397;
      5'd19   : freq =    11'd1568;
      5'd20   : freq =    11'd1760;
      5'd21   : freq =    11'd1976;
      default : freq =    11'd1;
    endcase
  end
  
  always @ (posedge clk, negedge rst) begin
    if (!rst)
      divnum <= 24'd12_000_000;
    else
      divnum <= 12_000_000/freq; //每数这么多次响一下
  end

endmodule

 

以250ms为一个音符的周期,每过250ms,计数器加一,开始下一个音符的输出。模块module next_key代码如下:

module next_key (clk, rst, cnt_key, flag_cnt, key_down);

	input   wire           	clk;
	input   wire           	rst;
	input	wire			flag_cnt;
	input 	wire 			key_down;
	
	output  reg		[8:0]	cnt_key;
	
	// each key last 1/4 second. 12_000_000 / 4 = 3_000_000. log2(3_000_000)=22;
	parameter WIDTH = 22;
	parameter CNT = 3000000;
	
	reg		[WIDTH-1:0] count;
	wire    			flag;
  

  
  always @ (posedge clk, negedge rst) begin
    if (!rst) count <= 22'd0;
    else
      if (count >= CNT-1'b1)
        count <= 22'd0;
      else
        count <= count + 1'b1;
  end

  assign flag = (count == CNT - 1'b1) ? 1'b1 : 1'b0;
    
  always @ (posedge clk, negedge rst, posedge key_down) begin
    if (!rst) cnt_key <= 7'd0;
	else if (key_down) cnt_key <= 7'd0;
    else if (flag_cnt==1'b0) cnt_key <= 7'd0;
	else cnt_key <= cnt_key + flag;
  end

endmodule

 

根据三首歌曲的简谱,依次去索引音符库内的音符,决定在每个250ms内输出那个音符。输出为分频系数。三首歌曲简谱以及代码如下(图三、四、五):

FvOWD9j-QACNEkrYllG4W9_Gnk4y

图三:我心永恒简谱

Fgrowhs1yIU8em64P_idZpKetUld

图四:爱美丽简谱

FgKqiPmNs0I59XAzagC2yu_53fxF

图五:百年孤寂简谱

 

我心永恒模块module heart代码如下:

module heart (clk,rst,cnt_key,key_num, flag_cnt);

  input   wire            clk;
  input   wire            rst;
  input   wire    [8:0]   cnt_key;
  
  output  reg     [4:0]   key_num;
  output	  reg	   		 flag_cnt;
  
 
  
  always @ (posedge clk, negedge rst) begin
    if (rst == 1'b0)
      key_num <= 5'd0;
    else
      case (cnt_key)
        9'd0    :   begin
				   key_num <= 5'd15; flag_cnt<=1'b1; end 
        9'd1    :   key_num <= 5'd15;
        9'd2    :   key_num <= 5'd15;
        9'd3    :   key_num <= 5'd15;
        9'd4    :   key_num <= 5'd15;
        9'd5    :   key_num <= 5'd15;
        9'd6    :   key_num <= 5'd15;
        9'd7    :   key_num <= 5'd15;
        9'd8    :   key_num <= 5'd15;
        9'd9    :   key_num <= 5'd14;
        9'd10   :   key_num <= 5'd14;
        9'd11   :   key_num <= 5'd15;
        9'd12   :   key_num <= 5'd15;
		9'd13   :   key_num <= 5'd15;
        9'd14   :   key_num <= 5'd15;
        9'd15   :   key_num <= 5'd15;
        9'd16   :   key_num <= 5'd15;
        9'd17   :   key_num <= 5'd14;
        9'd18   :   key_num <= 5'd14;
        9'd19   :   key_num <= 5'd15;
        9'd20   :   key_num <= 5'd15;
        9'd21   :   key_num <= 5'd15;
        9'd22   :   key_num <= 5'd15;
        9'd23   :   key_num <= 5'd16;
        9'd24   :   key_num <= 5'd16;
        9'd25   :   key_num <= 5'd17;
        9'd26   :   key_num <= 5'd17;
        9'd27   :   key_num <= 5'd17;
        9'd28   :   key_num <= 5'd17;
        9'd29   :   key_num <= 5'd16;
        9'd30   :   key_num <= 5'd16;
        9'd31   :   key_num <= 5'd16;
        9'd32   :   key_num <= 5'd16;
        9'd33   :   key_num <= 5'd15;
        9'd34   :   key_num <= 5'd15;
        9'd35   :   key_num <= 5'd15;
        9'd36   :   key_num <= 5'd15;
        9'd37   :   key_num <= 5'd15;
        9'd38   :   key_num <= 5'd15;
        9'd39   :   key_num <= 5'd15;
        9'd40   :   key_num <= 5'd15;
        9'd41   :   key_num <= 5'd15;
        9'd42   :   key_num <= 5'd14;
        9'd43   :   key_num <= 5'd14;
        9'd44   :   key_num <= 5'd15;
        9'd45   :   key_num <= 5'd15;
        9'd46   :   key_num <= 5'd15;
        9'd47   :   key_num <= 5'd15;
        9'd48   :   key_num <= 5'd15;
        9'd49   :   key_num <= 5'd15;
        9'd50   :   key_num <= 5'd12;
        9'd51   :   key_num <= 5'd12;
        9'd52   :   key_num <= 5'd12;
        9'd53   :   key_num <= 5'd12;
        9'd54   :   key_num <= 5'd12;
        9'd55   :   key_num <= 5'd12;
        9'd56   :   key_num <= 5'd12;
        9'd57   :   key_num <= 5'd12;
        9'd58   :   key_num <= 5'd12;
        9'd59   :   key_num <= 5'd12;
        9'd60   :   key_num <= 5'd12;
        9'd61   :   key_num <= 5'd12;
        9'd62   :   key_num <= 5'd12;
        9'd63   :   key_num <= 5'd12;
        9'd64   :   key_num <= 5'd12;
		9'd65   :   key_num <= 5'd12;
        9'd66   :   key_num <= 5'd12;
		9'd67   :   key_num <= 5'd12;
        9'd68   :   key_num <= 5'd12;
        9'd69   :   key_num <= 5'd12;
		
        9'd70    :   key_num <= 5'd15;
        9'd71    :   key_num <= 5'd15;
        9'd72    :   key_num <= 5'd15;
        9'd73    :   key_num <= 5'd15;
        9'd74    :   key_num <= 5'd15;
        9'd75    :   key_num <= 5'd15;
        9'd76    :   key_num <= 5'd15;
        9'd77    :   key_num <= 5'd15;
        9'd78    :   key_num <= 5'd15;
        9'd79    :   key_num <= 5'd14;
		9'd80    :   key_num <= 5'd 14 ;
        9'd81    :   key_num <= 5'd15;
        9'd82    :   key_num <= 5'd15;
        9'd83    :   key_num <= 5'd15;
        9'd84    :   key_num <= 5'd15;
        9'd85    :   key_num <= 5'd15;
        9'd86    :   key_num <= 5'd15;
        9'd87    :   key_num <= 5'd14;
        9'd88    :   key_num <= 5'd14;
        9'd89    :   key_num <= 5'd15;
        9'd90    :   key_num <= 5'd15;
        9'd91    :   key_num <= 5'd15;
        9'd92    :   key_num <= 5'd15;
        9'd93    :   key_num <= 5'd16;
        9'd94    :   key_num <= 5'd16;
        9'd95    :   key_num <= 5'd17;
        9'd96    :   key_num <= 5'd17;
        9'd97    :   key_num <= 5'd17;
        9'd98    :   key_num <= 5'd17;
        9'd99    :   key_num <= 5'd16;
        9'd100   :   key_num <= 5'd 16 ;
        9'd101   :   key_num <= 5'd 16 ;
        9'd102   :   key_num <= 5'd 16 ;
        9'd103   :   key_num <= 5'd 15 ;
        9'd104   :   key_num <= 5'd 15 ;
        9'd105   :   key_num <= 5'd 15 ;
        9'd106   :   key_num <= 5'd 15 ;
        9'd107   :   key_num <= 5'd 15 ;
        9'd108   :   key_num <= 5'd 15 ;
        9'd109   :   key_num <= 5'd 15 ;
        9'd110   :   key_num <= 5'd 15 ;
        9'd111   :   key_num <= 5'd 15 ;
        9'd112   :   key_num <= 5'd 14 ;
        9'd113   :   key_num <= 5'd 14 ;
        9'd114   :   key_num <= 5'd 15 ;
        9'd115   :   key_num <= 5'd 15 ;
        9'd116   :   key_num <= 5'd 15 ;
        9'd117   :   key_num <= 5'd 15 ;
        9'd118   :   key_num <= 5'd 15 ;
        9'd119   :   key_num <= 5'd 15 ;
        9'd120   :   key_num <= 5'd 12 ;
        9'd121   :   key_num <= 5'd 12 ;
        9'd122   :   key_num <= 5'd 12 ;
        9'd123   :   key_num <= 5'd 12 ;
        9'd124   :   key_num <= 5'd 12 ;
        9'd125   :   key_num <= 5'd 12 ;
        9'd126   :   key_num <= 5'd 12 ;
        9'd127   :   key_num <= 5'd 12 ;
        9'd128   :   key_num <= 5'd 12 ;
        9'd129   :   key_num <= 5'd 12 ;
        9'd130   :   key_num <= 5'd 12  ;
        9'd131   :   key_num <= 5'd 12 ;
		9'd132    :   key_num <=5'd 12 ;
        9'd133   :   key_num <= 5'd 12 ;
		9'd134   :   key_num <= 5'd 12 ;
		9'd135   :   key_num <= 5'd 12 ;
		9'd136   :   key_num <= 5'd 12 ;
		9'd137   :   key_num <= 5'd 12 ;
		9'd138   :   key_num <= 5'd 12 ;
		9'd139   :   key_num <= 5'd 12 ;
		
		9'd140   :   key_num <= 5'd15;
		9'd141   :   key_num <= 5'd15;
		9'd142   :   key_num <= 5'd15;
		9'd143   :   key_num <= 5'd15;
		9'd144   :   key_num <= 5'd15;
		9'd145   :   key_num <= 5'd15;
		9'd146   :   key_num <= 5'd15;
		9'd147   :   key_num <= 5'd15;
		9'd148   :   key_num <= 5'd16;
		9'd149   :   key_num <= 5'd16;
		9'd150   :   key_num <= 5'd16;
		9'd151   :   key_num <= 5'd16;
		9'd152   :   key_num <= 5'd16;
		9'd153   :   key_num <= 5'd16;
		9'd154   :   key_num <= 5'd16;
		9'd155   :   key_num <= 5'd16;
		9'd156   :   key_num <= 5'd12;
		9'd157   :   key_num <= 5'd12;
		9'd158   :   key_num <= 5'd19;
		9'd159   :   key_num <= 5'd19;
		9'd160   :   key_num <= 5'd19;
		9'd161   :   key_num <= 5'd19;
		9'd162   :   key_num <= 5'd18;
		9'd163   :   key_num <= 5'd18;
		9'd164   :   key_num <= 5'd17;
		9'd165   :   key_num <= 5'd17;
		9'd166   :   key_num <= 5'd16;
		9'd167   :   key_num <= 5'd16;
		9'd168   :   key_num <= 5'd16;
		9'd169   :   key_num <= 5'd16;
		9'd170   :   key_num <= 5'd17;
		9'd171   :   key_num <= 5'd17;
		9'd172   :   key_num <= 5'd18;
		9'd173   :   key_num <= 5'd18;
		9'd174   :   key_num <= 5'd17;
		9'd175   :   key_num <= 5'd17;
		9'd176   :   key_num <= 5'd17;
		9'd177   :   key_num <= 5'd17;
		9'd178   :   key_num <= 5'd16;
		9'd179   :   key_num <= 5'd16;
		9'd180   :   key_num <= 5'd15;
		9'd181   :   key_num <= 5'd15;
		9'd182   :   key_num <= 5'd14;
		9'd183   :   key_num <= 5'd14;
		9'd184   :   key_num <= 5'd15;
		9'd185   :   key_num <= 5'd15;
		9'd186   :   key_num <= 5'd15;
		9'd187   :   key_num <= 5'd15;
		9'd188   :   key_num <= 5'd14;
		9'd189   :   key_num <= 5'd14;
		9'd190   :   key_num <= 5'd13;
		9'd191   :   key_num <= 5'd13;
		9'd192   :   key_num <= 5'd13;
		9'd193   :   key_num <= 5'd13;
		9'd194   :   key_num <= 5'd13;
		9'd195   :   key_num <= 5'd13;
		9'd196   :   key_num <= 5'd13;
		9'd197   :   key_num <= 5'd13;
		9'd198   :   key_num <= 5'd12;
		9'd199   :   key_num <= 5'd12;
		9'd200   :   key_num <= 5'd12;
		9'd201   :   key_num <= 5'd12;
		9'd202   :   key_num <= 5'd12;
		9'd203   :   key_num <= 5'd12;
		9'd204   :   key_num <= 5'd12;
		9'd205   :   key_num <= 5'd12;
		
		9'd206   :   key_num <= 5'd15;
		9'd207   :   key_num <= 5'd15;
		9'd208   :   key_num <= 5'd15;
		9'd209   :   key_num <= 5'd15;
		9'd210   :   key_num <= 5'd15;
		9'd211   :   key_num <= 5'd15;
		9'd212   :   key_num <= 5'd15;
		9'd213   :   key_num <= 5'd15;
		9'd214   :   key_num <= 5'd16;
		9'd215   :   key_num <= 5'd16;
		9'd216   :   key_num <= 5'd16;
		9'd217   :   key_num <= 5'd16;
		9'd218   :   key_num <= 5'd16;
		9'd219   :   key_num <= 5'd16;
		9'd220   :   key_num <= 5'd16;
		9'd221   :   key_num <= 5'd16;
		9'd222   :   key_num <= 5'd12;
		9'd223   :   key_num <= 5'd12;
		9'd224   :   key_num <= 5'd19;
		9'd225   :   key_num <= 5'd19;
		9'd226   :   key_num <= 5'd19;
		9'd227   :   key_num <= 5'd19;
		9'd228   :   key_num <= 5'd18;
		9'd229   :   key_num <= 5'd18;
		9'd230   :   key_num <= 5'd17;
		9'd231   :   key_num <= 5'd17;
		9'd232   :   key_num <= 5'd16;
		9'd233   :   key_num <= 5'd16;
		9'd234   :   key_num <= 5'd16;
		9'd235   :   key_num <= 5'd16;
		9'd236   :   key_num <= 5'd17;
		9'd237   :   key_num <= 5'd17;
		9'd238   :   key_num <= 5'd18;
		9'd239   :   key_num <= 5'd18;
		9'd240   :   key_num <= 5'd17;
		9'd241   :   key_num <= 5'd17;
		9'd242   :   key_num <= 5'd17;
		9'd243   :   key_num <= 5'd17;
		9'd244   :   key_num <= 5'd16;
		9'd245   :   key_num <= 5'd16;
		9'd246   :   key_num <= 5'd15;
		9'd247   :   key_num <= 5'd15;
		9'd248   :   key_num <= 5'd14;
		9'd249   :   key_num <= 5'd14;
		9'd250   :   key_num <= 5'd15;
		9'd251   :   key_num <= 5'd15;
		9'd252   :   key_num <= 5'd15;
		9'd253   :   key_num <= 5'd15;
		9'd254   :   key_num <= 5'd14;
		9'd255   :   key_num <= 5'd14;
		9'd256   :   key_num <= 5'd14;
		9'd257   :   key_num <= 5'd14;
		9'd258   :   key_num <= 5'd15;
		9'd259   :   key_num <= 5'd15;
		9'd260   :   key_num <= 5'd15;
		9'd261   :   key_num <= 5'd15;
		9'd262   :   key_num <= 5'd16;
		9'd263   :   key_num <= 5'd16;
		9'd264   :   key_num <= 5'd17;
		9'd265   :   key_num <= 5'd17;
		9'd266   :   key_num <= 5'd17;
		9'd267   :   key_num <= 5'd17;
		9'd268   :   key_num <= 5'd16;
		9'd269   :   key_num <= 5'd16;
		9'd270   :   key_num <= 5'd16;
		9'd271   :   key_num <= 5'd16;
		
		9'd272   :   key_num <= 5'd15;
		9'd273   :   key_num <= 5'd15;
		9'd274   :   key_num <= 5'd15;
		9'd275   :   key_num <= 5'd15;
		9'd276   :   key_num <= 5'd15;
		9'd277   :   key_num <= 5'd15;
		9'd278   :   key_num <= 5'd15;
		9'd279   :   key_num <= 5'd15;
		9'd280   :   key_num <= 5'd15;
		9'd281   :   key_num <= 5'd15;
		9'd282   :   key_num <= 5'd15;
		9'd283   :   key_num <= 5'd15;
		9'd284   :   key_num <= 5'd15;
		9'd285   :   key_num <= 5'd15;
		9'd286   :   key_num <= 5'd16;
		9'd287   :   key_num <= 5'd16;
		
		9'd288   :   key_num <= 5'd0 ;
		9'd289   :   key_num <= 5'd0 ;
		9'd290   :   key_num <= 5'd0 ;
		9'd291   :   key_num <= 5'd0 ;
		9'd292   :   key_num <= 5'd0 ;
		9'd293   :   key_num <= 5'd0 ;
		9'd294   :   key_num <= 5'd0 ;
		9'd295   :   begin
				     key_num <= 5'd0 ; flag_cnt <= 0; end
		

		
		default :   key_num <= 5'd0;
      endcase
  end

endmodule

爱美丽模块module emily代码如下:

module emily (clk,rst,cnt_key,key_num, flag_cnt);

  input   wire            clk;
  input   wire            rst;
  input   wire    [8:0]   cnt_key;
  
  output  reg     [4:0]   key_num;
  output	  reg	   		 flag_cnt;
  
 
  
  always @ (posedge clk, negedge rst) begin
    if (rst == 1'b0)
      key_num <= 5'd0;
    else
      case (cnt_key)
        9'd0    :   begin
				    key_num <= 5'd0 ; flag_cnt<=1'b1; end 
        9'd1    :   key_num <= 5'd0 ;
        9'd2    :   key_num <= 5'd0 ;
        9'd3    :   key_num <= 5'd0 ;
        9'd4    :   key_num <= 5'd13;
        9'd5    :   key_num <= 5'd13;
        9'd6    :   key_num <= 5'd13;
        9'd7    :   key_num <= 5'd13;
        9'd8    :   key_num <= 5'd14;
        9'd9    :   key_num <= 5'd14;
        9'd10   :   key_num <= 5'd14;
        9'd11   :   key_num <= 5'd14;
        9'd12   :   key_num <= 5'd15;
		9'd13   :   key_num <= 5'd15;
        9'd14   :   key_num <= 5'd15;
        9'd15   :   key_num <= 5'd15;
        9'd16   :   key_num <= 5'd14;
        9'd17   :   key_num <= 5'd14;
        9'd18   :   key_num <= 5'd14;
        9'd19   :   key_num <= 5'd14;
        9'd20   :   key_num <= 5'd15;
        9'd21   :   key_num <= 5'd15;
        9'd22   :   key_num <= 5'd15;
        9'd23   :   key_num <= 5'd15;
		
        9'd24   :   key_num <= 5'd16;
        9'd25   :   key_num <= 5'd16;
        9'd26   :   key_num <= 5'd16;
        9'd27   :   key_num <= 5'd16;
        9'd28   :   key_num <= 5'd16;
        9'd29   :   key_num <= 5'd16;
        9'd30   :   key_num <= 5'd16;
        9'd31   :   key_num <= 5'd16;
        9'd32   :   key_num <= 5'd16;
        9'd33   :   key_num <= 5'd16;
        9'd34   :   key_num <= 5'd16;
        9'd35   :   key_num <= 5'd0 ;
        9'd36   :   key_num <= 5'd16;
        9'd37   :   key_num <= 5'd16;
        9'd38   :   key_num <= 5'd16;
        9'd39   :   key_num <= 5'd16;
        9'd40   :   key_num <= 5'd16;
        9'd41   :   key_num <= 5'd16;
        9'd42   :   key_num <= 5'd16;
        9'd43   :   key_num <= 5'd16;
        9'd44   :   key_num <= 5'd16;
        9'd45   :   key_num <= 5'd16;
        9'd46   :   key_num <= 5'd15;
        9'd47   :   key_num <= 5'd15;
        9'd48   :   key_num <= 5'd14;
        9'd49   :   key_num <= 5'd14;
        9'd50   :   key_num <= 5'd14;
        9'd51   :   key_num <= 5'd14;
        9'd52   :   key_num <= 5'd14;
        9'd53   :   key_num <= 5'd14;
        9'd54   :   key_num <= 5'd14;
        9'd55   :   key_num <= 5'd14;
        9'd56   :   key_num <= 5'd14;
        9'd57   :   key_num <= 5'd14;
        9'd58   :   key_num <= 5'd14;
        9'd59   :   key_num <= 5'd14;
        9'd60   :   key_num <= 5'd13;
        9'd61   :   key_num <= 5'd13;
        9'd62   :   key_num <= 5'd13;
        9'd63   :   key_num <= 5'd13;
        9'd64   :   key_num <= 5'd13;
		9'd65   :   key_num <= 5'd13;
        9'd66   :   key_num <= 5'd13;
		9'd67   :   key_num <= 5'd13;
        9'd68   :   key_num <= 5'd13;
        9'd69   :   key_num <= 5'd13;
        9'd70    :   key_num <= 5'd13;
        9'd71    :   key_num <= 5'd13;
        9'd72    :   key_num <= 5'd16;
        9'd73    :   key_num <= 5'd16;
        9'd74    :   key_num <= 5'd16;
        9'd75    :   key_num <= 5'd16;
        9'd76    :   key_num <= 5'd16;
        9'd77    :   key_num <= 5'd16;
        9'd78    :   key_num <= 5'd16;
        9'd79    :   key_num <= 5'd16;
		9'd80    :   key_num <= 5'd16 ;
        9'd81    :   key_num <= 5'd16;
        9'd82    :   key_num <= 5'd16;
        9'd83    :   key_num <= 5'd16;
        9'd84    :   key_num <= 5'd16;
        9'd85    :   key_num <= 5'd16;
        9'd86    :   key_num <= 5'd17;
        9'd87    :   key_num <= 5'd17;
        9'd88    :   key_num <= 5'd16;
        9'd89    :   key_num <= 5'd16;
        9'd90    :   key_num <= 5'd15;
        9'd91    :   key_num <= 5'd15;
        9'd92    :   key_num <= 5'd14;
        9'd93    :   key_num <= 5'd14;
        9'd94    :   key_num <= 5'd15;
        9'd95    :   key_num <= 5'd15;
        9'd96    :   key_num <= 5'd14;
        9'd97    :   key_num <= 5'd14;
        9'd98    :   key_num <= 5'd14;
        9'd99    :   key_num <= 5'd14;
        9'd100   :   key_num <= 5'd14;
        9'd101   :   key_num <= 5'd14;
        9'd102   :   key_num <= 5'd14;
        9'd103   :   key_num <= 5'd14;
        9'd104   :   key_num <= 5'd14;
        9'd105   :   key_num <= 5'd14;
        9'd106   :   key_num <= 5'd14;
        9'd107   :   key_num <= 5'd14;
        9'd108   :   key_num <= 5'd13;
        9'd109   :   key_num <= 5'd13;
        9'd110   :   key_num <= 5'd13;
        9'd111   :   key_num <= 5'd13;
        9'd112   :   key_num <= 5'd13;
        9'd113   :   key_num <= 5'd13;
        9'd114   :   key_num <= 5'd13;
        9'd115   :   key_num <= 5'd13;
        9'd116   :   key_num <= 5'd13;
        9'd117   :   key_num <= 5'd13;
        9'd118   :   key_num <= 5'd13;
        9'd119   :   key_num <= 5'd13;
        9'd120   :   key_num <= 5'd15;
        9'd121   :   key_num <= 5'd15;
        9'd122   :   key_num <= 5'd15;
        9'd123   :   key_num <= 5'd15;
        9'd124   :   key_num <= 5'd15;
        9'd125   :   key_num <= 5'd15;
        9'd126   :   key_num <= 5'd15;
        9'd127   :   key_num <= 5'd15;
        9'd128   :   key_num <= 5'd15;
        9'd129   :   key_num <= 5'd15;
        9'd130   :   key_num <= 5'd15;
        9'd131   :   key_num <= 5'd15;
		9'd132    :   key_num <=5'd15;
        9'd133   :   key_num <= 5'd0 ;
		9'd134   :   key_num <= 5'd15;
		9'd135   :   key_num <= 5'd15;
		9'd136   :   key_num <= 5'd15;
		9'd137   :   key_num <= 5'd15;
		9'd138   :   key_num <= 5'd15;
		9'd139   :   key_num <= 5'd15;
		9'd140   :   key_num <= 5'd15;
		9'd141   :   key_num <= 5'd15;
		9'd142   :   key_num <= 5'd14;
		9'd143   :   key_num <= 5'd14;
		9'd144   :   key_num <= 5'd10;
		9'd145   :   key_num <= 5'd10;
		9'd146   :   key_num <= 5'd10;
		9'd147   :   key_num <= 5'd10;
		9'd148   :   key_num <= 5'd10;
		9'd149   :   key_num <= 5'd10;
		9'd150   :   key_num <= 5'd10;
		9'd151   :   key_num <= 5'd10;
		9'd152   :   key_num <= 5'd10;
		9'd153   :   key_num <= 5'd10;
		9'd154   :   key_num <= 5'd10;
		9'd155   :   key_num <= 5'd0 ;
		9'd156   :   key_num <= 5'd10;
		9'd157   :   key_num <= 5'd10;
		9'd158   :   key_num <= 5'd10;
		9'd159   :   key_num <= 5'd10;
		9'd160   :   key_num <= 5'd10;
		9'd161   :   key_num <= 5'd10;
		9'd162   :   key_num <= 5'd10;
		9'd163   :   key_num <= 5'd10;
		9'd164   :   key_num <= 5'd11;
		9'd165   :   key_num <= 5'd11;
		9'd166   :   key_num <= 5'd11;
		9'd167   :   key_num <= 5'd11;
		9'd168   :   key_num <= 5'd15;
		9'd169   :   key_num <= 5'd15;
		9'd170   :   key_num <= 5'd15;
		9'd171   :   key_num <= 5'd15;
		9'd172   :   key_num <= 5'd15;
		9'd173   :   key_num <= 5'd15;
		9'd174   :   key_num <= 5'd15;
		9'd175   :   key_num <= 5'd15;
		9'd176   :   key_num <= 5'd15;
		9'd177   :   key_num <= 5'd15;
		9'd178   :   key_num <= 5'd15;
		9'd179   :   key_num <= 5'd0 ;
		9'd180   :   key_num <= 5'd15;
		9'd181   :   key_num <= 5'd15;
		9'd182   :   key_num <= 5'd16;
		9'd183   :   key_num <= 5'd16;
		9'd184   :   key_num <= 5'd15;
		9'd185   :   key_num <= 5'd15;
		9'd186   :   key_num <= 5'd14;
		9'd187   :   key_num <= 5'd14;
		9'd188   :   key_num <= 5'd15;
		9'd189   :   key_num <= 5'd15;
		9'd190   :   key_num <= 5'd14;
		9'd191   :   key_num <= 5'd14;
		9'd192   :   key_num <= 5'd10;
		9'd193   :   key_num <= 5'd10;
		9'd194   :   key_num <= 5'd10;
		9'd195   :   key_num <= 5'd10;
		9'd196   :   key_num <= 5'd10;
		9'd197   :   key_num <= 5'd10;
		9'd198   :   key_num <= 5'd10;
		9'd199   :   key_num <= 5'd10;
		9'd200   :   key_num <= 5'd10;
		9'd201   :   key_num <= 5'd10;
		9'd202   :   key_num <= 5'd10;
		9'd203   :   key_num <= 5'd0 ;
		9'd204   :   key_num <= 5'd10;
		9'd205   :   key_num <= 5'd10;
		9'd206   :   key_num <= 5'd10;
		9'd207   :   key_num <= 5'd10;
		9'd208   :   key_num <= 5'd11;
		9'd209   :   key_num <= 5'd11;
		9'd210   :   key_num <= 5'd11;
		9'd211   :   key_num <= 5'd11;
		9'd212   :   key_num <= 5'd10;
		9'd213   :   key_num <= 5'd10;
		9'd214   :   key_num <= 5'd10;
		9'd215   :   key_num <= 5'd10;
		
		9'd216   :   key_num <= 5'd9 ;
		9'd217   :   key_num <= 5'd9 ;
		9'd218   :   key_num <= 5'd10;
		9'd219   :   key_num <= 5'd10;
		9'd220   :   key_num <= 5'd11;
		9'd221   :   key_num <= 5'd11;
		9'd222   :   key_num <= 5'd10;
		9'd223   :   key_num <= 5'd10;
		9'd224   :   key_num <= 5'd11;
		9'd225   :   key_num <= 5'd11;
		9'd226   :   key_num <= 5'd10;
		9'd227   :   key_num <= 5'd10;
		9'd228   :   key_num <= 5'd16;
		9'd229   :   key_num <= 5'd16;
		9'd230   :   key_num <= 5'd10;
		9'd231   :   key_num <= 5'd10;
		9'd232   :   key_num <= 5'd11;
		9'd233   :   key_num <= 5'd11;
		9'd234   :   key_num <= 5'd15;
		9'd235   :   key_num <= 5'd15;
		9'd236   :   key_num <= 5'd10;
		9'd237   :   key_num <= 5'd10;
		9'd238   :   key_num <= 5'd11;
		9'd239   :   key_num <= 5'd11;
		9'd240   :   key_num <= 5'd14;
		9'd241   :   key_num <= 5'd14;
		9'd242   :   key_num <= 5'd9 ;
		9'd243   :   key_num <= 5'd9 ;
		9'd244   :   key_num <= 5'd10;
		9'd245   :   key_num <= 5'd10;
		9'd246   :   key_num <= 5'd9 ;
		9'd247   :   key_num <= 5'd9 ;
		9'd248   :   key_num <= 5'd10;
		9'd249   :   key_num <= 5'd10;
		9'd250   :   key_num <= 5'd9 ;
		9'd251   :   key_num <= 5'd9 ;
		9'd252   :   key_num <= 5'd13;
		9'd253   :   key_num <= 5'd13;
		9'd254   :   key_num <= 5'd8 ;
		9'd255   :   key_num <= 5'd8 ;
		9'd256   :   key_num <= 5'd9 ;
		9'd257   :   key_num <= 5'd9 ;
		9'd258   :   key_num <= 5'd10;
		9'd259   :   key_num <= 5'd10;
		9'd260   :   key_num <= 5'd9 ;
		9'd261   :   key_num <= 5'd9 ;
		9'd262   :   key_num <= 5'd8 ;
		9'd263   :   key_num <= 5'd8 ;
		9'd264   :   key_num <= 5'd9 ;
		9'd265   :   key_num <= 5'd9 ;
		9'd266   :   key_num <= 5'd10;
		9'd267   :   key_num <= 5'd10;
		9'd268   :   key_num <= 5'd11;
		9'd269   :   key_num <= 5'd11;
		9'd270   :   key_num <= 5'd10;
		9'd271   :   key_num <= 5'd10;
		9'd272   :   key_num <= 5'd11;
		9'd273   :   key_num <= 5'd11;
		9'd274   :   key_num <= 5'd10;
		9'd275   :   key_num <= 5'd10;
		9'd276   :   key_num <= 5'd16;
		9'd277   :   key_num <= 5'd16;
		9'd278   :   key_num <= 5'd10;
		9'd279   :   key_num <= 5'd10;
		9'd280   :   key_num <= 5'd11;
		9'd281   :   key_num <= 5'd11;
		9'd282   :   key_num <= 5'd15;
		9'd283   :   key_num <= 5'd15;
		9'd284   :   key_num <= 5'd10;
		9'd285   :   key_num <= 5'd10;
		9'd286   :   key_num <= 5'd11;
		9'd287   :   key_num <= 5'd11;
		9'd288   :   key_num <= 5'd14;
		9'd289   :   key_num <= 5'd14;
		9'd290   :   key_num <= 5'd9 ;
		9'd291   :   key_num <= 5'd9 ;
		9'd292   :   key_num <= 5'd10;
		9'd293   :   key_num <= 5'd10;
		9'd294   :   key_num <= 5'd9 ;
		9'd291   :   key_num <= 5'd9 ;
		9'd292   :   key_num <= 5'd10;
		9'd293   :   key_num <= 5'd10;
		9'd294   :   key_num <= 5'd9 ;
		9'd295   :   key_num <= 5'd9 ;
		
		9'd296   :   key_num <= 5'd13;
		9'd297   :   key_num <= 5'd13;
		9'd298   :   key_num <= 5'd8 ;
		9'd299   :   key_num <= 5'd8 ;
		9'd300   :   key_num <= 5'd9 ;
		9'd301   :   key_num <= 5'd9 ;
		9'd302   :   key_num <= 5'd10;
		9'd303   :   key_num <= 5'd10;
		9'd304   :   key_num <= 5'd9;
		9'd305   :   key_num <= 5'd9;
		9'd306   :   key_num <= 5'd8 ;
		9'd307   :   key_num <= 5'd8 ;
		9'd308   :   key_num <= 5'd15;
		9'd309   :   key_num <= 5'd15;
		9'd310   :   key_num <= 5'd10;
		9'd311   :   key_num <= 5'd10;
		9'd312   :   key_num <= 5'd11;
		9'd313   :   key_num <= 5'd11;
		9'd314   :   key_num <= 5'd10;
		9'd315   :   key_num <= 5'd10;
		9'd316   :   key_num <= 5'd11;
		9'd317   :   key_num <= 5'd11;
		9'd318   :   key_num <= 5'd10;
		9'd319   :   key_num <= 5'd10;
		9'd320   :   key_num <= 5'd15;
		9'd321   :   key_num <= 5'd15;
		9'd322   :   key_num <= 5'd10;
		9'd323   :   key_num <= 5'd10;
		9'd324   :   key_num <= 5'd11;
		9'd325   :   key_num <= 5'd11;
		9'd326   :   key_num <= 5'd10;
		9'd327   :   key_num <= 5'd10;
		9'd328   :   key_num <= 5'd11;
		9'd329   :   key_num <= 5'd11;
		9'd330   :   key_num <= 5'd9 ;
		9'd331   :   key_num <= 5'd9 ;
		9'd332   :   key_num <= 5'd12;
		9'd333   :   key_num <= 5'd12;
		9'd334   :   key_num <= 5'd9 ;
		9'd335   :   key_num <= 5'd9 ;
		9'd336   :   key_num <= 5'd10;
		9'd337   :   key_num <= 5'd10;
		9'd338   :   key_num <= 5'd9 ;
		9'd339   :   key_num <= 5'd9 ;
		9'd340   :   key_num <= 5'd10;
		9'd341   :   key_num <= 5'd10;
		9'd342   :   key_num <= 5'd9 ;
		9'd343   :   key_num <= 5'd9 ;
		9'd344   :   key_num <= 5'd10;
		9'd345   :   key_num <= 5'd10;
		9'd346   :   key_num <= 5'd8 ;
		9'd347   :   key_num <= 5'd8 ;
		9'd348   :   key_num <= 5'd9 ;
		9'd349   :   key_num <= 5'd9 ;
		9'd350   :   key_num <= 5'd10;
		9'd351   :   key_num <= 5'd10;
		9'd352   :   key_num <= 5'd9 ;
		9'd353   :   key_num <= 5'd9 ;
		9'd354   :   key_num <= 5'd8 ;
		9'd355   :   key_num <= 5'd8 ;
		9'd356   :   key_num <= 5'd15;
		9'd357   :   key_num <= 5'd15;
		9'd358   :   key_num <= 5'd10;
		9'd359   :   key_num <= 5'd10;
		9'd360   :   key_num <= 5'd11;
		9'd361   :   key_num <= 5'd11;
		9'd362   :   key_num <= 5'd10;
		9'd363   :   key_num <= 5'd10;
		9'd364   :   key_num <= 5'd11;
		9'd365   :   key_num <= 5'd11;
		9'd366   :   key_num <= 5'd10;
		9'd367   :   key_num <= 5'd10;
		9'd368   :   key_num <= 5'd15;
		9'd369   :   key_num <= 5'd15;
		9'd370   :   key_num <= 5'd10;
		9'd371   :   key_num <= 5'd10;
		9'd372   :   key_num <= 5'd11;
		9'd373   :   key_num <= 5'd11;
		9'd374   :   key_num <= 5'd10;
		9'd375   :   key_num <= 5'd10;
		9'd376   :   key_num <= 5'd11;
		9'd377   :   key_num <= 5'd11;
		9'd378   :   key_num <= 5'd9 ;
		9'd379   :   key_num <= 5'd9 ;
		9'd380   :   key_num <= 5'd12;
		9'd381   :   key_num <= 5'd12;
		9'd382   :   key_num <= 5'd9 ;
		9'd383   :   key_num <= 5'd9 ;
		9'd384   :   key_num <= 5'd10;
		9'd385   :   key_num <= 5'd10;
		9'd386   :   key_num <= 5'd9 ;
		9'd387   :   key_num <= 5'd9 ;
		9'd388   :   key_num <= 5'd10;
		9'd389   :   key_num <= 5'd10;
		9'd390   :   key_num <= 5'd9 ;
		9'd391   :   key_num <= 5'd9 ;
		9'd392   :   key_num <= 5'd10;
		9'd393   :   key_num <= 5'd10;
		9'd394   :   key_num <= 5'd8 ;
		9'd395   :   key_num <= 5'd8 ;
		9'd396   :   key_num <= 5'd9 ;
		9'd397   :   key_num <= 5'd9 ;
		9'd398   :   key_num <= 5'd10;
		9'd399   :   key_num <= 5'd10;
		9'd400   :   key_num <= 5'd9 ;
		9'd401   :   key_num <= 5'd9 ;
		9'd402   :   key_num <= 5'd8 ;
		9'd403   :   key_num <= 5'd8 ;
		9'd404   :   key_num <= 5'd0 ;
		9'd405   :   key_num <= 5'd0 ;
		9'd406   :   key_num <= 5'd0 ;
		9'd407   :   key_num <= 5'd0 ;
		9'd408   :   key_num <= 5'd0 ;
		9'd409   :   key_num <= 5'd0 ;
		9'd410   :   key_num <= 5'd0 ;
		9'd411   :   begin
					 key_num <= 5'd0 ; flag_cnt <= 0; end
		
		default :   key_num <= 5'd0;
      endcase
  end

endmodule

百年孤寂模块module lonely代码如下:

module lonely (clk,rst,cnt_key,key_num, flag_cnt);

  input   wire            clk;
  input   wire            rst;
  input   wire    [8:0]   cnt_key;
  
  output  reg     [4:0]   key_num;
  output	  reg	   		 flag_cnt;
  
  always @ (posedge clk, negedge rst) begin
    if (rst == 1'b0)
      key_num <= 5'd0;
    else
      case (cnt_key)
        9'd0    :   begin
				   key_num <= 5'd14; flag_cnt<=1'b1; end
        9'd1    :   key_num <= 5'd14;
        9'd2    :   key_num <= 5'd14;
        9'd3    :   key_num <= 5'd14;
        9'd4    :   key_num <= 5'd14;
        9'd5    :   key_num <= 5'd14;
        9'd6    :   key_num <= 5'd14;
        9'd7    :   key_num <= 5'd14;
        9'd8    :   key_num <= 5'd9 ;
        9'd9    :   key_num <= 5'd8 ;
        9'd10   :   key_num <= 5'd6 ;
        9'd11   :   key_num <= 5'd6 ;
        9'd12   :   key_num <= 5'd8 ;
		9'd13   :   key_num <= 5'd8 ;
        9'd14   :   key_num <= 5'd0 ;
        9'd15   :   key_num <= 5'd0 ;
        9'd16   :   key_num <= 5'd6 ;
        9'd17   :   key_num <= 5'd6 ;
        9'd18   :   key_num <= 5'd12;
        9'd19   :   key_num <= 5'd12;
        9'd20   :   key_num <= 5'd11;
        9'd21   :   key_num <= 5'd11;
        9'd22   :   key_num <= 5'd12;
        9'd23   :   key_num <= 5'd12;
        9'd24   :   key_num <= 5'd11;
        9'd25   :   key_num <= 5'd11;
        9'd26   :   key_num <= 5'd0 ;
        9'd27   :   key_num <= 5'd0 ;
        9'd28   :   key_num <= 5'd0 ;
        9'd29   :   key_num <= 5'd0 ;
        9'd30   :   key_num <= 5'd0 ;
        9'd31   :   key_num <= 5'd0 ;
        9'd32   :   key_num <= 5'd0 ;
        9'd33   :   key_num <= 5'd0 ;
        9'd34   :   key_num <= 5'd0 ;
        9'd35   :   key_num <= 5'd0 ;
        9'd36   :   key_num <= 5'd9 ;
        9'd37   :   key_num <= 5'd9 ;
        9'd38   :   key_num <= 5'd10;
        9'd39   :   key_num <= 5'd10;
        9'd40   :   key_num <= 5'd6 ;
        9'd41   :   key_num <= 5'd6 ;
        9'd42   :   key_num <= 5'd7 ;
        9'd43   :   key_num <= 5'd7 ;
        9'd44   :   key_num <= 5'd8 ;
        9'd45   :   key_num <= 5'd8 ;
        9'd46   :   key_num <= 5'd8 ;
        9'd47   :   key_num <= 5'd8 ;
        9'd48   :   key_num <= 5'd8 ;
        9'd49   :   key_num <= 5'd9 ;
        9'd50   :   key_num <= 5'd9 ;
        9'd51   :   key_num <= 5'd7 ;
        9'd52   :   key_num <= 5'd7 ;
        9'd53   :   key_num <= 5'd7 ;
        9'd54   :   key_num <= 5'd7 ;
        9'd55   :   key_num <= 5'd7 ;
        9'd56   :   key_num <= 5'd7 ;
        9'd57   :   key_num <= 5'd7 ;
        9'd58   :   key_num <= 5'd7 ;
        9'd59   :   key_num <= 5'd7 ;
        9'd60   :   key_num <= 5'd7 ;
        9'd61   :   key_num <= 5'd7 ;
        9'd62   :   key_num <= 5'd7 ;
        9'd63   :   key_num <= 5'd0 ;
        9'd64   :   key_num <= 5'd0 ;
		9'd65   :   key_num <= 5'd0 ;
        9'd66   :   key_num <= 5'd0 ;
		
		9'd67    :   key_num <= 5'd14;
        9'd68    :   key_num <= 5'd14;
        9'd69    :   key_num <= 5'd14;
        9'd70    :   key_num <= 5'd14;
        9'd71    :   key_num <= 5'd14;
        9'd72    :   key_num <= 5'd14;
        9'd73    :   key_num <= 5'd14;
        9'd74    :   key_num <= 5'd14;
        9'd75    :   key_num <= 5'd9 ;
        9'd76    :   key_num <= 5'd8 ;
        9'd77    :   key_num <= 5'd7 ;
        9'd78    :   key_num <= 5'd7 ;
        9'd79    :   key_num <= 5'd8 ;
		9'd80    :   key_num <= 5'd8 ;
        9'd81    :   key_num <= 5'd0 ;
        9'd82    :   key_num <= 5'd0 ;
        9'd83    :   key_num <= 5'd6 ;
        9'd84    :   key_num <= 5'd6 ;
        9'd85    :   key_num <= 5'd12;
        9'd86    :   key_num <= 5'd12;
        9'd87    :   key_num <= 5'd11;
        9'd88    :   key_num <= 5'd11;
        9'd89    :   key_num <= 5'd12;
        9'd90    :   key_num <= 5'd12;
        9'd91    :   key_num <= 5'd11;
        9'd92    :   key_num <= 5'd11;
        9'd93    :   key_num <= 5'd0 ;
        9'd94    :   key_num <= 5'd0 ;
        9'd95    :   key_num <= 5'd0 ;
        9'd96    :   key_num <= 5'd0 ;
        9'd97    :   key_num <= 5'd0 ;
        9'd98    :   key_num <= 5'd0 ;
        9'd99    :   key_num <= 5'd0 ;
        9'd100   :   key_num <= 5'd0 ;
        9'd101   :   key_num <= 5'd0 ;
        9'd102   :   key_num <= 5'd0 ;
        9'd103   :   key_num <= 5'd9 ;
        9'd104   :   key_num <= 5'd9 ;
        9'd105   :   key_num <= 5'd10;
        9'd106   :   key_num <= 5'd10;
        9'd107   :   key_num <= 5'd6 ;
        9'd108   :   key_num <= 5'd6 ;
        9'd109   :   key_num <= 5'd7 ;
        9'd110   :   key_num <= 5'd7 ;
        9'd111   :   key_num <= 5'd8 ;
        9'd112   :   key_num <= 5'd8 ;
        9'd113   :   key_num <= 5'd8 ;
        9'd114   :   key_num <= 5'd8 ;
        9'd115   :   key_num <= 5'd8 ;
        9'd116   :   key_num <= 5'd9 ;
        9'd117   :   key_num <= 5'd9 ;
        9'd118   :   key_num <= 5'd10;
        9'd119   :   key_num <= 5'd10;
        9'd120   :   key_num <= 5'd10;
        9'd121   :   key_num <= 5'd10;
        9'd122   :   key_num <= 5'd10;
        9'd123   :   key_num <= 5'd10;
        9'd124   :   key_num <= 5'd10;
        9'd125   :   key_num <= 5'd10;
        9'd126   :   key_num <= 5'd10;
        9'd127   :   key_num <= 5'd10;
        9'd128   :   key_num <= 5'd10;
        9'd129   :   key_num <= 5'd10;
        9'd130   :   key_num <= 5'd10 ;
        9'd131   :   key_num <= 5'd11;
		9'd132   :   key_num <=5'd10;
        9'd133   :   key_num <= 5'd11;
		
		9'd134   :   key_num <= 5'd12;
		9'd135   :   key_num <= 5'd12;
		9'd136   :   key_num <= 5'd8 ;
		9'd137   :   key_num <= 5'd8 ;
		9'd138   :   key_num <= 5'd8 ;
		9'd139   :   key_num <= 5'd8 ;
		9'd140   :   key_num <= 5'd8 ;
		9'd141   :   key_num <= 5'd8 ;
		9'd142   :   key_num <= 5'd12;
		9'd143   :   key_num <= 5'd12;
		9'd144   :   key_num <= 5'd8 ;
		9'd145   :   key_num <= 5'd8 ;
		9'd146   :   key_num <= 5'd8 ;
		9'd147   :   key_num <= 5'd8 ;
		9'd148   :   key_num <= 5'd8 ;
		9'd149   :   key_num <= 5'd8 ;
		9'd150   :   key_num <= 5'd15;
		9'd151   :   key_num <= 5'd14;
		9'd152   :   key_num <= 5'd14;
		9'd153   :   key_num <= 5'd12;
		9'd154   :   key_num <= 5'd12;
		9'd155   :   key_num <= 5'd12;
		9'd156   :   key_num <= 5'd12;
		9'd157   :   key_num <= 5'd11;
		9'd158   :   key_num <= 5'd11;
		9'd159   :   key_num <= 5'd10;
		9'd160   :   key_num <= 5'd10;
		9'd161   :   key_num <= 5'd10;
		9'd162   :   key_num <= 5'd10;
		9'd163   :   key_num <= 5'd10;
		9'd164   :   key_num <= 5'd10;
		9'd165   :   key_num <= 5'd10;
		9'd166   :   key_num <= 5'd10;
		9'd167   :   key_num <= 5'd0 ;
		9'd168   :   key_num <= 5'd0 ;
		9'd169   :   key_num <= 5'd0 ;
		9'd170   :   key_num <= 5'd0 ;
		9'd171   :   key_num <= 5'd11;
		9'd172   :   key_num <= 5'd11;
		9'd173   :   key_num <= 5'd10;
		9'd174   :   key_num <= 5'd10;
		9'd175   :   key_num <= 5'd11;
		9'd176   :   key_num <= 5'd11;
		9'd177   :   key_num <= 5'd10;
		9'd178   :   key_num <= 5'd10;
		9'd179   :   key_num <= 5'd10;
		9'd180   :   key_num <= 5'd10;
		9'd181   :   key_num <= 5'd6 ;
		9'd182   :   key_num <= 5'd6 ;
		9'd183   :   key_num <= 5'd7 ;
		9'd184   :   key_num <= 5'd7 ;
		9'd185   :   key_num <= 5'd7 ;
		9'd186   :   key_num <= 5'd7 ;
		9'd187   :   key_num <= 5'd7 ;
		9'd188   :   key_num <= 5'd7 ;
		9'd189   :   key_num <= 5'd7 ;
		9'd190   :   key_num <= 5'd7 ;
		9'd191   :   key_num <= 5'd7 ;
		9'd192   :   key_num <= 5'd7 ;
		9'd193   :   key_num <= 5'd7 ;
		9'd194   :   key_num <= 5'd7 ;
		9'd195   :   key_num <= 5'd0 ;
		9'd196   :   key_num <= 5'd0 ;
		9'd197   :   key_num <= 5'd0 ;
		9'd198   :   begin
					 key_num <= 5'd0 ; flag_cnt <= 0; end
				
		default :   key_num <= 5'd0;
      endcase
  end

endmodule

 

通过分频数后,产生相应的波形。模块module drop_da_beat代码如下:

module drop_da_beat (

  input   wire            clk,
  input   wire            rst,
  
  input   wire  [23:0]    divnum,
  
  output  reg             drive
);
  
  reg           [23:0]    count;
  
  always @ (posedge clk, negedge rst) begin
    if (!rst) count <= 24'd0;
    else if (count >= divnum - 1'b1) count <= 24'd0;
	else count <= count + 1'b1;
  end
  
  always @ (posedge clk, negedge rst) begin
    if (!rst) drive <= 1'b0;
    else if (count < divnum[23:1]) drive <= 1'b0;
    else drive <= 1'b1;
  end

endmodule

 

引入2位寄存器[1:0]flag,通过按键控制flag,决定当前播放的歌曲。连接上述模块,形成音频部分的顶层模块module auditory_top。代码如下:

module auditory_top (

	input   wire      		clk,
	input   wire      		rst,
	input	wire			key_down,
	input	wire	[1:0]	flag,
	
	output 	wire   			drive
);


	reg						flag_cnt;
	reg			[4:0]		key_num;
	
	wire         [8:0]      	cnt_key;
	wire         [4:0]      	key_num_lonely, key_num_heart, key_num_emily;
	wire         [23:0]     	divnum;
	wire				   	flag_cnt_lonely, flag_cnt_heart, flag_cnt_emily;
	
  

	
			
	always@(posedge clk, negedge rst) begin
		if (!rst) begin 
			flag_cnt <= flag_cnt_heart;
			key_num <= key_num_heart;
		end
		else
			case(flag)
					2'd0: begin flag_cnt <= flag_cnt_heart; key_num <= key_num_heart; end
					2'd1: begin flag_cnt <= flag_cnt_emily; key_num <= key_num_emily; end
					2'd2: begin flag_cnt <= flag_cnt_lonely; key_num <= key_num_lonely; end
					default: begin flag_cnt <= flag_cnt_heart; key_num <= key_num_heart; end
			endcase
	end
  
  
  next_key next_key_inst(

      .clk		(clk),
      .rst    	(rst),
      .flag_cnt	(flag_cnt),
      .cnt_key 	(cnt_key),
	  .key_down 	(key_down)
    );
    

   heart music_u1(

      .clk         	(clk),
      .rst       	(rst),
      
      .cnt_key     	(cnt_key),
      
      .key_num    	(key_num_heart),
	  .flag_cnt		(flag_cnt_heart)
    );
	
	
	emily music_u2(

      .clk         	(clk),
      .rst       	(rst),
      .cnt_key     	(cnt_key),
      
      .key_num    	(key_num_emily),
	  .flag_cnt		(flag_cnt_emily)
    );
	
	
	lonely music_u3(

      .clk         	(clk),
      .rst       	(rst),
      .cnt_key     	(cnt_key),
      
      .key_num    	(key_num_lonely),
	  .flag_cnt		(flag_cnt_lonely)
    );
    
  key_lib key_lib_inst(
  
      .clk                  (clk),
      .rst                	(rst),
      
      .key_num              (key_num),
      
      .divnum               (divnum)
    );

  drop_da_beat drop_da_beat_inst(

      .clk                  (clk),
      .rst                  (rst),
      
      .divnum               (divnum),
      
      .drive                 (drive)
    );
    
endmodule

 

4.2 将正在播放的曲目名称通过SPI OLED显示

由于OLED这一个从设备,#CS始终接地拉低。所以此SPI OLED的模块接口为6-pin SPI。

包含7个工作状态:INIT, IDLE, MAIN, SCAN, CHINESE, WRITE, DELAY。

通过汉字字模转换工具,建立汉字字符库。字模转换工具设定如下图所示(图六)。

FkOnROyoqOnP0ypXR0OAnrxP6AG8

图六:OLED取模设置

 

通过与音频模块共享的flag信号,完成对应歌曲名称字符的选择与输出。

模块module OLED12864代码如下:

module OLED12864
(
	input				clk,		//12MHz系统时钟
	input				rst_n,		//系统复位,低有效
	
	input				key_up,
	input				key_down,

	
	output	reg	[1:0]	flag,
	output	reg			oled_csn,	//OLCD液晶屏使能
	output	reg			oled_rst,	//OLCD液晶屏复位
	output	reg			oled_dcn,	//OLCD数据指令控制
	output	reg			oled_clk,	//OLCD时钟信号
	output	reg			oled_dat	//OLCD数据信号
);
	
	localparam INIT_DEPTH = 16'd23; //LCD初始化的命令的数量
	localparam IDLE = 7'h1, MAIN = 7'h2, INIT = 7'h4, SCAN = 7'h8, WRITE = 7'h10, DELAY = 7'h20,CHINESE=7'h40;
	localparam HIGH	= 1'b1, LOW = 1'b0;
	localparam DATA	= 1'b1, CMD = 1'b0;
	
	reg 	[7:0] 			cmd [22:0];
	reg 	[39:0] 			mem [122:0];
	reg		[127:0]			mem_hanzi[16:0];
	reg		[1:0]			flag;
	reg		[7:0]			mem_hanzi_num;
	reg	[7:0]				y_p, x_ph, x_pl;
	reg	[(8*21-1):0]   char;
	reg	[7:0]				num, char_reg;				
	reg	[4:0]				cnt_main, cnt_init, cnt_scan, cnt_write;
	reg	[5:0]			cnt_chinese;
	reg	[15:0]			num_delay, cnt_delay, cnt;
	reg	[6:0] 			state, state_back;
	
	
	always @ (posedge clk or negedge rst_n) begin
		if(!rst_n) begin
			cnt_main <= 1'b0; cnt_init <= 1'b0; cnt_scan <= 1'b0; cnt_write <= 1'b0;cnt_chinese <= 1'b0;
			y_p <= 1'b0; x_ph <= 1'b0; x_pl <= 1'b0;
			num <= 1'b0; char <= 1'b0; char_reg <= 1'b0;
			num_delay <= 16'd5; cnt_delay <= 1'b0; cnt <= 1'b0;
			oled_csn <= HIGH; oled_rst <= HIGH; oled_dcn <= CMD; oled_clk <= HIGH; oled_dat <= LOW;
			state <= IDLE; state_back <= IDLE;
		end else begin
			case(state)
				IDLE:begin
						cnt_main <= 1'b0; cnt_init <= 1'b0; cnt_scan <= 1'b0; cnt_write <= 1'b0;
						y_p <= 1'b0; x_ph <= 1'b0; x_pl <= 1'b0;
						num <= 1'b0; char <= 1'b0; char_reg <= 1'b0;
						num_delay <= 16'd5; cnt_delay <= 1'b0; cnt <= 1'b0;mem_hanzi_num<=8'd0;
						oled_csn <= HIGH; oled_rst <= HIGH; oled_dcn <= CMD; oled_clk <= HIGH; oled_dat <= LOW;
						state <= MAIN; state_back <= MAIN;
					end
				MAIN:begin
						if(cnt_main >= 5'd16) cnt_main <= 5'd13;//接下来执行空操作,实现数据只刷新一次
						else cnt_main <= cnt_main + 1'b1;
						case(cnt_main)	//MAIN状态							
							5'd0 :	begin state <= INIT; end
																														
							5'd 1:	begin y_p <= 8'hb0; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							5'd 2:	begin y_p <= 8'hb1; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end												
							5'd 3:	begin y_p <= 8'hb2; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							5'd 4:	begin y_p <= 8'hb3; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							5'd 5:	begin y_p <= 8'hb4; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							5'd 6:	begin y_p <= 8'hb5; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							5'd 7:	begin y_p <= 8'hb6; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							5'd 8:	begin y_p <= 8'hb7; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end	
								
							
							
							
													
							5'd 9:	begin y_p <= 8'hb1; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= 8'd0 ; state <= CHINESE; end
							5'd10:	begin y_p <= 8'hb1; x_ph <= 8'h13; x_pl <= 8'h00; mem_hanzi_num <= 8'd2 ; state <= CHINESE; end
							5'd11 :	begin y_p <= 8'hb1; x_ph <= 8'h14; x_pl <= 8'h00; mem_hanzi_num <= 8'd4 ; state <= CHINESE; end
							5'd12:	begin y_p <= 8'hb1; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= 8'd6 ; state <= CHINESE; end
							
							5'd13:	begin y_p <= 8'hb4; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= 8'd8 ; state <= CHINESE; end
							5'd14:	begin y_p <= 8'hb4; x_ph <= 8'h13; x_pl <= 8'h00; mem_hanzi_num <= 8'd10; state <= CHINESE; end
							5'd15:	begin y_p <= 8'hb4; x_ph <= 8'h14; x_pl <= 8'h00; mem_hanzi_num <= 8'd12; state <= CHINESE; end
							5'd16:	begin y_p <= 8'hb4; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= 8'd14; state <= CHINESE; end

							//default: state <= IDLE;   //如果你需要动态刷新一些信息,此行应该取消注释
						endcase
					end
				INIT:begin	//初始化状态
						case(cnt_init)
							5'd0:	begin oled_rst <= LOW; cnt_init <= cnt_init + 1'b1; end	//复位有效
							5'd1:	begin num_delay <= 16'd25000; state <= DELAY; state_back <= INIT; cnt_init <= cnt_init + 1'b1; end	//延时大于3us
							5'd2:	begin oled_rst <= HIGH; cnt_init <= cnt_init + 1'b1; end	//复位恢复
							5'd3:	begin num_delay <= 16'd25000; state <= DELAY; state_back <= INIT; cnt_init <= cnt_init + 1'b1; end	//延时大于220us
							5'd4:	begin 
										if(cnt>=INIT_DEPTH) begin	//当25条指令及数据发出后,配置完成
											cnt <= 1'b0;
											cnt_init <= cnt_init + 1'b1;
										end else begin	
											cnt <= cnt + 1'b1; num_delay <= 16'd5;
											oled_dcn <= CMD; char_reg <= cmd[cnt]; state <= WRITE; state_back <= INIT;
										end
									end
							5'd5:	begin cnt_init <= 1'b0; state <= MAIN; end	//初始化完成,返回MAIN状态
							default: state <= IDLE;
						endcase
					end
				SCAN:begin	//刷屏状态,从RAM中读取数据刷屏
						if(cnt_scan == 5'd11) begin
							if(num) cnt_scan <= 5'd3;
							else cnt_scan <= cnt_scan + 1'b1;
						end 
						else if(cnt_scan == 5'd12) cnt_scan <= 1'b0;
						else cnt_scan <= cnt_scan + 1'b1;
						case(cnt_scan)
							5'd 0:	begin oled_dcn <= CMD; char_reg <= y_p; state <= WRITE; state_back <= SCAN; end		//定位列页地址
							5'd 1:	begin oled_dcn <= CMD; char_reg <= x_pl; state <= WRITE; state_back <= SCAN; end	//定位行地址低位
							5'd 2:	begin oled_dcn <= CMD; char_reg <= x_ph; state <= WRITE; state_back <= SCAN; end	//定位行地址高位
							
							5'd 3:	begin num <= num - 1'b1;end
							5'd 4:	begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end	//将5*8点阵编程8*8
							5'd 5:	begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end	//将5*8点阵编程8*8
							5'd 6:	begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end	//将5*8点阵编程8*8
							5'd 7:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][39:32]; state <= WRITE; state_back <= SCAN; end
							5'd 8:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][31:24]; state <= WRITE; state_back <= SCAN; end
							5'd 9:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][23:16]; state <= WRITE; state_back <= SCAN; end
							5'd10:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][15: 8]; state <= WRITE; state_back <= SCAN; end
							5'd11:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][ 7: 0]; state <= WRITE; state_back <= SCAN; end
							5'd12:	begin state <= MAIN; end
							default: state <= IDLE;
						endcase
					end
					
					
			
					
				CHINESE:begin	//显示汉字
						
						if(cnt_chinese == 6'd38) cnt_chinese <= 1'b0;
						else cnt_chinese <= cnt_chinese+1'b1;
						case(cnt_chinese)    
							6'd 0:	begin oled_dcn <= CMD; char_reg <= y_p; state <= WRITE; state_back <= CHINESE; end		//定位列页地址
							6'd 1:	begin oled_dcn <= CMD; char_reg <= x_pl; state <= WRITE; state_back <= CHINESE; end	//定位行地址低位
							6'd 2:	begin oled_dcn <= CMD; char_reg <= x_ph; state <= WRITE; state_back <= CHINESE; end	//定位行地址高位
							
							6'd3 :	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][127:120]; state <= WRITE; state_back <= CHINESE; end
							6'd4 :	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][119:112]; state <= WRITE; state_back <= CHINESE; end
							6'd5 :	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][111:104]; state <= WRITE; state_back <= CHINESE; end
							6'd6 :	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][103:96] ; state <= WRITE; state_back <= CHINESE; end
							6'd7 :	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][95:88]  ; state <= WRITE; state_back <= CHINESE; end
							6'd8 :	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][87:80]  ; state <= WRITE; state_back <= CHINESE; end
							6'd9 :	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][79:72]  ; state <= WRITE; state_back <= CHINESE; end
							6'd10:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][71:64]  ; state <= WRITE; state_back <= CHINESE; end 
							6'd11:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][63:56];   state <= WRITE; state_back <= CHINESE; end
							6'd12:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][55:48];   state <= WRITE; state_back <= CHINESE; end
							6'd13:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][47:40];   state <= WRITE; state_back <= CHINESE; end
							6'd14:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][39:32];   state <= WRITE; state_back <= CHINESE; end
							6'd15:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][31:24];   state <= WRITE; state_back <= CHINESE; end
							6'd16:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][23:16];   state <= WRITE; state_back <= CHINESE; end
							6'd17:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][15: 8];   state <= WRITE; state_back <= CHINESE; end
							6'd18:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][ 7: 0];   state <= WRITE; state_back <= CHINESE; end 
							
							6'd19:	begin oled_dcn <= CMD; char_reg <= y_p+1; state <= WRITE; state_back <= CHINESE; end		//定位列页地址
							6'd20:	begin oled_dcn <= CMD; char_reg <= x_pl; state <= WRITE; state_back <= CHINESE; end	//定位行地址低位
							6'd21:	begin oled_dcn <= CMD; char_reg <= x_ph; state <= WRITE; state_back <= CHINESE; end	//定位行地址高位
							6'd22:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][127:120]; state <= WRITE; state_back <= CHINESE; end
							6'd23:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][119:112]; state <= WRITE; state_back <= CHINESE; end
							6'd24:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][111:104]; state <= WRITE; state_back <= CHINESE; end
							6'd25:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][103:96] ; state <= WRITE; state_back <= CHINESE; end
							6'd26:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][95:88]  ; state <= WRITE; state_back <= CHINESE; end
							6'd27:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][87:80]  ; state <= WRITE; state_back <= CHINESE; end
							6'd28:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][79:72]  ; state <= WRITE; state_back <= CHINESE; end
							6'd29:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][71:64]  ; state <= WRITE; state_back <= CHINESE; end 
							6'd30:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][63:56];   state <= WRITE; state_back <= CHINESE; end
							6'd31:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][55:48];   state <= WRITE; state_back <= CHINESE; end
							6'd32:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][47:40];   state <= WRITE; state_back <= CHINESE; end
							6'd33:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][39:32];   state <= WRITE; state_back <= CHINESE; end
							6'd34:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][31:24];   state <= WRITE; state_back <= CHINESE; end
							6'd35:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][23:16];   state <= WRITE; state_back <= CHINESE; end
							6'd36:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][15: 8];   state <= WRITE; state_back <= CHINESE; end
							6'd37:	begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][ 7: 0];   state <= WRITE; state_back <= CHINESE; end 
                            
							6'd38:	begin state <= MAIN; end
							default: state <= IDLE;
						endcase
					end
					
					
					
				WRITE:begin	//WRITE状态,将数据按照SPI时序发送给屏幕
						if(cnt_write >= 5'd17) cnt_write <= 1'b0;
						else cnt_write <= cnt_write + 1'b1;
						case(cnt_write)
							5'd 0:	begin oled_csn <= LOW; end	//9位数据最高位为命令数据控制位
							5'd 1:	begin oled_clk <= LOW; oled_dat <= char_reg[7]; end	//先发高位数据
							5'd 2:	begin oled_clk <= HIGH; end
							5'd 3:	begin oled_clk <= LOW; oled_dat <= char_reg[6]; end
							5'd 4:	begin oled_clk <= HIGH; end
							5'd 5:	begin oled_clk <= LOW; oled_dat <= char_reg[5]; end
							5'd 6:	begin oled_clk <= HIGH; end
							5'd 7:	begin oled_clk <= LOW; oled_dat <= char_reg[4]; end
							5'd 8:	begin oled_clk <= HIGH; end
							5'd 9:	begin oled_clk <= LOW; oled_dat <= char_reg[3]; end
							5'd10:	begin oled_clk <= HIGH; end
							5'd11:	begin oled_clk <= LOW; oled_dat <= char_reg[2]; end
							5'd12:	begin oled_clk <= HIGH; end
							5'd13:	begin oled_clk <= LOW; oled_dat <= char_reg[1]; end
							5'd14:	begin oled_clk <= HIGH; end
							5'd15:	begin oled_clk <= LOW; oled_dat <= char_reg[0]; end	//后发低位数据
							5'd16:	begin oled_clk <= HIGH; end
							5'd17:	begin oled_csn <= HIGH; state <= DELAY; end	//
							default: state <= IDLE;
						endcase
					end
				DELAY:begin	//延时状态
						if(cnt_delay >= num_delay) begin
							cnt_delay <= 16'd0; state <= state_back; 
						end else cnt_delay <= cnt_delay + 1'b1;
					end
				default:state <= IDLE;
			endcase
		end
	end
	
	//OLED配置指令数据
	always@(posedge rst_n)
		begin
			cmd[0 ] = {8'hae}; 
			cmd[1 ] = {8'hd5}; 
			cmd[2 ] = {8'h80}; 
			cmd[3 ] = {8'ha8}; 
			cmd[4 ] = {8'h3f}; 
			cmd[5 ] = {8'hd3}; 
			cmd[6 ] = {8'h00}; 
			cmd[7 ] = {8'h40}; 
			cmd[8 ] = {8'h8d}; 
			cmd[9 ] = {8'h14}; 
			cmd[10] = {8'h20}; 
			cmd[11] = {8'h02};
			cmd[12] = {8'hc8};
			cmd[13] = {8'ha1};
			cmd[14] = {8'hda};
			cmd[15] = {8'h12};
			cmd[16] = {8'h81};
			cmd[17] = {8'hcf};
			cmd[18] = {8'hd9};
			cmd[19] = {8'hf1};
			cmd[20] = {8'hdb};
			cmd[21] = {8'h40};
			cmd[22] = {8'haf};
			
		end 
		
	//5*8点阵字库数据
	always@(posedge rst_n)
		begin
			mem[  0] = {8'h3E, 8'h51, 8'h49, 8'h45, 8'h3E};   // 48  0
			mem[  1] = {8'h00, 8'h42, 8'h7F, 8'h40, 8'h00};   // 49  1
			mem[  2] = {8'h42, 8'h61, 8'h51, 8'h49, 8'h46};   // 50  2
			mem[  3] = {8'h21, 8'h41, 8'h45, 8'h4B, 8'h31};   // 51  3
			mem[  4] = {8'h18, 8'h14, 8'h12, 8'h7F, 8'h10};   // 52  4
			mem[  5] = {8'h27, 8'h45, 8'h45, 8'h45, 8'h39};   // 53  5
			mem[  6] = {8'h3C, 8'h4A, 8'h49, 8'h49, 8'h30};   // 54  6
			mem[  7] = {8'h01, 8'h71, 8'h09, 8'h05, 8'h03};   // 55  7
			mem[  8] = {8'h36, 8'h49, 8'h49, 8'h49, 8'h36};   // 56  8
			mem[  9] = {8'h06, 8'h49, 8'h49, 8'h29, 8'h1E};   // 57  9
			mem[ 10] = {8'h7C, 8'h12, 8'h11, 8'h12, 8'h7C};   // 65  A
			mem[ 11] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h36};   // 66  B
			mem[ 12] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h22};   // 67  C
			mem[ 13] = {8'h7F, 8'h41, 8'h41, 8'h22, 8'h1C};   // 68  D
			mem[ 14] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h41};   // 69  E
			mem[ 15] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h01};   // 70  F

			mem[ 32] = {8'h00, 8'h00, 8'h00, 8'h00, 8'h00};   // 32  sp 
			mem[ 33] = {8'h00, 8'h00, 8'h2f, 8'h00, 8'h00};   // 33  !  
			mem[ 34] = {8'h00, 8'h07, 8'h00, 8'h07, 8'h00};   // 34  
			mem[ 35] = {8'h14, 8'h7f, 8'h14, 8'h7f, 8'h14};   // 35  #
			mem[ 36] = {8'h24, 8'h2a, 8'h7f, 8'h2a, 8'h12};   // 36  $
			mem[ 37] = {8'h62, 8'h64, 8'h08, 8'h13, 8'h23};   // 37  %
			mem[ 38] = {8'h36, 8'h49, 8'h55, 8'h22, 8'h50};   // 38  &
			mem[ 39] = {8'h00, 8'h05, 8'h03, 8'h00, 8'h00};   // 39  '
			mem[ 40] = {8'h00, 8'h1c, 8'h22, 8'h41, 8'h00};   // 40  (
			mem[ 41] = {8'h00, 8'h41, 8'h22, 8'h1c, 8'h00};   // 41  )
			mem[ 42] = {8'h14, 8'h08, 8'h3E, 8'h08, 8'h14};   // 42  *
			mem[ 43] = {8'h08, 8'h08, 8'h3E, 8'h08, 8'h08};   // 43  +
			mem[ 44] = {8'h00, 8'h00, 8'hA0, 8'h60, 8'h00};   // 44  ,
			mem[ 45] = {8'h08, 8'h08, 8'h08, 8'h08, 8'h08};   // 45  -
			mem[ 46] = {8'h00, 8'h60, 8'h60, 8'h00, 8'h00};   // 46  .
			mem[ 47] = {8'h20, 8'h10, 8'h08, 8'h04, 8'h02};   // 47  /
			mem[ 48] = {8'h3E, 8'h51, 8'h49, 8'h45, 8'h3E};   // 48  0
			mem[ 49] = {8'h00, 8'h42, 8'h7F, 8'h40, 8'h00};   // 49  1
			mem[ 50] = {8'h42, 8'h61, 8'h51, 8'h49, 8'h46};   // 50  2
			mem[ 51] = {8'h21, 8'h41, 8'h45, 8'h4B, 8'h31};   // 51  3
			mem[ 52] = {8'h18, 8'h14, 8'h12, 8'h7F, 8'h10};   // 52  4
			mem[ 53] = {8'h27, 8'h45, 8'h45, 8'h45, 8'h39};   // 53  5
			mem[ 54] = {8'h3C, 8'h4A, 8'h49, 8'h49, 8'h30};   // 54  6
			mem[ 55] = {8'h01, 8'h71, 8'h09, 8'h05, 8'h03};   // 55  7
			mem[ 56] = {8'h36, 8'h49, 8'h49, 8'h49, 8'h36};   // 56  8
			mem[ 57] = {8'h06, 8'h49, 8'h49, 8'h29, 8'h1E};   // 57  9
			mem[ 58] = {8'h00, 8'h36, 8'h36, 8'h00, 8'h00};   // 58  :
			mem[ 59] = {8'h00, 8'h56, 8'h36, 8'h00, 8'h00};   // 59  ;
			mem[ 60] = {8'h08, 8'h14, 8'h22, 8'h41, 8'h00};   // 60  <
			mem[ 61] = {8'h14, 8'h14, 8'h14, 8'h14, 8'h14};   // 61  =
			mem[ 62] = {8'h00, 8'h41, 8'h22, 8'h14, 8'h08};   // 62  >
			mem[ 63] = {8'h02, 8'h01, 8'h51, 8'h09, 8'h06};   // 63  ?
			mem[ 64] = {8'h32, 8'h49, 8'h59, 8'h51, 8'h3E};   // 64  @
			mem[ 65] = {8'h7C, 8'h12, 8'h11, 8'h12, 8'h7C};   // 65  A
			mem[ 66] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h36};   // 66  B
			mem[ 67] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h22};   // 67  C
			mem[ 68] = {8'h7F, 8'h41, 8'h41, 8'h22, 8'h1C};   // 68  D
			mem[ 69] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h41};   // 69  E
			mem[ 70] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h01};   // 70  F
			mem[ 71] = {8'h3E, 8'h41, 8'h49, 8'h49, 8'h7A};   // 71  G
			mem[ 72] = {8'h7F, 8'h08, 8'h08, 8'h08, 8'h7F};   // 72  H
			mem[ 73] = {8'h00, 8'h41, 8'h7F, 8'h41, 8'h00};   // 73  I
			mem[ 74] = {8'h20, 8'h40, 8'h41, 8'h3F, 8'h01};   // 74  J
			mem[ 75] = {8'h7F, 8'h08, 8'h14, 8'h22, 8'h41};   // 75  K
			mem[ 76] = {8'h7F, 8'h40, 8'h40, 8'h40, 8'h40};   // 76  L
			mem[ 77] = {8'h7F, 8'h02, 8'h0C, 8'h02, 8'h7F};   // 77  M
			mem[ 78] = {8'h7F, 8'h04, 8'h08, 8'h10, 8'h7F};   // 78  N
			mem[ 79] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h3E};   // 79  O
			mem[ 80] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h06};   // 80  P
			mem[ 81] = {8'h3E, 8'h41, 8'h51, 8'h21, 8'h5E};   // 81  Q
			mem[ 82] = {8'h7F, 8'h09, 8'h19, 8'h29, 8'h46};   // 82  R
			mem[ 83] = {8'h46, 8'h49, 8'h49, 8'h49, 8'h31};   // 83  S
			mem[ 84] = {8'h01, 8'h01, 8'h7F, 8'h01, 8'h01};   // 84  T
			mem[ 85] = {8'h3F, 8'h40, 8'h40, 8'h40, 8'h3F};   // 85  U
			mem[ 86] = {8'h1F, 8'h20, 8'h40, 8'h20, 8'h1F};   // 86  V
			mem[ 87] = {8'h3F, 8'h40, 8'h38, 8'h40, 8'h3F};   // 87  W
			mem[ 88] = {8'h63, 8'h14, 8'h08, 8'h14, 8'h63};   // 88  X
			mem[ 89] = {8'h07, 8'h08, 8'h70, 8'h08, 8'h07};   // 89  Y
			mem[ 90] = {8'h61, 8'h51, 8'h49, 8'h45, 8'h43};   // 90  Z
			mem[ 91] = {8'h00, 8'h7F, 8'h41, 8'h41, 8'h00};   // 91  [
			mem[ 92] = {8'h55, 8'h2A, 8'h55, 8'h2A, 8'h55};   // 92  .
			mem[ 93] = {8'h00, 8'h41, 8'h41, 8'h7F, 8'h00};   // 93  ]
			mem[ 94] = {8'h04, 8'h02, 8'h01, 8'h02, 8'h04};   // 94  ^
			mem[ 95] = {8'h40, 8'h40, 8'h40, 8'h40, 8'h40};   // 95  _
			mem[ 96] = {8'h00, 8'h01, 8'h02, 8'h04, 8'h00};   // 96  '
			mem[ 97] = {8'h20, 8'h54, 8'h54, 8'h54, 8'h78};   // 97  a
			mem[ 98] = {8'h7F, 8'h48, 8'h44, 8'h44, 8'h38};   // 98  b
			mem[ 99] = {8'h38, 8'h44, 8'h44, 8'h44, 8'h20};   // 99  c
			mem[100] = {8'h38, 8'h44, 8'h44, 8'h48, 8'h7F};   // 100 d
			mem[101] = {8'h38, 8'h54, 8'h54, 8'h54, 8'h18};   // 101 e
			mem[102] = {8'h08, 8'h7E, 8'h09, 8'h01, 8'h02};   // 102 f
			mem[103] = {8'h18, 8'hA4, 8'hA4, 8'hA4, 8'h7C};   // 103 g
			mem[104] = {8'h7F, 8'h08, 8'h04, 8'h04, 8'h78};   // 104 h
			mem[105] = {8'h00, 8'h44, 8'h7D, 8'h40, 8'h00};   // 105 i
			mem[106] = {8'h40, 8'h80, 8'h84, 8'h7D, 8'h00};   // 106 j
			mem[107] = {8'h7F, 8'h10, 8'h28, 8'h44, 8'h00};   // 107 k
			mem[108] = {8'h00, 8'h41, 8'h7F, 8'h40, 8'h00};   // 108 l
			mem[109] = {8'h7C, 8'h04, 8'h18, 8'h04, 8'h78};   // 109 m
			mem[110] = {8'h7C, 8'h08, 8'h04, 8'h04, 8'h78};   // 110 n
			mem[111] = {8'h38, 8'h44, 8'h44, 8'h44, 8'h38};   // 111 o
			mem[112] = {8'hFC, 8'h24, 8'h24, 8'h24, 8'h18};   // 112 p
			mem[113] = {8'h18, 8'h24, 8'h24, 8'h18, 8'hFC};   // 113 q
			mem[114] = {8'h7C, 8'h08, 8'h04, 8'h04, 8'h08};   // 114 r
			mem[115] = {8'h48, 8'h54, 8'h54, 8'h54, 8'h20};   // 115 s
			mem[116] = {8'h04, 8'h3F, 8'h44, 8'h40, 8'h20};   // 116 t
			mem[117] = {8'h3C, 8'h40, 8'h40, 8'h20, 8'h7C};   // 117 u
			mem[118] = {8'h1C, 8'h20, 8'h40, 8'h20, 8'h1C};   // 118 v
			mem[119] = {8'h3C, 8'h40, 8'h30, 8'h40, 8'h3C};   // 119 w
			mem[120] = {8'h44, 8'h28, 8'h10, 8'h28, 8'h44};   // 120 x
			mem[121] = {8'h1C, 8'hA0, 8'hA0, 8'hA0, 8'h7C};   // 121 y
			mem[122] = {8'h44, 8'h64, 8'h54, 8'h4C, 8'h44};   // 122 z
		end


		
	//16*16	汉字
		always@(posedge rst_n, posedge key_up)
		begin
			mem_hanzi[  0 ] = {8'h00,8'h02,8'h02,8'hC2,8'h02,8'h02,8'h02,8'hFE,8'h82,8'h82,8'h82,8'h82,8'h82,8'h02,8'h00,8'h00};
			mem_hanzi[  1 ] = {8'h40,8'h40,8'h40,8'h7F,8'h40,8'h40,8'h40,8'h7F,8'h40,8'h40,8'h40,8'h40,8'h40,8'h40,8'h40,8'h00};//正0
			mem_hanzi[  2 ] = {8'h08,8'h08,8'h88,8'hC8,8'h38,8'h0C,8'h0B,8'h08,8'h08,8'hE8,8'h08,8'h08,8'h08,8'h08,8'h08,8'h00};
			mem_hanzi[  3 ] = {8'h02,8'h01,8'h00,8'hFF,8'h40,8'h41,8'h41,8'h41,8'h41,8'h7F,8'h41,8'h41,8'h41,8'h41,8'h40,8'h00};//在1
			mem_hanzi[  4 ] = {8'h10,8'h10,8'hFF,8'h10,8'h90,8'h82,8'h56,8'h3A,8'h12,8'h7F,8'h11,8'h39,8'h55,8'h90,8'h80,8'h00};
			mem_hanzi[  5 ] = {8'h42,8'h82,8'h7F,8'h01,8'h00,8'h00,8'hFF,8'h49,8'h49,8'h7F,8'h49,8'h49,8'hFF,8'h00,8'h00,8'h00};//播2
			mem_hanzi[  6 ] = {8'h08,8'h08,8'hF9,8'h4A,8'h48,8'hC8,8'h48,8'h20,8'hD8,8'h17,8'h10,8'h10,8'hF0,8'h10,8'h10,8'h00};
			mem_hanzi[  7 ] = {8'h40,8'h30,8'h0F,8'h20,8'h40,8'h3F,8'h80,8'h40,8'h21,8'h16,8'h08,8'h16,8'h21,8'h40,8'h80,8'h00};//放3
			
			case(flag)
			2'd0: begin 
				mem_hanzi[  8 ] = {8'h20,8'h24,8'h24,8'h24,8'hFE,8'h23,8'h22,8'h20,8'h20,8'hFF,8'h20,8'h22,8'h2C,8'hA0,8'h20,8'h00};
				mem_hanzi[  9 ] = {8'h00,8'h08,8'h48,8'h84,8'h7F,8'h02,8'h41,8'h40,8'h20,8'h13,8'h0C,8'h14,8'h22,8'h41,8'hF8,8'h00};//我0
				mem_hanzi[ 10 ] = {8'h00,8'h00,8'h80,8'h00,8'h00,8'hE0,8'h02,8'h04,8'h18,8'h00,8'h00,8'h00,8'h40,8'h80,8'h00,8'h00};
				mem_hanzi[ 11 ] = {8'h10,8'h0C,8'h03,8'h00,8'h00,8'h3F,8'h40,8'h40,8'h40,8'h40,8'h40,8'h78,8'h00,8'h01,8'h0E,8'h00};//心1
				mem_hanzi[ 12 ] = {8'h00,8'h40,8'h40,8'h48,8'h48,8'hC8,8'h09,8'hFA,8'hC4,8'h00,8'h80,8'h40,8'h20,8'h10,8'h00,8'h00};
				mem_hanzi[ 13 ] = {8'h20,8'h20,8'h10,8'h08,8'h06,8'h41,8'h80,8'h7F,8'h00,8'h03,8'h04,8'h08,8'h10,8'h20,8'h20,8'h00};//永2
				mem_hanzi[ 14 ] = {8'h00,8'hE0,8'h00,8'hFF,8'h10,8'h20,8'h02,8'hF2,8'h92,8'h92,8'h92,8'h92,8'h92,8'hF2,8'h02,8'h00};
				mem_hanzi[ 15 ] = {8'h01,8'h00,8'h00,8'hFF,8'h00,8'h00,8'h40,8'h4F,8'h44,8'h44,8'h44,8'h44,8'h44,8'h4F,8'h40,8'h00};//恒3
				end
			2'd1: begin				
				mem_hanzi[  8 ] = {8'h80,8'h64,8'h2C,8'h34,8'h24,8'h24,8'hEC,8'h32,8'h22,8'h22,8'h32,8'h2E,8'h23,8'hA2,8'h60,8'h00};//
				mem_hanzi[  9 ] = {8'h00,8'h41,8'h21,8'h91,8'h89,8'h87,8'h4D,8'h55,8'h25,8'h25,8'h55,8'h4D,8'h81,8'h80,8'h80,8'h00};//爱0
				mem_hanzi[ 10 ] = {8'h00,8'h04,8'h24,8'h24,8'h25,8'h26,8'h24,8'hFC,8'h24,8'h26,8'h25,8'h24,8'h24,8'h04,8'h00,8'h00};//
				mem_hanzi[ 11 ] = {8'h81,8'h89,8'h89,8'h49,8'h49,8'h29,8'h19,8'h0F,8'h19,8'h29,8'h49,8'h49,8'h89,8'h89,8'h81,8'h00};//美1
				mem_hanzi[ 12 ] = {8'h02,8'h02,8'hF2,8'h12,8'h12,8'h12,8'hF2,8'h02,8'hF2,8'h12,8'h12,8'h12,8'hF2,8'h02,8'h02,8'h00};//
				mem_hanzi[ 13 ] = {8'h00,8'h00,8'hFF,8'h01,8'h46,8'h80,8'h7F,8'h00,8'hFF,8'h01,8'h46,8'h80,8'h7F,8'h00,8'h00,8'h00};//丽2
				mem_hanzi[ 14 ] = {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00};// 3
				mem_hanzi[ 15 ] = {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00};// 4
				end	
			2'd2: begin
				mem_hanzi[  8 ] = {8'h02,8'h02,8'hE2,8'h22,8'h22,8'h32,8'h2A,8'h26,8'h22,8'h22,8'h22,8'h22,8'hE2,8'h02,8'h02,8'h00};
				mem_hanzi[  9 ] = {8'h00,8'h00,8'hFF,8'h42,8'h42,8'h42,8'h42,8'h42,8'h42,8'h42,8'h42,8'h42,8'hFF,8'h00,8'h00,8'h00};//百0
				mem_hanzi[ 10 ] = {8'h00,8'h20,8'h18,8'hC7,8'h44,8'h44,8'h44,8'h44,8'hFC,8'h44,8'h44,8'h44,8'h44,8'h04,8'h00,8'h00};
				mem_hanzi[ 11 ] = {8'h04,8'h04,8'h04,8'h07,8'h04,8'h04,8'h04,8'h04,8'hFF,8'h04,8'h04,8'h04,8'h04,8'h04,8'h04,8'h00};//年1
				mem_hanzi[ 12 ] = {8'h02,8'h02,8'hF2,8'h8A,8'h46,8'h00,8'hFC,8'h04,8'hFC,8'h04,8'h02,8'hFE,8'h03,8'h02,8'h00,8'h00};
				mem_hanzi[ 13 ] = {8'h42,8'h82,8'h7F,8'h00,8'h80,8'h60,8'h1F,8'h00,8'h7F,8'h28,8'h10,8'h61,8'h0E,8'h30,8'h40,8'h00};//孤2
				mem_hanzi[ 14 ] = {8'h10,8'h0C,8'h04,8'h04,8'hF4,8'h24,8'h25,8'h26,8'h04,8'hE4,8'h24,8'h24,8'h24,8'hF4,8'h0C,8'h00};
				mem_hanzi[ 15 ] = {8'h21,8'h11,8'h49,8'h81,8'h7D,8'h01,8'h09,8'h31,8'h80,8'h41,8'h26,8'h18,8'h26,8'h41,8'h80,8'h00};//寂3
				end
			
			endcase
			
			//此处可以导入需要的字模
			
		end 
	/*汉字:硬禾学堂
	以汉字“硬禾学堂”RAM生成步骤为例:
	1、阴码、列行式、逆向 生成字模
	2、然后把生成的字模作为RAM的元素
	*/
	
	always@(posedge key_down, negedge rst_n) begin
		if (!rst_n) flag = 1'b0;
		else if (key_down) begin
			if (flag>=2'd2) flag=2'd0;
			else flag = flag + 1'b1; 
		end
		else;
	end
	
endmodule

 

4.3 用含有代码消抖的按键切换歌曲

抖动的产生 :通常的按键所用的开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。

软件消除抖动的实现方法:检测到按键按下动作之后进行10ms~20ms左右的延时,当前沿的抖动消失之后再一次检测按键的状态。如果仍然是按下的电平状态,则认为这是一次真正的按键按下;同样检测到按键释放,也要做10ms~20ms延时,检测到后沿抖动消失后认为是一个完整的按键弹起过程。

按键按下消抖模块module debounce_down代码如下:

module debounce_down (clk,rst,key,key_down);
 
    parameter       N  =  1;                      //要消除的按键的数量
 
	input             clk;
    input             rst;
    input 	[N-1:0]   key;                        //输入的按键					
	output  [N-1:0]   key_down;                  //按键动作产生的脉冲	
 
    reg     [N-1:0]   key_rst_pre;                //定义一个寄存器型变量存储上一个触发时的按键值
    reg     [N-1:0]   key_rst;                    //定义一个寄存器变量储存储当前时刻触发的按键值
 
    wire    [N-1:0]   key_edge;                   //检测到按键由高到低变化是产生一个高脉冲
 
    //利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
    always @(posedge clk  or  negedge rst) begin
		if (!rst) begin
			key_rst <= {N{1'b1}};                //初始化时给key_rst赋值全为1,{}中表示N个1
            key_rst_pre <= {N{1'b1}};
        end
        else begin
			key_rst <= key;                     //第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
			key_rst_pre <= key_rst;             //非阻塞赋值。相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
        end    
	end
 
    assign  key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平
 
    reg	[17:0]	  cnt;                       //产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器     
 
        //产生20ms延时,当检测到key_edge有效是计数器清零开始计数
    always @(posedge clk or negedge rst) begin
        if(!rst)
           cnt <= 18'h0;
        else if(key_edge)
           cnt <= 18'h0;
        else
           cnt <= cnt + 1'h1;
        end  
 
        reg     [N-1:0]   key_sec_pre;                //延时后检测电平寄存器变量
        reg     [N-1:0]   key_sec;                    
 
 
        //延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效
        always @(posedge clk  or  negedge rst)
          begin
             if (!rst) 
                 key_sec <= {N{1'b1}};                
             else if (cnt==18'h3ffff)
                 key_sec <= key;  
          end
       always @(posedge clk  or  negedge rst)
          begin
             if (!rst)
                 key_sec_pre <= {N{1'b1}};
             else                   
                 key_sec_pre <= key_sec;             
         end      
       assign  key_down = key_sec_pre & (~key_sec);     
 
endmodule

 

按键释放消抖模块module debounce_up代码如下:

module debounce_up (clk,rst,key,key_up);
 
    parameter       N  =  1;                      //要消除的按键的数量
 
	input             clk;
    input             rst;
    input 	[N-1:0]   key;                        //输入的按键					
	output  [N-1:0]   key_up;                  //按键动作产生的脉冲	
 
    reg     [N-1:0]   key_rst_pre;                //定义一个寄存器型变量存储上一个触发时的按键值
    reg     [N-1:0]   key_rst;                    //定义一个寄存器变量储存储当前时刻触发的按键值
 
    wire    [N-1:0]   key_edge;                   //检测到按键由高到低变化是产生一个高脉冲
 
    //利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
    always @(posedge clk  or  negedge rst) begin
		if (!rst) begin
			key_rst <= {N{1'b1}};                //初始化时给key_rst赋值全为1,{}中表示N个1
            key_rst_pre <= {N{1'b1}};
        end
        else begin
			key_rst <= key;                     //第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
			key_rst_pre <= key_rst;             //非阻塞赋值。相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
        end    
	end
 
    assign  key_edge = key_rst & (~key_rst_pre);//脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平
 
    reg	[17:0]	  cnt;                       //产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器     
 
        //产生20ms延时,当检测到key_edge有效是计数器清零开始计数
    always @(posedge clk or negedge rst) begin
        if(!rst)
           cnt <= 18'h0;
        else if(key_edge)
           cnt <= 18'h0;
        else
           cnt <= cnt + 1'h1;
        end  
 
        reg     [N-1:0]   key_sec_pre;                //延时后检测电平寄存器变量
        reg     [N-1:0]   key_sec;                    
 
 
        //延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效
        always @(posedge clk  or  negedge rst)
          begin
             if (!rst) 
                 key_sec <= {N{1'b1}};                
             else if (cnt==18'h3ffff)
                 key_sec <= key;  
          end
       always @(posedge clk  or  negedge rst)
          begin
             if (!rst)
                 key_sec_pre <= {N{1'b1}};
             else                   
                 key_sec_pre <= key_sec;             
         end      
       assign  key_up = key_sec & (~key_sec_pre);     
 
endmodule

 

4.4 呼吸灯指示按键的触发

核心板上的RGB LED原理图如下图所示(图七)。由此可见,当收到高电平,LED不导通,不发光;当收到低电平,LED导通,发光。

Fi9A3dHtrZ2v965Qk8XUVu4dluk4

图七: RGB LED原理图

 

原理:通过PWM脉宽调制决定LED的明暗程度。在按键回弹后的一个时间段T(=1s)内不变,调整高电平脉宽t的时间,从而改变占空比,实现LED由明到暗的效果。

通过两个计数器cnt1和cnt2,cnt1随系统时钟同步计数(系统时钟上升沿时cnt1自加1)范围为0~T,cnt2随cnt1的周期同步计数(cnt1等于T时,cnt2自加1)范围也是0~T,这样每次cnt1在0~T的计数时,cnt2为一个固定值,相邻cnt1计数周期对应的cnt2的值逐渐增大,我们将cnt1计数0~T的时间作为脉冲周期,cnt2的值作为脉冲宽度,则占空比 = cnt2/T,占空比从0%到100%的时间 = cnt2*cnt1 = T^2 = 1s = 12M个系统时钟,T = 2400,我们定义CNT_NUM = 2400作为两个计数器的计数最大值。当cnt1<cnt2时,输出高电平;反之,输出低电平。

模块module press_key代码如下:

module press_key(clk,click,ledr,ledg,ledb);

	input clk, click;
	output ledr, ledg, ledb;
	
	reg [11:0] cnt1, cnt2;
	
	parameter CNT = 2400;
	
	always@(posedge clk, negedge click) begin
		if (!click) cnt1 <= 12'd0;
		else if (cnt1 >= CNT-1) cnt1 <= 12'd0;
		else cnt1 <= cnt1 + 1'b1;
	end
	
	always@(posedge clk, negedge click) begin
		if (!click) cnt2 <= 12'd0;
		else if (cnt2 < CNT) begin
			if (cnt1 >= CNT-1) cnt2<=cnt2+1'b1;
			else; 
		end
		else;
	end
	
	assign ledr=(cnt1<cnt2)?1'b1:1'b0;
	assign ledg=(cnt1<cnt2)?1'b1:1'b0;
	assign ledb=(cnt1<cnt2)?1'b1:1'b0;
	
endmodule

 

将OLED显示与LED显示合成一个显示的顶层模块module vision_top,代码如下:

module vision_top(
	input					clk_in,		//系统时钟
	input					rst_n_in,	//系统复位,低有效
	input					key_in,

	
	output				oled_rst,	//OLCD液晶屏复位
	output				oled_dcn,	//OLCD数据指令控制
	output				oled_clk,	//OLCD时钟信号
	output				oled_dat, 	//OLCD数据信号
	output				ledr_out,
    output               ledg_out,
	output             	ledb_out,
	output		[1:0]	flag,
	output				key_down
);

OLED12864	OLED12864_u1 (
			.clk     (clk_in) ,		
			.rst_n   (rst_n_in),		
			.key_up	 (key_up),
			.key_down	 (key_down),
			
			//.oled_csn(oled_csn),			
			.oled_rst(oled_rst),			
			.oled_dcn(oled_dcn),	
			.oled_clk(oled_clk),	
			.oled_dat(oled_dat),
			.flag(flag)
);

press_key response(
			.clk	(clk_in) ,			
			.click	 (key_in),
						
			.ledr(ledr_out),			
			.ledg(ledg_out),	
			.ledb(ledb_out)	
);

debounce_up up(
			.clk	(clk_in),
			.rst	(rst_n_in),
			.key	(key_in),
			.key_up	(key_up)
);

debounce_down down(
			.clk	(clk_in),
			.rst	(rst_n_in),
			.key	(key_in),
			
			.key_down(key_down)
);



endmodule

 

项目顶层模块module top例化了声音与显示的顶层模块Auditory_top与vision_top,代码如下:

module top (
	input				clk_in,		//系统时钟
	input				rst_n_in,	//系统复位,低有效
	input				key_in,

	output				oled_rst,	//OLCD液晶屏复位
	output				oled_dcn,	//OLCD数据指令控制
	output				oled_clk,	//OLCD时钟信号
	output				oled_dat, 	//OLCD数据信号
	output				ledr_out,
    output               ledg_out,
	output             	ledb_out,	
	output 	   			drive
);

	wire			key_down;
	wire	[1:0]	flag;
	
vision_top	u1(
	.clk_in		(clk_in),
	.rst_n_in	(rst_n_in),
	.key_in		(key_in),

	
	.oled_rst	(oled_rst),	//OLCD液晶屏复位
	.oled_dcn	(oled_dcn),	//OLCD数据指令控制
	.oled_clk	(oled_clk),	//OLCD时钟信号
	.oled_dat	(oled_dat), 	//OLCD数据信号
	.ledr_out	(ledr_out),
    .ledg_out	(ledg_out),
	.ledb_out	(ledb_out),
	.flag		(flag),
	.key_down	(key_down)
);
	
auditory_top u2(	
	.clk		(clk_in),
	.rst		(rst_n_in),
	.key_down	(key_down),
	.flag		(flag),
	
	.drive		(drive)
);

endmodule
	

 

5 FPGA资源占用报告

FPGA资源占用报告如图八、九所示。

FsBjC6lRCFcGQszHLN0KN2BLWf6h

图八:资源占用(1)

FiXBE_4VvIRVZnqdy3zMZp9Eo2GR

图九:资源占用(2)

6 遇到的主要难题

FPGA驱动SSD1306-OLED, 歌曲对照简谱转化为音符。

 

7 未来的改进

利用另一个按键,实现歌曲的播放与暂停功能,并在OLED上显示“已暂停”。

附件下载
project.rar
项目压缩文件
codes.rar
verilog代码和pin分配
团队介绍
个人:黄世辰 Shichen Huang 就读高校:西交利物浦大学,电子科学与技术专业 EST@XJTLU
团队成员
Undefined_User
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号