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;
end
1: begin
count_preload <= 8;
end
2: begin
count_preload <= 9;
end
3: begin
count_preload <= 10;
end
endcase
end
end
// 计数
always @(posedge SysClk or posedge ResetCounter)
if(ResetCounter) count <= 4'b0;
else begin
if(Increment) begin
if(count == count_preload) count <= 4'b0;
else count <= count + 1'b1;
end
else count <= count;
end
// 产生Count10
always @(posedge SysClk or posedge ResetCounter)
if(ResetCounter) Count_finish <= 1'b0;
else begin
if(count == count_preload) Count_finish <= 1'b1;
else Count_finish <= 1'b0;
end
endmodule
(3)奇偶校验
module Parity_Generator(
input [7:0] Din,
input ParitySelect,
output ParityBit
);
assign ParityBit = ParitySelect?(~(^Din)):(^Din);//ParitySelect=1,偶校验;ParitySelect=0,奇校验
//^按位异或
endmodule
(4)移位模块
module Shift_Register(
input SysClk,
input rst_n,
input [7:0] Din,
input [1:0] mode, //模式选择 5-8位情况 0-5 1-6 2-7 3-8
input Shift,
input Load,
input ParityBit,//æ ¡éªŒä½?
output wire Dout
);
wire Start_bit;//èµ·å§‹ä½?
wire Stop_bit; //åœæ¢ä½?
assign Start_bit = 1'b0;
assign Stop_bit = 1'b1;
reg [10:0] Data_Pack;//ä¸?帧数æ?
// æ•°æ®ç§»ä½
always @(posedge SysClk or negedge rst_n)
if(!rst_n) begin
Data_Pack <= 10'b1111111111; //复位值全为1,避免误触发
end
else begin
if(Load == 1'b1) begin
case (mode)
0: begin
Data_Pack <= {3'b111,Stop_bit,ParityBit,Din[4:0],Start_bit};
end
1: begin
Data_Pack <= {2'b11,Stop_bit,ParityBit,Din[5:0],Start_bit};
end
2: begin
Data_Pack <= {1'b1,Stop_bit,ParityBit,Din[6:0],Start_bit};
end
3: begin
Data_Pack <= {Stop_bit,ParityBit,Din[7:0],Start_bit};
end
endcase
end
else if(Shift == 1'b1) begin
Data_Pack <= {1'b1,Data_Pack[9:1]};
end
else Data_Pack <= Data_Pack;
end
// æ•°æ®è¾“出
assign Dout = (!rst_n)?1'b1:Data_Pack[0];
endmodule
(5)时钟模块
//输入50MHZ
//preload 5207 3471 2603 1301
//波特率 9600 14400 19200 38400
module Timer_300Hz(
input SysClk,//50MHz
input ResetTimer,//高电平有效
input [13:0] preload,
output reg NextBit
);
reg [13:0] count;
// assign preload = 3;//1MHz--->300Hz,每隔333个系统时钟周期发送一次NextBit
//计数
always @(posedge SysClk or posedge ResetTimer)
if(ResetTimer) count <= 14'b0;
else begin
if(count == preload) count <= 14'b0;
else count <= count + 1'b1;
end
// 产生NestBit
always @(posedge SysClk or posedge ResetTimer)
if(ResetTimer) NextBit <= 1'b0;
else begin
if(count == preload) NextBit <= 1'b1;
else NextBit <= 1'b0;
end
endmodule
6.接收模块的代码
(1)状态转移
module RSM(
input SysClk,
input rst_n,
input Start_rx,
input NextBit,
input Count_finish,
output reg Busy,
output reg ResetTimer,
output reg Increment,
output reg ResetCounter,
output reg Shift
);
//-----------------------------------
//状态变量、状态编码(初始值为0的独热码)
//-----------------------------------
reg [3:0]CS,NS;//CS:当前状态;NS:下一状态
parameter [3:0]
IDLE = 4'b0000,
COUNT = 4'b0001,
SHIFT = 4'b0010,
Finish = 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 Start_rx or NextBit or Count_finish)//敏感列表中为复位信号、当前状态和输入条件
begin
NS = 4'bx;//默认状态为不定态X
case(CS)//敏感列表为当前状态
IDLE: begin
if(!Start_rx) NS = IDLE;
if(Start_rx) NS = COUNT;
end
COUNT: begin
if(!NextBit) NS = COUNT;
if(NextBit) NS = SHIFT;
end
SHIFT: begin
if(!Count_finish) NS = COUNT;
if(Count_finish) NS = Finish;
end
Finish: begin
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;//复位信号高有效
Shift <= 1'b0;
Busy <= 1'b0;
Increment <= 1'b0;
end
else begin
case(NS)//敏感列表为下一状态
IDLE: begin
ResetCounter <= 1'b1;
ResetTimer <= 1'b1;
Shift <= 1'b0;
Busy <= 1'b0;
Increment <= 1'b0;
end
COUNT: begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;
Shift <= 1'b0;
Busy <= 1'b1;
Increment <= 1'b0;
end
SHIFT: begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;
Shift <= 1'b1;
Busy <= 1'b1;
Increment <= 1'b1;
end
Finish: begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;
Shift <= 1'b0;
Busy <= 1'b0;
Increment <= 1'b0;
end
default:begin
ResetCounter <= 1'b0;
ResetTimer <= 1'b0;
Shift <= 1'b0;
Busy <= 1'b0;
Increment <= 1'b0;
end
endcase
end
endmodule
(2)移位模块
module Shift_Register_rx(
input Sysclk,
// input [8:0] D_in,
input rst_n,
input Shift,
input Count_finish,
input ParitySelect,
input [1:0] mode,
input rx_bit,
output [7:0] D_out,
output D_out_valid,
output ParityBit,
output error
);
wire Sysclk;
reg [10:0] reg_D_out;
reg [7:0] reg_D_data;
reg Shift_1;
reg ParityBit;
wire error;
reg D_out_valid;
//将shift信号延迟一个周期
always @(posedge Sysclk or negedge rst_n) begin
if(~rst_n) begin
Shift_1 <= 0;
end else begin
Shift_1 <= Shift;
end
end
// 数据移位
always @(posedge Sysclk or negedge rst_n)
if(!rst_n) begin
reg_D_out <= {11{1'b0}};
end
else begin
if(Shift == 1'b1) begin
reg_D_out <= {rx_bit,reg_D_out[10:1]};
end
else reg_D_out <= reg_D_out;
end
always @(posedge Sysclk or negedge rst_n) begin
if(~rst_n) begin
reg_D_data <= 0;
ParityBit <= 0;
D_out_valid <=0 ;
end else begin
if( Shift_1 & Count_finish) begin
case (mode)
0: begin
reg_D_data <= {3'b0,reg_D_out[8:4]};
ParityBit <= reg_D_out[9];
end
1: begin
reg_D_data <= {2'b0,reg_D_out[8:3]};
ParityBit <= reg_D_out[9];
end
2: begin
reg_D_data <= {1'b0,reg_D_out[8:2]};
ParityBit <= reg_D_out[9];
end
3: begin
reg_D_data <= reg_D_out[8:1];
ParityBit <= reg_D_out[9];
end
endcase
D_out_valid <= 1;
end
else
D_out_valid <= 0;
end
end
assign error = D_out_valid?(ParityBit^(ParitySelect?(~(^reg_D_data)):(^reg_D_data))):0;
assign D_out = reg_D_data;
endmodule
(3)时钟模块
//输入50MHZ
//preload 5207 3471 2603 1301
//波特率 9600 14400 19200 38400
module Timer_rx(
input SysClk,//50MHz
input ResetTimer,//高电平有效
input [13:0] preload,
output reg NextBit
);
reg [13:0] count;
// assign preload = 3;//1MHz--->300Hz,每隔333个系统时钟周期发送一次NextBit
//计数
always @(posedge SysClk or posedge ResetTimer)
if(ResetTimer) count <= 14'b0;
else begin
if(count == preload) count <= 14'b0;
else count <= count + 1'b1;
end
// 产生NestBit
always @(posedge SysClk or posedge ResetTimer)
if(ResetTimer) NextBit <= 1'b0;
else begin
if(count == preload/2) NextBit <= 1'b1;
else NextBit <= 1'b0;
end
endmodule
(4)计数模块
module Mod_Counter_rx(
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;
end
1: begin
count_preload <= 8;
end
2: begin
count_preload <= 9;
end
3: begin
count_preload <= 10;
end
endcase
end
end
// 计数
always @(posedge SysClk or posedge ResetCounter)
if(ResetCounter) count <= 4'b0;
else begin
if(Increment) begin
if(count == count_preload) count <= 4'b0;
else count <= count + 1'b1;
end
else count <= count;
end
// 产生Count10
always @(posedge SysClk or posedge ResetCounter)
if(ResetCounter) Count_finish <= 1'b0;
else begin
if(count == count_preload) Count_finish <= 1'b1;
else Count_finish <= 1'b0;
end
endmodule
7.整体的UART模块
(1)发送的APB模块
// Programmer's model
// 0x00 DATA R RXD[7:0] Received Data
// DATA W TXD[7:0] Transmit data
module apb_uart(
input [7:0] Din,
input Send,
input SysClk,
input rst_n,
input [1:0] mode,
input [13:0] preload,
input ParitySelect,
output Busy,
output Dout
);
wire SysClk,Send,ParitySelect,rst_n,NextBit;
wire [7:0] Din;
wire [13:0] preload;
reg [7:0] Din_inside;
always @(posedge SysClk or negedge rst_n) begin
if(~rst_n) begin
Din_inside <= 0;
end else begin
case (mode)
0: begin
Din_inside <= {3'b000,Din[4:0]};
end
1: begin
Din_inside <= {2'b00,Din[5:0]};
end
2: begin
Din_inside <= {1'b0,Din[6:0]};
end
3: begin
Din_inside <= {Din[7:0]};
end
endcase
end
end
Mod10_Counter inst_Mod10_Counter
(
.SysClk (SysClk),
.ResetCounter (ResetCounter),
.Increment (Increment),
.mode (mode),
.Count_finish (Count_finish)
);
Timer_300Hz inst_Timer_300Hz (.SysClk(SysClk), .ResetTimer(ResetTimer), .preload(preload),.NextBit(NextBit));
Parity_Generator inst_Parity_Generator (.Din(Din_inside), .ParitySelect(ParitySelect), .ParityBit(ParityBit));
Shift_Register inst_Shift_Register
(
.SysClk (SysClk),
.rst_n (rst_n),
.Din (Din_inside),
.mode (mode),
.Shift (Shift),
.Load (Load),
.ParityBit (ParityBit),
.Dout (Dout)
);
FSM inst_FSM (
.SysClk (SysClk),
.rst_n (rst_n),
.Send (Send),
.NextBit (NextBit),
.Count_finish (Count_finish),
.Busy (Busy),
.ResetTimer (ResetTimer),
.Increment (Increment),
.ResetCounter (ResetCounter),
.Shift (Shift),
.Load (Load)
);
endmodule
(2)接收的APB模块
// Programmer's model
// 0x00 DATA R RXD[7:0] Received Data
// DATA W TXD[7:0] Transmit data
module apb_uart_rx(
input Din,
input SysClk,
input rst_n,
input [1:0] mode,
input [13:0] preload,
input ParitySelect,
output Busy,
output error,
output D_out_valid,
output [7:0] D_out
);
wire ParitySelect,rst_n,NextBit;
wire [1:0] mode;
wire Din,error;
reg Din_1;
reg Din_2; //两级同步后的数据
reg Din_3;
wire Start_rx;
wire [13:0] preload;
wire [7:0] D_out;
//为避免亚稳态,使用两级同步
always @(posedge SysClk or negedge rst_n) begin
if(~rst_n) begin
Din_1 <= 0;
Din_2 <= 0;
Din_3 <= 0;
end else begin
Din_1 <= Din;
Din_2 <= Din_1;
Din_3 <= Din_2;
end
end
//取Din的下降沿信号
assign Start_rx = (~Din_2)&Din_3 ;
Mod_Counter_rx inst_Mod_Counter_rx
(
.SysClk (SysClk),
.ResetCounter (ResetCounter),
.Increment (Increment),
.mode (mode),
.Count_finish (Count_finish)
);
Timer_rx inst_Timer_rx (.SysClk(SysClk), .ResetTimer(ResetTimer), .preload(preload),.NextBit(NextBit));
Shift_Register_rx inst_Shift_Register_rx
(
.Sysclk (SysClk),
.rst_n (rst_n),
.mode (mode),
.rx_bit (Din_2),
.Count_finish (Count_finish),
.ParitySelect (ParitySelect),
.ParityBit (ParityBit),
.Shift (Shift),
.D_out_valid (D_out_valid),
.error (error),
.D_out (D_out)
);
RSM inst_RSM (
.SysClk (SysClk),
.rst_n (rst_n),
.Start_rx (Start_rx),
.NextBit (NextBit),
.Count_finish (Count_finish),
.Busy (Busy),
.ResetTimer (ResetTimer),
.Increment (Increment),
.ResetCounter (ResetCounter),
.Shift (Shift)
);
endmodule
(2)整个模块
`timescale 1ns/1ns
//定义寄存器的地址
//`define reg_enable 8'h00
//`define reg_mode 8'h04
//`define reg_preload 8'h08
//`define reg_counter 8'h0c
module apb_uart_tx_rx(
input PCLK, //时钟
input PRESETn, //复位
input [15:0] PADDR, //地址信号
input PWRITE, //控制信号 1:写 0:读
input [31:0] PWDATA, //写数据
input PENABLE, //使能信号
input PSEL, //片选信号
input RXD,
output [31:0] PRDATA, //读数据
output TXD,
output wire PREADY, // Device ready
output wire PSLVERR, // Device error response
output uart_intr //中断输出
);
assign PREADY = 1'b1; // Always ready
assign PSLVERR = 1'b0; // Always okay
reg Send_reg;
reg [1:0] mode_reg;
reg ParitySelect_reg;
reg [7:0] Din_reg;
reg [13:0] preload_reg;
reg [31:0] prdata_r;
wire Busy_rx;
wire [7:0] D_out_reg;
//// 写寄存器 //////////
always @(posedge PCLK or negedge PRESETn) begin
if(~PRESETn) begin
Send_reg <= 0;
mode_reg <= 0;
preload_reg <= 0;
ParitySelect_reg <= 0;
Din_reg <= 0;
end
else if(PSEL && PENABLE && PWRITE)
case (PADDR[4:2])
3'b000: Send_reg <= PWDATA[0];
3'b001: mode_reg <= PWDATA[1:0];
3'b010: preload_reg <= PWDATA[13:0];
3'b011: ParitySelect_reg <= PWDATA[0];
3'b100: Din_reg <= PWDATA[7:0];
default : begin
Send_reg <= 0;
mode_reg <= 0;
preload_reg <= 0;
ParitySelect_reg <= 0;
Din_reg <= 0;
end
endcase
end
//// 读寄存器 //////////
always @(posedge PCLK or negedge PRESETn) begin
if(~PRESETn) begin
prdata_r <= 32'b0;
end
else if(PSEL && !PENABLE && !PWRITE)
case (PADDR[4:2])
3'b000: prdata_r <= {31'b0,Send_reg};
3'b001: prdata_r <= {30'b0,mode_reg};
3'b010: prdata_r <= {18'b0,preload_reg};
3'b011: prdata_r <= {31'b0,Busy_reg};
3'b100: prdata_r <= {31'b0,Busy_rx};
3'b101: prdata_r <= {31'b0,D_out_valid};
3'b110: prdata_r <= {24'b0,D_out_reg};
default : begin
prdata_r <= 32'b0;
end
endcase
end
assign PRDATA = prdata_r;
apb_uart inst_apb_uart_tx
(
.Din (Din_reg),
.Send (Send_reg),
.SysClk (PCLK),
.rst_n (PRESETn),
.mode (mode_reg),
.preload (preload_reg),
.ParitySelect (ParitySelect_reg),
.Busy (Busy_reg),
.Dout (TXD)
);
apb_uart_rx inst_apb_uart_rx
(
.Din (RXD),
.SysClk (PCLK),
.rst_n (PRESETn),
.mode (mode_reg),
.preload (preload_reg),
.ParitySelect (ParitySelect_reg),
.Busy (Busy_rx),
.error (error),
.D_out_valid (D_out_valid),
.D_out (D_out_reg)
);
endmodule
本文详细介绍了UART通信协议,包括硬件连接、软件通信协议,并提供了STM32的发送和接收模块介绍及代码示例,涵盖了时钟、计数、奇偶校验和移位寄存器等内容。
&spm=1001.2101.3001.5002&articleId=120019026&d=1&t=3&u=f2ff87de78164cf9bd815cc0aae1f714)
4837
&spm=1001.2101.3001.11663&articleId=120019026&d=1&t=3&u=0faa6348b52c41669e835e4bdc28a107)

被折叠的 条评论
为什么被折叠?



