串行通信是指外部設備與計算機間只使用一根資料線(另外需要地線,還可能需要控制線)進行資料傳送的方式,資料在一根資料線上按位依次傳送,由于CPU與介面之間按并行方式傳輸,介面與外設之間按串行方式傳輸,因此串行通信的基本功能是:在發送時,把CPU送來的并行資料轉換為串行資料,逐位依次發送出去;在接受時,把外部設備發送過來的的串行資料逐位地接受,組裝成并行資料,并行地送給CPU去處理,
異步通信是以一個字符作為傳輸方式,通信中兩個字符間的時間間隔多少不固定,但同一個字符的兩個相鄰位的時間間隔固定,通信程序中沒有時鐘線,
UART使用的是串行異步通信,
基本的UART通信協議:

波特率:表示每秒鐘傳輸字符數的多少
起始位:一般為邏輯“0”
資料位:一般位6~8位之間可變,資料低位在前,高位在后
校驗位:可以為無校驗位,奇校驗,偶校驗,常“0”或常“1”之間可選
停止位:必須為邏輯“1”
空閑位:處于邏輯“1”狀態
UART發送功能模塊:
`define NONE 0 //無校驗位
`define ODD 1 //奇校驗
`define EVEN 2 //偶校驗
`define MARK 3 //常“1”
`define SPACE 4 //常“0”
`define STOPBITS_ONE 0 //1位停止位
`define STOPBITS_ONEHALF 1 //1.5位停止位
`define STOPBITS_TWO 2 //2位停止位
module uart_tx #(
parameter CLK_FREQ = 50_000_000, //時鐘頻率
parameter BPS = 9600, //波特率
parameter PARITY = `NONE, //資料位寬
parameter DATA_BITS = 8, //校驗位
parameter STOP_BITS = `STOPBITS_ONE //停止位位寬
)
(
input clk,
input rst_n,
input [DATA_BITS-1:0] data,
input enable, //定義一個發送使能信號
output reg tx,
output wire free //定義一個發送端空閑狀態
);
reg [DATA_BITS-1:0] data_2 = 0;
reg flag = 0; //定義一個flag信號來鎖住enable
wire stop_flag; //定義一個傳輸停止脈沖
reg [31:0] cnt = 0;
localparam [31:0] CNT_MAX = CLK_FREQ/BPS;
reg [2:0] cstate = 0;
localparam [2:0]
FSM_IDEL = 0, //空閑位
FSM_START = 1, //開始位
FSM_DATA = 2, //資料位
FSM_PARITY = 3, //校驗位
FSM_STOP = 4; //停止位
reg ifparity = 0; //有無校驗位
reg parity_value = 0; //校驗位的值
reg [3:0] num = 0; //定義一個計數num
assign free = ~flag;
assign stop_flag = (cstate == FSM_STOP && ((STOP_BITS == `STOPBITS_ONE && cnt == CNT_MAX-1) || (STOP_BITS == `STOPBITS_ONEHALF && num == 1 && cnt == CNT_MAX>>1) || (STOP_BITS == `STOPBITS_TWO && num == 1 && cnt == CNT_MAX-1))) ? 1'b1 : 1'b0;
always @(posedge clk or negedge rst_n)
if (!rst_n)
data_2 <= 0;
else if (enable && flag == 0)
data_2 <= data;
else data_2 <= data_2;
always @(posedge clk or negedge rst_n)
if (!rst_n)
flag <= 0;
else if (enable)
flag <= 1;
else if (stop_flag)
flag <= 0;
else flag <= flag;
always @(posedge clk or negedge rst_n)
if (!rst_n)
cnt <= 0;
else if (cnt == CNT_MAX-1 || flag == 0 )
cnt <= 0;
else if (flag)
cnt <= cnt + 1;
else cnt <= cnt;
always @(posedge clk or negedge rst_n)
if (!rst_n)
cstate <= FSM_IDEL;
else case (cstate)
FSM_IDEL : begin
tx <= 1;
if (flag)
cstate <= FSM_START;
else cstate <= FSM_IDEL;
end
FSM_START : begin
tx <= 0;
if (cnt == CNT_MAX-1)
cstate <= FSM_DATA;
else cstate <= FSM_START;
end
FSM_DATA : begin
tx <= data_2 [num];
if (cnt == CNT_MAX-1 && num == DATA_BITS-1)
begin
num <= 0;
cstate <= ifparity ? FSM_PARITY : FSM_STOP;
end
else if (cnt == CNT_MAX-1)
num <= num + 1;
else num <= num;
end
FSM_PARITY : begin
tx <= parity_value;
if (cnt == CNT_MAX-1)
cstate <= FSM_STOP;
else cstate <= FSM_PARITY;
end
FSM_STOP : begin
tx <= 1;
if (STOP_BITS == `STOPBITS_ONE && cnt == CNT_MAX-1)
cstate <= FSM_IDEL;
else if (STOP_BITS == `STOPBITS_ONEHALF) begin
if (num == 1 && cnt == CNT_MAX>>1)
begin cstate <= FSM_IDEL; num <= 0; end
else if (cnt == CNT_MAX-1)
num <=1;
else cstate <= FSM_STOP;
end
else if (STOP_BITS == `STOPBITS_TWO) begin
if (num == 1 && cnt == CNT_MAX-1)
begin cstate <= FSM_IDEL; num <= 0; end
else if (cnt == CNT_MAX-1)
num <=1;
else cstate <= FSM_STOP;
end
end
default : cstate <= FSM_IDEL;
endcase
always @(*)
if (!rst_n)
begin
ifparity = 0;
parity_value = 0;
end
else case (PARITY)
`NONE : begin
ifparity = 0;
parity_value = 0;
end
`ODD : begin
ifparity = 1;
parity_value = ~(^data_2);
end
`EVEN : begin
ifparity = 1;
parity_value = ^data_2;
end
`MARK : begin
ifparity = 1;
parity_value = 1;
end
`SPACE : begin
ifparity = 1;
parity_value = 0;
end
default : begin
ifparity = 0;
parity_value = 0;
end
endcase
UART接收功能模塊:
`define NONE 0 //無校驗位
`define ODD 1 //奇校驗
`define EVEN 2 //偶校驗
`define MARK 3 //常"1"
`define SPACE 4 //常"0"
`define STOPBITS_ONE 0 //1位停止位
`define STOPBITS_ONEHALF 1 //1.5位停止位
`define STOPBITS_TWO 2 //2位停止位
module uart_rx #(
parameter BPS = 9600, //波特率
parameter CLK_FREQ = 50_000_000, //時鐘頻率
parameter DATA_BITS = 8, //資料位寬
parameter PARITY = `NONE, //校驗位
parameter STOP_BITS = `STOPBITS_ONE //停止位位寬
)
(
input clk,
input rst_n,
input rx,
output reg [DATA_BITS-1:0] data,
output reg done,
output reg err
);
reg [1:0] in;
always @(posedge clk or negedge rst_n)
if (!rst_n)
in <= 0;
else in <= {in[0],rx};
wire en;
assign en = (in[1] == 1 && in[0] == 0) ? 1 : 0;
reg flag = 0; //定義一個接收信號標志位
always @(posedge clk or negedge rst_n)
if (!rst_n)
flag <= 0;
else if (en)
flag <= 1;
else if (cstate == FSM_STOP && sampling)
flag <= 0;
else flag <= flag;
reg [31:0] cnt = 0;
localparam [31:0] CNT_MAX = CLK_FREQ/BPS;
always @(posedge clk or negedge rst_n)
if (!rst_n)
cnt <= 0;
else if (cnt == CNT_MAX-1 || flag == 0)
cnt <= 0;
else if (flag)
cnt <= cnt + 1;
else cnt <= cnt;
reg sampling = 0; //定義一個采樣脈沖信號
always @(posedge clk or negedge rst_n)
if (!rst_n)
sampling = 0;
else if (cnt == CNT_MAX>>1)
sampling = 1;
else sampling = 0;
reg [3:0] num = 0; //定位計數num
reg ifparity = 0; //有無校驗位
reg parity_value = 0; //定義校驗位的值
reg parity_rx = 0; //定義接受信號中校驗位的值
reg [2:0] cstate = 0;
localparam [2:0]
FSM_IDEL = 0, //空閑位
FSM_START = 1, //開始位
FSM_DATA = 2, //資料位
FSM_PARITY = 3, //校驗位
FSM_STOP = 4; //停止位
always @(posedge clk or negedge rst_n)
if (!rst_n) begin
cstate <= FSM_IDEL;
parity_rx <= 0;
done <= 0;
err <= 0;
data <= 0;
num <= 0;
end
else case (cstate)
FSM_IDEL : if (flag)
cstate <= FSM_START;
else cstate <= FSM_IDEL;
FSM_START : begin
done <= 0;
if (sampling)
cstate <= FSM_DATA;
else cstate <= FSM_START;
end
FSM_DATA : if (sampling && num <= DATA_BITS-1)
begin
data[num] <= rx;
num <= num + 1;
end
else if (num == DATA_BITS) begin
num <= 0;
cstate <= ifparity ? FSM_PARITY : FSM_STOP ;
end
FSM_PARITY : if (sampling)
begin
parity_rx <= rx;
cstate <= FSM_STOP;
end
else cstate <= FSM_PARITY;
FSM_STOP : if (sampling)
begin
done <= 1;
cstate <= FSM_IDEL;
err <= ifparity ? (parity_rx == parity_value ? 0 : 1) : 0;
end
else cstate <= FSM_STOP;
default : begin
cstate <= FSM_IDEL;
parity_rx <= 0;
done <= 0;
err <= 0;
end
endcase
always @(*)
if (!rst_n) begin
ifparity = 0;
parity_value = 0;
end
else case (PARITY)
`NONE : begin ifparity = 0; parity_value = 0; end
`ODD : begin ifparity = 1; parity_value = ~(^data); end
`EVEN : begin ifparity = 1; parity_value = ^data; end
`MARK : begin ifparity = 1; parity_value = 1; end
`SPACE : begin ifparity = 1; parity_value = 0; end
default : begin ifparity = 0; parity_value = 0; end
endcase
endmodule
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/231513.html
標籤:其他
