一,UART是什麼?
來自百度百科:https://baike.baidu.com/item/UART/4429746
二,UART通信協議
(1)UART傳輸速度
UART作爲異步串行通信接口,也就是說,它的數據傳輸不需要時鐘,只要兩條信號線分別進行數據收發。收發雙方只需要約定好數據傳輸的速度和幀格式,就能保證數據收發的準確性。簡單的講就是約定好一個數據位傳輸的時間和一個數據的長短。
UART的數據傳輸速度是用波特率來描述的,即每秒鐘傳輸的數據位,例如1000波特率表示每秒鐘傳輸1000比特的數據,或者說每個數據位持續1毫秒。波特率不是隨意的,必須服從一定的標準,如果希望設計123456波特率的RS-232接口,是不行的。常用的串行傳輸速率值包括以下幾種:1200bps,9600bps,38400bps,115200bps等、在115200bps下,每位數據持續(1/114200)=8.68us.如果傳輸8位數據,共持續8*8.68us=69.44us。但是每個字節的傳輸又要求額外的“開始位”和“停止位”,所以實際上需要10*8.68us=86.8us的時間。因此最大的有效數據傳輸率只有達到11.5KBytes每秒。
(2)UART的幀格式
通過該圖,我們可以看出, 它是由1個起始位(必須爲0),8個數據位(用戶數據),1個奇偶校驗位(用於簡單地糾錯保證傳輸可靠性)和1或2個停止位(必須爲1)組成。除了奇偶校驗位,其他3個部分都是必須的。通過這個UART幀格式圖我們可以知道,UART的通信是十分簡單的,它是以低電平作爲起始位,高電平作爲停止位,中間可傳輸5~8比特數據和1比特奇偶校驗位,奇偶校驗位的有無和數據比特的長度由通信雙方約定。發送端發送數據時先發一低電平,然後發送8比特數據,之後馬上把信號拉高,從而完成一幀數據傳送。接收端收到低電平開始計數,然後接受8比特信息位後如果檢測到高電平即認爲已接受完一幀數據,繼續等待下一幀起始信號低電平的到來,若接受完8比特數據後沒有檢測到高電平則認爲這不是一幀有效數據,將其丟棄,繼續等待起始信號。收發可同時進行,互不干擾。一幀數據傳輸完畢後可以繼續傳輸下一幀數據,也可以繼續保持爲高電平。兩幀之間保持高電平,持續時間可以任意長。
(3)UART協議使用。
發送0-9這十個數字來控制蜂鳴器的發聲。
1,功能模塊圖
(2)verilog代碼:
//波特率產生採樣信號模塊
module Uart_Bps_Module
(
//輸入端口
CLK_50M,RST_N,bps_start,
//輸出端口
bps_flag
);
input CLK_50M;
input RST_N;
input bps_start; //接受和發送端口的波特率時鐘啓動信號
output bps_flag; //接受數據位的中間採樣點,發送數據的數據改變點
reg [12:0] time_cnt;
reg [12:0] time_cnt_n;
reg bps_flag;
reg bps_flag_n;
//波特率爲115200,一位週期爲1/115200=8.69us,8.68/(1/50)=434
parameter BPS_PARA=9'd434;
parameter BPS_PARA_2=8'd217;//中間採樣
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
time_cnt<=13'b0;
else
time_cnt<=time_cnt_n;
end
always @ (*)
begin
if((time_cnt==BPS_PARA)||(!bps_start))
time_cnt_n=1'b0;
else
time_cnt_n=time_cnt+1'b1;
end
alwways @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
bps_flag<=1'b0;
else
bps_flag<=bps_flag_n;
end
always @ (*)
begin
if(time_cnt==BPS_PARA_2)
bps_flag_n=1'b1;//採樣標誌
else
bps_flag_n=1'b0;
end
endmodule
//UART解析模塊
module Uart_Rx_Module
(
//input
CLK_50M,RST_N,UART_RX,rx_bps_flag,
//output
out_rx_data,rx_bps_start
);
input CLK_50M;
input RST_N;
input UART_RX;//FPGA的接受端口,串口cp2102的發送端口
input rx_bps_flag;
output rx_bps_start; //接受端口的波特率時鐘啓動信號
output [7:0] out_rx_data;//解析完成的數據
reg [1:0] detect_edge;//下降沿
wire [1:0] detect_edge_n;
reg negedge_reg;//下降沿標誌
wire negedge_reg_n;
reg rx_bps_start;
reg rx_bps_start_n;
reg [3:0] bit_cnt;//記錄接受數據位
reg [3:0] bit_cnt_n;
reg [7:0] shift_data;//接受串行數據流中用到的移位寄存器
reg [7:0] shift_data_n;
reg [7:0] out_rx_data;//從UART_RX數據線中解析完後的數據
reg [7:0] out_rx_data_n;
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
detect_edge<=2'b11;
else
detect_edge<=detect_edge_n;
end
//接受uart_rx信號
assign detect_edge_n={detect_edge[0],UART_RX};
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
negedge_reg<=1'b0;
else
negedge_reg<=negedge_reg_n;
end
//判斷下降沿
assign negedge_reg_n=(detect_edge==2'b10)?1'b1:1'b0;
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
rx_bps_start<=1'b0;
else
rx_bps_start<=rx_bps_start_n;
end
//下降沿到來,就啓動波特率計數器
always @(*)
begin
if(negedge_reg)
rx_bps_start_n=1'b1;
else if(bit_cnt==4'd9)
rx_bps_start_n=1'b0;
else
rx_bps_start_n=rx_bps_start;
end
always @(posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
bit_cnt<=4'b0;
else
bit_cnt<=bit_cnt_n;
end
//判斷是否中間採樣點採樣
always @(*)
begin
if(rx_bos_flag)
bit_cnt_n=bit_cnt+1'b1;
else if(bit_cnt==4'd9)
bit_cnt_n=1'b0;
else
bit_cnt_n=bit_cnt;
end
always @(posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
shift_data<=8'b0;
else
shift_data<=shift_data_n;
end
//中間點採樣,每採樣一個便開始啓動移位寄存器記錄數據
always @(*)
begin
if(rx_bps_flag)
shift_data_n={UART_RX,shift_data[7:1]};
else
shift_data_n=shift_data;
end
always @(posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
out_rx_data<=8'b0;
else
out_rx_data<=out_rx_data_n;
end
//數據是否接受完成
always @(*)
begin
if(bit_cnt==4'd9)
out_rx_data_n=shift_data;
else
out_rx_data_n=out_rx_data;
end
endmodule
//蜂鳴器模塊
module Bepp_Module
(
//input
CLK_50M,RST_N,KEY,
//output
BEEP
);
input CKL_50M;
input RST_N;
intput [7:0] KEY;
output BEEP;
reg [15:0] time_cnt;
reg [15:0] time_cnt_n;
reg [15:0] freq;
reg [15:0] freq_n;
reg beep_reg;
reg beep_reg_n;
always @(posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
time_cnt<=16'b0;
else
time_cnt<=time_cnt_n;
end
always @(*)
begin
if(time_cnt==freq)
time_cnt_n=16'b0;
else
time_cnt_n=time_cnt+1'b1;
end
always @(posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
beep_reg<=1'b0;
else
beep_reg<=beep_reg_n;
end
always @(*)
begin
if(time_cnt==freq)
beep_reg_n=~beep_reg;
else
beep_reg_n=beep_reg;
end
always @(posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
freq<=16'b0;
else
freq<=freq_n;
end
always @(*)
begin
case(KEY)
8'h30:freq_n=16'd0;
8'h31:freq_n=16'd47774;
8'h32:freq_n=16'd42568;
8'h33:freq_n=16'd37919;
8'h34:freq_n=16'd35791;
8'h35:freq_n=16'd31888;
8'h36:freq_n=16'd28409;
8'h37:freq_n=16'd25309;
8'h38:freq_n=16'd23889;
8'h39:freq_n=16'd21276;
default:feq_n=freq;
endcase
end
assign BEEP=beep_reg;
endmodule