HDLBits/Sequential Logic/Finite State Machines/Fsm serial
n many (older) serial communications protocols, each data byte is sent along with a start bit and a stop bit, to help the receiver delimit bytes from the stream of bits. One common scheme is to use one start bit (0), 8 data bits, and 1 stop bit (1). The line is also at logic 1 when nothing is being transmitted (idle).
Design a finite state machine that will identify when bytes have been correctly received when given a stream of bits. It needs to identify the start bit, wait for all 8 data bits, then verify that the stop bit was correct. If the stop bit does not appear when expected, the FSM must wait until it finds a stop bit before attempting to receive the next byte.
串列通信協議发送過程中會在Data前後增加Mark來標識字節首尾(Start , Stop ),即包含 start 位和 stop 位,比如 UART 協議就是這樣。
本題的Start 標記Mark 是低電平(Low),結束(Stop )的標記是高電平(High),在開始和結束之間傳輸的 bit 位為8即一個Byte,這是正確接收的條件,
當滿足該條件後會在 stop 位後面的時鐘沿給出 done 的輸出標記(Mark)。
如果不滿足該條件,比如起始 start 條件不滿足,則會一直等待知道接收到低電平信號才開始;又如 start 開始後,中間的位數超過了8 bit,即8 bit 後一直是低電平信號,不出現高電平的 stop 信號,則 receiver 繼續等待知道出現高電平位才結束,但這是一個錯誤接收,不會給出 done 的輸出標記。波形圖如下所示。
狀態機,本題設計了五個狀態,分別是 IDLE, START, DATA, STOP, ERROR。
狀態機如下圖所示(畫圖畫的,湊合看吧)。這里控制狀態轉移的有輸入信號 in 和自定義的計數器 cnt,計數器用於計數 start 和 stop 之間的位數是數據是否滿足1 byte。
cnt的條件判斷只用在 DATA 狀態中,在 DATA 狀態時,cnt 實行計數,當 cnt 為8時表示真正的數據夠了,此時再比較輸入 in,如果 in 為高電平則數據接收正常,跳轉至 STOP,否則表示出現錯誤,進入 ERROR。跳出 ERROR 的條件是輸入in出現高電平。這里需要注意 STOP 狀態可以直接跳轉至 START 狀態,即 in 為高電平後緊接著出現低電平情況,如果輸入 in 為連續的幾個高電平,則 STOP 會進入 IDLE 等待低電平到來。另外這里的 START 狀態應該可以合並到 DATA 狀態中實現狀態機化簡。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
parameter idle = 0,start = 1,data = 2,stop =3,error = 4;
reg[2:0] state, next_state;
reg[3:0] cnt;
reg done_r;
//state
always@(posedge clk)begin
if(reset)
state <= idle;
else
state <= next_state;
end
//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
//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;
endmodule
沒有留言:
張貼留言