(一) UART 介绍
略……(后续会补上)
(二) UART 软件
PC 端使用的软件为“串口调试助手 ComAssistant”
(三) UART 模块介绍
下面先介绍 UART 关键的3个模块,可以先不理解其中的工作原理,先了解这几个模块的作用与效果。
1. Uart_ClkDiv
/* Uart时钟信号 */
module Uart_ClkDiv(
input Sys_CLK, //50Mhz系统时钟
output Uart_CLK //9600bps
);
上述 Uart_ClkDiv 用来生成 Uart 传输所需要的时钟信号,输入 50Mhz 系统时钟,输出 Uart 时钟
2. Uart_Rx
/* Uart_Rx 用于接收数据 */
module Uart_Rx(
input Uart_CLK,//采样时钟
input RST,//复位信号
input Signal_Rx,//UART数据输入
output reg [7:0] Data_Rx,//接收数据输出
output reg Rdsig,//置1时表示上层模块已经可以读8位数据了
output reg DataError_Flag,//数据出错指示
output reg FrameError_Flag//帧出错指示
);
上述 Uart_Rx 用于接收数据,输入的 Uart_CLK 为模块 Uart_ClkDiv 生成的 Uart 时钟信号,RST 为复位键信号(低电平有效),Signal_Rx 为 Uart 数据输入信号
8bit 输出 Data_Rx 为一次接收获取的数据,Rdsig 为低电平表示正在接收数据,当一次数据接收完毕后会置成一段时间的高电平
DataError_Flag 和 FrameError_Flag 都是出错提示,当接收数据过程发送错误会被置成高电平,需要注意此处的校验位为偶校验位(Even)
3. Uart_Tx
/* Uart_Tx发送数据 */
module Uart_Tx(
input Uart_CLK,
input RST,
input [7:0] Data_Tx,//8位待发送数据
input Wrsig,
output reg Idle,//空闲状态,0表示空闲,1表示忙碌
output reg Signal_Tx//并转串,1位输出
);
上述 Uart_Tx 用于发送数据,输入的 Uart_CLK 为模块 Uart_ClkDiv 生成的 Uart 时钟信号,RST 为复位键信号(低电平有效)
Data_Tx 为 8bit 待发送数据,Wrsig 上升沿时开始发送
Idle 是 Uart_Tx 发送器的状态,0表示空闲,1表示忙碌, Signal_Tx 是数据输出信号
上述三个模块是 UART 发送的核心,但要实现超过 8 位的数据传输,单靠上面还不够
(四) 实现多比特数据传输
由于 UART 的资料位(数据位)一般是8位,但实际应用中需要传输多位数据。
根据 Uart_Rx 和 Uart_Tx 各接口的效果,使用时钟周期进行循环接收与发送
此处以接收 64bit 数据,并将接收到的数据发送为例,演示多位数据传输的原理
注意:图中的校验位为EVEN,应该为偶校验,猜测软件将EVEN(偶)错误标记成EVEN(奇)
1. 顶层模块
/* 顶层模块 */
module uart_top(
input sys_clk,//系统时钟
input sys_rst,//复位键
input signal_rx,//接收信号rx
input enable,//使能信号
output isEnable,//是否能够运行
output Err,//错误信号
output busy,//忙碌信号
output finish,//完成信号
output signal_tx//tx发送信号
);
上述为顶层模块的接口,由于代码实现的原因,在每次发送数据至 FPGA 板子前需要按下复位键,否则将无法正常接收
运行中信号,错误信号,忙碌信号,完成信号分别绑在 FPGA 的 4 个 LED 灯中,作为 FPGA 传输数据时的反馈
使能信号 enable 绑于一个拨码开关上,高电平运行
2. 循环接收模块
2.1 接口定义
/* 循环接收模块 */
module Uart_Receive_Top(
input sys_clk,//系统时钟
input sys_rst,//系统复位键
input signal_rx,//接收信号rx
input enable,//使能信号
output reg[63:0] data_input,//数据输入
output reg Err,//报错,高电平出错
output reg finish,//接收完成信号
output reg busy//高电平忙碌
);
上述是接收模块的接口定义,在此模块中实现循环接收数据,接收完毕后会将 finish 信号置1,表示接收完成
如果接收未完成,busy 信号为1,如果接收出错,Err信号为1
2.2 核心代码
/* 循环接收模块 */
case(state)
4'd00 : begin
if(Rdsig && !DataError && !FrameError) begin
data_input[64-0*8-1:64-(0+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1;
end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd01 : begin
if(!Rdsig)state <= state + 1;
end
4'd02 : begin
if(Rdsig && !DataError && !FrameError) begin
data_input[64-1*8-1:64-(1+1)*8] <= data_rx;
busy <= 1'b1;
state <= state + 1;
end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
4'd03 : begin
if(!Rdsig)state <= state + 1;
end
...
4'd14 : begin
if(Rdsig && !DataError && !FrameError) begin
data_input[64-7*8-1:64-(7+1)*8] <= data_rx;
finish <= 1;
busy <= 0;
state <= state;
end
else if(DataError || FrameError) begin
Err <= 1;
state <= 4'b1111;
end
end
//报错
4'b1111:Err<=1;
default:;
endcase
上述是接收过程的其中几个状态,每两个状态完成一次接收操作
第一个状态进行接收,当 Rwsig 为 1 时表示接收完毕,DataError 和 FrameError 都不为 0 表示未发生错误
故一次接收完成,进行 data_input 的赋值,并让 state + 1 跳转至下一个状态;如果发生错误,将状态跳转到报错状态
第二个状态等待下一次接收的开始,当 Rwsig 为 0 后表明接收开始,跳转到下一个状态等待接收完毕
当最后一个数据接收完毕后,将 finish 置 1,busy 置 0,表明接收完毕
3. 发送模块
3.1 接口定义
module Uart_Send_Top(
input sys_clk,//系统时钟50MHz
input sys_rst,//重置键rst
input [63:0] data_output,//待发送数据
input enable,//发送使能,1为可以发送
output wire signal_tx,//uart发送信号tx
output reg Err,//报错,高电平出错
output reg finish,//完成信号
output reg busy//高电平时表示忙碌
);
上述是循环发送模块的接口定义,与接收接口类似
3.2 核心代码
/* 循环发送模块 */
case(state)
4'd00 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-0*8-1:64-(0+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_cnt <= 12'd0;
wait_finished <= 1'b0;
end
end
4'd01 : begin
if(Busy_Tx) begin
Wrsig <= 0;
end
else begin
wait_cnt <= wait_cnt + 1;
if(wait_cnt == 12'hA00) begin
wait_cnt <= 12'd0;
wait_finished <= 1'b1;
end
else if(wait_cnt == 12'd0 && wait_finished) state <= state + 1;
end
end
4'd02 : begin
if(!Busy_Tx) begin
Data_Tx <= data_output[64-1*8-1:64-(1+1)*8];
Wrsig <= 1;
state <= state + 1;
wait_