最新fpga实现串行接口 rs232资料讲解.docx
- 文档编号:15622448
- 上传时间:2023-07-06
- 格式:DOCX
- 页数:13
- 大小:43.23KB
最新fpga实现串行接口 rs232资料讲解.docx
《最新fpga实现串行接口 rs232资料讲解.docx》由会员分享,可在线阅读,更多相关《最新fpga实现串行接口 rs232资料讲解.docx(13页珍藏版)》请在冰点文库上搜索。
最新fpga实现串行接口rs232资料讲解
FPGA实现串行接口RS232
串行接口(RS-232)
串行接口是连接FPGA和PC机的一种简单方式。
这个项目向大家展示了如果使用FPGA来创建RS-232收发器。
整个项目包括5个部分
1RS232是怎样工作的
2如何产生需要的波特率
3发送模块
4接收模块
5应用实例
RS-232接口是怎样工作的
作为标准设备,大多数的计算机都有1到2个RS-232串口。
特性
RS-232有下列特性:
∙使用9针的"DB-9"插头(旧式计算机使用25针的"DB-25"插头).
∙允许全双工的双向通讯(也就是说计算机可以在接收数据的同时发送数据).
∙最大可支持的传输速率为10KBytes/s.
DB-9插头
你可能已经在你的计算机背后见到过这种插头
它一共有9个引脚,但是最重要的3个引脚是:
∙引脚2:
RxD(接收数据).
∙引脚3:
TxD(发送数据).
∙引脚5:
GND(地).
仅使用3跟电缆,你就可以发送和接收数据.
串行通讯
数据以每次一位的方式传输;每条线用来传输一个方向的数据。
由于计算机通常至少需要若干位数据,因此数据在发送之前先“串行化”。
通常是以8位数据为1组的。
。
先发送最低有效位,最后发送最高有效位。
异步通讯
RS-232使用异步通讯协议。
也就是说数据的传输没有时钟信号。
接收端必须有某种方式,使之与接收数据同步。
对于RS-232来说,是这样处理的:
6串行线缆的两端事先约定好串行传输的参数(传输速度、传输格式等)
7当没有数据传输的时候,发送端向数据线上发送"1"
8每传输一个字节之前,发送端先发送一个"0"来表示传输已经开始。
这样接收端便可以知道有数据到来了。
9开始传输后,数据以约定的速度和格式传输,所以接收端可以与之同步
10每次传输完成一个字节之后,都在其后发送一个停止位("1")
让我们来看看0x55是如何传输的:
0x55的二进制表示为:
01010101。
但是由于先发送的是最低有效位,所以发送序列是这样的:
1-0-1-0-1-0-1-0.
下面是另外一个例子:
传输的数据为0xC4,你能看出来吗?
从图中很难看出来所传输的数据,这也说明了事先知道传输的速率对于接收端有多么重要。
数据传输可以多快?
数据的传输速度是用波特来描述的,亦即每秒钟传输的数据位,例如1000波特表示每秒钟传输100比特的数据,或者说每个数据位持续1毫秒。
波特率不是随意的,必须服从一定的标准,如果希望设计123456波特的RS-232接口,对不起,你很不幸运,这是不行的。
常用的串行传输速率值包括以下几种:
∙1200波特.
∙9600波特.
∙38400波特.
∙115200波特(通常情况下是你可以使用的最高速度).
在115200波特传输速度下,每位数据持续(1/115200)=8.7μs.如果传输8位数据,共持续8x8.7μs=69μs。
但是每个字节的传输又要求额外的“开始位”和“停止位”,所以实际上需要花费10x8.7μs=87μs的时间。
最大的有效数据传输率只能达到11.5KBytes每秒。
在115200波特传输速度下,一些使用了不好的芯片的计算机要求一个长的停止位(1.5或2位数据的长度),这使得最大传输速度降到大约10.5KBytes每秒
物理层
电缆上的信号使用正负电压的机制:
∙"1"用-10V的电压表示(或者在-5V与-15V之间的电压).
∙"0"用+10V的电压表示(或者在5V与15V之间的电压).
所以没有数据传输的电缆上的电压应该为-10V或-5到-10之间的某个电压。
波特率发生器
这里我们使用串行连接的最大速度115200波特,其他较慢的波特也很容易由此产生。
FPGA通常运行在远高于115200Hz的时钟频率上(对于今天的标准的来说RS-232真是太慢了),这就意味着我们需要用一个较高的时钟来分频产生尽量接近于115200Hz的时钟信号。
从1.8432MHz的时钟产生
通常RS-232芯片使用1.8432MHz的时钟,以为这个时钟很容易产生标准的波特率,所以我们假设已经拥有了一个这样的时钟源。
只需要将1.8432MHz16分频便可得到115200Hz的时钟,多方便啊!
reg[3:
0]BaudDivCnt;
always@(posedgeclk)BaudDivCnt<=BaudDivCnt+1;
wireBaudTick=(BaudDivCnt==15);
所以"BaudTick"每16个时钟周期需要置位一次,从而从1.8432MHz的时钟得到115200Hz的时钟。
从任意频率产生
早期的发生器假设使用1.8432MHz的时钟。
但如果我们使用2MHz的时钟怎么办呢?
要从2MHz的时钟得到115200Hz,需要将时钟"17.361111111..."分频,并不是一个整数。
我的解决办法是有时候17分频,有时候18分频,使得整体的分频比保持在"17.361111111"。
这是很容易做到的。
下面是实现这个想法的C语言代码:
while
(1)//死循环
{
acc+=115200;
if(acc>=2000000)printf("*");elseprintf("");
acc%=2000000;
}
这段代码会精确的以平均每"17.361111111..."个时钟间隔打印出一个"*"。
为了从FPGA得到同样的效果,考虑到串行接口可以容忍一定的波特率误差,所以即使我们使用17.3或者17.4这样的分频比也是没有关系的。
FPGA波特率发生器
我们希望2000000是2的整数幂,但很可惜,它不是。
所以我们改变分频比,"2000000/115200"约等于"1024/59"=17.356.这跟我们要求的分频比很接近,并且使得在FPGA上实现起来相当有效。
//10位的累加器([9:
0]),1位进位输出([10])
reg[10:
0]acc;//一共11位!
always@(posedgeclk)
acc<=acc[9:
0]+59;//我们使用上一次结果的低10位,但是保留11位结果
wireBaudTick=acc[10];//第11位作为进位输出
使用2MHz时钟,"BaudTick"为115234波特,跟理想的115200波特存在0.03%的误差。
参数化的FPGA波特率发生器
前面的设计我们使用的是10位的累加器,如果时钟频率提高的话,需要更多的位数。
下面是一个使用25MHz时钟和16位累加器的设计,该设计是参数化的,所以很容易根据具体情况修改。
parameterClkFrequency=25000000;//25MHz
parameterBaud=115200;
parameterBaudGeneratorAccWidth=16;
parameterBaudGeneratorInc=(Baud< reg[BaudGeneratorAccWidth: 0]BaudGeneratorAcc; always@(posedgeclk) BaudGeneratorAcc<=BaudGeneratorAcc[BaudGeneratorAccWidth-1: 0]+BaudGeneratorInc; wireBaudTick=BaudGeneratorAcc[BaudGeneratorAccWidth]; 上面的设计中存在一个错误: "BaudGeneratorInc"的计算是错误的,因为Verilog使用32位的默认结果,但实际计算过程中的某些数据超过了32位,所以改变一种计算方法。 parameterBaudGeneratorInc=((Baud<<(BaudGeneratorAccWidth-4))+(ClkFrequency>>5))/(ClkFrequency>>4); 这行程序也使得结果成为整数,从而避免截断。 这就是整个的设计方法了。 现在我们已经得到了足够精确的波特率,可以继续设计串行接收和发送模块了。 RS-232发送模块 下面是我们所想要实现的: 它应该能像这样工作: ∙发送器接收8位的数据,并将其串行输出。 ("TxD_start"置位后开始传输). ∙当有数传输的时候,使"busy"信号有效,此时“TxD_start”信号被忽略. RS-232模块的参数是固定的: 8位数据,2个停止位,无奇偶校验. 数据串行化 假设我们已经有了一个115200波特的"BaudTick"信号. 我们需要产生开始位、8位数据以及停止位。 用状态机来实现看起来比较合适。 reg[3: 0]state; always@(posedgeclk) case(state) 4'b0000: if(TxD_start)state<=4'b0100; 4'b0100: if(BaudTick)state<=4'b1000;//开始位 4'b1000: if(BaudTick)state<=4'b1001;//bit0 4'b1001: if(BaudTick)state<=4'b1010;//bit1 4'b1010: if(BaudTick)state<=4'b1011;//bit2 4'b1011: if(BaudTick)state<=4'b1100;//bit3 4'b1100: if(BaudTick)state<=4'b1101;//bit4 4'b1101: if(BaudTick)state<=4'b1110;//bit5 4'b1110: if(BaudTick)state<=4'b1111;//bit6 4'b1111: if(BaudTick)state<=4'b0001;//bit7 4'b0001: if(BaudTick)state<=4'b0010;//停止位1 4'b0010: if(BaudTick)state<=4'b0000;//停止位2 default: if(BaudTick)state<=4'b0000; endcase 注意看这个状态机是怎样实现当"TxD_start"有效就开始,但只在"BaudTick"有效的时候才转换状态的。 . 现在,我们只需要产生"TxD"输出即可. regmuxbit; always@(state[2: 0]) case(state[2: 0]) 0: muxbit<=TxD_data[0]; 1: muxbit<=TxD_data[1]; 2: muxbit<=TxD_data[2]; 3: muxbit<=TxD_data[3]; 4: muxbit<=TxD_data[4]; 5: muxbit<=TxD_data[5]; 6: muxbit<=TxD_data[6]; 7: muxbit<=TxD_data[7]; endcase //将开始位、数据以及停止位结合起来 assignTxD=(state<4)|(state[3]&muxbit); RS232接收模块 下面是我们想要实现的模块: 我们的设计目的是这样的: 1.当RxD线上有数据时,接收模块负责识别RxD线上的数据 2.当收到一个字节的数据时,锁存接收到的数据到"data"总线,并使"data_ready"有效一个周期。 注意: 只有当"data_ready"有效时,"data"总线的数据才有效,其他的时间里不要使用"data"总线上的数据,因为新的数据可能已经改变了其中的部分数据。 过采样 异步接收机必须通过一定的机制与接收到的输入信号同步(接收端没有办法得到发送断的时钟)。 这里采用如下办法。 1.为了确定新数据的到来,即检测开始位,我们使用几倍于波特率的采样时钟对接收到的信号进行采样。 2.一旦检测到"开始位",再将采样时钟频率降为已知的发送端的波特率。 典型的过采样时钟频率为接收到的信号的波特率的16倍,这里我们使用8倍的采样时钟。 当波特率为115200时,采样时钟为921600Hz。 假设我们已经有了一个8倍于波特率的时钟信号"Baud8Tick",其频率为921600Hz。 具体设计 首先,接受到的"RxD"信号与我们的时钟没有任何关系,所以采用两个D触发器对其进行过采样,并且使之我我们的时钟同步。 reg[1: 0]RxD_sync; always@(posedgeclk)if(Baud8Tick)RxD_sync<={RxD_sync[0],RxD}; 首先我们对接收到的数据进行滤波,这样可以防止毛刺信号被误认为是开始信号。 reg[1: 0]RxD_cnt; regRxD_bit; always@(posedgeclk) if(Baud8Tick) begin if(RxD_sync[1]&&RxD_cnt! =2'b11)RxD_cnt<=RxD_cnt+1; else if(~RxD_sync[1]&&RxD_cnt! =2'b00)RxD_cnt<=RxD_cnt-1; if(RxD_cnt==2'b00)RxD_bit<=0; else if(RxD_cnt==2'b11)RxD_bit<=1; end 一旦检测到"开始位",使用如下的状态机可以检测出接收到每一位数据。 reg[3: 0]state; always@(posedgeclk) if(Baud8Tick) case(state) 4'b0000: if(~RxD_bit)state<=4'b1000;//startbitfound? 4'b1000: if(next_bit)state<=4'b1001;//bit0 4'b1001: if(next_bit)state<=4'b1010;//bit1 4'b1010: if(next_bit)state<=4'b1011;//bit2 4'b1011: if(next_bit)state<=4'b1100;//bit3 4'b1100: if(next_bit)state<=4'b1101;//bit4 4'b1101: if(next_bit)state<=4'b1110;//bit5 4'b1110: if(next_bit)state<=4'b1111;//bit6 4'b1111: if(next_bit)state<=4'b0001;//bit7 4'b0001: if(next_bit)state<=4'b0000;//stopbit default: state<=4'b0000; endcase 注意,我们使用了"next_bit"来遍历所有数据位。 reg[2: 0]bit_spacing; always@(posedgeclk) if(state==0) bit_spacing<=0; else if(Baud8Tick) bit_spacing<=bit_spacing+1; wirenext_bit=(bit_spacing==7); 最后我们使用一个移位寄存器来存储接受到的数据。 reg[7: 0]RxD_data; always@(posedgeclk)if(Baud8Tick&&next_bit&&state[3])RxD_data<={RxD_bit,RxD_data[7: 1]}; 怎样使用发送和接收模块 这个设计似的我们可以通过计算机的串行口来控制FPGA的几个引脚。 具体来说,该设计完成以下功能。 1.将FPGA的8个引脚作为输出(称为“通用输出”)。 FPGA收到任何数据时都会更新这8个GPout的值。 2.将FPGA的8个引脚作为输入(称为“通用输入”)。 FPGA收到仁厚数据后,都会将GPin上的数值通过串行口发送出去。 通用输出可以用来通过计算机远程控制任何东西,例如FPGA板上的LED,甚至可以再添加一个继电器来控制咖啡机。 moduleserialfun(clk,RxD,TxD,GPout,GPin); inputclk; inputRxD; outputTxD; output[7: 0]GPout; input[7: 0]GPin; /////////////////////////////////////////////////// wireRxD_data_ready; wire[7: 0]RxD_data; async_receiverdeserializer(.clk(clk),.RxD(RxD),.RxD_data_ready(RxD_data_ready),.RxD_data(RxD_data)); reg[7: 0]GPout; always@(posedgeclk)if(RxD_data_ready)GPout<=RxD_data; /////////////////////////////////////////////////// async_transmitterserializer(.clk(clk),.TxD(TxD),.TxD_start(RxD_data_ready),.TxD_data(GPin)); endmodule 记得包含异步发送和接收模块的设计文件,并更新里面的时钟频率。 数学专业英语词汇 multiple decision problem 多重判定问题 multiple edge 多重棱 multiple fourier series 多重傅里叶级数 multiple hypergraph 多重超图 multiple markov process 多重马尔可夫过程 multiple point 多重点 multiple regression 多重回归 multiple root 多重根 multiple sequence 多重序列 multiple series 多重级数 multiple stratification 多层化 multiple tangent 多重切线 multiple test 多重检验 multiple valued 多值的 multiple valued function 多值函数 multiplicand 被乘数 multiplicand register 被乘数寄存器 multiplication 乘 multiplication operator 乘法算子 multiplication ring 乘环 multiplication sign 乘号 multiplication table 九九表 multiplication theorem 乘法定理 multiplicative 乘法的 multiplicative axiom 乘法公理 multiplicative character 乘法特贞 multiplicative group 乘法群 multiplicative lattice 乘格 multiplicative process 繁殖过程 multiplicatively closed set 积闭集 multiplicator 乘数 multiplicity 重数 multiplicity of a root 根的重数 multiplier 乘数;乘群 multiplier register 乘数寄存器 multiply 乘 multiply connected domain 多连通区域 multiply connected region 多连通区域 multiply connected sequence 多连通序列 multiply connected space 多连通空间 multiply monotone sequence 多重单凋列 multiply periodic function 多重周期函数
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 最新fpga实现串行接口 rs232资料讲解 最新 fpga 实现 串行 接口 rs232 资料 讲解