赞
踩
电子系统设计课程标志性内容的设计理解和综合运用,鼓励独立性设计和功能扩展的创新实践。
(1)采用6位共阳极数码管(SEGLED)来显示日期或者时间。
(2)显示器的驱动可采用“动态扫描驱动”,利用视觉残留效果实现连贯显示。
(3)键盘的按键数目有限,应采用“一键多用”的构思和设计,减少按键的数目。
(4)整体设计上考虑系统的结构简单﹑操作简便﹑布局美观﹑成本低廉。
(5)可以考虑使用小数点或其他提示标志表示闹钟设置状态。
2月另外计算;
4月﹑6月﹑9月﹑11 月为月小30天,其余为月大31天。
平年的2月为28天;
润年的2月为29天。
为了丰富产品功能、进一步锻炼自身的工程实践能力,本项目在课程要求的基础上,合理增加了两项外设:扬声器模块和红外遥控模块。
(1)扬声器模块本身无源,受变频方波驱动,用来播放闹钟音乐。
(2)红外遥控模块用于闹钟的远程控制,与按键的功能一致。本项目所使用遥控器含17个按键,方便进一步扩展功能。
图4.1实验使用的按键电路
REST为复位按键,按下时低电平复位。KEY0~KEY3为普通按键输入,外接上拉电阻,未按下时按下端口输出高电平,按下时输出低电平。按键作为最简单的输入设备,适合在需要给系统输入控制信号的场合使用。
按下key3,可实现功能模块的顺序切换,切换顺序如下:
……—>24小时制时钟—>12小时制时钟—>日历显示—>
闹钟设置—>电子秒表—>星期数显示—>24小时制时钟—>……
a)时钟显示:如图4.2所示:
图4.2 时钟显示
系统复位后,能够按照设定的初始时间进行走时,并用8段数码管显示。时、分、秒之间以小数点分隔。
b)时钟校准:
按key3,切换成下一模式。
a)日历显示
日历以“XX.XX.XX”的形式显示,如“23.07.14”,表示2023年7月14日。年、月、日以小数点相隔。
能够实现秒-分-时-日-月-年的进位。能自动识别大、小月份和闰年、平年,采取不同的“天->月”进位模式。
考虑到数码管只有六位,且实际用途是记录当下的日期,因此将年分的可设定范围设置为2000年-2099年。
b)日历校准
按key0,日增加1。
按key1,月增加1。
按key2,年增加1。
按key3,切换成下一功能。
a)LED显示
闹钟模块的LED以“XX.XX.XX”的形式显示,如“00.12.OF”,表示闹钟关闭,响铃时间设定为00时12分;“20.32.ON”,表示闹钟开启,响铃时间设定为20时32分。
b)闹钟设置
按key0,ON和OF切换。
按key1,分增加1。
按key2,时增加1。
按key3,切换成下一功能。
c)响铃
当时钟(24小时制)的时、分与闹钟设定响铃时间均一致时,蜂鸣器发出警报,持续约10s。同时,开发板的D6口输出变频方波,驱动扬声器(外设)播放一段音乐。
a)LED显示
秒表模块的LED以“XX.XX.XX”的形式显示,如“00.12.13”,表示0分钟12秒钟13*10毫秒。
b)按键设置
按key0,秒表归零。
按key1,秒表暂停/启动。
按key3,切换成下一模式。
a)LED显示
秒表模块的LED以“XX.XX.-X”的形式显示,如“12.11.-4”,表示特定年(依据日历模块)的12月11号对应星期四。
b)按键设置
按key0,月加1。
按key1,日加1。
按key3,切换成下一功能。
注:该模式的月、日和日历模式是同步调节的,始终保持一致。
图4.3 红外遥控
启用了1、2、3、4四个按钮。分别对应按键的key0,key1,key2,key3。
采用6位共阳极数码管来显示日期或者时间。显示器的驱动采用“动态扫描驱动”,各位数码管以极高的频率分时点亮,依靠人体视觉的暂留效果,实现了多位同时显示。
图4.4 数码管
数字编码表:
数码管:8段
led1: out std_logic_vector(7 downto 0);低电平有效
选通位:6位
s : out std_logic_vector(5 downto 0);低电平有效
采用有源蜂鸣器,本身自带振荡电路,采用直流供电即可发出固定频率的蜂鸣。
图4.5 独立按键模块
图4.6 时钟晶振电路50MHz
如图4.6所示为系统的时钟晶振电路,振荡频率为50MHz,为系统提供时间基准。对上升沿计数,50000000次为一秒。
图4.7 红外接头
图4.9 实体列表
对应实体: clkdiv
图4.10 分频器RTL图
原理:
已知系统时钟的固有频率为50Mhz,取以下四种计数值进行分频,得到周期为1s、1ms、140ms、0.01s的数字方波。其中,周期为1s的波用于时钟模块;周期为1s的波用于led动态显示、按键消抖等模块上;周期为140ms的波用于蜂鸣器模块和音乐播放模块;周期为0.01s的波用于秒表模块。
- signal timecnt:integer range 0 to 50000000;--1s
-
- signal timecnt2:integer range 0 to 50000;--1ms
-
- signal timecnt3:integer range 0 to 7000000;--140ms
-
- signal timecnt4:integer range 0 to 500000;--0.01s
对应实体:ledout
原理:
将所有的数码管的段选线并接在一起,用IO接口控制,6个数码管轮流显示相应的信息,一遍显示完毕,隔一段时间,又这样循环显示。从算法的角度,每个数码管隔一段时间才显示一次,但是由于人的视觉暂留效应,只要隔离时间足够短,循环的周期足够长,每秒达到24次以上,看起来数码管就一直稳定显示了,这就是动态显示原理。
动态显示时候需要注意闪烁的频率。如果每秒显示的次数少,频率低,则显示的信息是闪烁的,这时候应该增加显示频率。如果每个数码管在每秒钟显示的总时间太短,则显示的亮度低,显示的信息不清楚,这时候应该增加显示的时间。
代码思路:
1.设计一个6进制计数器,对应数码管的6个选通位。以1ms周期信号的上升沿进行控制:每次检测到上升沿,则计数值加一(计数值满则清零),同时更改数码管的选通位,如此循环。
2.应用case语句,在每个上升沿对输入cnt进行一次检测,依据输入设制八段数码管的选通,以6位数码管的第1位为例,具体代码如下。
- case cnt_one is
-
-
-
- when"0000"=>led1<="11000000";
-
-
-
- when"0001"=>led1<="11111001";
-
-
-
- when"0010"=>led1<="10100100";
-
-
-
- when"0011"=>led1<="10110000";
-
-
-
- when"0100"=>led1<="10011001";
-
-
-
- when"0101"=>led1<="10010010";
-
-
-
- when"0110"=>led1<="10000010";
-
-
-
- when"0111"=>led1<="11111000";
-
-
-
- when"1000"=>led1<="10000000";
-
-
-
- when"1001"=>led1<="10010000";
-
-
-
- when"1010"=>led1<="10001110";
-
-
-
- when"1011"=>led1<="11001000";
-
-
-
- when"1100"=>led1<="10111111";
-
-
-
- when others=>null;
-
-
-
- end case;
-
-
-
对应实体:key_xiaodou(板载按键)、red_key(红外遥控)
利用了计数器对按键进行消抖。定义一个变量count。
以周期1ms的上升沿检测,检测出键闭合,若count<10,则count执行一次累加。当count=9时,输出由0置1,即输出一次上升沿,表示“键按下一次”;当count=10时,若检测到键闭合,count不变,输出保持0。当检测到按键释放后,count由10开始递减,到0后保持不变。
对于红外信号的“消抖”,也采用了同样的原理。但由于后续逻辑控制的需要,在count由2减少至1时,也输出一个上升沿,表示“键释放一次”。即用户按下按键和松开按键,均输出一次上升沿。
图4.11 按键RTL图
按键检测程序:
- if clk'event and clk = '1' then
-
-
-
- if key_in = '0' then
-
-
-
- if count < 10
-
- then count := count + 1;
-
- else count := count;
-
- end if;
-
-
-
- if count = 9
-
- then key_out <= '1';
-
- else key_out <= '0';
-
- end if;
-
-
-
- else
-
-
-
- if count > 0
-
- then count := count - 1;
-
- else count := count;
-
- end if;
-
- end if;
-
- end if;
相关实体:
miao_biao --秒表模块
counter_60 --通用计数模块
counter_12h --时计数模块(12小时制)
counter_day --日计数模块
counter_month --月计数模块
counter_week --星期计算模块
a)通用计数模块 counter_60
counter_60是本次设计中采用最多的计数模块,通用于时钟模式、日历模式、闹钟模式,其RTL图如图4.12所示:
图4.12 计数器RTL图
端口介绍:
clk:上一级进位信号/基础时钟信号的输入,上升沿触发。
例如:分钟计时模块的clk是秒钟计时模块的进位输出。
key_add:直接进位指令,上升沿触发。作用是让c_out直接输出一个进位信号,相当于是下一级计数模块的“加一”指令。
例如:秒钟计时模块的key_add每触发一次,分钟计时就加一。
reset:复位指令。
top_ten/top_one:计数模块的计数上限,决定了计数模块的计数逻辑和进位逻辑。
c_out:进位信号,传入下一级计数器。
cnt_ten/cnt_one:三位二进制信号,输出当前计数值的十位/个位。
模块的具体代码如下(结构体部分):
- ARCHITECTURE behave OF counter_60 IS
-
- SIGNAL cnt_ten_buf : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";--计数值十位
-
- SIGNAL cnt_one_buf : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";--计数值个位
-
- signal count_en : std_logic;
-
- BEGIN
-
- c_out <= key_add OR count_en;
-
- PROCESS (clk,reset)
-
- BEGIN
-
- IF(reset='0')THEN--异步复位(zhiwei)
-
- cnt_ten_buf <= "0000";
-
- cnt_one_buf <= "0000";
-
- ELSIF (clk'EVENT AND clk = '1') THEN--正常计时
-
- IF (cnt_ten_buf = top_ten AND cnt_one_buf = top_one) THEN--59后变为00
- cnt_ten_buf <= "0000";
- cnt_one_buf <= "0000";
- count_en <= '1';
- ELSIF (cnt_ten_buf < top_ten and cnt_one_buf = "1001") THEN--个位为9,十位加1
- cnt_ten_buf <= cnt_ten_buf + "0001";
- cnt_one_buf <= "0000";
- count_en <= '0';
-
- ELSE--个位累加
- cnt_ten_buf <= cnt_ten_buf;
- cnt_one_buf <= cnt_one_buf + "0001";
- count_en <= '0';
- END IF;
- END IF;
- END PROCESS;
- cnt_ten <= cnt_ten_buf;--to计数值十位
- cnt_one <= cnt_one_buf;--to计数值个位
- END behave;
b)其它计数模块:
由于12小时制、日、月、星期的计数逻辑和进位逻辑比较特殊,所以无法用通用计数器实现,需要使用单独的计数器模块。
12小时制:特点在于小时位的计数逻辑存在“am”和“pm”的差别,am的计数范围是00-12,而pm则是01-11。因此,要定义一个标志信号:SIGNAL am_pm :std_logic。am_pm的逻辑值在0和1间切换,am_pm=0时对应am,反之对应pm。
日:特点在于下限为01且上限按月和年变化,需要增加输入端口,根据输入的月份和年份决定计数逻辑。
月:特点在于下限为01而非00。
星期:特点在于星期的复杂计算。“counter_week”严格来说不是计数模块,而是进行了一套复杂的数学运算和逻辑运算。
运算代码如下:
- if (m_buf=13 or m_buf=14) and y_buf=0 then
-
- week_buf<=((y_buf+99)+(y_buf+99)/4-2*y_hun_buf+2*m_buf+3*(m_buf+1)/5+d_buf+7)mod 7;
-
-
-
- elsif m_buf=13 or m_buf=14 then
-
- week_buf<=((y_buf-1)+(y_buf-1)/4-2*y_hun_buf+2*m_buf+3*(m_buf+1)/5+d_buf+6)mod 7;
-
-
-
- else
-
- week_buf<=( y_buf+y_buf/4-2*y_hun_buf+2*m_buf+3*(m_buf+1)/5+d_buf+6) mod 7;
-
-
-
- end if;
该运算逻辑的数学基础是蔡勒公式:
w=(y+y/4-2*h+2*m+3*(m+1)/5+d+6) mod 7;
其中,w表示星期,y表示年份的十位和个位,h表示年份的千位和百位,m表示月份,d表示日。w=0时,对应星期日。其余1-6对应星期一到星期六。当月份为1月或者2月时,应更改为前一年的13月和14月。
y的计算公式为:
y=a*10+b ,其中a为年份十位,b为年份个位。例如17年表示17=1*10+7。
对于一般的情况,前一年的年份为y-1。而对于2000年,则前一年的年份为y+99,且h改为19。
c)秒表模块
秒表模式与其它计数器相关模式不同。其它计数器相关模式由多个计数器实例级联而成,而秒表采用了单一的实例实现,集成度较高。RTL图如图4.13所示:
图4.13 秒表RTL图
clear:计时器清空信号。
clk :时钟信号,信号周期0.01s,上升沿触发。
reset:复位信号。
stop :计数开启/停止信号,电平触发。由于是电平触发,因此消抖模块的输出信号需要先经过一个T触发器,才能控制秒表模块。RTL图如图4.13所示:
图4.13 T触发器与秒表RTL图
运用if-elsif-else语句,确定了reset,clear,stop,clk这四种信号指令的优先级。
其中reset和clear的优先级最高,其次是stop,最后是clk。
百分之一秒级计数范围为00-99;秒级计数范围为00-59;分级计数范围为00-59。
RTL图:
图4.14按键总控模块RTL图
端口解释:
输入:
o_key0:按键0信号检测,上升沿触发。
o_key1: 按键1信号检测,电平触发。
o_key2: 按键2信号检测,电平触发。
o_key3: 按键3信号检测,电平触发。
输出:
key0_sec, key1_min, key2_hour:时钟的秒、分、时“加一”指令。
key0_day, key1_month, key2_year :日历的日、月、年“加一”指令。
model(2 downto 0):
模式选择信号,从“000”到“100”分别对应系统“24/12小时制时钟、日历、闹钟、秒表、星期”这五种模式,对于模式切换和按键复用起到关键的作用。
am_add_m, am_add_h, key_swith :闹钟的分加一、时加一和开/关指令。
key_clear,key_stop :运动秒表的清零和启动/停止指令。
程序设计思路:
a)由o_key3 信号控制模式的切换:定义一个范围为000-100的中间变量rest_count,对于的o_key3每个上升沿,rest_count计数一次。
b)由o_key0、o_key1、o_key2进行具体模式的控制:运用if-else语句,同时考虑按键输入o_key0、o_key1、o_key2和模式控制变量res_count,输出相应的控制信号。
示例:
- if (o_key1 = '1' and (reset_count = "000" or reset_count = "001" )) then key1_min<= '1';
-
- else key1_min<= '0';
-
- end if;
相关实体:
alarm_clock:内含闹钟的开关逻辑。输出端的flag的表示闹钟的开关情况,接入alarm_ring的使能端口。model_l&model_r有两种取值,分别对应了数码管的“0F”和“0N”。当swith信号触发时,flag翻转一次,model&model_r相应变化。其RTL图如图4.15所示:
图4.15 alarm_clockRTL图
alarm_ring:若使能端口显示闹钟处于“开”状态,则比对时钟的时、分与闹钟设置的时、分,若相同且时钟的秒处于0-10之间,则输出高电平。
MusicBox:通用型音乐播放模块。
如下图所示,模块内部是一个计数器,clk决定计数频率,selection决定了计数器的上限。计数器每达上限,则final翻转,形成了方波。因此改变selection可以更改输出方波final的频率。对于V2,其输入selection为一定值“1011”,控制final输出一个直流电平,该直流电平可驱动蜂鸣器工作。而对于U11,其输入selection范围为“0000”到“1010”,对应着11种不同频率的输出,可以驱动扬声器发出不同频率的声音。其RTL图如图4.16所示:
图4.16 音乐播放模块RTL图
voice_dlay和music_1:
voice_dlay的RTL图如图4.17所示,music_1的端口结构与之相同。
图4.16 voice_dlayRTL图
此两模块受周期为140ms的时钟信号控制,输出端连接MusicBox的selection输入。使能信号en来自alarm_ring,当输入为1时,时钟上升沿触发输出信号按程序设定的规律进行变化,从而控制MusicBox输出既定规律的方波,进而驱动扬声器发出特点的音乐。
参考文章:
红外遥控解码设计与验证VHDL_用vhdl红外发射接收电路代码-CSDN博客
相关实体:
图4.17 红外解码实体列表
红外遥控的通信原理[1]:
红外发射部分电路包括矩阵键盘,红外发光二极管,编码以及调制电路,这些都已经集成在红外遥控器上(遥控器示意图如下图所示)。接收部分包括光敏二极管,解调以及解码电路。在编写程序时,我们仅需要对其输出的信号进行解码操作。
NEC协议
HT6221为Holtek公司生产的一款基于NEC红外通信协议的遥控编码芯片,采用Pulse Position Modulation(PPM)进行编码。HT6221芯片的红外遥控发送一次数据的数据帧定义如下图所示:一帧数据:帧头,16位地址码,8位数据码,8位数据反码以及1bit结束位(可忽略)组成。
图4.18 数据帧定义
数据发送:
引导码由9ms高电平和4.5ms的低电平构成,代码一个数据帧的帧头;
地址码由16位地址构成,低8位在前,高8位在后(对于一个红外遥控器,地址为固定值)。所以NEC协议理论上能最多支持65536个不同的用户。
数据码由数据原码和数据反码构成(可以通过比较这两个8位数据检测数据接收是否正确)。所以理论上支持256种指令。
数据发送0/1:
数据发送1: 560μs高电平+1.69ms低电平
数据发送0: 560μs高电平+560μs低电平
图4.19数据编码发送波形
数据接收:
对于数据接收端,接收到信号之后再输出的波形和输入端发送的波形反相。因此对于FPGA中接收端输出的波形为: 9ms低+4.5ms高 + 0.56ms 低+ 1.69ms高(1)/ 0.56ms高(0)。本模块就是检测此波形然后输出数据(由于红外传感器的品质不同,因此本模块的检测时间为一个区间范围)
图4.20 数据接收波形
本模块只进行短按时数据波形设计。
状态机:
idle: 空闲态,当检测下降沿开始计数,转到wait9ms_low状态
wait9ms_low: 等待9ms低电平计数,当上升沿没到来的时候,计数器一直计数。当检测到上升沿时,如果9ms计时完成,将计数器使能无效(计数器清零),跳到wait4_5ms_high状态,否则说明接受错误,回到idle状态。
wait4_5ms_high: 等待4.5ms高电平计数。如果下降沿未到来,那么计数使能,一直计数等待下降沿的到来。当检测到下降沿,如果T4_5ms_ok=1,说明4.5ms计数完成,将计数器使能无效,跳转到data_get_56ms_low状态;如果检测到下降沿但是4.5ms计数未完成,说明接受错误,回到idle态。
data_get_56ms_low: 等待0.56ms低电平计数完成。 当未检测到上升沿,计数使能,一直计数,等待上升沿。 当检测到上升沿,并且0.56ms计时完成,将计数器使能无效,跳到data_get_01状态。;如果0.56ms计时没有完成,跳到idle态。
data_get_01: 等到1.69 ms或者0.56 ms高电平计数完成。 当没检测到下降沿,一直计时。检测到下降沿之后,如果还没有接收到32位数据(地址+数据+反码),并且0.56ms/1.69ms 高电平接收完成,回到data_get_56ms_low状态继续检测下一个数据。 当检测到下降沿,但是0.56/1.69ms 计数都未完成,或者当32位数据接收完成,回到idle态。
图4.21H6221红外遥控器接收状态图
当timeout=0的时候才能进入状态机,当timeout=1意味着计时器超出10ms了,此时将state置为idle并且计数器使能无效。
一帧数据传输完成标志data_get_done:
由于每个传输的数据0/1都需要在下降沿才能判断是0/1,所以对于最后一位数据,在下降沿拉低后0.56ms之后信号又会重新拉高,然后等待下一次9ms的拉低(红外接收器输出波形iIR默认高电平)。
32个数据有32个下降沿,33个上升沿(最后的拉高),因此当检测到第33个上升沿的时候,表明数据接收完成。在最后data_get_01状态检测到下降沿之后将数据赋给寄存器,最后一个上升沿的时候将寄存器的数据输出。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。