UART
通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART。它将要传输的资料在串行通信与并行通信之间加以转换。作为把并行输入信号转成串行输出信号的芯片,UART通常被集成于其他通讯接口的连结上。
本文详细文档和完整的代码会在后面文章以文档的形式发出来
1. 硬件连接
硬件连接比较简单,仅需要3条线,注意连接时两个设备UART电平,如电平范围不一致请做电平转换后再连接,如下图所示:
TX:发送数据端,要接对面设备的RX
RX:接收数据端,要接对面设备的TX
GND:保证两设备共地,有统一的参考平面
2. 软件通信协议
空闲位:
UART协议规定,当总线处于空闲状态时信号线的状态为‘1’即高电平
起始位:
开始进行数据传输时发送方要先发出一个低电平’0’来表示传输字符的开始。因为空闲位一直是高电平所以开始第一次通讯时先发送一个明显区别于空闲状态的信号即为低电平。
数据位:
起始位之后就是要传输的数据,数据可以是5,6,7,8,9位,构成一个字符,一般都是8位。先发送最低位最后发送最高位。
奇偶校验位:
数据位传送完成后,要进行奇偶校验,校验位其实是调整个数,串口校验分几种方式:
1.无校验(no parity)
2.奇校验(odd parity):如果数据位中’1’的数目是偶数,则校验位为’1’,如果’1’的数目是奇数,校验位为’0’。
3.偶校验(even parity):如果数据为中’1’的数目是偶数,则校验位为’0’,如果为奇数,校验位为’1’。
4.mark parity:校验位始终为1
5.space parity:校验位始终为0
停止位:
数据结束标志,可以是1位,1.5位,2位的高电平。
波特率:
数据传输速率使用波特率来表示,单位bps(bits per second),常见的波特率9600bps,115200bps等等,其他标准的波特率是1200,2400,4800,19200,38400,57600。举个例子,如果串口波特率设置为9600bps,那么传输一个比特需要的时间是1/9600≈104.2us。
3. 发送具体模块介绍
(1)发送的框图:
(2)发送的状态转移图:
(3)时钟产生模块:
(4)计数器模块:
(5)奇偶校验模块:
(6)移位寄存器模块:
4.接收具体模块介绍:
(1)接收模块的框图:
(2)接收模块的状态转移图:
5.发送模块的代码
(1)状态机代码
module FSM(
input SysClk,
input rst_n,
input Send,
input NextBit,
input Count_finish,
output reg Busy,
output reg ResetTimer,
output reg Increment,
output reg ResetCounter,
output reg Shift,
output reg Load
);
//-----------------------------------
//状态变量、状态编码(初始值为0的独热码)
//-----------------------------------
reg [3:0]CS,NS;//CS:当前状态;NS:下一状态
parameter [3:0]
IDLE = 4'b0000,
LOAD = 4'b0001,
COUNT = 4'b0010,
SHIFT = 4'b0100,
WAIT = 4'b1000;
//-----------------------------------
//时序逻辑描述状态转移
//-----------------------------------
always @(posedge SysClk or negedge rst_n)
if(!rst_n) CS <= IDLE;
else CS <= NS;
//-----------------------------------
//组合逻辑判断状态转移条件,描述状态转移规律
//-----------------------------------
always @(rst_n or CS or Send or NextBit or Count_finish)//敏感列表中为复位信号、当前状态和输入条件
begin
NS = 4'bx;//默认状态为不定态X
case(CS)//敏感列表为当前状态
IDLE: begin
if(!Send) NS = IDLE;
if(Send) NS = LOAD;
end
LOAD: NS = COUNT;
COUNT: begin
if(!NextBit) NS = COUNT;
if(NextBit) NS = SHIFT;
end
SHIFT: begin
if(!Count_finish) NS = COUNT;
if(Count_finish) NS = WAIT;
end
WAIT: begin
if(Send) NS = WAIT;
if(!Send) NS = IDLE;
end
default: NS = IDLE;
endcase
end
//-----------------------------------
//时序逻辑描述每个状态的输出
//-----------------------------------
always @(posedge SysClk or negedge rst_n)
if(!rst_n) begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;//复位信号高有效
Load <= 1'b0;
Shift <= 1'b0;
Busy <= 1'b0;
Increment <= 1'b0;
end
else begin
case(NS)//敏感列表为下一状态
IDLE: begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;
Load <= 1'b0;
Shift <= 1'b0;
Busy <= 1'b0;
Increment <= 1'b0;
end
LOAD: begin
ResetCounter <= 1'b1;
ResetTimer <= 1'b1;
Load <= 1'b1;
Shift <= 1'b0;
Busy <= 1'b1;
Increment <= 1'b0;
end
COUNT: begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;
Load <= 1'b0;
Shift <= 1'b0;
Busy <= 1'b1;
Increment <= 1'b0;
end
SHIFT: begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;
Load <= 1'b0;
Shift <= 1'b1;
Busy <= 1'b1;
Increment <= 1'b1;
end
WAIT: begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;
Load <= 1'b0;
Shift <= 1'b0;
Busy <= 1'b0;
Increment <= 1'b0;
end
default:begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;
Load <= 1'b0;
Shift <= 1'b0;
Busy <= 1'b0;
Increment <= 1'b0;
end
endcase
end
endmodule
(2)计数器模块:
module Mod10_Counter(
input SysClk,
input ResetCounter,//高电平有效
input Increment,
input [1:0] mode,
output reg Count_finish
);
reg [3:0] count;
reg [3:0] count_preload;
// 模式选择
always @(posedge SysClk or negedge ResetCounter) begin
if(ResetCounter) begin
count_preload <= 0;
end else begin
case (mode)
0: begin
count_preload <= 7;<