0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于FPGA的电子琴设计

FPGA技术江湖 来源:FPGA技术江湖 2025-01-20 14:07 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

设计原理

在之前也出了几篇源码系列,基本上都是一些小设计,源码系列主要就会想通过实操训练让各位学习者,尤其是初学者去更好的理解学习FPGA,或者给要的学生提供一些源码,之前设计过各个芯片的配置等,之后笔者会通过简单的例子来让大家去系统的学习和认识FPGA。本次的电子琴设计也算是一次简单的各个模块的联系调用的一个过程,也可以帮助各位去加深理解,多动手,熟练掌握会有意想不到的效果。

本次的设计主要是通过控制ps2键盘来使蜂鸣器发出哆来咪法嗦拉西7种音,音符又有高低音之分等,本次只选择发出高音的多来咪发嗦啦西。本设计中还用到了VGA的设计,通过VGA来在显示屏上画出如下图的黑白的电子琴键:

当按下多来咪发嗦啦西时,对应的键值变颜色表示按下,不变色表示不按下,颜色自己可以调节,但是琴的按键必须为黑白色来显示出来。

当按下按键的时候,蜂鸣器来鸣响对应时间的音符,本设计蜂鸣器响的时间为0.25S一个音符持续的时间。

本次设计用到的PS2和VGA的设计原理笔者在这里就不过多的介绍了,不明白的可以翻看前面发的文档内容。

在本设计中介绍蜂鸣器的使用和各音符发声的频率大小。本设计用的是无源蜂鸣器,原理图如下:

0bee9e88-d6e4-11ef-9310-92fbcf53809c.png

由于FPGA的驱动能力不够,我们添加了一个三极管来驱动这个无源蜂鸣器,而无源蜂鸣器的主要特点是内部不带振荡源,所以如果使用直流信号是无法使无源蜂鸣器鸣叫的,必须使用方波去驱动它。

现在我们明白了,只要往蜂鸣器发送一定频率的方波,就可以使得蜂鸣器发出声音,然后现在的问题是,我们究竟要往蜂鸣器发送什么频率的方波信号呢?具体的频率可以查看下图:

0bff6b28-d6e4-11ef-9310-92fbcf53809c.png

现在我们知道如何让蜂鸣器响起,又知道发送什么频率可以让蜂鸣器响起什么的声音,所以我相信我们已经有能力让蜂鸣器响起我们需要的音乐了。

设计架构

设计架构图:

在这里没有去画设计框架图,就直接给大家展示RTL级视图,各位也可以通过RTL级视图看到设计的总框架。

0c250f36-d6e4-11ef-9310-92fbcf53809c.png

设计代码

顶层模块music_ps2代码:

module music_ps2(clk, rst_n, hs, vs, r_g_b, ps2_clk, ps2_data, beep);
  
  input clk;
  input rst_n;


  output  hs;
  output  vs;
  output  [7:0]r_g_b;
  output  beep;
  
  input ps2_clk;
  input ps2_data;
  
  wire flag;
  wire [7:0] data, data_n;
  wire clk_1M;
  
  
  frenp frep_dut(
    .clk(clk),
    .rst_n(rst_n),
    .clk_1M(clk_1M)
    );
    
  ps2_rec rec_dut(
    .clk(clk_1M),
    .rst_n(rst_n),
    .ps2_clk(ps2_clk),
    .ps2_data(ps2_data),
    .flag(flag),
    .data(data)
  );
  
  decode decode_dut(
    .clk(clk_1M),
    .rst_n(rst_n),
    .flag(flag),
    .data(data),
    .data_n(data_n)
  );
  
  music music_dut(
    .clk(clk_1M),
    .rst_n(rst_n),
    .data_n(data_n),
    .beep(beep)
  );
  
  vga vga_dut(
    .clk(clk),
    .rst_n(rst_n),
    .hs(hs),
    .vs(vs),
    .r_g_b(r_g_b),
    .data_n(data_n)
  );
endmodule 

蜂鸣器music模块代码:

module music(clk, rst_n, data_n, beep); 端口列表


  input clk;
  input rst_n;
  input [7:0] data_n;  //输入的键值
  output reg beep;     //蜂鸣器
  
  reg [10:0] music_data;
  wire [10:0] data;


  always @ (posedge clk)
    if(!rst_n)
      begin
        music_data <= 0;
      end
    else
      case (data_n)
        1  :  music_data <= 478;  //蜂鸣器的高音1
        2  :  music_data <= 425;  //蜂鸣器的高音2
        3  :  music_data <= 379;  //蜂鸣器的高音3
        4  :  music_data <= 358;  //蜂鸣器的高音4
        
        5  :  music_data <= 319;  //蜂鸣器的高音5
        6  :  music_data <= 284;  //蜂鸣器的高音6
        7  :  music_data <= 253;  //蜂鸣器的高音7
        default: music_data <= 0;
      endcase
  
  
  reg [20:0] count, cnt;


  always @ (posedge clk)
    if(!rst_n && !data_n)
      begin
        count <= 0;
      end
    else
      if(count < 250_000 - 1)
        begin
          count <= count + 1;
        end
      else
        begin
          count <= 0;
        end
  
  //计数0.25S的时间
  assign data = (count == 250_000 - 1) ? music_data : data;
   
  always @ (posedge clk)
    if(!rst_n)
      begin
        cnt <= 1;
        beep <= 0;
      end
    else
      if(data == 0)    //控制蜂鸣器不响
        begin
          cnt <= 1;
          beep <= 0;
        end
      else if(cnt < data)    //计数对应的频率
        begin
          cnt <= cnt + 1;
        end
      else
        begin
          cnt <= 1;     //蜂鸣器响
          beep <= ~beep;
        end






endmodule 

frenp模块代码:

module frenp(clk,rst_n,clk_1M);


  input clk;
  input rst_n;
  
  output reg clk_1M;
  
  reg [4:0] count;
  
  always @(posedge clk or negedge rst_n)
    if(!rst_n)
      begin
        count <= 5'd0;
        clk_1M <= 1'b1;
      end
    else
      begin
        if(count == 50_000_000 / 1000_000 / 2 - 1)
          begin
            count <= 5'd0;
            clk_1M <= ~clk_1M;
          end
        else
          begin
            count <= count + 1'b1;
          end
      end


endmodule
VGA模块代码:
module vga(
      clk,
      rst_n,
      hs,
      vs,
      r_g_b,
      data_n
      );
  input clk;
  input rst_n;
  input [7:0] data_n;


  output reg hs;
  output reg vs;
  output reg [7:0]r_g_b;


  reg [10:0] count_hs;  //列计数
  reg [10:0] count_vs; //行计数
  parameter h_a=96,h_b=48,h_c=640,h_d=16,h_e=800,
         v_a=2,v_b=33,v_c=480,v_d=10,v_e=525;




  reg clk_25M;
  always @ (posedge clk)
    if(!rst_n)
      clk_25M <= 1;
    else
      clk_25M <= ~ clk_25M;
  /*================列扫描=================*/


  always@(posedge clk_25M or negedge rst_n )
    begin
      if(!rst_n)
        begin
        count_hs<=0;
        end 
      else
        begin
          if(count_hs==h_e)
            count_hs<=0;
          else
            count_hs<=count_hs+11'd1;
        end 
    end 
  /*================行扫描=================*/
  always@(posedge clk_25M or negedge rst_n )
    begin
      if(!rst_n)
        begin
      count_vs<=0;
        end 
      else
        begin
          if(count_vs==v_e)
            count_vs<=0;
          else
            begin
              if(count_hs==h_e)
                count_vs<=count_vs+11'd1;
              else
                count_vs<=count_vs;
            end
        end 
    end 
  /*================列同步=================*/
  always@(posedge clk_25M or negedge rst_n )
    begin
      if(!rst_n)
        begin
        hs<=1;
        end 
      else
        begin
          if(count_hs>=h_a)
            hs<=1;
          else
            hs<=0;  
        end 
    end 
  /*================行同步=================*/
  always@(posedge clk_25M or negedge rst_n )
    begin
      if(!rst_n)
        begin
        vs<=1;
        end 
      else
        begin
          if(count_vs>=v_a)
            vs<=1;
          else
            vs<=0;
        end 
    end 
    /*=============有效区域显示====================*/
  reg yes;
  always@(posedge clk_25M or negedge rst_n)
    begin
      if(!rst_n)
        begin
          yes <= 0;
        end 
      else
        begin
          if((count_hs>h_a+h_b)&&(count_hsv_a+v_b)&&(count_vs 100 )
          flag <= 1;   
        else if ((count_hs - (144 + 30 * 1)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 0;   // 黑
        else if ((count_hs - (144 + 30 * 2)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 2;     
        else if ((count_hs - (144 + 30 * 3)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 0; 
        else if ((count_hs - (144 + 30 * 4)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 3;   
        else if ((count_hs - (145 + 30 * 5)) <= 4  && count_vs > 100 )
          flag <= 0;   
      
        else if ((count_hs - (149 + 30 * 5)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 4;   // 白
        else if ((count_hs - (149 + 30 * 6)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 0;   // 黑
        else if ((count_hs - (149 + 30 * 7)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 5;     
        else if ((count_hs - (149 + 30 * 8)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 0; 
        else if ((count_hs - (149 + 30 * 9)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 6;   
        else if ((count_hs - (149 + 30 * 10)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 0;  
        else if ((count_hs - (149 + 30 * 11)) <= 30  && count_vs < 400 && count_vs > 100 )
          flag <= 7;     
        else if ((count_hs - (150 + 30 * 12))  <= 4  && count_vs > 100 )
          flag <= 0;  
        
        
        else if (count_hs < 186 && count_vs >= 400)
            flag <= 1; 
        else if (count_hs < 190 && count_vs >= 400)
            flag <= 0; 
        else if (count_hs < 234 + 12 && count_vs >= 400)
            flag <= 2;  
        else if (count_hs < 250 && count_vs >= 400)
            flag <= 0;   
        else if (count_hs < 295 && count_vs >= 400)
            flag <= 3;  
        
        
        else if (count_hs < 329 + 12 && count_vs >= 400)
            flag <= 4; 
        else if (count_hs < 329 + 16 && count_vs >= 400)
            flag <= 0;  
        else if (count_hs < 389+12 && count_vs >= 400)
            flag <= 5;   
        else if (count_hs < 389 + 16 && count_vs >= 400)
            flag <= 0;  
        else if (count_hs < 449 + 12   && count_vs >= 400)
            flag <= 6; 
        else if (count_hs < 449 + 16&& count_vs >= 400)
            flag <= 0; 
        else if (count_hs < 510 && count_vs >= 400)
            flag <= 7; 
        else
          flag <= 8; ;
        
      end
    else
      flag<=0;


  reg [1:0] state;
    
  always @ (posedge clk)
    if(!rst_n)
      begin
        state <= 0;
        r_g_b<=8'b000_000_00;
      end
    else 
      if(data_n)
        begin
          if(flag == data_n)
            r_g_b<=8'b111_100_11;
          else if(flag != data_n && flag !=8 && flag !=0)
            r_g_b<=8'b111_111_111;
          else if (flag == 0)
            r_g_b<=8'b000_000_000;
          else if(flag == 8)
            r_g_b<=8'b000_111_00;
        end
      else
        begin
          if(flag !=8 && flag !=0)
            r_g_b<=8'b111_111_111;
          else if (flag == 0)
            r_g_b<=8'b000_000_000;
          else if(flag == 8)
            r_g_b<=8'b000_111_00;
            
        end
        
endmodule
ps_2rec模块代码:
module ps2_rec(clk,rst_n,ps2_clk,ps2_data,flag,data);


  input clk;
  input rst_n;
  input ps2_clk;
  input ps2_data;
  
  output reg flag;
  output  [7:0] data;
  
  wire  nege_dge;
  
  reg  [1:0] signle_s;
  always @ (posedge clk or negedge rst_n)
    if(!rst_n)
      begin
        signle_s <= 2'b11;
      end
    else
      begin
        signle_s[0] <= ps2_clk;
        signle_s[1] <= signle_s[0];
      end
  
  assign nege_dge = ~signle_s[0] && signle_s[1]; 


  
  reg [3:0] count;
  reg [10:0] temp ;
  
  assign data = temp[8:1];
  
  always @  (posedge clk or negedge rst_n)
    if(!rst_n)
      begin
        count <= 4'd0;
        flag <= 1'b0;
        temp <= 11'd0;
      end
    else
      begin
        if(nege_dge && count < 11)
          begin
            count <= count + 1'd1;
            temp[count] <= ps2_data;
          end
        else
          begin
            if(count == 11)
              begin
                count <= 4'd0;
                flag <= 1'b1;
              end
            else
              begin
                flag <= 1'b0;
              end
          end
      end
      
endmodule 
代码验证正确无误,笔者在这边就不过多的验证,源工程已提供给各位大侠,如有需要,可以自行获取,供大家参考学习。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1655

    文章

    22283

    浏览量

    630273
  • 三极管
    +关注

    关注

    145

    文章

    3678

    浏览量

    126733
  • 电子琴
    +关注

    关注

    4

    文章

    154

    浏览量

    31589
  • 无源蜂鸣器
    +关注

    关注

    0

    文章

    43

    浏览量

    11562

原文标题:源码系列:基于FPGA的电子琴设计(附源工程)

文章出处:【微信号:HXSLH1010101010,微信公众号:FPGA技术江湖】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    fpga电子琴,可扬声器双键和弦,可蜂鸣器和扬声器切换,可自动演奏

    元器件扬声器电子琴乐器/玩具喇叭/蜂鸣器
    游泳的鸟儿
    发布于 :2022年08月15日 16:36:29

    基于FPGA电子琴设计

    基于FPGA电子琴设计代码谁有吗?想要一份学习一下
    发表于 05-19 23:25

    【Artix-7 50T FPGA申请】基于Artix-7的智能家居

    ,在此基础上设计过基于FPGA电子琴。同时此前在电子发烧友成功申请获得过云路由和树莓派的试用,认真对待每次试用机会,认真撰写心得体会。如果获得Artix-7 FPGA的试用机会,试用
    发表于 11-10 12:34

    基于FPGA电子琴设计

    基于FPGA电子琴设计
    发表于 12-11 09:46

    电子琴设计

    电子琴设计
    发表于 08-19 12:01 252次下载

    基于FPGA的PS2键盘鼠标控制电子琴

    基于 FPGA的PS2键盘鼠标控制电子琴论文
    发表于 10-29 17:18 31次下载

    基于FPGA电子琴设计 毕业论文分享

    基于FPGA电子琴设计毕业时的论文
    发表于 04-29 16:20 34次下载

    简易电子琴设计及FPGA功能验证

    FPGA简易电子琴设计具体的模块分析和源程序,
    发表于 02-16 16:32 31次下载

    基于FPGA电子琴设计与实现

    乐曲都是由一连串的音符组成,按照乐曲的乐谱依次输出这些音符所对应的频率,就可以在扬声器上连续地发出各个音符的音调。为了准确地演奏出一首乐曲,仅仅让扬声器能够发出声音是远远不够的,还必须准确地控制乐曲的节奏,即每个音符的持续时间。由此可见,乐曲中每个音符的发音频率以及音符持续的时间是乐曲能够连续演奏的两个关键因素。
    发表于 11-28 15:09 2.8w次阅读
    基于<b class='flag-5'>FPGA</b>的<b class='flag-5'>电子琴</b>设计与实现

    基于fpga电子琴电路图分析

    我们生活在一个信息高速发达的时代,各种各样电子产品层出不穷。对于广大老百姓来说,电子琴可以说已经不再是什么“新鲜玩意”了,它现在作为一种休闲和娱乐的产品早就推出市面,面向百姓,进入了我们的生活。作为
    发表于 11-29 08:09 1.3w次阅读
    基于<b class='flag-5'>fpga</b><b class='flag-5'>电子琴</b>电路图分析

    使用FPGA设计电子琴的工程文件和九个数电实验报告资料合集免费下载

    本文档的主要内容详细介绍的是使用FPGA设计电子琴的工程文件和九个数电实验报告资料合集免费下载包括了:  TTL和CMOS集成门电路参数测试,  译码器、编码器的应用 ,  数据选择器
    发表于 06-03 08:00 5次下载
    使用<b class='flag-5'>FPGA</b>设计<b class='flag-5'>电子琴</b>的工程文件和九个数电实验报告资料合集免费下载

    使用FPGA设计电子琴的资料合集免费下载

    本文档的主要内容详细介绍的是使用FPGA设计电子琴的资料合集免费下载。
    发表于 05-29 08:00 4次下载
    使用<b class='flag-5'>FPGA</b>设计<b class='flag-5'>电子琴</b>的资料合集免费下载

    使用FPGA实现电子琴设计的论文

    介绍了基于FPGA电子琴的工作原理和设计过程。用Altera 公司的EP2C8Q208C8N 芯片为核心器件,通过运用硬件编程语言VHDL 描述,在Quartus II 平台上,实现了电子琴
    发表于 07-24 16:51 18次下载
    使用<b class='flag-5'>FPGA</b>实现<b class='flag-5'>电子琴</b>设计的论文

    基于FPGA的简易电子琴的实现

    本系统是采用EDA技术设计的一个简易的八音符电子琴,该系统基于计算机中时钟分频器的原理,采用自顶向下的设计方法来实现,它可以通过按键输入来控制音响。多功能电子琴的设计是在原有普通电子琴的基础上
    发表于 04-28 11:16 47次下载

    基于FPGA电子琴设计

    电子发烧友网站提供《基于FPGA电子琴设计.pdf》资料免费下载
    发表于 10-10 09:40 13次下载
    基于<b class='flag-5'>FPGA</b>的<b class='flag-5'>电子琴</b>设计