-- 本模块的功能是验证实现和PC机进行基本的串口通信的功能。需要在 --PC机上安装一个串口调试工具来验证程序的功能。 -- 程序实现了一个收发一帧10个bit(即无奇偶校验位)的串口控 --制器,10个bit是1位起始位,8个数据位,1个结束 --位。串口的波特律由程序中定义的div_par参数决定,更改该参数可以实 --现相应的波特率。程序当前设定的div_par 的值是0x104,对应的波特率是 --9600。用一个8倍波特率的时钟将发送或接受每一位bit的周期时间 --划分为8个时隙以使通信同步. --程序的工作过程是:串口处于全双工工作状态,按动key2,CPLD向PC发送 elcome" --字符串(串口调试工具设成按ASCII码接受方式);PC可随时向CPLD发送0-F的十六进制 --数据,CPLD接受后显示在7段数码管上。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY UART IS PORT ( clk : IN std_logic; rst : IN std_logic; rxd : IN std_logic; --串行数据接收端 txd : OUT std_logic; --串行数据发送端 en : OUT std_logic_vector(7 downto 0); -- 数码管使能 seg_data : OUT std_logic_vector(7 DOWNTO 0); --数码管数据 key_input : IN std_logic --按键输入 ); END UART;
ARCHITECTURE arch OF UART IS --//////////////////inner reg//////////////////// SIGNAL div_reg : std_logic_vector(15 DOWNTO 0);--分频计数器,分频值由波特率决定。分频后得到频率8倍波特率的时钟 SIGNAL div8_tras_reg : std_logic_vector(2 DOWNTO 0);--该寄存器的计数值对应发送时当前位于的时隙数 SIGNAL div8_rec_reg : std_logic_vector(2 DOWNTO 0); --寄存器的计数值对应接收时当前位于的时隙数 SIGNAL state_tras : std_logic_vector(3 DOWNTO 0); -- 发送状态寄存器 SIGNAL state_rec : std_logic_vector(3 DOWNTO 0); -- 接受状态寄存器 SIGNAL clkbaud_tras : std_logic; --以波特率为频率的发送使能信号 SIGNAL clkbaud_rec : std_logic; --以波特率为频率的接受使能信号 SIGNAL clkbaud8x : std_logic; --以8倍波特率为频率的时钟,它的作用是将发送或接受一个bit的时钟周期分为8个时隙 SIGNAL recstart : std_logic; -- 开始发送标志 SIGNAL recstart_tmp : std_logic; --开始接受标志 SIGNAL trasstart : std_logic; SIGNAL rxd_reg1 : std_logic; --接收寄存器1 SIGNAL rxd_reg2 : std_logic; --接收寄存器2,因为接收数据为异步信号,故用两级缓存 SIGNAL txd_reg : std_logic; --发送寄存器 SIGNAL rxd_buf : std_logic_vector(7 DOWNTO 0);--接受数据缓存 SIGNAL txd_buf : std_logic_vector(7 DOWNTO 0);--发送数据缓存 SIGNAL send_state : std_logic_vector(2 DOWNTO 0);--每次按键给PC发送"Welcome"字符串,这是发送状态寄存器 SIGNAL cnt_delay : std_logic_vector(19 DOWNTO 0);--延时去抖计数器 SIGNAL start_delaycnt : std_logic; --开始延时计数标志 SIGNAL key_entry1 : std_logic; --确定有键按下曛? SIGNAL key_entry2 : std_logic; --确定有键按下标志 --////////////////////////////////////////////// CONSTANT div_par : std_logic_vector(15 DOWNTO 0) := "0000000100000100"; --分频参数,其值由对应的波特率计算而得,按此参数分频的时钟频率是波倍特率的8倍,此处值对应9600的波特率,即分频出的时钟频率是9600*8 SIGNAL txd_xhdl3 : std_logic;
BEGIN en <="01010101" ;--7段数码管使能信号赋值 txd <= txd_xhdl3; txd_xhdl3 <= txd_reg ;
PROCESS(clk,rst) BEGIN IF (NOT rst = '1') THEN cnt_delay <= "00000000000000000000"; start_delaycnt <= '0'; ELSIF(clk'EVENT AND clk='1')THEN IF (start_delaycnt = '1') THEN IF (cnt_delay /= "11000011010100000000") THEN cnt_delay <= cnt_delay + "00000000000000000001"; ELSE cnt_delay <= "00000000000000000000"; start_delaycnt <= '0'; END IF; ELSE IF ((NOT key_input='1') AND (cnt_delay = "00000000000000000000")) THEN start_delaycnt <= '1'; END IF; END IF; END IF; END PROCESS;
PROCESS(clk,rst) BEGIN IF (NOT rst = '1') THEN key_entry1 <= '0'; ELSIF(clk'EVENT AND clk='1')THEN IF (key_entry2 = '1') THEN key_entry1 <= '0'; ELSE IF (cnt_delay = "11000011010100000000") THEN IF (NOT key_input = '1') THEN key_entry1 <= '1'; END IF; END IF; END IF; END IF; END PROCESS;
PROCESS(clk,rst) BEGIN IF (NOT rst = '1') THEN div_reg <= "0000000000000000"; ELSIF(clk'EVENT AND clk='1')THEN IF (div_reg = div_par - "0000000000000001") THEN div_reg <= "0000000000000000"; ELSE div_reg <= div_reg + "0000000000000001"; END IF; END IF; END PROCESS;
PROCESS(clk,rst) --分频得到8倍波特率的时钟 BEGIN IF (NOT rst = '1') THEN clkbaud8x <= '0'; ELSIF(clk'EVENT AND clk='1')THEN IF (div_reg = div_par - "0000000000000001") THEN clkbaud8x <= NOT clkbaud8x; END IF; END IF; END PROCESS;
PROCESS(clkbaud8x,rst) BEGIN IF (NOT rst = '1') THEN div8_rec_reg <= "000"; ELSE IF(clkbaud8x'EVENT AND clkbaud8x = '1') THEN IF (recstart = '1') THEN --接收开始标志 div8_rec_reg <= div8_rec_reg + "001";--接收开始后,时隙数在8倍波特率的时钟下加1循环 END IF; END IF; END IF; END PROCESS;
PROCESS(clkbaud8x,rst) BEGIN IF (NOT rst = '1') THEN div8_tras_reg <= "000"; ELSE IF(clkbaud8x'EVENT AND clkbaud8x = '1') THEN IF (trasstart = '1') THEN div8_tras_reg <= div8_tras_reg + "001";--发送开始后,时隙数在8倍波特率的时钟下加1循环 END IF; END IF; END IF; END PROCESS;
PROCESS(div8_rec_reg) BEGIN IF (div8_rec_reg = "111") THEN clkbaud_rec <= '1'; ---在第7个时隙,接收 ELSE clkbaud_rec <= '0'; END IF; END PROCESS;
PROCESS(div8_tras_reg) BEGIN IF (div8_tras_reg = "111") THEN clkbaud_tras <= '1'; --在第7个时隙,发送使能信号有效,将数据发出 ELSE clkbaud_tras <= '0'; END IF; END PROCESS;
PROCESS(clkbaud8x,rst) BEGIN IF (NOT rst = '1') THEN txd_reg <= '1'; trasstart <= '0'; txd_buf <= "00000000"; state_tras <= "0000"; send_state <= "000"; key_entry2 <= '0'; ELSE IF(clkbaud8x'EVENT AND clkbaud8x = '1') THEN IF (NOT key_entry2 = '1') THEN IF (key_entry1 = '1') THEN key_entry2 <= '1'; txd_buf <= "01110111"; --"w" END IF; ELSE CASE state_tras IS WHEN "0000" => --发送起始位 IF ((NOT trasstart='1') AND (send_state < "111") ) THEN trasstart <= '1'; ELSE IF (send_state < "111") THEN IF (clkbaud_tras = '1') THEN txd_reg <= '0'; state_tras <= state_tras + "0001"; END IF; ELSE key_entry2 <= '0'; state_tras <= "0000"; END IF; END IF; WHEN "0001" => --发送第1位 IF (clkbaud_tras = '1') THEN txd_reg <= txd_buf(0); txd_buf(6 DOWNTO 0) <= txd_buf(7 DOWNTO 1); state_tras <= state_tras + "0001"; END IF; WHEN "0010" => --发送第2位 IF (clkbaud_tras = '1') THEN txd_reg <= txd_buf(0); txd_buf(6 DOWNTO 0) <= txd_buf(7 DOWNTO 1); state_tras <= state_tras + "0001"; END IF; WHEN "0011" => --发送第3位 IF (clkbaud_tras = '1') THEN txd_reg <= txd_buf(0); txd_buf(6 DOWNTO 0) <= txd_buf(7 DOWNTO 1); state_tras <= state_tras + "0001"; END IF; WHEN "0100" => --发送第4位 IF (clkbaud_tras = '1') THEN txd_reg <= txd_buf(0); txd_buf(6 DOWNTO 0) <= txd_buf(7 DOWNTO 1); state_tras <= state_tras + "0001"; END IF; WHEN "0101" => --发送第5位 IF (clkbaud_tras = '1') THEN txd_reg <= txd_buf(0); txd_buf(6 DOWNTO 0) <= txd_buf(7 DOWNTO 1); state_tras <= state_tras + "0001"; END IF; WHEN "0110" => --发送第6位 IF (clkbaud_tras = '1') THEN txd_reg <= txd_buf(0); txd_buf(6 DOWNTO 0) <= txd_buf(7 DOWNTO 1); state_tras <= state_tras + "0001"; END IF; WHEN "0111" => --发送第7位 IF (clkbaud_tras = '1') THEN txd_reg <= txd_buf(0); txd_buf(6 DOWNTO 0) <= txd_buf(7 DOWNTO 1); state_tras <= state_tras + "0001"; END IF; WHEN "1000" => --发送第8位 IF (clkbaud_tras = '1') THEN txd_reg <= txd_buf(0); txd_buf(6 DOWNTO 0) <= txd_buf(7 DOWNTO 1); state_tras <= state_tras + "0001"; END IF; WHEN "1001" => --发送停止位 IF (clkbaud_tras = '1') THEN txd_reg <= '1'; txd_buf <= "01010101"; state_tras <= state_tras + "0001"; END IF; WHEN "1111" => IF (clkbaud_tras = '1') THEN state_tras <= state_tras + "0001"; send_state <= send_state + "001"; trasstart <= '0'; CASE send_state IS WHEN "000" => txd_buf <= "01100101"; --"e" WHEN "001" => txd_buf <= "01101100"; --"l" WHEN "010" => txd_buf <= "01100011"; --"c" WHEN "011" => txd_buf <= "01101111"; --"o" WHEN "100" => txd_buf <= "01101101"; --"m" WHEN "101" => txd_buf <= "01100101";-- "e" WHEN OTHERS => txd_buf <= "00000000"; END CASE; END IF; WHEN OTHERS => IF (clkbaud_tras = '1') THEN state_tras <= state_tras + "0001"; trasstart <= '1'; END IF; END CASE; END IF; END IF; END IF; END PROCESS;
PROCESS(clkbaud8x,rst) --接受PC机的数据 BEGIN IF (NOT rst = '1') THEN rxd_reg1 <= '0'; rxd_reg2 <= '0'; rxd_buf <= "00000000"; state_rec <= "0000"; recstart <= '0'; recstart_tmp <= '0'; ELSE IF(clkbaud8x'EVENT AND clkbaud8x = '1') THEN rxd_reg1 <= rxd; rxd_reg2 <= rxd_reg1; IF (state_rec = "0000") THEN IF (recstart_tmp = '1') THEN recstart <= '1'; recstart_tmp <= '0'; state_rec <= state_rec + "0001"; ELSE IF ((NOT rxd_reg1 AND rxd_reg2) = '1') THEN --检测到起始位的下降沿,进入接受状态 recstart_tmp <= '1'; END IF; END IF; ELSE IF (state_rec >= "0001" AND state_rec<="1000") THEN IF (clkbaud_rec = '1') THEN rxd_buf(7) <= rxd_reg2; rxd_buf(6 DOWNTO 0) <= rxd_buf(7 DOWNTO 1); state_rec <= state_rec + "0001"; END IF; ELSE IF (state_rec = "1001") THEN IF (clkbaud_rec = '1') THEN state_rec <= "0000"; recstart <= '0'; END IF; END IF; END IF; END IF; END IF; END IF; END PROCESS;
PROCESS(rxd_buf) --将接受的数据用数码管显示出来 BEGIN CASE rxd_buf IS WHEN "00110000" => seg_data <= "00000011"; --0 WHEN "00110001" => seg_data <= "10011111"; --1 WHEN "00110010" => seg_data <= "00100101"; --2 WHEN "00110011" => seg_data <= "00001101"; --3 WHEN "00110100" => seg_data <= "10011001"; --4 WHEN "00110101" => seg_data <= "01001001"; --5 WHEN "00110110" => seg_data <= "01000001"; --6 WHEN "00110111" => seg_data <= "00011111"; --7 WHEN "00111000" => seg_data <= "00000001"; --8 WHEN "00111001" => seg_data <= "00001001"; --9 WHEN "01000001" => seg_data <= "00010001"; --A WHEN "01000010" => seg_data <= "11000001"; --B WHEN "01000011" => seg_data <= "01100011"; --C WHEN "01000100" => seg_data <= "10000101"; --D WHEN "01000101" => seg_data <= "01100001"; --E WHEN "01000110" => seg_data <= "01110001"; --F WHEN OTHERS => seg_data <= "11111111"; END CASE; END PROCESS; END arch;
|