莫尔斯或者摩尔斯电码(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) //分频成约1350Hzif (!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) //分频成约52Hzif (!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 //初始状态S0else case(state)S0:begin if (key) begin state<=S0; kcnt<=0; endelse begin i<=(i>=5)?1:i+1; state<=S1; endendS1:begin if (key) begin state<=S2; kcnt<=0; end //短按(0.25S内)按键,S1状态else if (kcnt<=13) begin state<=S1; kcnt<=kcnt+1; endelse state<=S3; endS2: 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;endelsei<=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;endelsei<=i+1;end default:;endcasealways@(state) //发声case(state)S1,S3:beep=clk1k;default:beep=0;endcasealways@(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;end6'b111101:begin num=dh[5:4]+10; dg<=6'b111011;end6'b111011:begin num=dh[7:6]+10; dg<=6'b110111;end6'b110111:begin num=dh[9:8]+10; dg<=6'b101111;end6'b101111:begin num=number; dg<=6'b011111;enddefault:begin num=dh[1:0]+10;dg<=6'b111110;endendcase 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; //出错标示endcasealways @(num) //数码管译码,共阳极,0点亮,段码顺序:DP,G-Acase(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; //全暗不亮endcaseendmodule
运行时,将首先在左侧数码管显示“三”,表示等待输入,随着按键通过控制时间长短输入点和划,并同步显示在数码管上,键入5次后,译码输出数字,若出错,将显示出错符号“E”。