2 设计目标
(源码下载 技术交流群:544453837)
用户设置串口调试助手的参数:波特率为9600;数据位为8位;无奇偶校验位;停止位为2比特;接收和发送都是16进制数。
用户通过串口调试助手发送一个8位数据data,该8位数据data用于控制开发板上的8个LED灯。其中data[0]~data[7]分别控制LED0~LED7。当对应的数据位为0时,该LED灯保持为亮,如果对应的数据为1时,该LED保持为灭。例如,用记发送数据data=8’b10110010,发送后,开发板上的LED1、LED4、LED5和LED7保持为灭,其他保持为亮。
上板效果图如下图所示
3 设计实现
3.1 顶层信号
新建目录:D:\mdy_book\uart。在该目录中,新建一个名为uart.v的文件,并用GVIM打开,开始编写代码。
我们分析一下功能。串口调试助手发数据给FPGA,站在FPGA的角度来看,就是CH340通过控制RX信号,让RX信号根据串口时序变化,从而告知FPGA数据信号。那么FPGA工程必须有一个接口信号,命名为rx_uart。
FPGA要控制8个LED灯的亮灭,那就要8个信号,或者一个8比特的信号,命令为led。
下面表格表示了硬件电路图的连接关系。
综上所述,我们这个工程需要4个信号,时钟clk,复位rst_n,串口输入信号rx_uart和输出控制LED灯的8位信号led。
将module的名称定义为uart。并且我们已经知道该模块有四个信号:clk、rst_n、rx_uart和dout。为此,代码如下:
其中clk、rst_n和rx_uart是输入信号,dout是输出信号,其中clk、rst_n、rx_uart的值是0或者1,一根线即可,dout为8位位宽的,根据这些信息,我们补充输入输出端口定义。代码如下:
3.2 信号设计
我们先分析要实现的功能,led信号控制了8个LED灯的亮灭,而具体哪些灯亮哪些灯灭,是取决于串口过来的数据。那串口过来的数据,是如何告知FPGA,并与led对应起来呢?我们可以看一下串口过来的时序。
上面波形是CH340控制的信号rx_uart。如果CH340要发送一个8位数据data,它首先会将信号rx_uart变0并持续一段时间(起启位),然后发送data[0]并持续一段时间,然后发送data[1]并持续一段时间,以此类推,发送data[7]并持续一段时间,最后CH340将rx_uart为1并持续一段时间(结束位)。这样CH340就完成了数据的发送。
例如,CH340要发送的数据data=8’h00110001,则rx_uart的波形如下。
再考虑一下时间信息。由于波特率是9600,那么每位持续的时间是1s/9600=104166ns。将时间信息补上波形。
本开发板的晶振时钟是50Mz,104166ns/20ns 约等于5208个时钟周期。也就是说上面波形中,每个比特的持续时间约等于5208个时钟周期。需要注意的是,5208只是一个估计的大概数字,实际情况会有偏差。同时,我们还有计数这是第几个比特,用于让我们判断是开始位、数据位和停止位等。
可以看出,我们需要2个计数器,1个计数器用于计算1比特的位宽长度:5208个时钟周期,命名为cnt0;另一个用于计算有多少个比特,命名为cnt1。
很明显cnt0每次都是数5208个,但cnt0的加1条件需要仔细分析。我们很清楚cnt0的加1区域是下面的灰度地方。
目前没有任何信号可以区分出此区域。参考至简设计法案例2的方法,设计一个信号flag_add,当其为1表示上述灰度区域,即cnt0的加1区域。
有了flag_add,我们就很明确,cnt0的加1条件是flag_add==1,数到5208下就结束。为此,可以写出cnt0的代码。
接下来思考cnt1。Cnt1用于表示数到第几比特,每间隔一个比特时间,cnt1就会加1,也就是说,每当end_cnt0时,cnt1就会加1。所以cnt1的加1条件是:end_cnt0。而cnt1一共要数9个。故可以写出cnt1的代码。
我们增加了辅导信号flag_add,现在我们来思考如何设计这个flag_add。Flag_add有2个变化点:变0和变1。Flag_add什么时候会变1呢?我们从功能上来理解一下。上电后,PC如果没有发送任何数据,rx_uart是一直保持为1。此时cnt0和cnt1也无须计数,也就是flag_add也一直保持为0。当PC要发送数据了,rx_uart就按串口时序变化,首先会发送一个开始位,即rx_uart由1变成0。FPGA看到rx_uart变1变成0后,就明白PC有数据要过来了,并且现在是开始位,此时cnt0和cnt1要计数了,也就是flag_add要变成1了。
从功能上理解,很容易就知道当原来flag_add为0,此时收到rx_uart由1变0(下降沿)时,flag_add就变成1。关键的是,我们如何知道rx_uart变1变成0呢?
评论
查看更多