基于VHDLRS232串口通信控制器.docx
《基于VHDLRS232串口通信控制器.docx》由会员分享,可在线阅读,更多相关《基于VHDLRS232串口通信控制器.docx(31页珍藏版)》请在冰豆网上搜索。
基于VHDLRS232串口通信控制器
RS232串口通信控制器
摘要
本实验使用VHDL语言设计了一个串口通信控制器,实现了CPLD和PC机通过RS232协议进行数据通信。
利用MAXIIEPM1270T144C5为核心芯片的数电实验开发板下载实现。
串口的波特率选择9600bit,处于双工工作状态。
按“发送键”CPLD向PC发送字符串“welcome”;PC课随时向CPLD发送0~F的十六进制数据,CPLD接收后译码显示在7段数码管上。
Abstract
Inthisstudy,usingtheVHDLlanguagedesignedaserialcommunicationscontroller,toachievetheCPLDandthePCthroughRS232protocolfordatacommunication.CorechipusingMAXIIEPM1270T144C5severalpowerboarddownloadexperimentaldevelopmenttoachieve.Serialportbaudrateselection9600bit,intheduplexworkingcondition.Pressthe"Sendbutton"CPLDsendthestringtothePC"welcome";PCclassat0~FtotheCPLDsendthehexadecimaldata,CPLDdecodingafterreceivingthe7-segmentdisplayon.
关键词:
VHDLRAS232串口通信CPLD
正文
1.RS232协议简介
1.1串口
串口是计算机上一种非常通用设备通信的协议(不要与UniversalSerialBus或者USB混淆)。
大多数计算机包含两个基于RS232的串口。
串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有口。
同时,协议也可以用于获取远程采集设备的数据。
串口通信的概念非常简单,串口按位(bit)发送和接收字节。
尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。
它很简单并且能够实现远距离通信。
比如IEEE488定义并行通行状态时,规定设备线总长不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。
典型地,串口用于ASCII码字符的传输。
通信使用3根线完成:
(1)地线,
(2)发送,(3)接收。
由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。
其他线用于握手,但是不是必须的。
串口通信最重要的参数是、数据位、停止位和。
对于两个进行通行的端口,这些参数必须匹配:
a,波特率:
这是一个衡量通信速度的参数。
它表示每秒钟传送的bit的个数。
例如300波特表示每秒钟发送300个bit。
当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。
这意味着串口通信在数据线上的采样率为4800Hz。
通常电话线的波特率为14400,28800和36600。
波特率可以远远大于这些值,但是波特率和距离成反比。
高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。
b,数据位:
这是衡量通信中实际数据位的参数。
当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。
如何设置取决于你想传送的信息。
比如,标准的ASCII码是0~127(7位)。
扩展的ASCII码是0~255(8位)。
如果数据使用简单的文本(标准ASCII码),那么每个数据包使用7位数据。
每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。
由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。
c,停止位:
用于表示单个包的最后一位。
典型的值为1,和2位。
由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。
因此停止位不仅仅是表示传输的结束,并且提供计算机校正的机会。
适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
d,奇偶校验位:
在串口通信中一种简单的检错方式。
有四种检错方式:
偶、奇、高和低。
当然没有校验位也是可以的。
对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。
例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。
如果是奇校验,校验位位1,这样就有3个逻辑高位。
高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。
这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。
1.2RS232串口
RS-232(ANSI/EIA-232标准)是IBM-PC及其兼容机上的串行连接标准。
可用于许多用途,比如连接鼠标、打印机或者Modem,同时也可以接工业仪器仪表。
用于驱动和连线的改进,实际应用中RS-232的传输长度或者速度常常超过标准的值。
RS-232只限于PC串口和设备间点对点的通信。
RS-232串口通信最远距离是50英尺。
DB-9针连接头
-------------
\12345/
\6789/
-------
从计算机连出的线的截面。
RS-232针脚的功能:
数据:
TXD(pin3):
串口数据输出(TransmitData)
RXD(pin2):
串口数据输入(ReceiveData)
握手:
RTS(pin7):
发送数据请求(RequesttoSend)
CTS(pin8):
清除发送(CleartoSend)
DSR(pin6):
数据发送就绪(DataSendReady)
DCD(pin1):
数据载波检测(DataCarrierDetect)
DTR(pin4):
数据终端就绪(DataTerminalReady)
地线:
GND(pin5):
地线
其他
RI(pin9):
铃声指示
1.3数据帧
异步串行通信方式是把一个字符看作一个独立的信息单元,并且字符出现在数据流中的相对时间是任意的,而每一个字符中的各位是以固定的时间传送。
因此这种方式在同一字符内部是同步的,而字符间是异步的。
异步通信的主要特点是字符帧的传输格式,这样就使得发送方可以在字符之间可根据实际的需要插入不同的时间间隔,即每一个字符的发送是随机的。
异步串行通信是以数据帧的格式传送的,1个字符开始传输前,输出线必须在逻辑上处于‘1’状态,这称为标识态。
传输一开始,输出线由标识态变为‘o,状态,从而作为起始位。
起始位后面为5~8个信息位,信息位由低到高排列,即第1位为字符的最低位,在同一传输系统中,信息位的数目是固定的。
信息位后面为校验位,校验位可以按奇校验设置,也可以按偶校验设置,不过,校验位也可以不设置。
最后的数位为‘1’,它作为停止位,停止位可为1位、1.5位或者2位。
如果传输完1个字符以后,立即传输下一个字符,那么,后一个字符的起始位便紧挨着前一个字符的停止位了,否则,输出线又会立即进入标识态,即逻辑上处于‘l’。
2.系统设计
2.1总体设计
2.2各模块设计及参数
本实验是串口异步通信的典型应用,串口工作在全双工模式,采用正确的分频系数得出串口通信所需的波特率时钟。
把每一位的发送接受分成了8个时隙,这样更好的实现质量可靠的通信,在每次的第7个时隙时,发送接受使能信号有效。
发送部分采用并串转换,在先发送完一个低电平的起始位后,从LSB到MSB的顺序逐个发出,再发一个高电平结束发送过程。
接受部分采用串并转换,在检测到起始位的下降沿后,进入接受,接受采用两级缓存模式,保证高质量的通信。
显示部分,接受到的是相应数字和字符的ASCLL码,所以必须进行译码显示部分,在数码管上显示接受到的信息。
综上所述:
本实验大体上分为四个模块:
分频模块:
产生正确的满足实验要求的8×波特率的时钟。
发送模块:
把发送寄存器里的内容按正确的时序通过串口发送到计算机上。
接受模块:
通过串口把计算机发送过来的内容按着正确的时序存放在接受寄存器中。
显示模块:
把接受寄存器中的内容,正确译码显示在数码管上。
2.2.1分频模块
通过本模块要产生8×波特率的时钟,波特率时钟,以及完成可靠性判断。
系统时钟是50M,波特率是9600,所以得出分频系数=50M/(8*9600*2)=325,转换为二进制为00000001;用div_par表示,分频计数器为div_reg,时隙寄存器div8_tras_reg、div8_rec_reg,分别代表发送,接受两个过程。
2.2.2发送模块
发送过程其实是一个并转串的过程,在每到来一个发送使能信号后,发送出每一位,最先发送起始位----一个低电平信号,紧接着发送LSB,发送完8位数据位后,因为题目不要求发送奇偶校验位,所以直接发送一位结束位停止发送。
在每发送一帧数据前,先要检测译码,检测到拨码开关所输入的ASCll码,然后把正确的数据装入发送缓存寄存器txd_buf中。
本模块需要用到的信号量如下:
trasstart---开始发送标志,state_tras---发送状态寄存器。
初始化状态如下:
txd_reg<='1';trasstart<='0';txd_buf<="00000000";state_tras<="0000";
2.2.3接收模块
接受过程恰好是发送过程的逆过程,实现一个串并转换,把rxd上的来自PC的数据存放在rxd_buf中,实现通信。
由于接受为异步通信方式,故设计两级缓存来检测起始信号。
与此过程相关的信号量为:
rxd_reg1和rxd_reg2两级缓存,state_rec接受状态寄存器,初始化状态如下:
rxd_reg1<='0';rxd_reg2<='0';rxd_buf<="00000000";state_rec<="0000";recstart<='0';recstart_tmp<='0';
2.2.4显示模块
实验中用到的7段数码管是共阴极数码管,共6个。
数码管的共阴极端是各自独立的,当共阴极端CATn为低电平时,该数码管就亮。
6个数码管的8个输入端是并联在一起的,起名为AA~AG,AP,输入端为高电平时,对应段位就亮
对相应的输入十六进制数,进行译码后,使能数码管,即可显示。
3.系统调试
3.1仿真调试
3.1.1分频仿真
3.1.2发送仿真
从上图可以看出,在没有复位信号且按下key_input键后,时钟分频得到在8倍波特率的时钟,且在8倍波特率时钟下,每当第七个时隙时,发送出一位数据,从最开始的起始位,紧接着是LSB到MSB再到停止位高电平,共10位数据。
之后,send_state计数加一,传送下一个字母。
3.1.3接收和显示仿真
从上面这张图能完全看出接受和显示两部分的时序关系,同样从起始位开始,到最后9箭头所对应的rxd_buf和实际rxd上的数据是一致的,都是00110000,是接受到了数字0的ASCLL码,最后显示译码输出的是,即在数码管上显示0.
3.2下载调试
3.2.1按键抖动
使用按键作为key_input会出现按键抖动问题。
后增加延时去抖的代码。
也可以使用拨码开关做输入。
3.2.2实验仪器问题
本实验虽然涉及硬件仪器较少,但还是应当仔细阅读CPLD个模块使用说明。
特别注意区分COM1与COM2,切勿接错,白白浪费时间。
4.系统指标测试
4.1功能说明
本模块的功能是验证实现和PC机进行基本的串口通信的功能。
需要在PC机上安装一个串口调试工具来验证程序的功能。
程序实现了一个收发一帧10个bit(即无奇偶校验位)的串口控制器,10个bit是1位起始位,8个数据位,1个结束位。
串口的波特律由程序中定义的div_par参数决定,更改该参数可以实现相应的波特率。
程序当前设定的div_par的值是0x104,对应的波特率是9600。
用一个8倍波特率的时钟将发送或接受每一位bit的周期时间划分为8个时隙以使通信同步.程序的工作过程是:
串口处于全双工工作状态,按动key_input,CPLD向PC发送字符串“welcome”(串口调试工具设成按ASCII码接受方式);PC可随时向CPLD发送0-F的十六进制数据,CPLD接受后显示在7段数码管上。
具体实现如下:
按下键rst(124)进行复位,然后通过input(拨码开关)输入想要发送的字符的ASCLL码,然后按下键key(123)进行发送。
接受时,直接在串口调试工具上输入自己想要发送的数字即可。
4.2管脚分布及说明
4.3元件清单及资源利用情况
所用元件分硬件和软件:
其中硬件包括MAXⅡ实验板一个,USB下载线,PC以及9针串口线。
软件包括QUARTUS集成开发环境以及串口调试工具。
资料利用情况如下:
5.附录
5.1源程序
--
--本模块的功能是验证实现和PC机进行基本的串口通信的功能。
需要在
--PC机上安装一个串口调试工具来验证程序的功能。
--程序实现了一个收发一帧10个bit(即无奇偶校验位)的串口控
--制器,10个bit是1位起始位,8个数据位,1个结束
--位。
串口的波特律由程序中定义的div_par参数决定,更改该参数可以实
--现相应的波特率。
程序当前设定的div_par的值是0x104,对应的波特率是
--9600。
用一个8倍波特率的时钟将发送或接受每一位bit的周期时间
--划分为8个时隙以使通信同步.
--程序的工作过程是:
串口处于全双工工作状态,按动key2,CPLD向PC发送皐elcome"
--字符串(串口调试工具设成按ASCII码接受方式);PC可随时向CPLD发送0-F的十六进制
--数据,CPLD接受后显示在7段数码管上。
libraryIEEE;
use
ENTITYUARTIS
PORT(
clk:
INstd_logic;
rst:
INstd_logic;
rxd:
INstd_logic;--串行数据接收端
txd:
OUTstd_logic;--串行数据发送端
en:
OUTstd_logic_vector(5downto0);--数码管使能
seg_data:
OUTstd_logic_vector(7DOWNTO0);--数码管数据
key_input:
INstd_logic--按键输入
);
ENDUART;
ARCHITECTUREarchOFUARTIS
--//////////////////innerreg////////////////////
SIGNALdiv_reg:
std_logic_vector(15DOWNTO0);--分频计数器,分频值由波特率决定。
分频后得到频率8倍波特率的时钟
SIGNALdiv8_tras_reg:
std_logic_vector(2DOWNTO0);--该寄存器的计数值对应发送时当前位于的时隙数
SIGNALdiv8_rec_reg:
std_logic_vector(2DOWNTO0);--寄存器的计数值对应接收时当前位于的时隙数
SIGNALstate_tras:
std_logic_vector(3DOWNTO0);--发送状态寄存器
SIGNALstate_rec:
std_logic_vector(3DOWNTO0);--接受状态寄存器
SIGNALclkbaud_tras:
std_logic;--以波特率为频率的发送使能信号
SIGNALclkbaud_rec:
std_logic;--以波特率为频率的接受使能信号
SIGNALclkbaud8x:
std_logic;--以8倍波特率为频率的时钟,它的作用是将发送或接受一个bit的时钟周期分为8个时隙
SIGNALrecstart:
std_logic;--开始发送标志
SIGNALrecstart_tmp:
std_logic;--开始接受标志
SIGNALtrasstart:
std_logic;
SIGNALrxd_reg1:
std_logic;--接收寄存器1
SIGNALrxd_reg2:
std_logic;--接收寄存器2,因为接收数据为异步信号,故用两级缓存
SIGNALtxd_reg:
std_logic;--发送寄存器
SIGNALrxd_buf:
std_logic_vector(7DOWNTO0);--接受数据缓存
SIGNALtxd_buf:
std_logic_vector(7DOWNTO0);--发送数据缓存
SIGNALsend_state:
std_logic_vector(2DOWNTO0);--每次按键给PC发送"Welcome"字符串,这是发送状态寄存器
SIGNALcnt_delay:
std_logic_vector(19DOWNTO0);--延时去抖计数器
SIGNALstart_delaycnt:
std_logic;--开始延时计数标志
SIGNALkey_entry1:
std_logic;--确定有键按下曛?
SIGNALkey_entry2:
std_logic;--确定有键按下标志
--//////////////////////////////////////////////
CONSTANTdiv_par:
std_logic_vector(15DOWNTO0):
="00000001";
--分频参数,其值由对应的波特率计算而得,按此参数分频的时钟频率是波倍特率的8倍,此处值对应9600的波特率,即分频出的时钟频率是9600*8
SIGNALtxd_xhdl3:
std_logic;
BEGIN
en<="111110";--7段数码管使能信号赋值
txd_xhdl3<=txd_reg;
txd<=txd_xhdl3;
PROCESS(clk,rst)
BEGIN
IF(rst='1')THEN--如果重新开始
cnt_delay<="00000000000000000000";
start_delaycnt<='0';
ELSIF(clk'EVENTANDclk='1')THEN--否则在时钟上升沿
IF(start_delaycnt='1')THEN--每800000次,检测一次是否有按键按下
IF(cnt_delay/="0000000")THEN
cnt_delay<=cnt_delay+"00000000000000000001";--每次时钟到来加1
ELSE
cnt_delay<="00000000000000000000";
start_delaycnt<='0';
ENDIF;
ELSE
IF((key_input='1')AND(cnt_delay="00000000000000000000"))THEN
start_delaycnt<='1';
ENDIF;
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(clk,rst)
BEGIN
IF(rst='1')THEN
key_entry1<='0';
ELSIF(clk'EVENTANDclk='1')THEN
IF(key_entry2='1')THEN--如果key2=1
key_entry1<='0';--有键输入?
ELSE--如果key2=0,
IF(cnt_delay="0000000")THEN--检测键输入
IF(NOTkey_input='1')THEN--如果没有键输入
key_entry1<='1';
ENDIF;
ENDIF;
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(clk,rst)
BEGIN
IF(rst='1')THEN
div_reg<="0000000000000000";
ELSIF(clk'EVENTANDclk='1')THEN--div_reg是某个延时
IF(div_reg=div_par-"0000000000000001")THEN
div_reg<="0000000000000000";
ELSE
div_reg<=div_reg+"0000000000000001";
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(clk,rst)--分频得到8倍波特率的时钟
BEGIN
IF(rst='1')THEN
clkbaud8x<='0';
ELSIF(clk'EVENTANDclk='1')THEN
IF(div_reg=div_par-"0000000000000001")THEN
clkbaud8x<=NOTclkbaud8x;--产生时钟脉冲
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(clkbaud8x,rst)
BEGIN
IF(rst='1')THEN
div8_rec_reg<="000";
ELSEIF(clkbaud8x'EVENTANDclkbaud8x='1')THEN
IF(recstart='1')THEN--接收开始标志
div8_rec_reg<=div8_rec_reg+"001";--接收开始后,时隙数在8倍波特率的时钟下加1循环
ENDIF;
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(clkbaud8x,rst)
BEGIN
IF(rst='1')THEN
div8_tras_reg<="000";
ELSEIF(clkbaud8x'EVENTANDclkbaud8x='1')THEN
IF(trasstart='1')THEN
div8_tras_reg<=div8_tras_reg+