1、分频器源代码:(baud.vhd)
- library IEEE;
- use IEEE.STD_LOGIC_1164.ALL;
- use IEEE.STD_LOGIC_ARITH.ALL;
- use IEEE.STD_LOGIC_UNSIGNED.ALL;
- ---- Uncomment the following library declaration if instantiating
- ---- any Xilinx primitives in this code.
- --library UNISIM;
- --use UNISIM.VComponents.all;
- entity baud is
- Port ( clk : in STD_LOGIC; -- 待分频时钟
- resetb : in STD_LOGIC; -- RESET <= '1' 有效
- bclk : out STD_LOGIC -- 分频后时钟
- );
- end baud;
- architecture Behavioral of baud is
- begin
- process( clk, resetb)
- variable cnt: integer := 0; -- 分频计数器,若波特率使用115200,cnt := 67, 若为9600, cnt := 813
- begin
- if resetb = '1' then -- reset
- cnt := 0;
- bclk <= '0';
- elsif rising_edge(clk) then -- 上升沿有效
- if cnt >= 54 then -- 54 分频 = 115200 * 16
- cnt := 0;
- bclk <= '1';
- else
- cnt := cnt + 1;
- bclk <= '0';
- end if;
- end if;
- end process;
- end Behavioral;
2、发送器源代码(transfer.vhd)
- 串行通信的发送器有五个状态:
- X_IDLE(空闲)状态 : 当UART被复位后,状态机将立刻进入这一状态,在这个状态下,状态机一直等待发送命令XMIT_CMD,当接收到发送命令后,状态机进入X_START状态,准备发送起始位信号
- X_START状态 : 在这个状态下,UART发送一个位时间宽度的逻辑'0',信号至TXD,即起始位,紧接着状态机进入X_SHIFT状态,发一位数据
- X_WAIT状态 : 当状态机处于这一个状态时,等待计满15个bclk周期,在第16个bclk进入X_SHIFT状态进行数据位的发送,同时也判断发送的数据位长度是否已经达到数据帧的长度,如果 = framlent,就说明停止位发送进入停止状态.
- X_SHIFT状态 : 实现待发数据的并串转换,转换完成立即进入X_WAIT状态,进行下一次发送
- X_STOP状态 : 停止位发送,当数据帧发送完毕后,状态机进入该状态,并发送16个bclk周期的逻辑1信号,即1位停止位.然后进入X_IDLE状态,并等待另一个数据帧发送命令
-
- library IEEE;
- use IEEE.STD_LOGIC_1164.ALL;
- use IEEE.STD_LOGIC_ARITH.ALL;
- use IEEE.STD_LOGIC_UNSIGNED.ALL;
- ---- Uncomment the following library declaration if instantiating
- ---- any Xilinx primitives in this code.
- --library UNISIM;
- --use UNISIM.VComponents.all;
- entity transfer is
- GENERIC(framlent: INTEGER := 8);
- Port ( bclkt : in STD_LOGIC; -- 时钟, 波特率的 16倍
- resett : in STD_LOGIC; -- RESET 信号
- xmit_cmd_p : in STD_LOGIC; -- 发送命令
- txdbuf : in STD_LOGIC_VECTOR (7 DOWNTO 0) := "11001010"; -- 发送数据缓冲区
- busy : buffer std_logic;
- txd : out STD_LOGIC; -- 发送数据(Transmitted Data,TXD),通过TXD串行发送数据
- txd_done : out STD_LOGIC); -- 数据发送完毕信号,也是标志位,没有控制作用,在停止位后变化. <= '1' 表示数据发送完毕
- 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; -- 促使状态为X_IDLE状态
- --SIGNAL tcnt : INTEGER := 0; -- 发送周期计数器,每16个周期发送一位
- begin
- process(bclkt, resett, xmit_cmd_p, txdbuf)
- variable xcnt16: STD_LOGIC_VECTOR (3 DOWNTO 0) := "0000"; -- 发送周期计数器,每16个周期发送一位
- variable xbitcnt: INTEGER := 0; -- 发送缓冲区下标
- variable txds : STD_LOGIC; -- 临时变量TXD,
- begin
- if resett = '1' then -- 复位 <= '1'有效
- STATE <= X_IDLE; -- 复位后, 为 X_IDLE状态
- txd_done <= '0'; -- 发送完成标志
- txds := '1'; -- TXD
- elsif rising_edge(bclkt) then -- 上升沿
- case STATE is
- when X_IDLE => -- X_IDLE(空闲)状态 : 当UART被复位后,状态机将立刻进入这一状态,在这个状态下,状态机一直等待发送命令XMIT_CMD,当接收到发送命令后,状态机进入X_START状态,准备发送起始位信号
- if xmit_cmd_p = '1' and busy = '0' then -- 发送命令信号,'1'有效
- STATE <= X_START; -- 进入X_START,准备发送
- txd_done <= '0'; -- 清零发送完毕标志
- busy <= '1';
- --xcnt16 := "0000";
- else STATE <= X_IDLE; -- 等待发送命令信号
- busy <= '0';
- end if;
- when x_start => -- X_START状态 : 在这个状态下,UART发送一个位时间宽度的逻辑'0',信号至TXD,即起始位,紧接着状态机进入X_SHIFT状态,发送第一位数据
- if xcnt16 >= "1111" then -- 发送开始位
- STATE <= X_SHIFT; -- 开始位发送完毕后,开始发送数据
- xbitcnt := 0; -- 从低位开始发送
- xcnt16 := "0000"; -- 下一个时钟周期开始
- else
- xcnt16 := xcnt16 + 1; -- 循环计数16个周期
- txds := '0'; -- 发送开始位 . '0' 为开始位标志
- STATE <= X_START; --
- end if;
- when X_WAIT => -- X_WAIT状态 : 当状态机处于这一个状态时,等待计满15个bclk周期,在第16个bclk进入X_SHIFT状态进行数据位的传送,如果 = framlent,就说明停止位发送进入停止状态.
- if xcnt16 >= "1110" then -- 当第十五个周期时,
- if xbitcnt = framlent then -- 如果所有数据发送完毕,
- STATE <= X_STOP; -- 进入X_STOP状态
- --xbitcnt := 0;
- else
- STATE <= X_SHIFT; -- 未发送完毕,则第十六周期进入X_SHIFT状态,发送下一位
- end if;
- xcnt16 := "0000"; -- 进入下一个周期
- else xcnt16 := xcnt16 + 1;
- STATE <= X_WAIT; -- 等待第十五周期的到来
- end if;
- when X_SHIFT => -- 实现待发数据的并串转换,转换完成立即进入X_WAIT状态,进行下一次发送
- txds := txdbuf(xbitcnt); -- 发送当前位数据
- xbitcnt := xbitcnt +1; -- 为发送下一位准备
- STATE <= X_WAIT; -- ...........
- when X_STOP => -- X_STOP状态 : 停止位发送,当数据帧发送完毕后,状态机进入该状态,并发送16个bclk周期的逻辑1信号,即1位停止位.然后进入X_IDLE状态,并等待另一个数据帧发送命令
- if xcnt16 >= "1111" then -- 发送结束后,
- if xmit_cmd_p = '0' then -- 等待下一个发送周期到来,
- STATE <= X_IDLE;
- busy <= '0';
- xcnt16 := "0000";
- 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;
3、接收器源代码(receiver.vhd)
- 串行通信的接收器,分为五个状态
- R_START状态(等待起始位):当UART接收器复位后,接收状态机将处于这一个状态.在此状态下,状态机一直在等待RXD的电平跳转,从逻辑1变为逻辑0,即起始位,这意味着新的一帧UART数据帧的开始,一旦起始位被确定,状态机将转入R_CENTER状态
- R_CENTER状态(起始位确认状态): 当确认是起始位,并且稳定,转入R_WAIT?刺?本程序认为保持超过1/4个位时间的信号认为是起始信号
- R_WAIT状态 : 当状态机处于这一个状态时,等待计满15个bclk周期,在第16个bclk进入R_SAMPLE状态进行数据位的采样检测,同时也判断采集的数据位长度是否已经达到数据帧的长度,如果 = framlenr,就说明停止位来临
- R_SAMPLE状态: 即数据位采样检测,完成后无条件状态机转入R_WAIT等待,等待下次数据位的到来
- R_STOP状态: 输出 ready信号,表明该帧传输完毕,之后转入R_START状态
-
- library IEEE;
- use IEEE.STD_LOGIC_1164.ALL;
- use IEEE.STD_LOGIC_ARITH.ALL;
- use IEEE.STD_LOGIC_UNSIGNED.ALL;
- ---- Uncomment the following library declaration if instantiating
- ---- any Xilinx primitives in this code.
- --library UNISIM;
- --use UNISIM.VComponents.all;
- entity receiver is
- generic( framlenr: integer := 8); -- 接收缓冲区大小 ,framlenr,接收数据帧长度
- Port ( bclkr : in STD_LOGIC; -- 时钟,波特率的16倍
- resetr : in STD_LOGIC; -- 复位信号
- rxdr : in STD_LOGIC; -- 接受数据(Received Data,RXD),通过RXD终端接受
- r_ready : out STD_LOGIC; -- 数据接受完毕信号, <= '1',表示接受完毕,只是标志位而已,在本程序无控制作用
- rbuf : out STD_LOGIC_VECTOR (7 downto 0) -- 数据接受缓冲区,存放接受数据
- );
- end receiver;
- architecture Behavioral of receiver is
- type STATES is (R_START, R_CENTER, R_WAIT, R_SAMPLE, r_STOP); -- 接收器状态,5种,
- signal State: STATES := R_START; -- 初始状态,START
- signal rxd_sync: STD_LOGIC; -- rxdr的同步信号,因为在逻辑1或逻辑0判断时,不希望检测的信号是不稳定的,所以,不直接检测RXD信号,而是检测经过同步信号xd_sync
- begin
- pro1:process(rxdr) -- 传递 rxdr 给同步信号 rxd_sync
- 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) := "0000"; -- 计数器,用于记录时钟周期,每16个时钟一个周期,即信号有效间隔
- variable rcnt : INTEGER := 0; -- 接收缓冲帧下标
- variable rbufs: STD_LOGIC_VECTOR ( 7 downto 0) := "00000000"; -- 接收缓冲区
- begin
- if resetr = '1' then -- 复位信号
- State <= R_START; -- 复位后状态为 R_START
- count := "0000"; -- 计数器清零
- elsif rising_edge(bclkr) then -- 上升沿有效
- case State is
- when R_START => -- R_START状态
- if rxd_sync = '0' then -- 接收开始情形: 电平从1变为0,并且保持16个波特率周期
- State <= R_CENTER; -- 当接收到 时钟下降时,进入R_CENTER状态,检测是否是开始位
- r_ready <= '0'; -- 置 r_ready 为 '0',等待准备接收数据
- rcnt := 0; -- 数据缓冲区下标 rcnt 清零
- else State <= R_START; -- 如果没有 收到时钟下降,则仍为R_START,继续等待开始信号
- r_ready <= '0'; -- 置 r_ready 为 '0',等待准备接收数据
- end if;
- when R_CENTER => -- R_CENTER状态,该状态检测开始信号是否为稳定的开始信号,如果是,则准备接收数据,如果不是,转入R_START状态
- if rxd_sync = '0' then
- if count = "0100" then -- 1/4个时钟周期检测开始信号
- State <= R_WAIT; -- 保持逻辑0超过1/4个周期后,进入R_WAIT状态,
- count := "0000"; -- count 清0,为接收数据做准备,接收数据的新??周期的开始
- else count := count + 1; -- count++
- State <= R_CENTER;
- end if;
- else
- State <= R_START; -- 逻辑信号'0',不稳定,进入R_START状态,重新等待开始信号
- end if;
- when R_WAIT => -- R_WAIT状态 : 当状态机处于这一个状态时,等待计满15个bclk周期,在第16个bclk进入R_SAMPLE状态进行数据位的采样检测,同时也判断采集的数据位长度是否已经达到数据帧的长度,如果 = framlenr,就说明停止位来临
- if count >= "1110" then -- 第十五个周期时,
- if rcnt = framlenr then -- 所有数据接收完毕,进入停止状态
- State <= R_STOP;
- else State <= R_SAMPLE; -- 所有数据仍未接收完毕,则第十六个周期进入R_SAMPLE进行采样
- end if;
- count := "0000"; -- 下一个采样周期的开始
- else count := count + 1; -- 未达到第十五个周期,count++
- State <= R_WAIT; -- 等第十五个周期的到来
- end if;
- when R_SAMPLE => -- R_SAMPLE状态: 即数据位采样检测,完成后无条件状态机转入R_WAIT等待,等待下次数据位的到来
- rbufs(rcnt) := rxd_sync; -- 进行数据采样
- rcnt := rcnt + 1; -- 下标向高位移一位
- State <= R_WAIT; -- 等待下一次采样
- when R_STOP => -- R_STOP状态: 输出 ready信号,表明该帧传输完毕,之后转入R_START状态
- r_ready <= '1';
- rbuf <= rbufs; -- 保存接收数据
- State <= R_START; -- 等待下一帧数据开始
- when others => STATE <= R_START; -- 其他未知状态
- end case;
- end if;
- end process;
- end Behavioral;
原文:http://blog.chinaunix.net/uid-8196371-id-1746811.html

1万+

被折叠的 条评论
为什么被折叠?



