Verilog实现的莫尔斯电码发生器

莫尔斯或者摩尔斯电码(Morse Code),发明于1837年(另有一说是1836年),通过不同的排列顺序来表达不同的英文字母、数字和标点符号,在这里作一简单处理,仅产生点(Dit)和划(Dah),时长在0.25秒之内为点,超过为划,用按键控制时间模拟实现,5个点或划表示一个数字(0-9),通过数码管显示按键发声频率1350Hz。

//莫尔斯代码发生器
module morse(rst_n,clk,key,seg,dg,beep);
input clk,rst_n,key;//clk50M,rst_n低电平有效,key按下为0
output reg beep; //蜂鸣器
output reg[7:0]  seg;//段码
output reg[5:0]  dg;//位码
reg [10:0] ct; //1350Hz分频计数
reg [3:0] cnt,kcnt; //50Hz分频计数,按键计数
reg clk50hz,clk1k; //分频得到的时钟
reg [3:0] num,number; //要显示的数,点划编码数
reg [2:0] i=0;  //要显示的点划序号
reg [9:0] dh=10'b0000000000;  //点划输入,点为10,划为11,不按为00
wire clk5;  //PLL输出的5.4M
reg [2:0] state; //按键状态
localparam S0 = 0; //初始状态
localparam S1 = 1;  //按键按下0-0.25S
localparam S2 = 2; //按键在0.25S内释放
localparam S3 = 3; //按键按下超过0.25S
localparam S4 = 4; //按键在0.25S后释放

clk5m4 PLLA(   //PLL产生5.4M时钟
  .refclk(clk) ,
  .reset(~rst_n),
  .clk0_out(),
  .clk1_out(clk5) 
);

always @ (posedge clk5 or negedge rst_n)  //分频成约1350Hz
 if (!rst_n) 
     ct<=0;
   else if (ct>=2000-1)   //5.4M->1350Hz    
       begin clk1k<=~clk1k; ct<=0; end 
      else ct<=ct+1;

always @ (posedge clk1k or negedge rst_n)  //分频成约52Hz
 if (!rst_n) 
     cnt<=0;
   else if (cnt>=13-1)   //1k->50      
       begin clk50hz<=~clk50hz; cnt<=0; end 
    else cnt<=cnt+1;
    
always @ (posedge clk50hz or negedge rst_n)  //按键检测并计数
  if (!rst_n) begin  state<=S0; kcnt<=0; dh<=10'b0000000000; i<=0; end  //初始状态S0
    else case(state)
      S0:begin if (key) begin  state<=S0; kcnt<=0; end
             else begin i<=(i>=5)?1:i+1; state<=S1; end
         end
      S1:begin 
          if (key) begin  state<=S2; kcnt<=0; end  //短按(0.25S内)按键,S1状态
          else if (kcnt<=13) begin  state<=S1; kcnt<=kcnt+1; end
          else state<=S3; 
        end
      S2: if (key) begin {dh[11-2*i],dh[10-2*i]}<=2'b10; state<=S2; kcnt<=0; end //短按并释放,S2状态
              else begin 
                   state<=S1;
                   if (i>=5)
                    begin 
                     i<=1; dh<=10'b0000000000;
                    end
                   else
                     i<=i+1;
                  end 
      S3:state<=(!key)?S3:S4;                      //长按(>0.25S),S3状态
      S4:
      if (key) begin {dh[11-2*i],dh[10-2*i]}<=2'b11; state<=S4; kcnt<=0; end //长按释放,S4状态
              else  begin 
                   state<=S1;
                   if (i>=5)
                    begin 
                     i<=1; dh<=10'b0000000000;
                    end
                   else
                     i<=i+1;
                  end  
       default:;
   endcase
   
always@(state)   //发声
  case(state)
    S1,S3:beep=clk1k;
    default:beep=0;
  endcase

always@(posedge clk1k or  negedge rst_n) //数码管扫描显示(右5位为点划),最左为点划编码数字
  if (!rst_n) 
    dg<=6'b111111; 
    else case (dg)
       6'b111110:begin num=dh[3:2]+10;  dg<=6'b111101;end
       6'b111101:begin num=dh[5:4]+10;  dg<=6'b111011;end
       6'b111011:begin num=dh[7:6]+10;  dg<=6'b110111;end
       6'b110111:begin num=dh[9:8]+10;  dg<=6'b101111;end
       6'b101111:begin num=number;      dg<=6'b011111;end
       default:begin num=dh[1:0]+10;dg<=6'b111110;end
    endcase 
  
always@(dh)
  case({dh[9:8],dh[7:6],dh[5:4],dh[3:2],dh[1:0]})
   10'b1011111111:number<=1;
   10'b1010111111:number<=2;
   10'b1010101111:number<=3;
   10'b1010101011:number<=4;
   10'b1010101010:number<=5;
   10'b1110101010:number<=6;
   10'b1111101010:number<=7;
   10'b1111111010:number<=8;
   10'b1111111110:number<=9;
   10'b1111111111:number<=0;
   default:if (dh[1:0]==2'b00) number<=14;  //等待输入标示
            else number<=11;  //出错标示
  endcase
 
always @(num)   //数码管译码,共阳极,0点亮,段码顺序:DP,G-A
  case(num)
        0:seg<=8'b11000000;
        1:seg<=8'b11111001;
      	2:seg<=8'b10100100;
		3:seg<=8'b10110000;
    	4:seg<=8'b10011001;
		5:seg<=8'b10010010;
		6:seg<=8'b10000010;
		7:seg<=8'b11111000;
		8:seg<=8'b10000000;
        9:seg<=8'b10010000;
        11:seg<=8'b10000110;//出错标示
        12:seg<=8'b01111111; //点标示
        13:seg<=8'b11110111;//划标示
        14:seg<=8'b10110110; //等待输入标示
		default:seg<=8'b11111111; //全暗不亮
   endcase
    
endmodule

运行时,将首先在左侧数码管显示"三",表示等待输入,随着按键通过控制时间长短输入点和划,并同步显示在数码管上,键入5次后,译码输出数字,若出错,将显示出错符号"E"。

相关推荐
fei_sun11 小时前
【Verilog】第一章作业
fpga开发·verilog
深圳市雷龙发展有限公司longsto12 小时前
基于FPGA(现场可编程门阵列)的SD NAND图片显示系统是一个复杂的项目,它涉及硬件设计、FPGA编程、SD卡接口、NAND闪存控制以及图像显示等多个方面
fpga开发
9527华安17 小时前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
able陈17 小时前
为什么verilog中递归函数需要定义为automatic?
fpga开发
fei_sun17 小时前
【Verilog】第二章作业
fpga开发·verilog
碎碎思18 小时前
如何使用 Vivado 从源码构建 Infinite-ISP FPGA 项目
fpga开发·接口隔离原则
江山如画,佳人北望20 小时前
fpga-状态机的设计及应用
fpga开发
晓晓暮雨潇潇1 天前
Xilinx IP核(3)XADC IP核
fpga开发·vivado·xadc·ip核
CWNULT1 天前
AMD(Xilinx) FPGA配置Flash大小选择
fpga开发
碎碎思1 天前
很能体现FPGA硬件思维的一道面试题
fpga开发