UART
UART (Universal Asynchronous Receiver/Transmitter)代表通用异步接收器/发送器。 这不是像SPI和I2C这样的通信协议,而是微控制器中的物理电路或独立IC。 UART的主要目的是发送和接收串行数据。有关UART的最好的事情之一是它只使用两根线在设备之间传输数据。
UART通信简介
在UART通信中,两个UART直接相互通信。 发送UART将来自CPU等控制设备的并行数据转换为串行形式,并将其串行传输至接收UART,然后将接收设备的串行数据转换为并行数据。 在两个UART之间只需要两根线来传输数据。 数据从发送UART的Tx引脚流向接收UART的Rx引脚:
UARTs异步传输数据,这意味着没有时钟信号可将发送UART的位输出与接收UART的位采样同步。 发送UART不是时钟信号,而是将开始位和停止位添加到正在传输的数据包。 这些位定义数据包的开始和结束,以便接收UART知道何时开始读取位。
当接收UART检测到一个起始位时,它开始以称为波特率的特定频率读入输入位。 波特率是数据传输速度的度量,以每秒位数(bps)表示。 两个UART必须以大约相同的波特率运行。 发送UART和接收UART之间的波特率在比特的时序变得太远之前只能相差约10%。
两个UART必须也必须配置为发送和接收相同的数据包结构。
UART如何工作
要发送数据的UART从数据总线接收数据。 数据总线用于通过CPU,内存或微控制器等其他设备将数据发送到UART。 数据以并行形式从数据总线传输到发送UART。 发送UART从数据总线获得并行数据后,它会添加一个起始位,一个奇偶校验位和一个停止位,以创建数据包。 接下来,数据包在Tx引脚处逐位串行输出。 接收UART在其Rx引脚上逐位读取数据包。 接收UART然后将数据转换回并行格式并删除起始位,奇偶校验位和停止位。 最后,接收UART将数据包并行传输到接收端的数据总线上:
UART传输的数据被组织成数据包。 每个数据包包含1个起始位,5到9个数据位(取决于UART),可选奇偶校验位以及1或2个停止位:
起始位
不传输数据时,UART数据传输线通常保持高电平。 为了开始数据传输,发送UART在一个时钟周期内将传输线从高电平拉到低电平。 当接收UART检测到高电压至低电压转换时,它开始以波特率的频率读取数据帧中的位。
数据帧
数据帧包含正在传输的实际数据。 如果使用奇偶校验位,它可以是5位长达8位长。 如果不使用奇偶校验位,则数据帧可以是9位长。 在大多数情况下,数据首先以最低有效位发送。
奇偶性
奇偶性描述数字的均匀性或奇异性。 奇偶校验位是接收UART在传输过程中是否有数据发生变化的一种方式。 电磁辐射,不匹配的波特率或长距离数据传输可能会改变位。 在接收UART读取数据帧后,它会计数值为1的位数,并检查总数是偶数还是奇数。 如果奇偶校验位是0(偶校验),则数据帧中的1位应总计为偶数。 如果奇偶校验位是1(奇数奇偶校验位),则数据帧中的1位应该总数为奇数。 当奇偶校验位与数据匹配时,UART知道传输没有错误。 但是如果奇偶校验位是0,总数是奇数; 或奇偶校验位为1,且总数为偶数时,UART知道数据帧中的位已改变。
停止位
为了发信号通知数据包的结束,发送UART将数据传输线从低电压驱动到高电压持续至少两个比特持续时间。
UART传输步骤
1.发送UART从数据总线并行接收数据:
2.发送UART将起始位,奇偶校验位和停止位添加到数据帧中:
3.整个数据包从发送UART串行发送到接收UART。 接收UART以预配置的波特率对数据线进行采样:
4.接收UART丢弃数据帧中的起始位,奇偶校验位和停止位:
5.接收UART将串行数据转换为并行数据并将其传送到接收端的数据总线:
UARTS的优势和劣势
没有通信协议是完美的,但UART在他们所做的事情上相当出色。以下是一些优点和缺点,可帮助决定是否符合项目需求:
优点
只使用两根电线
没有时钟信号是必要的
有一个奇偶校验位允许进行错误检查
只要双方都建立起来,数据包的结构就可以改变
有据可查的和广泛使用的方法
劣势
数据帧的大小限制为最多9位
不支持多个从属或多个主系统
每个UART的波特率必须在彼此的10%以内
URAT VHDL程序
1. 顶层程序
--功能:顶层映射。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity top is
Port (clk32mhz,reset,rxd,xmit_cmd_p_in:in std_logic;--总的输入输出信号的定义
rec_ready,txd_out,txd_done_out:out std_logic;
txdbuf_in:in std_logic_vector(7 downto 0);--待发送数据输入
rec_buf:out std_logic_vector(7 downto 0));--接收数据缓冲
end top;
architecture Behavioral of top is
component transfer --发送器组件
Port (bclkt,resett,xmit_cmd_p:in std_logic;
txdbuf:in std_logic_vector(7 downto 0);
txd:out std_logic;
txd_done:out std_logic);
end component;
component reciever --接收器组件
Port (bclkr,resetr,rxdr:in std_logic;
r_ready:out std_logic;
rbuf:out std_logic_vector(7 downto 0));
end component;
component baud
Port (clk,resetb:in std_logic;
bclk:out std_logic);
end component;
signal b:std_logic;
begin
u1:baud port map(clk=>clk32mhz,resetb=>reset,bclk=>b); --顶层映射
u2:reciever port map(bclkr=>b,resetr=>reset,rxdr=>rxd,r_ready=>rec_ready,rbuf=>rec_buf);
u3:transfer port map(bclkt=>b,resett=>reset,xmit_cmd_p=>xmit_cmd_p_in,txdbuf=>txdbuf_in,txd=>txd_out,txd_done=>txd_done_out);
end Behavioral;
2.波特率发生器程序
--功能:将外部输入的32MHz的信号分成频率为153600Hz的信号。
--计算过程:(32*10^6)/(1.536*10^5)=208.333……
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity baud is
Port (clk,resetb:in std_logic;
bclk:out std_logic);
end baud;
architecture Behavioral of baud is
begin
process(clk,resetb)
variable cnt:integer;
begin
if resetb='1' then cnt:=0; bclk<='0'; --复位
elsif rising_edge(clk) then
if cnt>=208 then cnt:=0; bclk<='1'; --设置分频系数
else cnt:=cnt+1; bclk<='0';
end if;
end if;
end process;
end Behavioral;
3. UART发送器程序
--功能:UART发送器。
--说明:系统由五个状态(x_idle,x_start,x_wait,x_shift,x_stop)和一个进程构成。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity transfer is
generic(framlent:integer:=8);
Port (bclkt,resett,xmit_cmd_p:in std_logic; --定义输入输出信号
txdbuf:in std_logic_vector(7 downto 0):="11001010";
txd:out std_logic;
txd_done:out std_logic);
end transfer;
architecture Behavioral of transfer is
type states is (x_idle,x_start,x_wait,x_shift,x_stop); --定义个子状态
signal state:states:=x_idle;
signal tcnt:integer:=0;
begin
process(bclkt,resett,xmit_cmd_p,txdbuf) --主控时序、组合进程
variable xcnt16:std_logic_vector(4 downto 0):="00000"; --定义中间变量
variable xbitcnt:integer:=0;
variable txds:std_logic;
begin
if resett='1' then state<=x_idle; txd_done<='0'; txds:='1';--复位
elsif rising_edge(bclkt) then
case state is
when x_idle=> --状态1,等待数据帧发送命令
if xmit_cmd_p='1' then state<=x_start;txd_done<='0';
else state<=x_idle;
end if;
when x_start=> --状态2,发送信号至起始位
if xcnt16>="01111" then state<=x_wait; xcnt16:="00000";
else xcnt16:=xcnt16+1; txds:='0'; state<=x_start;
end if;
when x_wait=> --状态3,等待状态
if xcnt16>="01110" then
if xbitcnt=framlent then state<=x_stop; xbitcnt:=0;
else state<=x_shift;
end if;
xcnt16:="00000";
else xcnt16:=xcnt16+1; state<=x_wait;
end if;
when x_shift=>txds:=txdbuf(xbitcnt); xbitcnt:=xbitcnt+1; state<=x_wait; --状态4,将待发数据进行并串转换
when x_stop=> --状态5,停止位发送状态
if xcnt16>="01111" then
if xmit_cmd_p='0' then state<=x_idle; xcnt16:="00000";
else xcnt16:=xcnt16; state<=x_stop;
end if; txd_done<='1';
else xcnt16:=xcnt16+1; txds:='1'; state<=x_stop;
end if;
when others=>state<=x_idle;
end case;
end if;
txd<=txds;
end process;
end Behavioral;
4. UART接收器程序
--功能:UART接受器。
--说明:系统由五个状态(r_start,r_center,r_wait,r_sample,r_stop)和两个进程构成
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity reciever is
generic(framlenr:integer:=8);
Port (bclkr,resetr,rxdr:in std_logic; --定义输入输出信号
r_ready:out std_logic;
rbuf:out std_logic_vector(7 downto 0));
end reciever;
architecture Behavioral of reciever is
type states is (r_start,r_center,r_wait,r_sample,r_stop);--定义各子状态
signal state:states:=r_start;
signal rxd_sync:std_logic;
begin
pro1:process(rxdr)
begin
if rxdr='0' then rxd_sync<='0';
else rxd_sync<='1';
end if;
end process;
pro2:process(bclkr,resetr,rxd_sync) --主控时序、组合进程
variable count:std_logic_vector(3 downto 0); --定义中间变量
variable rcnt:integer:=0;
variable rbufs:std_logic_vector(7 downto 0);
begin
if resetr='1' then state<=r_start; count:="0000"; --复位
elsif rising_edge(bclkr) then
case state is
when r_start=> --状态1,等待起始位
if rxd_sync='0' then state<=r_center; r_ready<='0'; rcnt:=0;
else state<=r_start; r_ready<='0';
end if;
when r_center=> --状态2,求出每位的中点
if rxd_sync='0' then
if count="0100" then state<=r_wait; count:="0000";
else count:=count+1; state<=r_center;
end if;
else state<=r_start;
end if;
when r_wait=> --状态3,等待状态
if count>="1110" then
if rcnt=framlenr then state<=r_stop;
else state<=r_sample;
end if;
count:="0000";
else count:=count+1; state<=r_wait;
end if;
when r_sample=>rbufs(rcnt):=rxd_sync; rcnt:=rcnt+1;state<=r_wait; --状态4,数据位采样检测
when r_stop=>r_ready<='1'; rbuf<=rbufs; state<=r_start; --状态4,输出帧接收完毕信号
when others=>state<=r_start;
end case;
end if;
end process;
end Behavioral;
NUM464
个人博客式公众号
用心每一天