• VHDL 乐曲演奏电路设计


    前言

    无源蜂鸣器在直流信号下不会响,需要方波驱动。输入不同频率的方波会发出不同音调的声音,方波的幅值决定了声音的响度。

    目标

    乐曲发生电路在节拍(4Hz)的控制下根据乐谱产生合适的分频系数。分频器根据分频系数对时钟脉冲分频产生各种声调所需要的频率的信号。最后考虑到驱动蜂鸣器要足够的能量使用2分频器对信号进行二分频变为占空比50%的信号。

    模块设计

    分频器

    上面的框图中预分频器、可预置数分频器都是分频器。可以采用上一个设计“数字时钟”设计的“数控N分频器”,不同之处是传入N的位宽(12位)要满足产生音调对应的频率所需分频系数大小(最大3822),通过给分频器传入数值N来对时钟信号进行N分频。得到的信号频率为原时钟信号的频率/N,占空比为1/N。
    代码如下

    library IEEE;
    use IEEE.STD_LOGIC_1164.all;
    use IEEE.STD_LOGIC_UNSIGNED.all;
    
    entity ClkDiv is
        port(
        clk_i:IN STD_LOGIC;
        N_i:  IN STD_LOGIC_VECTOR(11 DOWNTO 0);
        clk_o:OUT STD_LOGIC);
    end ClkDiv;
    
    architecture behavior of ClkDiv is
    signal count:STD_LOGIC_VECTOR(11 DOWNTO 0):="000000000001";
    signal clk_temp:STD_LOGIC:='0';
    begin
        process(clk_i)
        begin
            if(clk_i'EVENT and clk_i='1')then  
                if (count=N_i)then
                    count<="000000000001";
                    clk_temp<='1';
                else
                    count<=count+1;
                    clk_temp<='0';
                end if;
            end if;
        end process;    
        clk_o<=clk_temp;
    end behavior;
    

    仿真结果见“数字时钟设计”

    乐曲发生器

    乐曲发生电路在节拍(4Hz)的控制下根据乐谱产生合适的分频系数。在分频器输入为1Mhz的情况下,各个音调对应的声音的分频系数如下图所示。虽然我们设计的分频器输入为2Mhz,但是在驱动蜂鸣器前还进行了二分频,所以以下分频系数对我们的设计而言是合适的。

    代码如下

    --乐曲发生器Director 在4Hz的信号激励下,产生不同的预置数
    
    library IEEE;
    use IEEE.STD_LOGIC_1164.all;  
    use IEEE.STD_LOGIC_ARITH.all;
    
    entity Director is  
                port(
                Director_i : IN STD_LOGIC; 
                Director_o: OUT STD_LOGIC_VECTOR(11 downto 0)
                );
    end Director;
    
    architecture rtl of Director is 
    signal count :integer:=0;
    signal s: STD_LOGIC_VECTOR(4 downto 0) :="00000";
    signal Director_temp: STD_LOGIC_VECTOR(11 downto 0) :="000000000000";
    begin
    
    
        process(Director_i)
        begin
            if(Director_i'EVENT and Director_i='1')then
                if(count>=47)then
                    count<=0;
                else
                    count<=count+1;
                end if;
                if (count=0)   then s<="00011"; --乐谱
                elsif (count=1)then s<="00011";     
                elsif (count=2)then s<="00011"; 
                elsif (count=3)then s<="00011";
    				
                elsif (count=4)then s<="00100";
                elsif (count=5)then s<="00100";
                elsif (count=6)then s<="00100";
    				
                elsif (count=7)then s<="00101";
    				
                elsif (count=8)then s<="00111";
                elsif (count=9)then s<="00111";
                elsif (count=10)then s<="00111";  
    				
                elsif (count=11)then s<="01000"; 
    				
                elsif (count=12)then s<="00101";
                elsif (count=13)then s<="00111";
    				
                elsif (count=14)then s<="00100";
                elsif (count=15)then s<="00100";
    				
                elsif (count=16)then s<="01011";
                elsif (count=17)then s<="01011";
                elsif (count=18)then s<="01011";
    				
                elsif (count=19)then s<="01110"; 
    				
                elsif (count=20)then s<="01100"; 
    				
                elsif (count=21)then s<="01011";
                elsif (count=22)then s<="01001";
                elsif (count=23)then s<="01011";
    				
                elsif (count=24)then s<="01000";
                elsif (count=25)then s<="01000";
                elsif (count=26)then s<="01000";
                elsif (count=27)then s<="01000";
                elsif (count=28)then s<="01000";     
                elsif (count=29)then s<="01000"; 
                elsif (count=30)then s<="01000";
                elsif (count=31)then s<="01000";
    				
                elsif (count=32)then s<="01000";
                elsif (count=33)then s<="01000";
                elsif (count=34)then s<="01000";
                elsif (count=35)then s<="01001";
    				
                elsif (count=36)then s<="00110";
                elsif (count=37)then s<="00110"; 
    				
                elsif (count=38)then s<="00101";
                elsif (count=39)then s<="00101";
    				
                elsif (count=40)then s<="00100";
                elsif (count=41)then s<="00100";
                elsif (count=42)then s<="00100";
    				
                elsif (count=43)then s<="00101";
                elsif (count=44)then s<="00111";	
                elsif (count=45)then s<="00111";
                elsif (count=46)then s<="01000";
                elsif (count=47)then s<="01000";						
                end if; 
            end if; 
        end process;   
    --    process(Director_i)
    --    begin
    --        if(Director_i'EVENT and Director_i='1')then
    --            if(count=9)then
    --                count<=0;
    --            else
    --                count<=count+1;
    --            end if;
    --            if (count=0)   then s<="00000"; --乐谱
    --            elsif (count=1)then s<="00001";     
    --            elsif (count=2)then s<="00011"; 
    --            elsif (count=3)then s<="00100";
    --            elsif (count=4)then s<="00101";
    --            elsif (count=5)then s<="00110";
    --            elsif (count=6)then s<="00111";
    --            elsif (count=7)then s<="01000";
    --            elsif (count=8)then s<="01001";
    --            elsif (count=9)then s<="01010";
    --            end if; 
    --        end if; 
    --    end process;
        
        process(s)
        begin                                                       --预分频数
            if   (S="00000") then Director_temp<="111011101110";--低音1     
            elsif(S="00001") then Director_temp<="110101001101";--低音2
            elsif(S="00010") then Director_temp<="101111011010";
            elsif(S="00011") then Director_temp<="101100101111";
            elsif(S="00100") then Director_temp<="100111110111";
            elsif(S="00101") then Director_temp<="100011100001";
            elsif(S="00110") then Director_temp<="011111101001";
                
            elsif(S="00111") then Director_temp<="011101110111";--中音1
            elsif(S="01000") then Director_temp<="011010100111";
            elsif(S="01001") then Director_temp<="010111101101";
            elsif(S="01010") then Director_temp<="010110011000";
            elsif(S="01011") then Director_temp<="010011111100";
            elsif(S="01100") then Director_temp<="010001110000";
            elsif(S="01101") then Director_temp<="001111110100";
                
            elsif(S="01110") then Director_temp<="001110111100";--高音1
            elsif(S="01111") then Director_temp<="001101010011";
            elsif(S="10000") then Director_temp<="001011110110";
            elsif(S="10001") then Director_temp<="001011001100";
            elsif(S="10010") then Director_temp<="001001111110";
            elsif(S="10011") then Director_temp<="001000111000";
            elsif(S="10100") then Director_temp<="000111111010";
            end if;         
                
                
        end process;
        Director_o<=Director_temp;
    end rtl;
    

    仿真结果如下,可以看到在4Hz输入信号的激励下,输出乐谱对应的分频系数

    顶层模块

    先对输入的时间脉冲33.8688MHz进行16分频得到2MHz的时间脉冲输入数控分频器。使用同样的方法得到4Hz脉冲输入乐曲发生电路得到音调对应的分频系数,把分频系数输入数控分频器得到音调对应的频率的信号,再对此信号二分频以增强驱动能力。
    代码如下

    
    library IEEE;
    use IEEE.STD_LOGIC_1164.all;
    
    entity TonePlayer is  
    	port(
    		TonePlayerClk_i:IN STD_LOGIC;
    		TonePlayerBeep_o:OUT STD_LOGIC);
    	
    end TonePlayer;
    
    
    
    architecture rtl of TonePlayer is
    	component ClkDiv is
    		port(
    			clk_i:IN STD_LOGIC;
    			N_i:  IN STD_LOGIC_VECTOR(11 DOWNTO 0);
    			clk_o:OUT STD_LOGIC);
    	end component;	   
    	
    	component Director is  
    		port(
    			Director_i : IN STD_LOGIC; 
    			Director_o: OUT STD_LOGIC_VECTOR(11 downto 0)
    			);
    	end component;
    	
    	signal N1: STD_LOGIC_VECTOR(11 DOWNTO 0):="000000011001";
    	signal Clk2M: STD_LOGIC:='0';
    	
    	signal N2: STD_LOGIC_VECTOR(11 DOWNTO 0):="001111101000"; 	
    	signal Clk2K: STD_LOGIC:='0';  
    	
    	signal N3: STD_LOGIC_VECTOR(11 DOWNTO 0):="000111110100"; 
    	signal Clk4Hz: STD_LOGIC:='0';
    	
    	signal DirectorTemp: STD_LOGIC_VECTOR(11 downto 0):="000000000000";	
    	
    	signal N4: STD_LOGIC_VECTOR(11 DOWNTO 0):="000000000010";  
    	
    	signal TonePlayerBeep_Temp: STD_LOGIC:='0';
    	
    begin 
    	Clock_Map: ClkDiv port map(
    		clk_i=>TonePlayerClk_i,
    		N_i=>N1,
    		clk_o=>Clk2M);
    		
    	Clock_Map2: ClkDiv port map(
    		clk_i=>Clk2M,
    		N_i=>N2,
    		clk_o=>Clk2K);		
    
    	Clock_Map3: ClkDiv port map(
    		clk_i=>Clk2K,
    		N_i=>N3,
    		clk_o=>Clk4Hz);	
    	
    	Director_Map: Director port map(
    			Director_i =>Clk4Hz, 
    			Director_o=>DirectorTemp); 
    			
    	CORE_Map4: ClkDiv port map(
    		clk_i=>Clk2M,
    		N_i=>DirectorTemp,
    		clk_o=>TonePlayerBeep_Temp); 
    		
    	Drive_Map: ClkDiv port map(
    		clk_i=>TonePlayerBeep_Temp,
    		N_i=>N4,
    		clk_o=>TonePlayerBeep_o);	
    		
    	
    	
    	
    end rtl;
    
    
    

    仿真结果,DirectorTemp指示了当前输出的音调,可以看到在音调的分界线处,驱动蜂鸣器的TonePlayerBeep_o频率明显改变。而且占空比为50%具有较强的驱动能力

  • 相关阅读:
    jQuery横向手风琴
    jQuery宽屏游戏焦点图
    手风琴式相册图片展开效果
    鼠标悬停图片分享按钮动画
    jQuery水平滑动菜单
    jQuery图片水平滑动延迟加载动画
    jQuery悬浮焦点图宽屏
    jQuery自定义美化下拉框
    纯CSS3垂直动画菜单
    面向服务与微服务架构
  • 原文地址:https://www.cnblogs.com/uestcman/p/10035135.html
Copyright © 2020-2023  润新知