1. UART介绍
UART全称为通用异步接收-发送器,嵌入式中说的串口,一般是指UART口。
在传输的过程中,UART传输端将字节数据以串行的方式逐个比特的发送出去,UART接收端诸葛比特地接收数据,然后将其重新组合为字节数据。
常见的传输数据格式如图所示:
- 在空闲时,UART输出保持高电平(在早期的发展历史中,电信传输用高电平表示线路没有被破坏掉),如果是低电平,就无法判定。
- UART在传输一个字节时,应发送一个低电平表示起始位。
- 在发送起始位之后,通常从低位到高位的顺序诸位传输一个字节的数据。(某些UART会以相反顺序进行传输)
- 传输完一个字节之后,可选地会传输一位或者多位奇偶校验位。
- 最后则是一位高电平停止位。
1.1 波特率
波特率是衡量串口传输速度的主要标准,与比特率区分开来。
- 在信息传输通道中,携带数据信号的单元称为码元(脉冲),每秒通过信道传输的码元叫做码元传输速率,简称波特率。波特率是传输通道频宽的指标。单位为Baud(波特)
- 每秒通过信道传输的信息称为位传输速率,简称比特率。比特率表示有效数据的传输速率。单位为bit/s(位/秒)
- 两者的关系:比特率=波特率*单个调制状态对应的二进制位数。
常见的串口通信波特率有2400 、9600、115200等,发送和接收波特率必须保持一致才能正确通信。波特率是指1 秒最大传输的数据位数,包括起始位、数据位、校验位、停止位。
如果波特率设定为9600,那么一个数据位的传输时间长度是1/9600秒。
2.RISCV-UART 特性
E203支持两个串口模块,分别位UART0和UART1。这两个模块基本相同。
- 支持发送和接受数据能力。
- 支持8-n-1和8-n-2的数据传输格式:即8位数据位,没有奇偶校验位,一位起始位和1(2)位停止位。
- 支持8个深度的发送和接受FIFO缓存,同时支持软件可编程的阈值。
- 在接受端(Rx),采用 16倍波特率的采样频率采样接受数据线,并且对于前后连续三次的采样结果进行判断,选择最多数的数值作为采样结果。
这一段是照搬《RISC-V架构与嵌入式快速开发入门》中关于UART的介绍,因蜂鸟E203的UART是有别的语言转到Verilog的,里面混杂了巨量的寄存器,我实在看不懂,理不清,就直接照搬了。
3.ASCII
ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符.
UART串口通信在传输字母时,采用ASCII编码将其转化成01信号进行传输。
4. 程序设计
顶层模块
module uart_test(
//Differential system clocks
input sys_clk_p,
input sys_clk_n,
input rst_n,
input uart_rx,
output uart_tx
);
parameter CLK_FRE = 200;//Mhz
localparam IDLE = 0;
localparam SEND = 1; //send HELLO ALINX\r\n
localparam WAIT = 2; //wait 1 second and send uart received data
reg[7:0] tx_data;
reg[7:0] tx_str;
reg tx_data_valid;
wire tx_data_ready;
reg[7:0] tx_cnt;
wire[7:0] rx_data;
wire rx_data_valid;
wire rx_data_ready;
reg[31:0] wait_cnt;
reg[3:0] state;
wire sys_clk;
IBUFDS sys_clk_ibufgds
(
.O (sys_clk ),
.I (sys_clk_p ),
.IB (sys_clk_n )
);
assign rx_data_ready = 1'b1;//always can receive data,
//if HELLO ALINX\r\n is being sent, the received data is discarded
always@(posedge sys_clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
wait_cnt <= 32'd0;
tx_data <= 8'd0;
state <= IDLE;
tx_cnt <= 8'd0;
tx_data_valid <= 1'b0;
end
else
case(state)
IDLE:
state <= SEND;
SEND:
begin
wait_cnt <= 32'd0;
tx_data <= tx_str;
if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1 && tx_cnt < 8'd12)//Send 12 bytes data
begin
tx_cnt <= tx_cnt + 8'd1; //Send data counter
end
else if(tx_data_valid && tx_data_ready)//last byte sent is complete
begin
tx_cnt <= 8'd0;
tx_data_valid <= 1'b0;
state <= WAIT;
end
else if(~tx_data_valid)
begin
tx_data_valid <= 1'b1;
end
end
WAIT:
begin
wait_cnt <= wait_cnt + 32'd1;
if(rx_data_valid == 1'b1