《数字电路课程设计》实验报告
题目:基于加速度传感器的计步器的设计实现
班级:29001040班
学号:2903003017
姓名:许芮铭
完成时间:20##年5月23
实验地点:英才实验学院实验室科A304
摘要
通过一段实践的学习,对数字电路设计有了最基本的认识,但对于这一门工程性较强的学科来说,只有实践与理论相结合才能更加加深对所学内容的理解。本次实验通过完成计步器从最初电路板焊接到FPGA编程,再到系统调试的整个过程,让我们对整个数字电路设计开发过程有更深入的了解。该报告将从原理阐述,系统设计,硬件制作和后期调试等几个方面对本次实验过程进行总结,并讲述我在这一过程中的收获与感想。
目录
第一章 实验任务与原理 -------------------------------
第二章 设计思路、方法及方案 -------------------------
第三章 硬件原理图设计、装配与调试 -------------------
第四章 FPGA 模块程序设计与仿真 ----------------------
第五章 系统调试及硬件检查 ---------------------------
第六章 结束语 ---------------------------------------
附录 1 ----------------------------------------------
附录 2 ----------------------------------------------
第一章 实验任务与原理
1.1 功能需求
设计完成一个电路来检测目标运动的次数,并在数码管上显示。
1.2 任务指标
1、记录并显示99以内的运动次数
2、数码管计数显示可以重置
1.3 原理阐述
利用重力感应芯片检测运动,将信号放大之后输入施密特触发器产生方波波形,并利用FPGA将方波波形计数并在数码管上显示。
第二章 设计思路、方法及方案
2.1 系统功能需求分析
本次实验采用的重力感应芯片是ADI公司生产的ADXL335加速度传感器,传感器本身支持三轴重力感应,驱动电压为3V。我们的实验只需要读取其中一轴的信号即可。但是感应器本身输出峰值在200mV左右,且为随着加速度大小连续改变的模拟信号,而FPGA的信号输入需要方波脉冲。传感器输出不论是峰值电压还是连续信号本身都不能满足要求。于是,我们需要首先对传感器的输出信号进行放大,并将其波形转换为方波信号,以便FPGA的进一步处理。
2.2方案确定及框图结构说明
根据前文所说,由于信号在生成方波以前需要进行电压幅度放大,考虑到放大电路本身存在噪声,再加上环境因素的影响,为了有效滤除噪声对方波信号的影响,我们选择施密特触发器而不是简单的比较器来产生方波,触发器由555电路为主构成,驱动电压为3.3V左右,最大转换电压越2V,最低转换电压为1V,以此为依据,我们可以设计出放大器的放大倍数。放大器设计中,我们使用简单的LM324集成运放,其价格便宜,设计指标也能满足信号放大的需求。使用LM324中的一个运算放大器,使用利用深度反馈原理,即可获得相应的放大倍数。由于传感器本身输出信号带有一定的直流偏执,所以在放大之前需要使用隔直电容将直流隔去。
在完成电路之后,将产生峰值在2V左右的方波信号,信号输入到FPGA开发板上,通过编程实现对方波的计数,并最终显示在数码管上。
下面是设计的框图。
最终确定的主要元器件和设备有:
1、ADXL335重力感应传感器
2、LM324集成运放
3、555电路
4、XC3S250E144型FPGA开发板
第三章 硬件原理图设计、装配与调试
3.1硬件原理
硬件原理如下图所示
本电路完成了运动信号的采集,放大,生成方波信号的操作,其中,LM324放大电路仅使用其中一个运算放大器,通过调节R1和R2电阻值的比值,将放大器增益设置在20dB左右。
原理图如下:
使用555电路组成施密特触发器的原理图如下:
3.2 装配成果
最后焊接完成后的电路板如下图所示。
正面图:
背面图:
3.3 调试结果
如下图所示,首先将示波器接头接在隔直电容前端,可以看到缓慢上下摇动一次传感器产生的带有直流分量的输出信号(模拟信号)。
将放大器和施密特触发器都调试完成后,不停摇动电路板,可以在最后的输出端看到如下的方波信号,可以看到,信号幅度在2.26V,且方波比较规则,仅有很小的失真。
第四章 FPGA模块程序设计
使用FPGA对施密特触发器产生的方波脉冲信号进行计数,并将数值显示在7段数码管上。在设计时应当注意的是,使用上升沿计数时,脉冲上升沿与系统时钟不同步,在7段数码管显示时,每个数码管都有一个使能信号。同时,整个系统需要设定复位信号。
最终整个FPGA设计框图如下:
具体VHDL代码见附录1.
代码完成之后,为了将VHDL模块的端口信号与FPGA的硬件接口关联起来,同时对一些信号进行约束,需要进行管教适配,适配所用代码见附录2.
第五章 系统调试及硬件检查
5.1系统调试过程
在实验过程中,曾经遇到了不小的困难,期间也经历过多次调试。
第一次困难在于产生的方波信号存在直流偏置,首先想到的是隔直电容出现短路,但是更换电容以后没有解决问题,后来我们偶然发现,如果将电容接地放电,可以解决存在直流偏置的问题,最后考虑到这应该和电容本身的充电现象有关。
第二次困难在于方波信号电压不足,导致FPGA难以检测到信号输入。该问题通过重新调节俩个变阻器的阻值之比得到解决。
第三次困难在于VHDL编程过程中,由于对进程和信号概念理解不清楚,在设计D触发器之后的比较器时,使用了错误的代码,导致系统自检出错,后来通过请教同学,改变设计方法,解决了这一问题。
在实验过程中,还因误触稳压电源旋钮烧坏了一个LM324运放,幸运的是并没有损坏其他电路原件,这也提醒我们在实验过程中一定要细致,小心。
5.2实验结果
在代码和硬件都分别完成并分块调试完毕以后,将VHDL代码下载到FPGA开发板上,并将整个系统连接好,即完成了实验主要内容。摇动电路板,FPGA上的数码管能正确显示计数到99次,按下reset键可以对显示清零并重新开始计数。
第六章 结束语
通过本次实验,第一次体会到了数字电路设计开发过程,对高精度的电路焊接,FPGA开发,系统调试等都有了更加深入的了解并增加了实践的经验。贴片芯片的焊接是一个对耐心和细致要求极高的工作,我也是通过仔细琢磨,并花了很长时间才掌握了焊接的诀窍。并成功将几根头发丝一样细的导线焊上去。同时,系统设计虽然很完善,但是实际电路完全和设计不同,反复的调试也让我体会到了电路设计一定要结合实际这一观点。正如一个学姐说的,“只有调的出来的电路设计,才是好设计”。反复调试也让我更加体会到耐心和坚持的重要,试想,如果一次两次调试失败就放弃,是不可能做得出来这个小装置的。
在实验过程中,我还发现,由于是两个同学共同完成一块板子的制作,所以很多同学不愿意亲自动手完成繁琐的焊接工作,完全交给另外一个同学完成(当然我们组是真正两个人合作完成的),这样的话就失去了这个宝贵的锻炼动手能力的机会,不得不说是一个遗憾,所以还是希望以后能够多采购一些元器件,让每个同学都能够充分感受制作的过程,毕竟培养同学动手能力也是实验目的的一部分。
最后,感谢在实验过程中给予我帮助的老师和同学们,没有你们的帮助和支持,我的实验将完成的非常困难,是你们让我感受到了团队合作的力量。
附录1
VHDL程序
---------------------------------------------------------------------
-- Company:
-- Engineer:
-- Create Date: 02:54:50 05/12/2011
-- Design Name:
-- Module Name: raysc- Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
-- Dependencies:
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
---------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
---------------------------------------------------------------------
entity raysc is
Port ( din : in STD_LOGIC;
clk : in STD_LOGIC;
reset : in STD_LOGIC;
dout : out STD_LOGIC_VECTOR (7 downto 0);
en_out : out STD_LOGIC_VECTOR (7 downto 0));
end raysc;
---------------------------------------------------------------------
architecture Behavioral of raysc is
signal cnt1,cnt2 : std_logic_vector(3 downto 0);--the outcomes of the counter
signal cont1,cont2 : std_logic_vector(7 downto 0);--the encodings of displayer
signal a,b : std_logic;
signal counter1 : std_logic_vector(12 downto 0);
signal counter2 : std_logic_vector(12 downto 0);
signal cnt_flag, en_flag: std_logic;
signal zer,one,two,thr,fou,fiv,six,sev,eig,nin,E:std_logic_vector(7 downto 0);
---------------------------------------------------------------------
begin
a <= din;
zer <= "11000000";
one <= "11111001";
two <= "10100100";
thr <= "10110000";
fou <= "10011001";
fiv <= "10010010";
six <= "10000010";
sev <= "11111000";
eig <= "10000000";
nin <= "10010000";
E <= "10000110";
---------------------------------------------------------------------
process (clk, reset)
begin
if reset='0' then
b <= '0';
elsif clk'event and clk='1' then
b <= a;
end if;
end process;
---------------------------------------------------------------------
process(clk,reset)
begin
if reset='0' then
cnt1 <= (others => '0');
cnt2 <= (others => '0');
elsif clk'event and clk='1' then
if a='1' and b='0' then
if cnt1 = "1001" then
cnt1 <= (others => '0');
cnt2 <= cnt2 + '1';
else
cnt1 <= cnt1 + '1';
end if;
end if;
end if;
end process;
---------------------------------------------------------------------
process(clk,reset)
begin
if reset='0' then
counter1 <= (others => '0');
cnt_flag <= '0';
-- en_flag <= '0';
elsif clk'event and clk='1' then
if counter1 = "1111111111111" then
counter1 <= (others => '0');
else
counter1 <= counter1 + '1';
end if;
end if;
end process;
---------------------------------------------------------------------
process(clk, reset)
begin
if clk'event and clk='1' then
if counter1 < "0111111111111" then
en_flag <= '0';
else
en_flag <= '1';
end if;
end if;
end process;
---------------------------------------------------------------------
process(cnt1,cnt2)
begin
case cnt1 is
when "0000" => cont1 <= zer;
when "0001" => cont1 <= one;
when "0010" => cont1 <= two;
when "0011" => cont1 <= thr;
when "0100" => cont1 <= fou;
when "0101" => cont1 <= fiv;
when "0110" => cont1 <= six;
when "0111" => cont1 <= sev;
when "1000" => cont1 <= eig;
when "1001" => cont1 <= nin;
when others => cont1 <= E;
end case;
case cnt2 is
when "0000" => cont2 <= zer;
when "0001" => cont2 <= one;
when "0010" => cont2 <= two;
when "0011" => cont2 <= thr;
when "0100" => cont2 <= fou;
when "0101" => cont2 <= fiv;
when "0110" => cont2 <= six;
when "0111" => cont2 <= sev;
when "1000" => cont2 <= eig;
when "1001" => cont2 <= nin;
when others => cont2 <= E;
end case;
end process;
---------------------------------------------------------------------
process(en_flag,cont1,cont2)
begin
if en_flag='0' then
dout <= cont1;
en_out <= "11111110";
else
dout <= cont2;
en_out <= "11111101";
end if;
end process;
---------------------------------------------------------------------
end Behavioral;
附录2
管脚适配
NET "clk"TNM_NET=clk;############################clock
TIMESPEC TS_clk=PERIOD "clk" 20 ns HIGH 50%;
NET "din" LOC=P21;
NET "clk" LOC=P128;
NET "reset" LOC=P38;
#NET "set" LOC=P41;
#################################################Nixie Tube
NET "dout(7)" LOC=P66;
NET "dout(6)" LOC=P53;
NET "dout(5)" LOC=P54;
NET "dout(4)" LOC=P77;
NET "dout(3)" LOC=P76;
NET "dout(2)" LOC=P58;
NET "dout(1)" LOC=P75;
NET "dout(0)" LOC=P52;
#################################################control
NET "en_out(7)" LOC=P51;
NET "en_out(6)" LOC=P59;
NET "en_out(5)" LOC=P74;
NET "en_out(4)" LOC=P43;
NET "en_out(3)" LOC=P82;
NET "en_out(2)" LOC=P83;
NET "en_out(1)" LOC=P85;
NET "en_out(0)" LOC=P81;