记录一下做这个EDA课设的过程,并总结一些学习收获。刚开始做的时候,老师就说:你们做这个课设呢,重要的不是结果,而是做的过程。我煞有其事的在笔记本上记录了这句话。OK,不废话了,开始学习吧!
1.能发出1、2、3、4、5、6、7、1八个音;
2.用按键作为键盘;
3.用LED指示灯显示节拍;
4.C调到B调对应频率为
调 | 频率(Hz) |
---|---|
Ċ | 261.63*2 |
B | 493.88 |
A | 440.00 |
G | 392.00 |
F | 349.23 |
E | 329.63 |
D | 293.66 |
C | 261.63 |
5. 数码管显示那部分是我自己加的,没有设计要求,也算是一种拓展吧。
说实话,刚开始的时候,我脑子一片空白,不知道该怎么做,于是做了个计划:
本来准备仿真完成之后就开始在板子上烧录的,但是板子数量不够,所以仿真完成后过了五天,我才拿到板子开始下载烧录。接下来看一看具体的设计过程吧。
第一天
用 quartus || 9.1 进行设计,首先得熟悉这个软件怎么用,我根据老师课上讲的例子以及指导书里的例子来练手,练了差不多一上午,聪明的孩子应该不用这么久,哈哈哈。
然后下午我就去找各种资料了。百度、CSDN等,还有图书馆,根据要做的八音电子琴,搜集各种资料,把觉得能用得到的资料保存或者收藏。
第二天
我把搜集到的资料都看了一遍,并理清需要的模块:1,音调发生模块,我取名为GetTone;2,分频器模块,我取名为FreqDivider;3,显示器模块,我取名为Disp。下面是整个系统的结构图:
这个已经分配好了管脚,我用的板子是EPM570T100C5。建立工程的时候一定要根据自己用的板子来选择。边上有PIN_的就是指管脚,可以先忽略,管脚最好仿真成功之后再分配。
每一个方图的左上角就是它们的名字。
VHDL硬件描述语言是一种“自上而下”的设计语言,通俗点说就是先有大局再考虑局部,从系统再到构成系统的每一个具体的模块。
GetTone模块:根据按键输入,控制Disp模块和FreqDivider模块这两个模块的输出。
Disp模块:根据GetTone模块给的信号,做相应的输出,控制数码管输出的数字和LED灯的亮灭。
FreqDivider模块:根据GetTone模块给的信号,做相应的输出,控制蜂鸣器的发声。
第三天
开始设计GetTone模块了。二话不说,先贴出VHDL代码:
LIBRARY IEEE ;
USE IEEE.STD_LOGIC_1164.ALL ;
USE IEEE.STD_LOGIC_ARITH.ALL ;
USE IEEE.STD_LOGIC_UNSIGNED.ALL ;
ENTITY GetTone IS
PORT ( index: IN STD_LOGIC_VECTOR (6 DOWNTO 0 );
code: out STD_LOGIC_VECTOR (3 DOWNTO 0);
tone1: OUT INTEGER RANGE 0 TO 4000 );
END GetTone;
ARCHITECTURE behavioral OF GetTone IS
BEGIN
search: PROCESS(index)
BEGIN
CASE index Is
WHEN "1111110"=>tone1<=3822;code<="0000"; --1
WHEN "1111101"=>tone1<=3405;code<="0001"; --2
WHEN "1111011"=>tone1<=3034;code<="0010"; --3
WHEN "1110111"=>tone1<=2863;code<="0011"; --4
WHEN "1101111"=>tone1<=2551;code<="0100"; --5
WHEN "1011111"=>tone1<=2273;code<="0101"; --6
WHEN "1110110"=>tone1<=2025;code<="0110"; --7
WHEN "1101101"=>tone1<=1911;code<="0111"; --8
WHEN OTHERS =>tone1<=0;code<="1111";
END CASE;
END PROCESS;
END behavioral;
还是做一点简单说明吧,具体每一句的意思一定要自己花时间理解清楚,只有这样当你最后检错纠错时才能知道自己错在哪里以及怎么改正错误。
这里说一下分频预置数tone1是怎么来的。分频遵循这样一个原则:分得越多(tone1越小),周期越大,频率越小。所以分得越少(tone1越大),频率越大。我用的板子只有一个固定的时钟频率50MHz,我在分频器模块先分成1MHz,再根据分频预置数动态分频。可以用这样一个公式来理解:tone1=1MHz/频率,比如C调的频率是261.63Hz,1MHz/261.63 取整就是3822,C调对应的tone1=3822。
调 | 频率 | Tone1分频预置数 |
---|---|---|
Ċ(高音) | 523.26 | 1911 |
B | 493.88 | 2025 |
A | 440.00 | 2273 |
G | 392.00 | 2551 |
F | 349.23 | 2863 |
E | 329.63 | 3034 |
D | 293.66 | 3405 |
C | 261.63 | 3822 |
第四天+第五天
开始设计FreqDivider模块,VHDL代码如下:
LIBRARY IEEE ;
USE IEEE.STD_LOGIC_1164.ALL ;
USE IEEE.STD_LOGIC_ARITH.ALL ;
USE IEEE.STD_LOGIC_UNSIGNED.ALL ;
ENTITY FreqDivider IS
PORT (clk1:IN STD_LOGIC;
tone2:IN INTEGER RANGE 0 TO 4000;
spks: OUT STD_LOGIC);
END FreqDivider;
ARCHITECTURE behavioral OF FreqDivider IS
SIGNAL preclk, fullspks:STD_LOGIC;
BEGIN
pusel1:PROCESS (clk1)
VARIABLE count:INTEGER RANGE 0 TO 49; --50MHz->1MHz
BEGIN
IF clk1'EVENT AND clk1='1' THEN
IF count<49 THEN count := count+1;
ELSE count := 0;
END IF;
IF count<25 THEN preclk <='0';
ELSE preclk <= '1';
END IF;
END IF;
END PROCESS pusel1;
conspks:PROCESS (preclk, tone2) --relevant Freq->fullspks
VARIABLE count1:INTEGER RANGE 0 TO 4000;
BEGIN
IF preclk'EVENT AND preclk='1' THEN
IF count1spks
VARIABLE count2:STD_LOGIC:='0';
BEGIN
IF fullspks'EVENT AND fullspks='1' THEN
count2:=NOT count2;
IF count2='1' THEN
spks<='1';
ELSE
spks<='0';
END IF;
END IF;
END PROCESS;
END behavioral;
这部分是整个系统中最复杂的,因为我们的VHDL课只上了一点,所以我花了两天时间去理解每一句话,还专门去找教这门课的老师请教。只言片语也讲不清楚,假如你看了一目了然那最好,如果自己花长时间去理解了还是有地方没有搞懂,也没有老师或者同学可以请教的话,可以加我QQ:703840079。
第六天
该设计Disp模块了,VHDL代码如下:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY Disp IS
PORT(code1:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
cs : OUT STD_LOGIC;
LED7S:OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
LED1: OUT STD_LOGIC;
LED2: OUT STD_LOGIC;
LED3: OUT STD_LOGIC;
LED4: OUT STD_LOGIC;
LED5: OUT STD_LOGIC;
LED6: OUT STD_LOGIC;
LED7: OUT STD_LOGIC;
LED8: OUT STD_LOGIC);
END ;
ARCHITECTURE one OF Disp IS
BEGIN
PROCESS(code1)
BEGIN
CASE code1(3 DOWNTO 0) IS --abcdefg
WHEN "0000" =>LED1<='0';LED2<='1';LED3<='1';LED4<='1';LED5<='1';LED6<='1';LED7<='1';LED8<='1';LED7S<="1001111";cs<='0';--1
WHEN "0001" =>LED1<='1';LED2<='0';LED3<='1';LED4<='1';LED5<='1';LED6<='1';LED7<='1';LED8<='1';LED7S<="0010010";cs<='0';--2
WHEN "0010" =>LED1<='1';LED2<='1';LED3<='0';LED4<='1';LED5<='1';LED6<='1';LED7<='1';LED8<='1';LED7S<="0000110";cs<='0';--3
WHEN "0011" =>LED1<='1';LED2<='1';LED3<='1';LED4<='0';LED5<='1';LED6<='1';LED7<='1';LED8<='1';LED7S<="1001100";cs<='0';--4
WHEN "0100" =>LED1<='1';LED2<='1';LED3<='1';LED4<='1';LED5<='0';LED6<='1';LED7<='1';LED8<='1';LED7S<="0100100";cs<='0';--5
WHEN "0101" =>LED1<='1';LED2<='1';LED3<='1';LED4<='1';LED5<='1';LED6<='0';LED7<='1';LED8<='1';LED7S<="0100000";cs<='0';--6
WHEN "0110" =>LED1<='1';LED2<='1';LED3<='1';LED4<='1';LED5<='1';LED6<='1';LED7<='0';LED8<='1';LED7S<="0001111";cs<='0';--7
WHEN "0111" =>LED1<='1';LED2<='1';LED3<='1';LED4<='1';LED5<='1';LED6<='1';LED7<='1';LED8<='0';LED7S<="0000000";cs<='0';--8
WHEN "1111" =>LED1<='1';LED2<='1';LED3<='1';LED4<='1';LED5<='1';LED6<='1';LED7<='1';LED8<='1';LED7S<="0000001";cs<='0';--8
WHEN others =>LED1<='1';LED2<='1';LED3<='1';LED4<='1';LED5<='1';LED6<='1';LED7<='1';LED8<='1';LED7S<="0000001";cs<='0';
END CASE;
END PROCESS;
END;
这个模块还是挺简单的:
调 | LED7S[6…0]–abcdefg | LED1-8 |
---|---|---|
Ċ(高音) | 0000000 | LED8亮 |
B | 0001111 | LED7亮 |
A | 0100000 | LED6亮 |
G | 0100100 | LED5亮 |
F | 1001100 | LED4亮 |
E | 0000110 | LED3亮 |
D | 0010010 | LED2亮 |
C | 1001111 | LED1亮 |
第七天
把上面三个模块整合一下吧!
某N天
终于到烧录这一步了。烧录?就是连接板子和电脑,开始在板子上验证自己的设计是否能实际实现。操作过程请看链接里的烧录文档。链接:https://pan.baidu.com/s/1cxaotp5YxtLt7juJ8EUqIQ
提取码:eda6
验证的过程中,如果老天保佑一下子就验证成功了,那么恭喜你;如果出错了,那么请一定要有耐心、细心和爱心,千万别一气之下把板子给砸了,相信吧,忧郁的日子总会过去。
第三次用这张图了:
本来应该还有个板子验证结果的,但是验收答辩后就把板子交回去了,也忘记录下来了,那就这样吧,用心体会一下就好,最好自己动手做出来体会,哈哈哈。
这张系统结构图用了多次,其实也是有理由的:做模块设计的时候,一定要牢记最后要实现的系统。
收获不少:
PS: 第一次写博客,哈哈哈哈,见笑了。