实验十四 UART串行通信 14.1 UART串口接收实验
一、实验设计目标
(1)在FPGA中实现串口协议,通过Anlogic_FPGA开发板上的“UART2USB”口接收从计算机发来的数据。
二、实验设计思路
UART串口是一种类似于USB、VGA的接口,有固定的引脚和通信协议。使用FPGA实现串口通信,可分为“计算机发送数据给FPGA”和“FPGA发送数据给计算机”两部分。本节为串口接收实验,使用FPGA接收从计算机发来的数据。
进行串口接收实验首先需要了解串口的接收时序,图4.1为接收一帧数据时的简单示意图。串口接收只使用一条数据线RX,特点如下:
图4.1 串口接收时序示意图
(1)当RX产生了一个下降沿后才开始一帧数据的接收,接收到的第一位为开始位。
(2)一帧周期内有11个时钟,第一个时钟是开始位,2~9个时钟为数据位,并且数据是从低位到高位的接收的。
(3)串口的接收时钟频率取决于它的波特率,常用的波特率是有几个固定值的。本实验的波特率选用9600bps,表明1秒内传送9600位数据,则一位数据的周期为:
(4.1)
可以看出,进行串口接收实验的关键在于准确读取RX上的数据,需做到以下两点:①判断什么时候RX开始接收一帧数据,即判断开始位;②判断什么时候读取D0~D7上的数据,即判断数据位。
为实现第①点,借鉴实验一PWM实验中的“消抖程序”的思想检测RX线上的信号,在RX信号产生了一个下降沿后才启动一帧数据的接收;并且,为保证每一次检测到的都是开始位,必须确定在一次接收中经过了11个时钟后才开始下一帧数据的接收,这可以通过编程实现。
对于第②点,为保证数据的准确,应在数据位的正中间读取数据。图4.2为读取数据的简单示意图,当BPS_CLK信号为高时,读取RX线上的数据,BPS_CLK信号的高电平出现的频率应为9600Hz。本实验首先将50MHz时钟通过计数器分频到500KHz,然后设计一个计数器Count_BPS,将500KHz的系统基准时钟进行分频,分频数为:
500000/9600 = 52 (4.2)
因此,当Count_BPS计数到26时,令BPS_CLK信号为高电平,其他计数值置低,这样使用500KHz时钟在BPS_CLK的高电平时读取数据,就可以在每一位数据的正中间读取数据,确保数据已完整建立。
图4.2 数据读取示意图
三、功能模块图与输入输出引脚说明
图4.3是本实验设计的串口接收系统的示意图,包含开始位检测模块U1、波特率控制模块U2、接收控制模块U3和LED显示模块U4。
图4.3 串口接收系统示意图
开始位检测模块用于检测一帧数据的开始位,功能如前所述。RX_In与串口的RX线相连,在没有数据传输时,RX线上为高电平;neg_sig为“下降沿标志位”,当检测到RX_In的下降沿时,neg_sig信号被置为1,其他时刻为0。
波特率控制模块内包含一个计数器Count_BPS,功能如前文所述。BPS_CLK为使能时钟信号,控制何时读取数据。Count_Sig为计数标志位,当一帧数据开始时,Count_Sig被置为1,此时计数器Count_BPS才能开始计数;当一帧数据接收完毕后,Count_Sig被置为0,计数器Count_BPS停止工作。
接收控制模块从RX_En_Sig信号上的数据帧中读取出数据位,将串行数据转换为并行8位数据并存储于RX_Data中。当一帧数据接收完毕时,“接收完成标志位”RX_Done_Sig被置为1。
LED显示模块将接收到的八位数据输送到LED灯上。
在FPGA中实现此系统,工程包含顶层模块DA与底层模块detect_module、rx_bps_module、rx_control_module、LED_display_module,底层模块从左至右依次对应于图4.3中的U1~U4。下面介绍一下顶层模块输入输出引脚的功能:
(1)CLK:50MHz的时钟信号输入。
(2)RSTn:复位输入信号,低电平有效。当RSTn信号为0时,LED_Out全为0。
(3)RX_In:接收输入信号。连接到串口的RX线。
(4)LED_Out:输送到LED灯,共有八位。LED_Out[7:0]存储了一帧数据的MSB至LSB位。
四、程序设计
串口接收程序中的大部分代码功能已在前面的实验中使用过,容易理解,此处仅简单说明。
(1)图4.4是截取自底层模块rx_control_module的部分代码:
图4.4 rx_control_module核心代码
49-54:数据位存储。计算机发送数据时,是先发(最低有效位)LSB的,53行代码依次将RX_In信号的值存储于rData[0]~rData[7]中,rData的值最终将赋给RX_Data。
(2)图4.6是根据rx_control_module模块中的代码并结合图4.2画出的过程示意图,State信号内寄存当前状态值,最后的“12→13→0”的状态改变是在500KHz时钟上升沿立刻发生的,与前面不同,请结合程序理解。时序设计满足串口通信协议。
图4.6 接收过程示意图
五、FPGA管脚配置
以下是Anlogic FPGA的IO Constraint,CLK信号与开发板上的50MHz的晶振时钟相连;RSTn信号与SWO相连;LED_Out[7:0]分别与LED7~LED0相连;RX_En_Sig信号与SW1相连;RX_In信号与T5管脚相连。
set_pin_assignment { CLK } { LOCATION = R7; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[0] } { LOCATION = B14; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[1] } { LOCATION = B15; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[2] } { LOCATION = B16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[3] } { LOCATION = C15; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[4] } { LOCATION = C16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[5] } { LOCATION = E13; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[6] } { LOCATION = E16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { LED_Out[7] } { LOCATION = F16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { RSTn } { LOCATION = A9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { RX_En_Sig } { LOCATION = A10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { RX_Pin_In } { LOCATION = F12; IOSTANDARD = LVCMOS33; }
串口接收实验IO Constraint
六、实验结果
串口通信实验需要通过Anlogic_FPGA开发板上的USB转串口接口完成,因此,直接使用2根USB数据线分别将开发板上的JTAG接口和UART2USB接口与计算机相连,并在电脑上使用串口调试助手,按照以下参数配置:
图4.8 硬件连接和“串口助手”参数设置
图4.8是使用“串口调试助手”发送数据“AA”的参数界面,实验前需下载串口的驱动程序并安装,插拔UART2USB口的线缆,观察在串口号内是否出现和消失COMx,选择COMx,配置波特率为9600,数据位8位,停止位1位,无校验位和流控制。点击开启串口,选择HEX发送,键入“AA”,(设置ChipWatcher的捕获触发条件为RX引脚的下降沿,并点击)然后点击发送按钮。
为了更好的理解程序,我们使用ChipWatcher来捕获关键信号,加以诠释,设置ChipWatcher时,关键是设置RX的下降沿为捕获的触发条件,点击Single Trigger,软件会等待RX的下降沿到来才会抓取完整的数据并显示出来:
图**4.**9 Chipwatcher设置
图**4.**10 Chipwatcher进入等待触发条件状态
图**4.**11 这时在串口助手上点击发送,Chipwatcher捕获到完整的一帧RX时序
我们可以看到关键信号的产生和相互关系:
\1. 当RX的下降沿到来时,利用neg1和neg2产生确定起始条件的neg_sig,neg_sig的产生方法在detect_module.v中描述;
\2. 在State=0时,在500K时钟的上升沿采到neg_sig为1就将isCount即Count_Sig赋值为1,同时将State值自加1,进入起始位状态,这在rx_control_module.v里描述;
\3. 当Count_Sig为1时,Count_BPS开始计数,仅当Count_BPS =26时,BPS_CLK被赋值为1,时序如下图:
这在rx_bps_module.v里描述:
\4. 随后就是关键的状态转换,当Count_Sig为1时,Count_BPS以500K时钟频率在0-52循环计数,每到26,BPS_CLK就为高,此时State信号自加1,当State=2,3,4,5,6,7,8,9时,把RX_Pin_In的值移位存到RX_DATA里(可以看到起始状态下RX_DATA里存的是上一次的数据8’h55,随着State的递增,RX_Pin的值依次赋值给对应的位,最终输出这一次的数据。注意是先发低位,后发高位,最终RX_DATA=8‘b10101010),对应ChipWatcher的图更容易理解如下程序:
\5. State = 10和11,是校验位和停止位状态;
\6. State=12,isDone信号置1,Count_Sig归零;State=13,State和isDone信号归零;注意State = 12和13没有判断条件,只要500KHz上升沿到来就跳转,因此对UART连续接收的时序没有影响。
七、思考与拓展
(1)图4.6中,State的值在发生“12→13→0”的变化时,是随着基准时钟CLK的上升沿而变化的,也就是说,停止位的持续时间只有半个周期,但依然得到
了正确的实验结果,请结合程序从“实际有用数据”的角度解释其原因。
(1)在使用“串口调试助手”时,若选择“无校验位”,实验现象是怎样的?请结合程序及“一帧数据”的格式解释其原因。