差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
uart_verilog [2020/08/22 16:39] gongyu [2. 串行接口的Verilog实现] |
uart_verilog [2021/02/06 16:25] (当前版本) gongyusu |
||
---|---|---|---|
行 1: | 行 1: | ||
- | ## 串行接口RS-232 | + | ## 异步收发器UART的Verilog代码 |
- | 串口UART是PC和FPGA通信的最简单的方式,它是一种异步串行/全双工的通信方式,尤其是目前的PC都是通过USB端口来进行UART数据的传输,可以实现更高的传输速率,比如1.5Mbps。 | + | 串口[[UART]]是PC和FPGA通信的最简单的方式,它是一种异步串行/全双工的通信方式,尤其是目前的PC都是通过USB端口来进行UART数据的传输,可以实现更高的传输速率,比如1.5Mbps。 |
--- | --- | ||
行 19: | 行 19: | ||
* 允许双向全双工通信(PC可以同时接收、发送数据). | * 允许双向全双工通信(PC可以同时接收、发送数据). | ||
* 最高的通信速率可以达到10KBytes/s. | * 最高的通信速率可以达到10KBytes/s. | ||
- | * DB-9连接器 | + | * DB-9连接器, 它有3根最重要的信号: |
- | + | ||
- | RS-232有9根管脚, 有3根最重要的信号: | + | |
{{ ::SerialConnector.jpg |}} | {{ ::SerialConnector.jpg |}} | ||
- | * 管脚2: RxD(接收数据). | + | * 管脚2: RxD(接收数据). |
- | * 管脚3: TxD(发送数据). | + | * 管脚3: TxD(发送数据). |
- | * 管脚5: GND(地). | + | * 管脚5: GND(地). |
只需要3根线,就可以进行数据的收、发。 | 只需要3根线,就可以进行数据的收、发。 | ||
行 43: | 行 40: | ||
{{ ::SerialCommunication55.gif |}} | {{ ::SerialCommunication55.gif |}} | ||
- | |||
一个字节0x55的数值用二进制表示就是01010101,由于先发送最低位(bit-0),线路的变化为: 1-0-1-0-1-0-1-0. | 一个字节0x55的数值用二进制表示就是01010101,由于先发送最低位(bit-0),线路的变化为: 1-0-1-0-1-0-1-0. | ||
行 54: | 行 50: | ||
这些位数很难看出来,可以看出,让接收端知道数据的发送速率是非常重要的。 | 这些位数很难看出来,可以看出,让接收端知道数据的发送速率是非常重要的。 | ||
- | #### 1.4 数据发送能够多块? | + | #### 1.4 数据发送能够多快? |
- | 发送的速度是以波特(每秒都少个位)来标称的,例如1000波特意味着每秒1000位,或者说每一位持续时间为1毫秒 | + | 发送的速度是以波特(每秒多少个位)来标称的,例如1000波特意味着每秒1000位,或者说每一位持续时间为1毫秒 |
RS-232接口的传输速率不是任意的,它有一些固定的值: | RS-232接口的传输速率不是任意的,它有一些固定的值: | ||
行 76: | 行 72: | ||
这里我们用115200波特率,FPGA一般运行在更高的频率,远高于115200Hz,我们需要用FPGA的时钟产生每秒115200个脉冲。 | 这里我们用115200波特率,FPGA一般运行在更高的频率,远高于115200Hz,我们需要用FPGA的时钟产生每秒115200个脉冲。 | ||
- | 传统上RS-232芯片采用1.8432MHz的时钟,可以通过/16分频轻松的到115200Hz以及其它波特率的频率。 | + | 传统上RS-232芯片采用1.8432MHz的时钟,可以通过/16分频能够轻松得到115200Hz以及其它波特率的频率。 |
<code verilog> | <code verilog> | ||
行 106: | 行 102: | ||
#### 2.1 参数化的FPGA波特率发生器 | #### 2.1 参数化的FPGA波特率发生器 | ||
- | 下面的设计为25MHz的系统时钟,使用一个16位的累加器,代码可以通过调节参数灵活定制 | + | 下面的设计为25MHz的系统时钟,使用一个16位的累加器,代码可以通过简单地配置一下参数就可以灵活定制,适用不同的系统时钟。 |
<code verilog> | <code verilog> | ||
- | parameter ClkFrequency = 25000000; // 25MHz | + | parameter ClkFrequency = 25000000; // 此处为25MHz,使用不同的系统只需要修改这个参数 |
- | parameter Baud = 115200; | + | parameter Baud = 115200; //此处设置波特率为115200,如果使用不同的波特率只需要修改这个参数 |
parameter BaudGeneratorAccWidth = 16; | parameter BaudGeneratorAccWidth = 16; | ||
parameter BaudGeneratorInc = (Baud<<BaudGeneratorAccWidth)/ClkFrequency; | parameter BaudGeneratorInc = (Baud<<BaudGeneratorAccWidth)/ClkFrequency; | ||
行 135: | 行 131: | ||
异步发送的固定参数:8个数据位,2个停止位,无奇偶校验。 | 异步发送的固定参数:8个数据位,2个停止位,无奇偶校验。 | ||
- | 发送端获取8位的数据,将其串行化(当Txd_start信号被断言的时候),当传输发生的时候“busy”信号会被断言,在此期间“TxD_start”信号被忽略。 | + | 发送端获取8位的数据,将其串行化(当Txd_start信号被断言的时候),当传输发生的时候“busy”信号会被拉高,在此期间“TxD_start”信号被忽略。 |
采用状态机进行发送比较合适: | 采用状态机进行发送比较合适: | ||
行 185: | 行 181: | ||
现在我们来看看数据的接收端。 | 现在我们来看看数据的接收端。 | ||
- | 该模块从RxD线上收集数据。当接收到一个字节时,它出现在“数据”总线上。 一旦接收到一个完整的字节,“data_ready”就会被断言一个时钟。 | + | 该模块从RxD线上收集数据。当接收到一个字节时,它出现在“数据”总线上。 一旦接收到一个完整的字节,“data_ready”就会被拉高一个时钟。 |
注意,只有在断言“ data_ready”时,“ data”才有效。 其余时间,请不要使用它,因为可能会出现新数据,从而使数据混乱。 | 注意,只有在断言“ data_ready”时,“ data”才有效。 其余时间,请不要使用它,因为可能会出现新数据,从而使数据混乱。 | ||
行 193: | 行 189: | ||
接收器通常以16倍波特率对输入信号进行过采样。 我们在这里使用了8倍...对于115200波特,采样率为921600Hz。 | 接收器通常以16倍波特率对输入信号进行过采样。 我们在这里使用了8倍...对于115200波特,采样率为921600Hz。 | ||
- | 假设我们有一个可用的“ Baud8Tick”信号,该信号每秒断言921600次。 | + | 假设我们有一个可用的“ Baud8Tick”信号,该信号每秒拉高921600次。 |
具体的设计 | 具体的设计 |