(原创声明:该文是作者的原创,面向对象是FPGA入门者,后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门,作者不光让大家知其然,还要让大家知其所以然!每个工程作者都搭建了全自动化的仿真环境,只需要双击top_tb.bat文件就可以完成整个的仿真(前提是安装了modelsim),降低了初学者的门槛。如需整个工程请留言(微信Blue23Light),不收任何费用,但是仅供参考,不建议大家获得资料后从事一些商业活动!)
前面通过计数器实现了UART单字节数据的发送了接收,上节课又学习了状态机,那现在实现多字节数据的通讯就相对简单了。首先把多字节的数据拆分成多个单字节的数据,然后通过UART的发送模块一个个发送即可;接收端把接收的单字节数据组合起来,就可以得到实际的数据。
思路很简单,但是实际工程应用中还要考虑更多的问题。最主要的就是如何保证数据的正确性。UART线上的数据一个个的接收下来,但是有效的数据从什么位置开始,有效数据的长度是多少,数据的正确性应该如何保证?这就要加一些冗余的信息,比如帧头,长度,校验,帧尾之类的。其中帧头是必须要加的,帧头就是一个定位,检测到帧头后面就可以正确采集数据了。
本节工程要求:系统时钟是100MHz,低电平复位,使用UART协议完成4byte数据的传输,为了保证数据传输的正确性,每帧数据添加帧头(5a),数据长度(4)和帧尾(a5)。UART的波特率是115200,有奇偶校验位,偶校验。
我们根据需求分析一下,由于UART单字节收发的模块设计都设计完毕了,那新的发送模块只需要把要发送的数据排好队,一个个往UART发送模块里面放即可,新的接收模块从UART接收模块里面收数,根据协议把有效的数据解析出来即可。
如下所示,一帧的数据由帧头,长度,数据1,数据2,数据3,数据4和帧尾组成,每个拆分的数据都是单字节。那我们可以设计发送状态机,发帧头->发长度->发数据1->发数据2->发数据3->发数据4->发帧尾即可,但是这样设计有个问题,如果数据不是4个字节而是100个字节,难道要写100个发送数据的状态机?这样既增加了代码量,又让设计的代码通用性降低!因为数据长度改变一次代码就要重新设计一次。
其实可以把4个发数据状态合并成发送数据的状态,在该状态里面设置一个计数器,发送一次计数一次,根据计数值跳出发送数据状态机,进入发送帧尾的状态机。所以发送的状态机应该如下所示。当又数据要发送的时候先进入发送帧头(HEAD)状态,帧头发送完毕后(tx_over拉高)进入发送数据长度(LEN)的状态,数据长度发送完毕后(tx_over拉高)进入数据发送(SEND)状态,然后进入数据发送等待状态(WAIT),如果一次数据发送完毕(tx_over拉高)判断已经发送数据的个数(send_cnt),如果有效数据没有发送完毕跳转到数据发送状态,如果有效数据发送完毕进入发送帧尾的状态(TAIL),帧尾发送完毕后(tx_over拉高)进入IDLE状态等待下一帧数据的发送。
接收状态机也是一样,当UART线上有数据的时候状态由IDLE跳转到帧头检测(CHK_HEAD)状态,在帧头接收完毕后(rx_over_dly),判读帧头是不是期望的帧头(chk_head_flag == 2'd1),如果是,就可以继续接收数据长度了,如果不是,那就回到IDLE状态继续等待接收。在数据长度检测(CHK_LEN)状态,在数据长度接收完毕后(rx_over_dly),判读长度是不是期望的长度(chk_head_flag == 2'd1),如果是,就可以继续接收数据了,如果不是,那就回到IDLE状态继续等待接收。经过了两轮的考验,终于可以接收数据了,也是将接收数据分为接收数据(RECV_DATE)和接收数据等待(RECV_WAIT)两个状态,如果接收的数据没有完成就会继续接收,等接收数据完成跳转到接收帧尾状态。在帧尾接收完毕后(rx_over_dly),判读帧尾是不是期望的帧头(chk_tail_flag == 2'd1),如果是,就可以跳转到END状态再跳转到IDLE状态,如果不是,那就直接回到IDLE状态等待接收。
有了上面的状态机,其实模块设计就很简单了,下面进行发送模块的讲解。通过参数传递的方式进行要发送数据的长度,帧头和帧尾的传递。
定义了相关的寄存器和状态机参数,本模块采用三段式的状态机设计方式。
第一段,用时序逻辑控制状态机的更新。
第二段,用组合逻辑控制状态机的跳转。
后面的都是第三段,主要控制数据传递给UART发送模块。首先是发送使能信号的产生,这儿之所以把发送数据分成SEND和WAIT两个状态就,就是为了方便tx_start信号的产生!
设置了发送数据的计数器send_cnt,在发送数据的状态下每发送一个数据增加一次,在IDLE状态清零,为下次传输做准备。4字节的数据通过移位的方式取出来要发送的数据。
下面是产生UART发送模块的数据tx_data,在不同的状态机下赋值即可,数据采用左移动的方式,所以每次取高8位即可。一帧数据发送完毕,产生send_done标志信号。
最后例化UART发送模块即可。
数据的接收模块类似,通过参数传递的方式进行要发送数据的长度,帧头和帧尾的传递。
定义了相关的寄存器和状态机参数,本模块采用三段式的状态机设计方式。
首先要时刻检测UART线上的变化,如果线上由空闲态(高电平)变成低电平,说明一次UART传输开始,检测到这个变化rx_signal_fedge,作为状态机跳转的依据。
第一段,用时序逻辑控制状态机的更新。
第二段,用组合逻辑控制状态机的跳转。
后面的都是第三段,主要控制从UART接收模块接收数据。从UART接收的帧头,数据长度,和帧尾只要有一个校验不过该帧的数据就不能使用。
使用计数器recv_cnt控制数据的接收,同时接收的数据右移动进行存储。这儿需要说明一下为什么会有一个END的状态机,主要是方便判读数据受否正确,状态机能运行到END状态说明帧头,数据长度和帧尾都是正确的,直接把数据锁存即可。
为了方便管理,新建了一个顶层文件uart_top,接口信号如下所示,该文件直接对新设计的发送和接收模块例化。
在仿真tb文件中,对uart_top文件进行例化和参数的传递,并产生4字节的随机数进行仿真,仿真结果如下所示,发送的数据和接收的数据是一致的,功能设计正确。
文章来源:https://www.toymoban.com/news/detail-757451.html
目前设计的工程再加上约束文件,编译后下载都FPGA内部是可以直接使用的!所以仅仅使用计数器和状态机模块,就可以完成大多数需求的设计!所以到现在为止,如果你能很快的手动写成这个工程的所有代码并且仿真通过,那你就入门FPGA了,而且达到一般FPGA开发者的水平!文章来源地址https://www.toymoban.com/news/detail-757451.html
到了这里,关于孩子都能学会的FPGA:第九课——多字节数据的发送和接收的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!