现在的位置: 首页 > 综合 > 正文

【连载】【FPGA黑金开发板】Verilog HDL那些事儿–蜂鸣器封装(十七)

2013年01月31日 ⁄ 综合 ⁄ 共 3882字 ⁄ 字号 评论关闭

声明:本文为原创作品,版权归akuei2及黑金动力社区(http://www.heijin.org)共同所有,如需转载,请注明出处http://www.cnblogs.com/kingst/

2


5.3 实验十六:蜂鸣器封装

当读者看到这章,不要笑出来,笔者连蜂鸣器也不放过,蜂鸣器也逃不过封装的命运。

在前面(5.15.2)的试验中,无论是独立键盘,还是数码管,它们都有自己的考虑,如:独立按键必须消抖,数码管有扫描的规则 ...

那么蜂鸣器要干什么!它这家伙那么单调,只要拉低电平,这家伙就会被驱动了。既然蜂鸣器那么单调,我们就要它不单调,那怎么不单调法呢?很简单,就是在蜂鸣器的封装中,为它加入“功能”。蜂鸣器应该加入什么功能?就加入产生S摩斯码和O模式码的功能吧。

我们利用4.3章的“命令式仿顺序操作”的方法来建立它的功能模块。(请稍微复习一下)

clip_image002

如上图。等等!这就不是一个模块吗!?封装 等于 建立模块!?那么问题来了“模块”和“接口”本质上到底有什么的不同呢?在这里我们需要重新为“接口”加入一个“新的定义”。 

5.15.2章中,我们定义了“接口”是“最后的工程”,不错“封装”却是针对某个资源的最后建模工程。但是读者有没有发现,起始在5.1 5.2 章还包含着一个信息?

那就是“接口都是独立性”这一个事实。

如果从另一个角度去理解“接口”,你可以把它看成是一个“部门”这样的存在。在现实中我们知道“部门和部门之间”都市独立性,而且每一个部门都是有内部的操作。那么如果要把这个观点放入“蜂鸣器的封装”里边,又应该如何实现呢?

clip_image004

在这里我们就需要用到“FIFO”。顾名思义 FIFO 就是“先入先读”的意思。但是在宏观来看FIFO是双向口的RAMFIFO可分为两方,“左方是写”和“右方是读”。然后经过一些内部加工,读和写可以在同时发生。

FIFO的被需要时绝对有目的的。我们重新复习一下仿顺序操作的概念。当某一个下层被使能时(Start_Sig 等于1),上一层模块就必须等待下层模块直到完成工作,才能执行下一个操作。为了避免上述的内容,我们必须借用FIFO的力量。

我们可以尝试这样想“如果我把操作信息全部缓冲到FIFO里的话 ...,那么上一层的模块可以将全部操作信息缓冲到 FIFO里面,就可以摆脱“反馈信息”的“束缚”。这话怎么讲呢?每当下一层模块完成工作以后,可以直接从FIFO里面读取操作信息,而不必依赖上一层模块所下达的操作指令。

clip_image006

如果以“图形”来表示,那么结果会是如图上。上图大致的操作如下:

(一)首先上一层模块可以往FIFO里边写入大量的操作信息。然后上一层模块可以执行其他的操作,而不必在乎“反馈信息”。

(二)FIFO里面存在信息,控制模块会从FIFO里面读取信息。信息被过滤以后,转换为执行命令,故启动功能模块。

(三)功能模很快便开始工作,直到工作结束,并且反馈完成信息给控制模块。

(四)当控制模块接收到从功能模块反馈回来的完成信息,会再度从FIFO读取信息,重复上述一样的动作,直到FIFO里面的信息全部读取完毕。

估计笔者们都对FIFO不怎么熟悉吧(笔者也是),那么我们就稍微的来理解一下FIFO的时序和操作:

 

clip_image008

(时间上升沿有效)

 

上图是8个深度的FIFO。在FIFO初始化的时候 wr_en_a_0拉高,然而Wr_data_a_0 wr_level_0 都呈现 32 的信息 。但是在第二个时钟的时候, 信息1就被存入深度1。第三个时钟信息2存入深度2。直到第七个时钟,当写入信息6到深度6的时候,FIFO的状态反应出“”,故此拉高 wr_full_0 信号,在同一个时间 we_en_a_0 被拉低。在第九个时钟 wr_en_a0 拉高,信息8被写入深度7。由于FIFO出现饱和状态,所以拉高 wr_full_0信号。

 

在上述的内容中,我们发现在初始化的时候FIFO的深度0是用来预备初始化信息。然而在第九个时钟的时候,基本上 FIFO已经饱和了。因此FIFO没有理由再往里面写入信息了,多以拉高 wr_en_a0 也没有任何意义。

// wr_en 写使能, wr_data 写数据, wr_full 写饱和。

 

下图是FIFO读数据的时序图:

 

clip_image010

(时间上升沿有效)

 

在初始化的时候 rd_data_b_0 呈现初始化信息“32”。在第二个时间中,从FIFO的深度7读出信息1。在第三个时间中,从深度6读出信息2。直到第八个时间从深度1读出信息8以后,FIFO反应出“FIFO没有信息了”,所以就拉高 rd_empty_0 信号。

// rd_en 读使能, rd_data 读数据, rd_empty 读空置。

 

上述FIFO读写内容的大致“图形”如下:

 

clip_image012

 

在时序图上分析FIFO看似很轻松,实际上FIFO的调用也挺别扭的。信息会发生“被卡现象”。

 

clip_image014

上图 beep_interface.v 组合模块中:

(一)FIFO拥有16个深度。

(二)蜂鸣器控制模块的主要功能是从FIFO读入一个信息经FIFO_Read_Data, 蜂鸣器控制模块,根据从FIFO读取的信息来使能“蜂鸣器功能模块”;

 

在这一章的实验中“蜂鸣器功能模块”只包含两个功能:就是产生S摩斯码和O摩斯码。

所以 Command_Sig 或者 Function_Start_Sig 都是2个位宽。

Function_Start_Sig = 2'b10

产生S摩斯码

Function_Start_Sig = 2'b01

产生O模式吗

整个 beep_interface.v 说穿了就是“如何调用FIFO”而已,  FIFO 的信号有

(一)Write_Req_Sig 等价于 write_en ;

(二)Read_Req_Sig 等价于 read_en ;

(三)Full_Sig 等价于 write_full ;

(四)Empty_SIg 等价于 read_empty ;

(五)FIFO_Write_Data 等价于 write_data ;

(六)FIFO_Read_Data 等价于 read_data ;

那么这个 beep_interface.v 具体是如何运作还是直接看代码好。

beep_function_module.v

clip_image016

clip_image018

 

clip_image019

5行中的[1:0]Start_Sig 表示了该功能模块包含了两个功能。11~40行是1ms定时器到1秒计数器。57~74行是S摩斯码的产生,反之75~92行是O摩斯码的产生。在97行,由于在实际资源,蜂鸣器的控制只挂着PNP三极管,rPin_Out的输出必须取反。

 

beep_control_module.v

clip_image021

clip_image022

17~31行是“加码操作”的部分,23行会判断经FIFO_Read_Data 读来的信息,将它加码为特定的命令。如通码S1B”加码为命令“2'b10”(25行),通码O44”加码为命令“2'b01”(26行)。然后将转换后的命令,暂存在rCmd寄存器。但是前提必须在步骤i等于1的时候才能执行(22行),和步骤i等于5的时候清零rCmd寄存器。为什么呢?

35~70行是该控制模块的核心部分。在50行,步骤0先判断FIFO是否为空,如果FIFO不是为空 Empty_Sig 信号就被拉低。如果FIFO不为空 if 条件成立,i递增以示下一步步骤。

52~56行是读FIFO的操作,在这里我先简单的介绍一下。在前面的 FIFO 时序图中,当FIFO为读状态,如果  Read_Reg_Sig ( read_en ) 不拉高,就无法把数据读出来。FIFO读数据是根据每一个时钟的上升沿,如果 Read_Reg_Sig read_en )拉高,那么在这一个上升沿中,数据就会被读出来。换句话说,我们可以利用 Read_Reg_Sig 来充当读取数据的“锁匙”。

1begin isRead <= 1'b1; i <= i + 1'b1; end

2begin isRead <= 1'b0; i <= i + 1'b1; end

如上的步骤12表示从FIFO读取“一个深度的数据”。

52~56行正是如上的操作。在53行将 isRead 拉高,从FIFO读取数据。在读入FIFO数据的一瞬间,“加码操作”发生了(22行),“加码成功的数据”会暂存在rCmd寄存器里。然后在56行将 isRead 拉低,为此我们已经完成“从FIFO读取数据,然后加码成功”。

在步骤358行先判断 rCmd的值是否为8'h00,如果 rCmd的我值为 8'h00表示这不是我们要的命令,然后步骤i清理,返回开始。如果 rCmd的值不是 8'h00 的话,i递增以示下一步步骤。

在步骤464行是使能 beep_function_module.v 的工作。isStart是作为 Function_Start_Sig 的驱动(75行)。加入我从FIFO读取的信息是 8'h1B,那么它会被加码为 2'b10 ,亦即执行“S摩斯码产生”的命令。接下来的工作就和“仿顺序操作一样”,直到下一层模块反馈完成信号,isStart会被清理 (63)i递增以示下一个步骤。

步骤566~67行)多出来是用来清零rCmd寄存器的(30行)。如果不清零 rCmd寄存器后果会很麻烦。最后i清零,以示返回开始。

beep_interface.v

clip_image024

clip_image025

beep_interface.v 组合模块的结果和“图形”一样。自己看着办吧。

实验十六说明:

实验十六的重点,就是“如何对FIFO读取”而已。其余的建模部分都是以往实验的复习。

完成扩展图:

clip_image027

实验十六结论:

在某种程度来说,实验十六的蜂鸣器接口,标准操作信息是“键盘通码”。

实验十六演示:

clip_image002

 

在上图的组合模块中,控制模块对蜂鸣器接口写入“8'h1B, 8'h44, 8'h1B”这三个信息,然后就停止操作。接着,蜂鸣器接口却会发出“

抱歉!评论已关闭.