串口通信--明德扬至简设计案例与应用FPGA
发布时间:2018-11-13 10:36
发布者:luckyb1
1 项目背景 技术交流群 :544453837 在使用教学板的串口前,需要安装CH340的驱动程序。下载后直接解压安装就可以了。 当用USB线接上电脑和教学板,并且教学板上电后,打开电脑的“设备管理器”,将会看到如下显示。当出现该显示时,表示驱程安装成功并且已经被电脑正确地识别。 我们可以从“设备管理器”中查看串口号,如下图所示。图中表示该串口号为XX。我们可以修改串口号,方法是:XXXXXX。 串口:可以选择串口号,支持串口号1~4。如果连接的串口号不在此范围,则需要从设备管理器中修改串口号,详细见本章前面的描述。 波特率:选择串口的波特率,支持9600、19200、38400、57600、115200。该选项影响了每一位码元占用的时间。 校验位:可选择没有检验位、奇校验和偶校验。 数据位:可以设置数据位的位数,可选择4~8位的数据拉。 停止位:可以设置停止位的时间长度。有1位、1.5位和2位可供选择。 打开/关闭串口:用来打开和关闭串口。打开软件时,串口默认是关闭状态。注意,一定要设置好参数后,才能打开串口;一定要关闭串口后,才能关掉教学板电源和拨掉USB线。 十六进制显示:本软件支持ASCII显示和十六进制显示。勾选后,用十六进制显示。例如FPGA发送8’b00110001,本软件收到后会显示31。如果不勾选,则是用ASCII码显示。下图就是ASCII表。FPGA发送8’b00110001,即下表中十六进制的31,它所对应的图形为1,所以软件只会显示1。假设FPGA发送的是8’h00100011,即下表中十六进制的23,它所对应的是图形是#,所示软件会显示#。 十六进制发送:本软件支持ASCII发送和十六进制发送。勾选后,用十六进制发送。例如填写“31”,按手动发送,那么FPGA收到的值是8’b00110001。如果不勾选,则是用ASCII码发送。例如填写“31”,按下手动发送,软件将首先发送ASCII码“3”所对应的十六进制值8’h33,再发送ASCII码“1”所对应的十六进制值8’h31。也就是FPGA将收到两个字节数据:8’h33和8’h31。 2 设计目标 上板效果图如下图所示 3 设计实现3.1 顶层信号 综上所述,我们这个工程需要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的代码。 中间信号,trigger连到触发器的信号输入端D,触发器的输出器连的是tri_ff0。将trigger取反,与tri_ff0相与,就得到信号neg_edge,如果neg_edge=1就表示检测到trigger的下降沿。将tri_ff0取反,与trigger相与,就得到信号pos_edge,如果pos_edge=1,就表示检测到trigger的上升沿。 我们来讲解这个原理,画出信号的波形图。 Tri_ff0是触发器的输出,因此tri_ff0的信号与trigger信号相似,只是相差一个时钟周期。我们也可以这样理解:每个时钟上升沿看到的tri_ff0的值,其实就是triffer信号上一个时钟看到的值,也就是tri_ff0是trigg 3.2.2 异步信号同步化 。 这样,flag_add变1的条件就变成:rx_uart_ff1==0&& rx_uart_ff2==1。 Flag_add变0的条件,可以完成收完9比特数据就变0,不用再计数了。所以变0条件:end_cnt1。 综上所述,可以写出flag_add的代码。 设计下data信号,该信号的值来自于图中第2~第9比特的值。第2比特的值赋给data[0],第3比特的值赋给data[1],以此类推,第9比特的值赋给data[7]。 由于每一个比特都持续5208个时钟周期,我们必须选定一个时刻,将值赋给data。 首先,不能在end_cnt0的时候赋值,如上图的点。因为我们这里的5208个时钟周期是理想、估算的数值,实际上是非常有可能有偏差的。如果我们在end_cnt0的时候取值,就有可能采错。 最保险的做法是在中间点取值。这样,即使有比较多的偏差,都不会影响到采样的正确性。 综上所述,我们在cnt0数到一半时采到当前rx_uart的值赋给dout,其中第2比特赋给led[0],第3比特赋给led[1],以此类推,第9比特赋给led[7]。 进一步用信号表示,可翻译成:数到add_cnt0 && cnt0==5208/2 -1时,如果cnt1==1,则将rx_uart_ff1赋给led[0]。如果cnt1==2,则将rx_uart_ff1赋给led[1],以此类推,如果cnt1==8,将rx_uart_ff1赋给led[7]。 那么直接翻译成代码。 上面代码可优化,简写成如下: 通常我们设计时,首先是想到实现功能,所以会先写出前面代码。在功能实现的前提下,再考虑有没有优化空间,从而写出后面代码。好代码都是一步步优化出来的。 注意,上面代码,我们采集的是rx_uart_ff1而不是rx_uart信号。这是因为rx_uart是异步信号,我们只能用同步化后的信号,否则会引起亚稳态。所以只能是rx_uart_ff1。 至此,主体程序已经完成。接下来是将module补充完整。 3.3 信号定义 cnt0是用always产生的信号,因此类型为reg。cnt0计数的最大值为5208,需要用13根线表示,即位宽是13位。因此代码如下: add_cnt0和end_cnt0都是用assign方式设计的,因此类型为wire。并且其值是0或者1,1个线表示即可。因此代码如下: cnt1是用always产生的信号,因此类型为reg。cnt1计数的最大值为9,需要用4根线表示,即位宽是4位。因此代码如下: add_cnt1和end_cnt1都是用assign方式设计的,因此类型为wire。并且其值是0或者1,1根线表示即可。因此代码如下: flag_add是用always方式设计的,因此类型为reg。并且其值是0或者1,1根线表示即可。因此代码如下: rx_uart_ff0、rx_uart_ff1和rx_uart_ff2是用always方式设计的,因此类型为reg。并且其值是0或1,需要1根线表示即可。因此代码如下: 4 综合工程和上板4.1 新建工程 1.首先在d盘中创建名为“uart”的工程文件夹,将写的代码命名为“uart.v”,顶层模块名为“uart”。 2. 然后打开Quartus ,点击File下拉列表中的New Project Wzard...新建工程选项。 3.在出现的界面中直接点击最下方的“Next”。 4.之后出现的是工程文件夹、工程名、顶层模块名设置界面。按照之前的命名进行填写,第一栏选择工程文件夹“uart”,第二栏选择工程文件“uart.v”,最后一栏选择顶层模块名“uart”,然后点击”Next”,再出现的界面选择empty project。 6. 器件型号选择界面。在“Device family”处选择Cyclone E,在“Available devices”处选择EP4CE15F23C8,然后点击“Next”。 7. EDA工具界面。该页面用默认的就行,直接点击最下方“Next”。 8.之后出现的界面是我们前面的设置的总结,确认没有错误后点击“Finish” 4.2 综合 1.新建工程步骤完成后,就会出现以下界面。在“Project Navigator”下选中要编译的文件,点击上方工具栏中“Start Compilation”编译按钮(蓝色三角形) 2.编译成功后会出现以下界面,点击“OK”。 4.3 配置管脚 在菜单栏中,选中Assignments,然后选择Pin Planner,就会弹出配置管脚的窗口。 在配置窗口最下方中的location一列,参考下表中最右两列配置好FPGA管脚。 配置完成后,关闭Pin Planner,软件自动会保存管脚配置信息。 4.4 再次综合 在菜单栏中,选中Processing,然后选择Start Compilation,再次对整个工程进行编译和综合。 出现上面的界面,就说明编译综合成功。 4.5 连接开发板 图中,下载器接入电脑USB接口,电源接入电源,uart线连接电脑USB,然后摁下电源开关,看到开发板灯亮。 4.6 上板 1.双击Tasks一栏中”Program Device” 2.会出现如下界面,点击add file添加.sof文件,在右侧点击“Start”,会在上方的“Progress”处显示进度。 3.进度条中提示成功后,即可在显示器上观察到相应的现象。 4.7 串口调试 1,安装串口调试工具。 2. 开发板连接完成,打开电源后,在设备管理器中查看串口名。填写图片摘要(选填) 3,打开串口调试助手,在串口处选择之前查看的串口名,波特率、校验位、数据位、停止位根据之前给出的数据进行填写,发送和接收都选择十六进制。 4,上板成功之后,在发送数据栏输入相应的数据(将8个LED灯对应的8位二进制数转化为十六进制),然后发送,即可在开发板上看到相应的现象。 |
网友评论