目錄
FPGA序列槽通信
1. 序列槽接收子產品
2. 序列槽發送子產品
FPGA序列槽通信
前面寫的序列槽通信子產品,沒有通用性,這裡寫一個可以通用的序列槽子產品,但凡以後需要序列槽通信的,就可以直接拿過來用。
1. 序列槽接收子產品
信号名稱 | I/O | 位數 | 功能描述 |
clk | I | 1 | 系統時鐘50MHz |
rst_n | I | 1 | 系統複位 |
rs232_tx | I | 1 | 序列槽串行資料發送資料口 |
baud_set | I | 3 | 波特率選擇信号 |
data_byte | O | 8 | 并行資料輸出 |
rx_done | O | 1 | 接收1位元組資料完成标志 |
代碼如下:UART_Byte_Rx.v
//-------------------------------------------------------------------
//https://blog.csdn.net/qq_33231534 PHF的CSDN
//File name: UART_Byte_Rx.v
//Last modified Date: 2020/5/22
//Last Version:
//Descriptions: 工業級别序列槽資料接收子產品,防幹擾。對每位資料内部采樣16個點,
// 對中間6位資料進行判定資料是1還是0
//-------------------------------------------------------------------
module UART_Byte_Rx(
input clk ,//系統時鐘50MHz
input rst_n ,//系統複位
input rs232_tx ,//序列槽串行資料發送資料口
input [ 2: 0] baud_set ,//波特率選擇信号
output reg [ 7: 0] data_byte ,//并行資料輸出
output reg rx_done //接收1位元組資料完成标志,rx_done可以作為輸出有效信号使用
);
reg [ 13: 0] baud_c ;//波特率對應計數次數(4800bps-10416),(9600bps-5208),(19200bps-2604),
//(38400bps-1302),(57600bps-868),(115200bps-434)
reg rs232_tx_ff0 ;
reg rs232_tx_ff1 ;
reg rs232_tx_ff2 ;
wire tx_neg_flag ;
reg add_flag ;
reg [ 13: 0] cnt0 ;
reg [ 3: 0] cnt1 ;
reg [ 9: 0] cnt2 ;
reg [ 3: 0] cnt3 ;
reg [ 2: 0] cnt_0 ;
reg [ 2: 0] cnt_1 ;
wire add_cnt0 ;
wire end_cnt0 ;
wire add_cnt1 ;
wire end_cnt1 ;
wire add_cnt2 ;
wire end_cnt2 ;
wire add_cnt3 ;
wire end_cnt3 ;
//查找表
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
baud_c <= 5208;
end
else begin
case(baud_set)
0: baud_c = 14'd10416;
1: baud_c = 14'd5208 ;
2: baud_c = 14'd2604 ;
3: baud_c = 14'd1302 ;
4: baud_c = 14'd868 ;
5: baud_c = 14'd434 ;
default:baud_c = 14'd5208 ;//預設9600bps
endcase
end
end
//打兩拍 防止亞穩态,同時scan negedge
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
rs232_tx_ff0 <= 1;
rs232_tx_ff1 <= 1;
rs232_tx_ff2 <= 1;
end
else begin
rs232_tx_ff0 <= rs232_tx;
rs232_tx_ff1 <= rs232_tx_ff0;
rs232_tx_ff2 <= rs232_tx_ff1;
end
end
//掃描下降沿
assign tx_neg_flag = rs232_tx_ff2 && !rs232_tx_ff1;
//計數标志信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
add_flag <= 0;
end
else if(tx_neg_flag) begin
add_flag <= 1;
end
else if(rx_done)begin
add_flag <= 0;
end
end
//計數器,計數1bit資料長度
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0 <= 0;
end
else if(add_cnt0)begin
if(end_cnt0)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1'b1;
end
end
assign add_cnt0 = add_flag;
assign end_cnt0 = add_cnt0 && cnt0==baud_c-1;
//計數器,計數8位接收資料長度
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1 <= 0;
end
else if(add_cnt1)begin
if(end_cnt1)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1'b1;
end
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1== 8;
//比特内部采樣點時鐘計數
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt2 <= 0;
end
else if(add_cnt2)begin
if(end_cnt2)
cnt2 <= 0;
else
cnt2 <= cnt2 + 1'b1;
end
end
assign add_cnt2 = add_flag;
assign end_cnt2 = add_cnt2 && (cnt2== (baud_c/16)-1 || end_cnt0);
//一個bit資料中16個采樣點計數
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt3 <= 0;
end
else if(add_cnt3)begin
if(end_cnt3)
cnt3 <= 0;
else
cnt3 <= cnt3 + 1'b1;
end
end
assign add_cnt3 = add_cnt2 && cnt2== (baud_c/16)-1;
assign end_cnt3 = end_cnt0 || (end_cnt2 && cnt3==16-1);
//比特内選取6個采樣點是0或1計數
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt_0 <= 0;
cnt_1 <= 0;
end
else if(add_flag) begin
if(cnt3>=6 && cnt3<=11)begin
if(cnt2==baud_c/16/2 && rs232_tx_ff1==0)
cnt_0 <= cnt_0 + 1'b1;
else if(cnt2==baud_c/16/2 && rs232_tx_ff1==1)
cnt_1 <= cnt_1 + 1'b1;
end
else if(end_cnt0)begin
cnt_0 <= 0;
cnt_1 <= 0;
end
end
else begin
cnt_0 <= 0;
cnt_1 <= 0;
end
end
//輸出并行資料data_byte
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
data_byte <= 0;
end
else if(end_cnt0 && cnt1>0 && cnt1 <9) begin
if(cnt_0 >= cnt_1)
data_byte[cnt1-1] = 0;
else if(cnt_0 < cnt_1)
data_byte[cnt1-1] = 1;
end
end
//輸出接收完成标志信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
rx_done <= 0;
end
else if(end_cnt1) begin
rx_done <= 1;
end
else begin
rx_done <= 0;
end
end
endmodule
測試代碼如下:
`timescale 1 ns/ 1 ns
module UART_Byte_Rx_tb();
// constants
// test vector input registers
reg [2:0] baud_set;
reg clk;
reg rs232_rx;
reg rst_n;
// wires
wire [7:0] data_byte;
wire rx_done;
parameter clk_period = 20;
// assign statements (if any)
UART_Byte_Rx i1 (
// port map - connection between master ports and signals/registers
.baud_set(baud_set),
.clk(clk),
.data_byte(data_byte),
.rs232_rx(rs232_rx),
.rst_n(rst_n),
.rx_done(rx_done)
);
initial clk = 0;
always #(clk_period/2) clk = ~clk;
initial begin
#1;
rst_n = 0;
baud_set = 0;
rs232_rx = 1;
#(clk_period*5);
rst_n = 1;
baud_set = 3'd1;
#(clk_period*3);
repeat(1)begin
//發送0000_1010
rs232_rx = 0;
#(clk_period*5208);
rs232_rx = 0;
#(clk_period*5208*4);
rs232_rx = 1;
#(clk_period*5208);
rs232_rx = 0;
#(clk_period*5208);
rs232_rx = 1;
#(clk_period*5208);
rs232_rx = 0;
#(clk_period*5208);
rs232_rx = 1;
#(clk_period*5208);
//發送1000_0101
rs232_rx = 0;
#(clk_period*5208);
rs232_rx = 1;
#(clk_period*5208);
rs232_rx = 0;
#(clk_period*5208*4);
rs232_rx = 1;
#(clk_period*5208);
rs232_rx = 0;
#(clk_period*5208);
rs232_rx = 1;
#(clk_period*5208);
rs232_rx = 1;
#(clk_period*5208);
end
#(clk_period*50);
$stop;
end
endmodule
其仿真圖形如下:
2. 序列槽發送子產品
這裡和序列槽接收子產品對應,發送的是8位資料,外加1位起始位和1位停止位。該子產品接口信号清單如下:
信号名稱 | I/O | 位數 | 功能描述 |
clk | I | 1 | 系統時鐘50MHz |
rst_n | I | 1 | 系統複位 |
send_en | I | 1 | 發送使能 |
data_byte | I | 8 | 發送的資料 |
baud_set | I | 3 | 波特率設定 |
rs232_tx | O | 1 | FPGA将資料轉換成串行資料發出 |
tx_done | O | 1 | 發送資料完畢标志 |
uart_state | O | 1 | 序列槽發送狀态,1為忙,0為空閑 |
代碼如下:Uart_Byte_Tx.v
//-------------------------------------------------------------------
//https://blog.csdn.net/qq_33231534 phf的CSDN
//File name: Uart_Byte_Tx.v
//Last modified Date: 2020/5/22
//Last Version:
//Descriptions: 序列槽發送子產品,8位資料位、1位起始位和1位停止位、無校驗位
//-------------------------------------------------------------------
module Uart_Byte_Tx(
input clk , //系統時鐘
input rst_n , //系統複位
input send_en , //發送使能
input [ 7 : 0 ] data_byte , //發送的資料
input [ 2 : 0 ] baud_set , //波特率設定
output reg rs232_tx , //FPGA将資料轉換成串行資料發出
output reg tx_done , //發送資料完畢标志
output reg uart_state //序列槽發送狀态,1為忙,0為空閑
);
reg [ 13: 0] baud_c ;//(4800bps-10416),(9600bps-5208),(19200bps-2604),
//(38400bps-1302),(57600bps-868),(115200bps-434)
wire [ 9: 0] data_out ;
reg [ 15: 0] cnt0 ; //1bit資料長度計數
reg [ 3: 0] cnt1 ; //發送一位元組資料對每個位元組計數
wire add_cnt0 ; //計數器cnt0加一條件
wire add_cnt1 ; //計數器cnt1加一條件
wire end_cnt0 ; //計數器cnt0結束條件
wire end_cnt1 ; //計數器cnt1結束條件
reg [ 7: 0] data_byte_ff ; //發送使能時将發送的資料寄存下來
//波特率查找表
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
baud_c <= 5208;
end
else begin
case(baud_set)
0: baud_c = 14'd10416;
1: baud_c = 14'd5208 ;
2: baud_c = 14'd2604 ;
3: baud_c = 14'd1302 ;
4: baud_c = 14'd868 ;
5: baud_c = 14'd434 ;
default:baud_c = 14'd5208 ;//預設9600bps
endcase
end
end
//序列槽狀态标志,0為空閑,1為忙
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
uart_state <= 0;
end
else if(send_en) begin
uart_state <= 1;
end
else if(end_cnt1)begin
uart_state <= 0;
end
else begin
uart_state <= uart_state;
end
end
//1bit資料長度計數
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0 <= 0;
end
else if(add_cnt0)begin
if(end_cnt0)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1'b1;
end
end
assign add_cnt0 = uart_state==1;
assign end_cnt0 = add_cnt0 && cnt0== baud_c-1;
//發送一位元組資料對每個位元組計數
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1 <= 0;
end
else if(add_cnt1)begin
if(end_cnt1)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1'b1;
end
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1== 10-1;
//序列槽發送結束标志
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
tx_done <= 0;
end
else if(end_cnt1) begin
tx_done <= 1;
end
else begin
tx_done <= 0;
end
end
//發送使能時将發送的資料寄存下來
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
data_byte_ff <= 0;
end
else if(send_en) begin
data_byte_ff <= data_byte;
end
end
//發送串行資料到序列槽
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
rs232_tx <= 1;
end
else if(uart_state && cnt0==0) begin
rs232_tx <= data_out[cnt1];
end
end
assign data_out = {1'b1,data_byte_ff,1'b0};
endmodule
測試代碼如下:
`timescale 1 ns/ 1 ns
module Uart_Byte_Tx_tb();
// constants
// test vector input registers
reg [2:0] baud_set;
reg clk;
reg [7:0] data_byte;
reg rst_n;
reg send_en;
// wires
wire rs232_tx;
wire tx_done;
wire uart_state;
parameter clk_period = 20;
// assign statements (if any)
Uart_Byte_Tx i1 (
// port map - connection between master ports and signals/registers
.baud_set(baud_set),
.clk(clk),
.data_byte(data_byte),
.rs232_tx(rs232_tx),
.rst_n(rst_n),
.send_en(send_en),
.tx_done(tx_done),
.uart_state(uart_state)
);
initial clk = 1;
always #(clk_period/2) clk = ~clk;
initial begin
rst_n = 0;
baud_set = 3'd1;
send_en = 0;
data_byte = 0;
#(clk_period*5);
rst_n = 1;
#(clk_period*5);
send_en = 1;
data_byte = 8'b0001_0100;
#(clk_period);
send_en = 0;
data_byte = 0;
#(clk_period*5208*15);
$stop;
end
endmodule
仿真波形如下:
仿真驗證後符合設計要求。