vhdl uart

1、分频器源代码:(baud.vhd)

  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.ALL;
  3. use IEEE.STD_LOGIC_ARITH.ALL;
  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;
  5. ---- Uncomment the following library declaration if instantiating
  6. ---- any Xilinx primitives in this code.
  7. --library UNISIM;
  8. --use UNISIM.VComponents.all;
  9. entity baud is
  10. Port ( clk : in STD_LOGIC; -- 待分频时钟
  11. resetb : in STD_LOGIC; -- RESET <= '1' 有效
  12. bclk : out STD_LOGIC -- 分频后时钟
  13. );
  14. end baud;
  15. architecture Behavioral of baud is
  16. begin
  17. process( clk, resetb)
  18. variable cnt: integer := 0; -- 分频计数器,若波特率使用115200,cnt := 67, 若为9600, cnt := 813
  19. begin
  20. if resetb = '1' then -- reset
  21. cnt := 0;
  22. bclk <= '0';
  23. elsif rising_edge(clk) then -- 上升沿有效
  24. if cnt >= 54 then -- 54 分频 = 115200 * 16
  25. cnt := 0;
  26. bclk <= '1';
  27. else
  28. cnt := cnt + 1;
  29. bclk <= '0';
  30. end if;
  31. end if;
  32. end process;
  33. end Behavioral;

2、发送器源代码(transfer.vhd)

  1. 串行通信的发送器有五个状态:
  2. X_IDLE(空闲)状态 : 当UART被复位后,状态机将立刻进入这一状态,在这个状态下,状态机一直等待发送命令XMIT_CMD,当接收到发送命令后,状态机进入X_START状态,准备发送起始位信号
  3. X_START状态 : 在这个状态下,UART发送一个位时间宽度的逻辑'0',信号至TXD,即起始位,紧接着状态机进入X_SHIFT状态,发一位数据
  4. X_WAIT状态 : 当状态机处于这一个状态时,等待计满15个bclk周期,在第16个bclk进入X_SHIFT状态进行数据位的发送,同时也判断发送的数据位长度是否已经达到数据帧的长度,如果 = framlent,就说明停止位发送进入停止状态.
  5. X_SHIFT状态 : 实现待发数据的并串转换,转换完成立即进入X_WAIT状态,进行下一次发送
  6. X_STOP状态 : 停止位发送,当数据帧发送完毕后,状态机进入该状态,并发送16个bclk周期的逻辑1信号,即1位停止位.然后进入X_IDLE状态,并等待另一个数据帧发送命令

  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.ALL;
  3. use IEEE.STD_LOGIC_ARITH.ALL;
  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;
  5. ---- Uncomment the following library declaration if instantiating
  6. ---- any Xilinx primitives in this code.
  7. --library UNISIM;
  8. --use UNISIM.VComponents.all;
  9. entity transfer is
  10. GENERIC(framlent: INTEGER := 8);
  11. Port ( bclkt : in STD_LOGIC; -- 时钟, 波特率的 16倍
  12. resett : in STD_LOGIC; -- RESET 信号
  13. xmit_cmd_p : in STD_LOGIC; -- 发送命令
  14. txdbuf : in STD_LOGIC_VECTOR (7 DOWNTO 0) := "11001010"; -- 发送数据缓冲区
  15. busy : buffer std_logic;
  16. txd : out STD_LOGIC; -- 发送数据(Transmitted Data,TXD),通过TXD串行发送数据
  17. txd_done : out STD_LOGIC); -- 数据发送完毕信号,也是标志位,没有控制作用,在停止位后变化. <= '1' 表示数据发送完毕
  18. end transfer;
  19. architecture Behavioral of transfer is
  20. TYPE STATES is (X_IDLE, X_START, X_WAIT, X_SHIFT, X_STOP); -- 五种状态
  21. SIGNAL STATE : STATES := X_IDLE; -- 促使状态为X_IDLE状态
  22. --SIGNAL tcnt : INTEGER := 0; -- 发送周期计数器,每16个周期发送一位
  23. begin
  24. process(bclkt, resett, xmit_cmd_p, txdbuf)
  25. variable xcnt16: STD_LOGIC_VECTOR (3 DOWNTO 0) := "0000"; -- 发送周期计数器,每16个周期发送一位
  26. variable xbitcnt: INTEGER := 0; -- 发送缓冲区下标
  27. variable txds : STD_LOGIC; -- 临时变量TXD,
  28. begin
  29. if resett = '1' then -- 复位 <= '1'有效
  30. STATE <= X_IDLE; -- 复位后, 为 X_IDLE状态
  31. txd_done <= '0'; -- 发送完成标志
  32. txds := '1'; -- TXD
  33. elsif rising_edge(bclkt) then -- 上升沿
  34. case STATE is
  35. when X_IDLE => -- X_IDLE(空闲)状态 : 当UART被复位后,状态机将立刻进入这一状态,在这个状态下,状态机一直等待发送命令XMIT_CMD,当接收到发送命令后,状态机进入X_START状态,准备发送起始位信号
  36. if xmit_cmd_p = '1' and busy = '0' then -- 发送命令信号,'1'有效
  37. STATE <= X_START; -- 进入X_START,准备发送
  38. txd_done <= '0'; -- 清零发送完毕标志
  39. busy <= '1';
  40. --xcnt16 := "0000";
  41. else STATE <= X_IDLE; -- 等待发送命令信号
  42. busy <= '0';
  43. end if;
  44. when x_start => -- X_START状态 : 在这个状态下,UART发送一个位时间宽度的逻辑'0',信号至TXD,即起始位,紧接着状态机进入X_SHIFT状态,发送第一位数据
  45. if xcnt16 >= "1111" then -- 发送开始位
  46. STATE <= X_SHIFT; -- 开始位发送完毕后,开始发送数据
  47. xbitcnt := 0; -- 从低位开始发送
  48. xcnt16 := "0000"; -- 下一个时钟周期开始
  49. else
  50. xcnt16 := xcnt16 + 1; -- 循环计数16个周期
  51. txds := '0'; -- 发送开始位 . '0' 为开始位标志
  52. STATE <= X_START; --
  53. end if;
  54. when X_WAIT => -- X_WAIT状态 : 当状态机处于这一个状态时,等待计满15个bclk周期,在第16个bclk进入X_SHIFT状态进行数据位的传送,如果 = framlent,就说明停止位发送进入停止状态.
  55. if xcnt16 >= "1110" then -- 当第十五个周期时,
  56. if xbitcnt = framlent then -- 如果所有数据发送完毕,
  57. STATE <= X_STOP; -- 进入X_STOP状态
  58. --xbitcnt := 0;
  59. else
  60. STATE <= X_SHIFT; -- 未发送完毕,则第十六周期进入X_SHIFT状态,发送下一位
  61. end if;
  62. xcnt16 := "0000"; -- 进入下一个周期
  63. else xcnt16 := xcnt16 + 1;
  64. STATE <= X_WAIT; -- 等待第十五周期的到来
  65. end if;
  66. when X_SHIFT => -- 实现待发数据的并串转换,转换完成立即进入X_WAIT状态,进行下一次发送
  67. txds := txdbuf(xbitcnt); -- 发送当前位数据
  68. xbitcnt := xbitcnt +1; -- 为发送下一位准备
  69. STATE <= X_WAIT; -- ...........
  70. when X_STOP => -- X_STOP状态 : 停止位发送,当数据帧发送完毕后,状态机进入该状态,并发送16个bclk周期的逻辑1信号,即1位停止位.然后进入X_IDLE状态,并等待另一个数据帧发送命令
  71. if xcnt16 >= "1111" then -- 发送结束后,
  72. if xmit_cmd_p = '0' then -- 等待下一个发送周期到来,
  73. STATE <= X_IDLE;
  74. busy <= '0';
  75. xcnt16 := "0000";
  76. else
  77. xcnt16 := xcnt16; -- 发送命令之间必须有停止切换
  78. STATE <= X_STOP;
  79. end if;
  80. txd_done <= '1'; -- 发送完成标志
  81. else xcnt16 := xcnt16 + 1; -- 等待第十六个周期的到来
  82. txds := '1'; -- 发送十六个周期的停止位
  83. STATE <= X_STOP;
  84. end if;
  85. when others => STATE <= X_IDLE; -- 其他未知状态
  86. end case;
  87. end if;
  88. txd <= txds; --
  89. end process;
  90. end Behavioral;

3、接收器源代码(receiver.vhd)

  1. 串行通信的接收器,分为五个状态
  2. R_START状态(等待起始位):当UART接收器复位后,接收状态机将处于这一个状态.在此状态下,状态机一直在等待RXD的电平跳转,从逻辑1变为逻辑0,即起始位,这意味着新的一帧UART数据帧的开始,一旦起始位被确定,状态机将转入R_CENTER状态
  3. R_CENTER状态(起始位确认状态): 当确认是起始位,并且稳定,转入R_WAIT?刺?本程序认为保持超过1/4个位时间的信号认为是起始信号
  4. R_WAIT状态 : 当状态机处于这一个状态时,等待计满15个bclk周期,在第16个bclk进入R_SAMPLE状态进行数据位的采样检测,同时也判断采集的数据位长度是否已经达到数据帧的长度,如果 = framlenr,就说明停止位来临
  5. R_SAMPLE状态: 即数据位采样检测,完成后无条件状态机转入R_WAIT等待,等待下次数据位的到来
  6. R_STOP状态: 输出 ready信号,表明该帧传输完毕,之后转入R_START状态

  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.ALL;
  3. use IEEE.STD_LOGIC_ARITH.ALL;
  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;
  5. ---- Uncomment the following library declaration if instantiating
  6. ---- any Xilinx primitives in this code.
  7. --library UNISIM;
  8. --use UNISIM.VComponents.all;
  9. entity receiver is
  10. generic( framlenr: integer := 8); -- 接收缓冲区大小 ,framlenr,接收数据帧长度
  11. Port ( bclkr : in STD_LOGIC; -- 时钟,波特率的16倍
  12. resetr : in STD_LOGIC; -- 复位信号
  13. rxdr : in STD_LOGIC; -- 接受数据(Received Data,RXD),通过RXD终端接受
  14. r_ready : out STD_LOGIC; -- 数据接受完毕信号, <= '1',表示接受完毕,只是标志位而已,在本程序无控制作用
  15. rbuf : out STD_LOGIC_VECTOR (7 downto 0) -- 数据接受缓冲区,存放接受数据
  16. );
  17. end receiver;
  18. architecture Behavioral of receiver is
  19. type STATES is (R_START, R_CENTER, R_WAIT, R_SAMPLE, r_STOP); -- 接收器状态,5种,
  20. signal State: STATES := R_START; -- 初始状态,START
  21. signal rxd_sync: STD_LOGIC; -- rxdr的同步信号,因为在逻辑1或逻辑0判断时,不希望检测的信号是不稳定的,所以,不直接检测RXD信号,而是检测经过同步信号xd_sync
  22. begin
  23. pro1:process(rxdr) -- 传递 rxdr 给同步信号 rxd_sync
  24. begin
  25. if rxdr = '0' then
  26. rxd_sync <= '0';
  27. else
  28. rxd_sync <= '1';
  29. end if;
  30. end process;
  31. pro2:process(bclkr, resetr, rxd_sync)
  32. variable count : STD_LOGIC_VECTOR (3 downto 0) := "0000"; -- 计数器,用于记录时钟周期,每16个时钟一个周期,即信号有效间隔
  33. variable rcnt : INTEGER := 0; -- 接收缓冲帧下标
  34. variable rbufs: STD_LOGIC_VECTOR ( 7 downto 0) := "00000000"; -- 接收缓冲区
  35. begin
  36. if resetr = '1' then -- 复位信号
  37. State <= R_START; -- 复位后状态为 R_START
  38. count := "0000"; -- 计数器清零
  39. elsif rising_edge(bclkr) then -- 上升沿有效
  40. case State is
  41. when R_START => -- R_START状态
  42. if rxd_sync = '0' then -- 接收开始情形: 电平从1变为0,并且保持16个波特率周期
  43. State <= R_CENTER; -- 当接收到 时钟下降时,进入R_CENTER状态,检测是否是开始位
  44. r_ready <= '0'; -- 置 r_ready 为 '0',等待准备接收数据
  45. rcnt := 0; -- 数据缓冲区下标 rcnt 清零
  46. else State <= R_START; -- 如果没有 收到时钟下降,则仍为R_START,继续等待开始信号
  47. r_ready <= '0'; -- 置 r_ready 为 '0',等待准备接收数据
  48. end if;
  49. when R_CENTER => -- R_CENTER状态,该状态检测开始信号是否为稳定的开始信号,如果是,则准备接收数据,如果不是,转入R_START状态
  50. if rxd_sync = '0' then
  51. if count = "0100" then -- 1/4个时钟周期检测开始信号
  52. State <= R_WAIT; -- 保持逻辑0超过1/4个周期后,进入R_WAIT状态,
  53. count := "0000"; -- count 清0,为接收数据做准备,接收数据的新??周期的开始
  54. else count := count + 1; -- count++
  55. State <= R_CENTER;
  56. end if;
  57. else
  58. State <= R_START; -- 逻辑信号'0',不稳定,进入R_START状态,重新等待开始信号
  59. end if;
  60. when R_WAIT => -- R_WAIT状态 : 当状态机处于这一个状态时,等待计满15个bclk周期,在第16个bclk进入R_SAMPLE状态进行数据位的采样检测,同时也判断采集的数据位长度是否已经达到数据帧的长度,如果 = framlenr,就说明停止位来临
  61. if count >= "1110" then -- 第十五个周期时,
  62. if rcnt = framlenr then -- 所有数据接收完毕,进入停止状态
  63. State <= R_STOP;
  64. else State <= R_SAMPLE; -- 所有数据仍未接收完毕,则第十六个周期进入R_SAMPLE进行采样
  65. end if;
  66. count := "0000"; -- 下一个采样周期的开始
  67. else count := count + 1; -- 未达到第十五个周期,count++
  68. State <= R_WAIT; -- 等第十五个周期的到来
  69. end if;
  70. when R_SAMPLE => -- R_SAMPLE状态: 即数据位采样检测,完成后无条件状态机转入R_WAIT等待,等待下次数据位的到来
  71. rbufs(rcnt) := rxd_sync; -- 进行数据采样
  72. rcnt := rcnt + 1; -- 下标向高位移一位
  73. State <= R_WAIT; -- 等待下一次采样
  74. when R_STOP => -- R_STOP状态: 输出 ready信号,表明该帧传输完毕,之后转入R_START状态
  75. r_ready <= '1';
  76. rbuf <= rbufs; -- 保存接收数据
  77. State <= R_START; -- 等待下一帧数据开始
  78. when others => STATE <= R_START; -- 其他未知状态
  79. end case;
  80. end if;
  81. end process;
  82. end Behavioral;



原文:http://blog.chinaunix.net/uid-8196371-id-1746811.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值