在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
查看: 1074|回复: 2

[原创] 孩子都能学会的FPGA:第五课——用计数器实现UART协议的发送模块

[复制链接]
发表于 2023-11-20 16:24:45 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
本帖最后由 chdaj58 于 2023-11-20 16:24 编辑

(原创声明:该文是作者的原创,面向对象是FPGA入门者,后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门作者不光让大家知其然,还要让大家知其所以然!每个工程作者都搭建了全自动化的仿真环境,只需要双击top_tb.bat文件就可以完成整个的仿真(前提是安装了modelsim),降低了初学者的门槛。如果需要整个工程请加微信15092150280索要即可,不收任何费用,但是仅供参考,不建议大家获得资料后从事一些商业活动!

到目前为止,笔者讲的最多的模块就是计数器,读者可能都听的厌烦了。笔者之所以一直强调计数器,就是因为计数器是FPGA开发中的最基本的模块之一,能真正掌握了这个模块,并能把这个模块如乐高积木一样进行简单的拼搭,就可以实现复杂的功能。下面我们只是用两个计数器来实现uart的单byte发送。

讲述设计之前,先介绍一下uart协议。通用异步收发器(Universal Asynchronous Receiver/Transmitter),uart是一种通用串行数据总线,用于异步通信,该总线双向通信,可以实现全双工的发送和接收。uart在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。


v2-76b44ac51bb7ae1ae5284f41120b8690_720w.png


由于uart采用异步通信方式,即发送端和接收端之间通过数据线进行数据传输,没有同步时钟。在异步通信中,发送端和接收端不需要同时处于激活状态,而是通过起始位停止位来标识数据帧的开始和结束。下面具体的解释uart协议的几个概念。

空闲位:uart的发送和接收线在空闲状态下是逻辑1,高电平

起始位:线上发出一个逻辑0,即低电平的信号,表示数据传输的开始;

数据位:紧接着起始位之后。 可以是5~8逻辑0或1 ,构成一个字符。从最低位开始传送,靠波特率进行定位。

奇偶校验位:在数据位加后,使得逻辑1的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。奇偶校验位可有可无。

停止位:它是一次传输的结束标志。可以是1位、1.5位、2位逻辑1,即高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

波特率:是控制数据传输速率的,表示每秒钟传送的位数。常用的波特率有9600,115200等等。

本节FPGA工程的要求是:系统时钟是100MHz,低电平复位,实现uart发送,其中波特兰是115200,8个数据位,没有奇偶校验位,1个停止位。

分析一下需求,一次uart的传输是1个起始位,8个数据位和1个终止位,即一次传输需要10位。波特率是115200,系统时钟是100MHz,那传输1位需要的计数值是100_000_000/115200≈868。所以uart的发送设计就很明确了,需要两个计数器,一个计数器用于控制发送1位数据,计数868次;一个计数器用于控制发送10位数据,计数10次。

如下所示,设置了一个传输标志寄存器send_domain,当有新的数据要传输时拉高,当一次10位的传输完成后拉低;byte_cnt计数器用于计数10位数据的传输,非传输状态下清理即可;bandrate_cnt计数器用于计数1位数据传输的计数值,从0计数到867。


v2-ecf20d84aa05fff7762275b3f6407332_720w.png


下面分析uart_byte_tx模块。输入信号clk和rst_n是时钟和复位。输入信号din_en是输入有效指示信号,当din_en信号拉高的时候表明输入的数据信号din有效,即要开始一次uart的发送。输入信号tx_signal即uart的输出线,输出tx_over信号用于指示一次uart传输完成。


v2-6f0aee49d425b65c04a5270a94416812_720w.png

然后定义了一次传输位数的计数值,一位传输的计数值。定义了wire类型的信号one_byte_cnt_done,用于指示1位传输完毕,拉高一个100MHz的时钟周期,用于计数器bandrate_cnt的清零;定义了wire类型的信号all_byte_cnt_done,用于指示1次uart传输完毕,用于计数器byte_cnt的清零,会拉高1位的时间。


v2-67d11c03c5248026e9b3a1e0dccbbca5_720w.png

传输标志寄存器send_domain,有新的数据要发送时拉高,一次uart传输完成拉低,有这个信号的好处是其它的控制信号都在send_domain高电平的时候变化,在send_domain低电平的时候清零或者默认值即可。


v2-9ac0917e09c0a7bd57177ad18f985c9a_720w.png

下面是两个计数器的实现,都是在send_domain拉高的时候变化,其中byte_cnt是在bandrate_cnt完成一次计数后加1,其它的清零和计数条件都很明显。


v2-8a0ed038e10a8333f3bdd89b5db4c732_720w.png

计数器都是设计好了,最后把要发送的数据在send_domain拉高的时候发出去即可,这而其实也可以用if/else if语句来实现,甚至用流水灯的移位也可以实现,只不过用case语句更直观明了而已,这儿的设计是因人而异的。


v2-f709cd0e06b0cca8bef3e0fd90838a76_720w.png

最后设置一次uart发送完成标志信号即可。


v2-f9b387d1131aee6f27066a853e5fb189_720w.png

仿真是产生8bit的随机数,完成一次uart的发送就会产生一个新的随机数。仿真结果如下所示,以仿真图中的要发送的数据00100100为例,数据先发低位,加上起始位和终止位,tx_signal要发送的数据应该是0_00100100_1,仿真图中的tx_signal信号确实符合要求。


v2-f8b23c0fcdb5463f78440ab6c3c5a908_720w.png

通过上面的讲解,是不是只需要两个简单的计数器就实现了uart的发送?所以FPGA的开发没有那么困难,把基本的模块合理的组合一下,这种功能就实现了。既然uart的发送设计如此简单,那uart的接收也应该不难,也是仅仅需要两个计数器即可,我们下节课来实现。

发表于 2024-6-25 13:37:56 | 显示全部楼层
感谢分享
发表于 2024-8-7 15:26:12 | 显示全部楼层
感谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条


小黑屋| 手机版| 关于我们| 联系我们| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-12-27 05:28 , Processed in 0.017297 second(s), 8 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表