基于LCD1602的简易秒表的设计与实现.doc
数字电路与逻辑设计实验报告学院: 电子工程学院班级: 2014211212姓名:学号: 班内序号:第 30 页 共 30 页一、 设计课题的任务要求简易秒表的设计与实现设计制作一个计时精度为百分之一秒的计时秒表基本要求:1. 用LCD1602液晶屏显示计时;2. 秒表计时长度为23小时59分59.99秒;3. 用BTN0作为启动/停止开关;4. 用BTN1作为复位开关,在任何情况下,只要按下复位开关,秒表都要无条件执行清零操作。提高要求:1。增加定时器功能,可根据用户设定的时间进行倒计时,时间到0后蜂鸣器报警提示;2.自拟其他功能.二、 系统设计(设计思路、总体框图、分块设计)1. 设计思路:分别设计6进制计数器、10进制计数器和24进制计数器用于秒表计时部分。具体来说:将两个10进制计数器级联分别作为秒表的十分秒位(最小单位为0。1秒)和百分秒位(最小单位为0。01秒);将一个10进制计数器和6进制计数器级联,分别作为秒表秒钟部分的个位(最小单位为1秒)和十位(最小单位为10秒);再将一个10进制计数器和6进制计数器级联,分别作为秒表分钟部分的个位(最小单位为1分钟)和十位(最小单位为10分钟);将24进制计数器作为秒表小时部分,其中低位输出作为秒表小时部分的个位(最小单位为1小时),高位输出作为秒表小时部分的十位(最小单位为10小时)。最后把秒表百分秒、十分秒部分、秒钟部分、分钟部分、小时部分这四部分级联起来便构成了简易数字秒表的计时部分。将各个计数器部分的输出信号通过译码模块,变成LCD1602液晶屏能够读取并从而显示相关字符的8位二进制数据。再定义一个存储器ram,存储各个计数器部分的输出信号经过译码部分之后得到的数据,然后将这个存储器ram代表的数据在LCD1602液晶屏上显示。考虑到秒表的最小计时长度为0.01秒(频率为100HZ),如果系统时钟设置为50MHZ,则需要500000分频;实验时发现LCD1602液晶屏的时钟在1KHZ时,显示效果较好,故需要在系统时钟为50MHZ的基础上进行50000分频。考虑到基本要求中需要用BTN0作为启动/停止开关,用BTN1作为复位开关,所以需要设计相应的按键防抖电路,这里我采用的是计数型防抖。2. 总体框图:图1系统结构框图3. 分块设计:系统共通过9个模块实现,分别是:500000分频模块fpq50000分频模块fpq16进制计数器模块cnt610进制计数器模块cnt1024进制计数器模块cnt24译码模块yimaLCD1602显示模块LCD1602BTN0启动/停止开关消抖模块xiaodouBTN1复位开关消抖模块fuweixiaodou具体设计如下:500000分频模块fpq输入端口:clk :in std_logic;输出端口:clkout : out std_logic;生成符号:设计思路:利用计数法实现分频主要代码:(完整代码请见源程序)signal clktmp : std_logic;signal tmp : integer range 0 to 249999; beginprocess (clk)beginif clkevent and clk='1' thenif tmp=249999 then-500000分频tmp<=0; clktmp<=not clktmp;else tmp<=tmp+1;end if;end if;end process;clkout<=clktmp;50000分频模块fpq1:输入端口:clk :in std_logic;输出端口:clkout : out std_logic;生成符号:设计思路:利用计数法实现分频主要代码:(完整代码请见源程序)signal clktmp : std_logic;signal tmp : integer range 0 to 24999; beginprocess (clk)beginif clk'event and clk=1' thenif tmp=24999 then-50000分频tmp<=0; clktmp=not clktmp;else tmp=tmp+1;end if;end if;end process;clkout<=clktmp;6进制计数器模块cnt6:输入端口:reset,en,clk:IN STD_LOGIC;输出端口:carry :OUT STD_LOGIC; q:OUT STD_LOGIC_VECTOR(3 DOWNTO 0);生成符号:设计思路:正常的计数状态是0->1>2->34-5->01;当计数到5时,进位信号变为1;否则状态自增,进位信号保持在0'主要代码:(完整代码请见源程序)SIGNAL qs :STD_LOGIC_VECTOR(3 DOWNTO 0); SIGNAL ca :STD_LOGIC;BEGIN PROCESS(clk)begin IF(reset=1)THEN qs<=”0000”;ELSIF(clkEVENT AND clk=1')THENIF(en='0') THENIF(qs="0101") THEN计数到5qs<= ”0000";ca<=1';ELSEqs=qs+1;ca='0';END IF;END IF; END IF; END PROCESS;PROCESS(ca,en)BEGINq=qs;carry=ca;END PROCESS;10进制计数器模块cnt10:输入端口:reset,en,clk:IN STD_LOGIC;输出端口:carry :OUT STD_LOGIC; q:OUT STD_LOGIC_VECTOR(3 DOWNTO 0);生成符号:设计思路:正常的计数状态是;0>1->2->3-4->5>6>78>901当计数到9时,进位信号变为1';否则状态自增,进位信号保持在0主要代码:(完整代码请见源程序)SIGNAL qs :STD_LOGIC_VECTOR(3 DOWNTO 0); SIGNAL ca :STD_LOGIC;BEGIN PROCESS(clk)begin IF(reset=1)THEN qs<="0000”;ELSIF(clk'EVENT AND clk='1)THENIF(en='0') THEN IF(qs="1001”) THEN 计数到9qs= ”0000”;ca=1;ELSEqs=qs+1;ca<=0;END IF;END IF; END IF; END PROCESS; PROCESS(ca)BEGINq=qs;carry=ca;END PROCESS;24进制计数器模块cnt24:输入端口en,Reset,clk: in STD_LOGIC;输出端口carry: out STD_LOGIC;qa: out STD_LOGIC_VECTOR(3 DOWNTO 0); qb: out STD_LOGIC_VECTOR(3 DOWNTO 0); 生成符号:设计思路:正常的计数状态是;低位qa状态变化:0>1>2-3->4>5-6-7>8-9-01高位qb状态变化:01->2->0->1当低位qa计数到9时,qb自增,进位信号保持在0'当低位qa为3且高位qb为2时,进位信号变为1, 同时qa变为0、qb变为0主要代码:(完整代码请见源程序)SIGNAL ca :STD_LOGIC;BEGINprocess(clk,Reset,en)variable tma: STD_LOGIC_VECTOR(3 DOWNTO 0);variable tmb: STD_LOGIC_VECTOR(3 DOWNTO 0);beginIf Reset = '1' then tma:=”0000”; tmb:=”0000”; else if clkevent and clk='1' then IF(en='0) THEN-当BTN0键没有第一次按下时,正常计数 if tma="1001" then tma:="0000”;tmb:=tmb+1;elsif tmb=”0010” and tma=”0011” then -计数到23tma:="0000”;tmb:="0000"; ca<='1;else tma:=tma+1; end if; end if;end if; end if; qa<=tma;qb<=tmb;carry<=ca; end process;译码模块yima:输入端口:carry: in STD_LOGIC;data: in std_logic_vector(3 downto 0);输出端口:dataout:out std_logic_vector(7 downto 0);生成符号:设计思路:根据输入信号的不同,使用case语句进行不同的译码操作即可。具体来说:0'(四位二进制)译为"30”(八位二进制)1'(四位二进制)译为"31"(八位二进制)2'(四位二进制)译为”32”(八位二进制)3(四位二进制)译为”33"(八位二进制)4'(四位二进制)译为"34”(八位二进制)5'(四位二进制)译为"35"(八位二进制)'6'(四位二进制)译为"36"(八位二进制)'7'(四位二进制)译为"37”(八位二进制)8'(四位二进制)译为"38”(八位二进制)'9(四位二进制)译为”39"(八位二进制)其他译为"20”(八位二进制)主要代码:(完整代码请见源程序)signal dis:std_logic_vector(7 downto 0);beginprocess(data)beginif(carry=1') thendis="11111111”;else case data iswhen ”0000”=>dis<=”00110000"-0'译为”30”when ”0001"=>dis=”00110001"-'1'译为”31”when "0010"=dis<="00110010”;-'2译为"32"when "0011"=dis<="00110011”;-3'译为"33” when ”0100”=dis=”00110100"4'译为”34” when ”0101"=>dis<="00110101”;-'5译为"35” when "0110”=>dis<="00110110”;-'6'译为"36”when "0111"=>dis<=”00110111";-'7译为"37”when "1000"=dis="00111000”;-8'译为"38" when "1001"=>dis=”00111001"-'9'译为”39” when others=dis="00100000”;-其他译为”20”end case;end if;end process;dataout=dis;LCD1602显示模块LCD1602: 输入端口:YIMA_DATA1: in std_logic_vector(7 downto 0); -译码数据信号1YIMA_DATA2: in std_logic_vector(7 downto 0); -译码数据信号2YIMA_DATA3: in std_logic_vector(7 downto 0); -译码数据信号3YIMA_DATA4: in std_logic_vector(7 downto 0); -译码数据信号4YIMA_DATA5: in std_logic_vector(7 downto 0); -译码数据信号5YIMA_DATA6: in std_logic_vector(7 downto 0); -译码数据信号6YIMA_DATA7: in std_logic_vector(7 downto 0); -译码数据信号7 YIMA_DATA8: in std_logic_vector(7 downto 0); 译码数据信号8LCD_Clk : in std_logic; -状态机时钟信号,同时也是液晶时钟信号,其周期应该满足液晶数据的建立时间carry : in STD_LOGIC;输出端口:LCD_RS : out std_logic; -寄存器选择信号LCD_RW : out std_logic; -液晶读写信号 LCD_EN : out std_logic; -液晶时钟信号 LCD_Data : out std_logic_vector(7 downto 0); -液晶数据信号 生成符号:设计思路:将各个计数器部分的输出信号通过译码模块,变成LCD1602液晶屏能够读取并从而显示相关字符的8位二进制数据.再定义一个存储器ram,存储各个计数器部分的输出信号经过译码部分之后得到的数据,然后将这个存储器ram代表的数据在LCD1602液晶屏上显示。主要代码:(完整代码请见源程序)type ram is array(0 to 10) of std_logic_vector(7 downto 0);signal ram1:ram;beginLCD_EN = LCD_Clk ; -液晶时钟信号LCD_RW = '0 ; 液晶读写信号ram1(0)=YIMA_DATA8;译码数据信号8,秒表小时部分十位ram1(1)=YIMA_DATA7;-译码数据信号7,秒表小时部分个位 ram1(2)=x”3a”;-显示冒号:ram1(3)=YIMA_DATA6;-译码数据信号6,秒表分钟部分十位ram1(4)<=YIMA_DATA5;-译码数据信号5,秒表分钟部分个位ram1(5)=x"3a”;-显示冒号: ram1(6)<=YIMA_DATA4;译码数据信号4,秒表秒钟部分十位ram1(7)<=YIMA_DATA3;-译码数据信号3,秒表秒钟部分个位ram1(8)<=x”2e"-显示小数点.ram1(9)=YIMA_DATA2;-译码数据信号2,秒表十分秒位 ram1(10)<=YIMA_DATA1;-译码数据信号1,秒表百分秒位process(LCD_Clk)variable cnt :integer range 0 to 37;begin if LCD_Clk'event and LCD_Clk = 1thenif cnt =37 then cnt :=0;else cnt :=cnt +1;end if;end if;case cnt is-Init LCD1602初始化部分-when 0 =>LCD_RS='0;lcd_data<="00111000";0x38when 1 =LCD_RS='0'lcd_data<=”00001100”;-0x0Cwhen 2 =LCD_RS<='0';lcd_data="00000001"0x01when 3 =>LCD_RS=0;lcd_data=”00000110”;-0x06- when 4 =>LCD_RS<=0';lcd_data=”10000000”;0x80-display,0x00+0x80-data display-when 5=>LCD_RS=1;lcd_data<=”10100000"空格 when 6=>LCD_RS=1;lcd_data<="10100000”;-空格 when 7=LCD_RS=1;lcd_data<="10100000”;-空格 when 8=>LCD_RS<='1;lcd_data=ram1(0);秒表小时部分十位when 9=>LCD_RS=1';lcd_data=ram1(1);-秒表小时部分个位when 10=LCD_RS<=1';lcd_data<=ram1(2);冒号: when 11=>LCD_RS<=1;lcd_data<=ram1(3);-秒表分钟部分十位when 12=>LCD_RS='1;lcd_data=ram1(4);-秒表分钟部分个位when 13=LCD_RS<=1;lcd_data=ram1(5);-冒号: when 14=LCD_RS=1;lcd_data<=ram1(6);-秒表秒钟部分十位when 15=>LCD_RS<='1'lcd_data<=ram1(7);-秒表秒钟部分个位when 16=>LCD_RS=1;lcd_data=ram1(8);-小数点。when 17=LCD_RS='1;lcd_data=ram1(9);-秒表十分秒位when 18=LCD_RS<=1;lcd_data<=ram1(10);-秒表百分秒位when 19=>LCD_RS<=1;lcd_data<=”10100000"空格 when 20=>LCD_RS=1'lcd_data="10100000”;-空格 -when 21=>LCD_RS<=0;lcd_data<=”11000000"-设定显示的位置在40H+80H,-when 22=>LCD_RS<=1';lcd_data<="10100000"-空格 when 23=LCD_RS<=1';lcd_data=”10100000"-空格when 24=LCD_RS=1'lcd_data=”10100000”;空格when 25=>LCD_RS<='1;lcd_data<=”10100000";-空格when 26=>LCD_RS='1';lcd_data<="10100000";-空格when 27=>LCD_RS<=1';lcd_data="10100000”;-空格when 28=LCD_RS=1;lcd_data<=”10100000”;空格when 29=>LCD_RS=1';lcd_data<=”10100000”;-空格when 30=>LCD_RS='1'lcd_data<="10100000”;-空格when 31=>LCD_RS<=1;lcd_data<="10100000";-空格when 32=>LCD_RS<=1'lcd_data<="10100000”;-空格when 33=>LCD_RS='1;lcd_data<=”10100000";-空格when 34=LCD_RS=1'lcd_data<="10100000”;空格when 35=>LCD_RS<=1'lcd_data<="10100000”;-空格when 36=>LCD_RS='1'lcd_data=”10100000”;-空格 when 37=LCD_RS<='1;lcd_data<="10100000"-空格 end case;end process;BTN0启动/停止开关消抖模块xiaodou: 输入端口:clk :in std_logic;key_en:in std_logic;输出端口: en_out:out std_logic; 生成符号:设计思路:采用计数型防抖当key_en第一次为1'时,en_out延迟一段时间后变为'1',并且en_out就此保持在高电平'1;直到key_en第二次为1'时,en_out延迟一段时间后变为0'。主要代码:(完整代码请见源程序)signal cnt:integer range 0 to 3;-采用计数型防抖signal en,en_tmp:std_logic;beginp0:process(clk)beginif clk'event and clk =1' thenif key_en =1 thenif cnt = 3 then en<=1;else cnt=cnt+1;en=0;end if;else cnt=0;en<='0;end if;end if;end process p0;p1:process(en)beginif en'event and en='1' thenen_tmp<=not en_tmp;end if;en_out=en_tmp;end process p1;BTN1复位开关消抖模块fuweixiaodou:输入端口:clk :in std_logic; fuwei:in std_logic;输出端口:fuwei_out:out std_logic; 生成符号:设计思路:采用计数型防抖当fuwei为1时,fuwei_out延迟一段时间后变为1,然后fuwei_out又重新回到低电平'0'.主要代码:(完整代码请见源程序)signal cnt:integer range 0 to 3;采用计数型防抖signal en:std_logic;beginprocess(clk)beginif clk'event and clk =1 thenif fuwei ='1 thenif cnt = 3 then en='1;else cnt<=cnt+1;en<='0;end if;else cnt<=0;en<='0';end if;end if;end process; fuwei_out=en;三、 仿真波形及波形分析500000分频模块fpq输入端口:clk : in std_logic;输出端口:clkout : out std_logic;仿真波形:波形分析: 输入时钟信号为clk, 频率为50MHZ(周期为20ns)输出时钟信号为clkout,频率为100HZ(周期为10ms) 达到了500000分频的目的。50000分频模块fpq1输入端口:clk : in std_logic;输出端口:clkout : out std_logic;仿真波形:波形分析:输入时钟信号为clk, 频率为50MHZ(周期为20ns)输出时钟信号为clkout,频率为1KHZ(周期为1ms)达到了50000分频的目的。6进制计数器模块cnt6:输入端口:reset,en,clk:IN STD_LOGIC;输出端口:carry :OUT STD_LOGIC; q :OUT STD_LOGIC_VECTOR(3 DOWNTO 0); 仿真波形: 波形分析:正常计数状态变化(16进制表示)是:01->2-34>5-0-1;当reset信号为1时(此时按下了复位开关BTN1),执行清零操作,状态变为0;当en信号为'1'时(此时第一次按下了启动/停止开关BTN0), 状态保持不变,停止计数;当en信号为'0时(此时第二次按下了启动/停止开关BTN0), 又继续计数。10进制计数器模块cnt10:输入端口:reset,en,clk:IN STD_LOGIC;输出端口:carry :OUT STD_LOGIC; q :OUT STD_LOGIC_VECTOR(3 DOWNTO 0); 仿真波形: 波形分析:正常计数状态变化(16进制表示)是:0-1>234>5->6->7->8-9->0->1;当reset信号为1'时(此时按下了复位开关BTN1),执行清零操作,状态变为0; 当en信号为'1时(此时第一次按下了启动/停止开关BTN0), 状态保持不变,停止计数;当en信号为0'时(此时第二次按下了启动/停止开关BTN0), 又继续计数。24进制计数器模块cnt24:输入端口en,Reset,clk: in STD_LOGIC;输出端口carry: out STD_LOGIC;qa: out STD_LOGIC_VECTOR(3 DOWNTO 0); qb: out STD_LOGIC_VECTOR(3 DOWNTO 0); 仿真波形: 波形分析:qa状态变化(16进制表示)是:0->1->23-4->5>6>7-8->9->0->1;qb状态变化(16进制表示)是:0>1->2>01;且当qa为9(16进制表示)时,qb的状态发生改变。当reset信号为'1'时(此时按下了复位开关BTN1),执行清零操作,状态变为0; 当en信号为'1'时(此时第一次按下了启动/停止开关BTN0), 状态保持不变,停止计数;当en信号为'0'时(此时第二次按下了启动/停止开关BTN0), 又继续计数。译码模块yima:输入端口:carry: in STD_LOGIC;data: in std_logic_vector(3 downto 0);输出端口: dataout:out std_logic_vector(7 downto 0); 仿真波形: 波形分析:当carry信号为1'时,dataout输出为FF(二进制表示为”11111111”);当carry信号为0'时,正常译码:data为'0'(二进制表示为"0000")时,dataout输出为"30”(二进制表示为"00110000”);data为'1(二进制表示为”0001")时,dataout输出为"31”(二进制表示为"00110001”);data为'2'(二进制表示为"0010")时,dataout输出为"32”(二进制表示为"00110010”);data为3(二进制表示为”0011”)时,dataout输出为"33”(二进制表示为”00110011");data为'4'(二进制表示为”0100”)时,dataout输出为”34”(二进制表示为"00110100”);data为'5(二进制表示为"0101”)时,dataout输出为”35”(二进制表示为”00110101");data为'6(二进制表示为”0110")时,dataout输出为”36”(二进制表示为"00110110");data为'7(二进制表示为”0111”)时,dataout输出为"37"(二进制表示为"00110111”);data为8'(二进制表示为”1000”)时,dataout输出为"38"(二进制表示为"00111000");data为'9(二进制表示为”1001")时,dataout输出为”39"(二进制表示为”00111001");data为其他数据时,dataout输出为”20”(二进制表示为"00100000”);LCD1602显示模块LCD1602:输入端口:LCD_Clk: in std_logic; -状态机时钟信号,同时也是液晶时钟信号,其周期应该满足液晶数据的建立时间 carry:in STD_LOGIC;前级计数部分输出的进位信号YIMA_DATA1: in std_logic_vector(7 downto 0); 译码数据信号1YIMA_DATA2: in std_logic_vector(7 downto 0); -译码数据信号2YIMA_DATA3: in std_logic_vector(7 downto 0); -译码数据信号3YIMA_DATA4: in std_logic_vector(7 downto 0); -译码数据信号4YIMA_DATA5: in std_logic_vector(7 downto 0); -译码数据信号5YIMA_DATA6: in std_logic_vector(7 downto 0); 译码数据信号6YIMA_DATA7: in std_logic_vector(7 downto 0); 译码数据信号7 YIMA_DATA8: in std_logic_vector(7 downto 0); -译码数据信号8输出端口: LCD_RS: out std_logic; -寄存器选择信号 LCD_RW: out std_logic; -液晶读写信号 LCD_EN: out std_logic; -液晶时钟信号 LCD_Data: out std_logic_vector(7 downto 0); 液晶数据信号仿真波形:接下图接下图 波形分析:仿真时假设YIMA_DATA1="00110001”;-代表数字1YIMA_DATA2=”00110001”;-代表数字1YIMA_DATA3="00110001";-代表数字1YIMA_DATA4="00110001"代表数字1YIMA_DATA5="00110001”;-代表数字1YIMA_DATA6="00110001”;-代表数字1YIMA_DATA7=”00110001”;代表数字1YIMA_DATA8=”00110001”;-代表数字1则对于输出信号LCD_Data:在初始化部分(LCD_RS=0)依次为”38"、”0C”、"01"、”06”、”80";在开始显示时(LCD_RS<=1)依次为”A0"、"A0”、"A0”显示空格”31"、”31”显示数字11”3a"-显示冒号:"31”、"31"-显示数字11"3a”-显示冒号:”31”、"31"显示数字11”2e"显示小数点."31"、"31”-显示数字11"A0”、”A0"-显示空格 -”C0"(此时LCD_RS=0')-在LCD1602液晶屏第二行显示"A0”、”A0"、"A0”、”A0”、"A0"-显示空格"A0”、"A0"、"A0"、”A0”、”A0"、"A0”显示空格”A0"、”A0”、"A0"、”A0”-显示空格BTN0启动/停止开关消抖模块xiaodou:输入端口:clk:in std_logic;key_en:in std_logic;输出端口: en_out:out std_logic;仿真波形:接下图 波形分析: 当key_en第一次为1'时,en_out延迟一段时间后变为'1',并且en_out就此保持在高电平1'; 直到key_en第二次为'1时,en_out延迟一段时间后变为'0。 以后的状态与此类似。BTN1复位开关消抖模块fuweixiaodou:输入端口:clk :in std_logic;fuwei:in std_logic;输出端口:fuwei_out:out std_logic;仿真波形: 波形分析:当fuwei为'1时,fuwei_out延迟一段时间后变为1',然后fuwei_out又重新回到低电平0.四、 源程序(完整代码、含注释)顶层文件LIBRARY IEEE;USE IEEE.STD_LOGIC_1164。ALL;USE IEEE。STD_LOGIC_UNSIGNED.ALL;ENTITY clock ISPORT( reset1: