HBLbits_Verilog Basic_Fsm serialdata
See also: Serial receiver
Now that you have a finite state machine that can identify when bytes are correctly received in a serial bitstream, add a datapath that will output the correctly-received data byte. out_byte needs to be valid when done is 1, and is don't-care otherwise.
Note that the serial protocol sends the least significant bit first.
Some timing diagrams
源自於 https://makerpro.cc/2019/08/the-difference-between-rs232-and-uart/UART 序列埠
UART(Universal Asynchronous Receiver/Transmitter)是 IC 吐資料的對外管道,電壓最高就是 chip 自身的邏輯電壓,通常是 5 V 或 3.3 V。由於電壓低、速度慢,通常用在裝置內部電路板的對外溝通,也就是 debug;如果你想讓程式印出變數值,通常會呼叫 printf( ) 函式對吧,這時字串就會從 UART 的 TXD 跑出來。
UART 只是晶片內序列傳輸模組的通稱,Universal 表示是泛用型,你可以 config 它成為各種形式的序列埠,例如要不要 parity check、bit rate 要多少之類的。換言之,UART 只是稱呼,不是標準,因此沒有定義接頭形狀,接頭形式完全看個人方便而定。
另外有人會問,UART 裡的「非同步 Asynchronous」是什麼意思?不知您有無發現 RS232/UART 只用一條線來傳資料,所以它沒有額外的 clock,沒有 clock 輔助表示「接收端即便知道發射端的 bit rate,自身的資料取樣速度也無法完全與發射端相同」,因此稱為非同步,若是像 I2C/SPI 等傳輸介面是包含 clock 訊號的,就稱為「同步傳輸」。
Protocol 通訊協定
簡單來說,我們可以將 RS232 視為 UART 的高電壓版本,下圖的 MAX232 就是做轉電壓。用有學問一點的說法來講,RS232 定義了實體層,方便各種裝置彼此交換資料,而每個裝置中處理器裡面的 UART 模組,則負責資料收送的功能。
UART 與 RS232 的接線方塊圖(圖片來源:實作派提供)
要提醒各位的是,當兩個裝置相連時,電壓準位要相同,千萬別將 RS232 與 UART 相接,這可能會把 UART 打壞,也就是 chip 會壞掉。UART 與 RS232 最大的差別有兩個:
- RS232 的 Vpp 電壓較高,有 6 V~30 V;UART 則是較低的 3.3 V 或 5 V
- RS232 為負邏輯, UART 為正邏輯,因此兩者波形是反相的
兩者的通訊協定如下圖所示(以 PC 為例),事實上它本來還有定義 parity check bit,只不過通常在 debug 連線時,大家只是看看變數,而且我目前在 debug 上也還沒看過有人用過 parity,但還是建議大家在長距離大量的連續資料傳送時,用一下 parity 比較保險。
UART 與 RS232 的資料格式(圖片來源:實作派提供)
表示 Serial port 資料送完了,目前沒事做,正在等待下一筆資料中,UART level 固定在 H。
將狀態反相,是送資料前的準備動作,這樣接收端才知道後面有資料要送,UART level 固定為 L。
送資料的順序是 D0 先送,D7 最後送,所以在示波器顯示的波形是 D0:D7,在判讀資料前記得先在腦中反序變成 D7:D0 再來判讀,也別忘了 RS232 是負邏輯喔!
資料送完後,要變成 Stop 狀態。Stop bit 很妙,我遇過 Stop bit 太短導致接收端誤判的情況(最短一個 bit,最長其實可以很長),由你決定。
實際上 Stop bit 本身可視為下個 bit 的 idle 狀態,因為兩個狀態其實一樣。邏輯上來說,你可以把 Stop state 經過 2 bit 後才視為 Idle,但實際上 D7 送完,接收器馬上就會準備接收下個 byte,除非你跟我一樣遇到兩光接收器,非得每個 byte 都間格一段時間,不然 stop bit 設定為 1 bit 應該就可以了。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
localparam idle=0,start=1,data=2,stop=3,error=4;
reg[2:0] state, next_state;
reg[3:0] cnt;
reg done_r;
reg[7:0] out;
//transition
always@(*)begin
case(state)
idle:next_state=in?idle:start;
start:next_state=data;
data:next_state=(cnt==8)?(in?stop:error):data;
stop:next_state=in?idle:start;
error:next_state=in?idle:error;
endcase
end
//state
always@(posedge clk)begin
if(reset)
state <= idle;
else
state <= next_state;
end
//out
always@(posedge clk)begin
if(reset)
out<=0;
else
case(next_state)
start:out<=0;
data:out<={in,out[7:1]}; //移位寄存器
endcase
end
//cnt
always@(posedge clk)begin
if(reset)
cnt<=0;
else
case(next_state)
start:cnt<=0;
data:cnt<=cnt+1;
default:cnt<=cnt;
endcase
end
//done_r
always@(posedge clk)
case(next_state)
stop:done_r <= 1;
default:done_r <= 0;
endcase
assign done = done_r;
assign out_byte = out;
endmodule
//另一方法
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
//定义状态
parameter [3:0] IDLE = 4'd0;
parameter [3:0] START = 4'd1;
parameter [3:0] BIT1 = 4'd2;
parameter [3:0] BIT2 = 4'd3;
parameter [3:0] BIT3 = 4'd4;
parameter [3:0] BIT4 = 4'd5;
parameter [3:0] BIT5 = 4'd6;
parameter [3:0] BIT6 = 4'd7;
parameter [3:0] BIT7 = 4'd8;
parameter [3:0] BIT8 = 4'd9;
parameter [3:0] STOP = 4'd10;
parameter [3:0] ERROR = 4'd11;
reg [3:0] state,nstate;
reg [7:0] data_r;
//状态转移
always @(posedge clk)begin
if(reset)begin
state <= IDLE;
end
else begin
state <= nstate;
end
end
always @(*)begin
nstate = IDLE;
case(state)
IDLE: nstate = in? IDLE:START;
START:nstate = BIT1;
BIT1: nstate = BIT2;
BIT2: nstate = BIT3;
BIT3: nstate = BIT4;
BIT4: nstate = BIT5;
BIT5: nstate = BIT6;
BIT6: nstate = BIT7;
BIT7: nstate = BIT8;
BIT8: nstate = in? STOP:ERROR;
STOP: nstate = in? IDLE:START;
ERROR: nstate = in? IDLE:ERROR;
default: nstate = IDLE;
endcase
end
//寄存输入数据
always @(posedge clk)begin
case(nstate)
BIT1: data_r <= {in,data_r[7:1]};
BIT2: data_r <= {in,data_r[7:1]};
BIT3: data_r <= {in,data_r[7:1]};
BIT4: data_r <= {in,data_r[7:1]};
BIT5: data_r <= {in,data_r[7:1]};
BIT6: data_r <= {in,data_r[7:1]};
BIT7: data_r <= {in,data_r[7:1]};
BIT8: data_r <= {in,data_r[7:1]};
endcase
end
//输出
assign done = (state == STOP);
assign out_byte = (state == STOP)? data_r:0;
endmodule
沒有留言:
張貼留言