UART(Universal Asynchronous Receiver/Transmitter),是一种非同步的传输协定,非同步传输的意思是,不管是接收端还是传送端都有自己传输资料的速度(鲍率(Baud Rate)),传输时两边必须以同样的鲍率来收发资料才不会出错。
UART 它的好处是线路简单,仅两条线路(RX&TX),但缺点是只能一对一连接,以及速度不是很快,一般而言最高为 115.2kbps(常规鲍率为 9600)
从图片中可以看到,Uart 的闲置状态(IDLE)是高电平的,而起始位元则是 1 bit 的低电平,再来是 8 bit 资料的传输,而且是由 LSB 开始传输的,最後则是 1 bit 的高电平当作是结束位元。
例如现在要传输一个 0x55 (0101_0101) 的资料:
我们刚刚看完了 timing diagram 後发现,Uart 大致可以切成四个状态,分别为 IDLE(闲置状态)、START(起始位元)、SHIFT(8bit的输出移位)以及STOP(停止位元)。
定义四个状态:
/*---------parameter---------*/
localparam IDLE = 2'd0;
localparam START = 2'd1;
localparam SHIFT = 2'd2;
localparam STOP = 2'd3;
再来定义输入输出,记得!这边还不是最外层的 Uart 模块,别搞混了(想整个写在一起也很好!)。
输入:
输出:
module Uart_TX(
tick_uart,
clk_50M,
rst_n,
count,
rstcount,
countEN,
TX_D,
LDEN,
SHEN,
en,
busy
);
/*---------ports declaration---------*/
input clk_50M;
input rst_n;
input en;
input tick_uart;
input [2:0] count;
output TX_D;
output LDEN;
output SHEN;
output rstcount;
output countEN;
output busy;
reg TX_D;
reg LDEN;
reg SHEN;
reg rstcount;
reg countEN;
wire busy;
/*---------assign wire---------*/
assign busy = (fstate!=IDLE);
宣告跑状态的变数:
/*---------variables---------*/
reg [1:0] fstate;
状态逻辑:
/*---------fstate state---------*/
always@(posedge clk_50M or negedge rst_n)begin
if(!rst_n)fstate <= IDLE;
else begin
case(fstate)
IDLE:begin
if(en)fstate <= START;
else fstate <= IDLE;
end
START:begin
if(tick_uart==1'b1)fstate <= SHIFT;
else fstate <= START;
end
SHIFT:begin
if(tick_uart==1'b1&&count==3'd6)fstate <= STOP;
else fstate <= SHIFT;
end
STOP:begin
if(tick_uart==1'b1)fstate <= IDLE;
else fstate <= STOP;
end
default:fstate <= IDLE;
endcase
end
end
输出逻辑:
/*---------fstate output---------*/
always@(posedge clk_50M or negedge rst_n)begin
if(!rst_n)begin
TX_D <= 1'b1;
SHEN <= 1'b0;
LDEN <= 1'b0;
rstcount <= 1'b0;
countEN <= 1'b0;
end
else begin
if(tick_uart==1'b1)begin
case(fstate)
IDLE:begin
TX_D <= 1'b1;
SHEN <= 1'b0;
LDEN <= 1'b0;
rstcount <= 1'b0;
countEN <= 1'b0;
end
START:begin
TX_D <= 1'b0;
SHEN <= 1'b0;
LDEN <= 1'b1;
rstcount <= 1'b0;
countEN <= 1'b0;
end
SHIFT:begin
TX_D <= 1'b0;
SHEN <= 1'b1;
LDEN <= 1'b0;
if(count==3'd6) rstcount <= 1'b1;
else if(count<3'd6)rstcount <= 1'b0;
else rstcount <= 1'b0;//prevent latch
countEN <= 1'b1;
end
STOP:begin
TX_D <= 1'b1;
SHEN <= 1'b0;
LDEN <= 1'b0;
rstcount <= 1'b0;
countEN <= 1'b0;
end
default:begin
TX_D <= 1'b1;
SHEN <= 1'b0;
LDEN <= 1'b0;
rstcount <= 1'b0;
countEN <= 1'b0;
end
endcase
end
else begin
TX_D <= TX_D;
SHEN <= SHEN;
LDEN <= LDEN;
rstcount <= rstcount;
countEN <= countEN;
end
end
end
endmodule
这边要注意的是,虽然说要数到 7 才跳下一个状态,以及要数到 7 时 rstcount 才等於 1,但是!,状态机模组发送讯号到外模组,外模组要在下一个 clk 才会收到,因此如果打 7 的话,会让 SHEN 延长至 9 个鲍率周期,导致输出移位的次数错误
以上就是我整个 Uart_TX 状态机设计的方法~~
<<: Day23 什麽是 HTTP 状态码(HTTP Status Code)?
>>: Day 19 [Python ML、资料视觉化] Seaborn介绍
多执行绪(multithreading) 所以我们的多执行绪在程序是怎麽运作呢? 一般情况: 假设 ...
Azure face service: Face recognition- 让你的机器人认得你 人脸...
网站涵盖了商业网点提供的一系列有益健康的设施和功能。无论是教育、新闻、博客还是电子商务商品,在线门...
先前将主机已经注册上去了 那接下来就是进到『Task Definitions』开始来建立服务 点选『...
欸!?这个不是在 hello world 的时候讲过了ㄇ?! 对。 其实函式还是有其他东西可以讲解的...