⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart.vhd

📁 在VHDL上编写了UART通信协议
💻 VHD
字号:
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity UART is
port(
	rst   : in std_logic;--复位 
	clk1  : in std_logic;--发送模块工作时钟
	clk16 : in std_logic;--接收模块工作时钟
	rd    : in std_logic;--MCU读UART
	wr    : in std_logic;--MCU写UART
	cs    : in std_logic;--UART片选 
	ad	  : in std_logic;--当前帧为地址帧还是数据帧 1--地址;0--数据
	rxd   : in std_logic;--串行接收 
	txd   : out std_logic;--串行发送 
	ri	  : out std_logic;--为1表示接收到一帧 
	ti    : out std_logic;--为1表示已经发送完一帧
	err	  : out std_logic;--为一表示接收到一个错误帧
	data  : inout std_logic_vector(7 downto 0)--数据总线
    );
end UART;

architecture behav of UART is

    constant s0 :std_logic_vector(2 downto 0):= "001";	--就绪
    constant s1 :std_logic_vector(2 downto 0):= "011";	--发送
    constant s2 :std_logic_vector(2 downto 0):= "111";  --发送完成
    constant s3 :std_logic_vector(2 downto 0):= "110";  --接收正确
    constant s4 :std_logic_vector(2 downto 0):= "100";  --接收错误
	constant address  : std_logic_vector(7 downto 0):="00000001";--本片地址
	constant close_all: std_logic_vector(7 downto 0):="11111111";--使所有从机的sm2置1	
	
	signal sst,ssr: std_logic_vector(2 downto 0);
	signal txdcnt,rxdcnt,cnt: std_logic_vector(3 downto 0);
	signal rbuf,tbuf: std_logic_vector(7 downto 0);
	signal r_shift,t_shift: std_logic_vector(11 downto 0);
	signal receive: std_logic;
	signal over: std_logic_vector(1 downto 0);
	signal sm2: std_logic :='1';

begin
	
	process(rst,clk1)	--状态转换
	begin
		if cs='0' then
			if rst = '0' then
				sst<=s0;
				ssr<=s0;
			elsif clk1'event and clk1 = '1' then
				case sst is 
					when s0 =>
						if wr='0' then
							sst<=s1;	
						end if;
					when s1 =>
						if txdcnt=12 then
							sst<=s2;
						end if;
					when s2 =>	
						sst<=s0;
					when others =>
						sst <= s0;
				end case;
				case ssr is
					when s0 =>
						if over="01" then
							ssr<=s3;
						elsif over="10" then
							ssr<=s4;
						end if;
					when s3 =>
						if rd='0' then
							ssr<=s0;
						elsif over="10" then
							ssr<=s4;
						end if;
					when s4 =>
						if rd='0' then
							ssr<=s0;
						end if;
					when others =>
						ssr<=s0;
					end case;
			end if;
		end if;
	end process;	
	
	
	process(rst,clk1)--串行发送
	begin
		if cs ='0' then
			if rst = '0' then
				txd<='1';
			elsif clk1'event and clk1 = '1' then
				if wr='0' then
					t_shift(0)<='0';
					t_shift(8 downto 1)<=tbuf;
					t_shift(9)<=tbuf(0)xor tbuf(1)xor tbuf(2)xor tbuf(3)xor tbuf(4)xor tbuf(5)xor tbuf(6)xor tbuf(7);
					t_shift(10)<=ad;
					t_shift(11)<='1';
				end if;
				if sst = s1 then
					txd <= t_shift(0);
					t_shift(0)<=t_shift(1);
					t_shift(1)<=t_shift(2);
					t_shift(2)<=t_shift(3);
					t_shift(3)<=t_shift(4);
					t_shift(4)<=t_shift(5);
					t_shift(5)<=t_shift(6);
					t_shift(6)<=t_shift(7);
					t_shift(7)<=t_shift(8);
					t_shift(8)<=t_shift(9);
					t_shift(9)<=t_shift(10);
					t_shift(10)<=t_shift(11);
				else txd<='1';
				end if;
			end if;
		end if;
	end process;
	
	process(rst,clk1)	--txd counter
	begin
		if cs ='0' then
			if rst= '0' then
				txdcnt<=(others =>'0');
			elsif clk1'event and clk1='1' then
				if sst=s1 then
					if txdcnt=12 then
						txdcnt<=(others=>'0');
					else txdcnt<=txdcnt+1;
					end if;
				end if;
			end if;
		end if;
	end process;
	----------------------------------------------------------------
	----------------------------------------------------------------
	process(rst,clk16)
		variable tem7,tem8 :std_logic;
	begin
		if cs ='0' then
			if rst='0' then
				tem7:='0';
				tem8:='0';		
				r_shift<=(others=>'0');	
			elsif clk16'event and clk16='1' then			
				if cnt=7 then
					tem7 :=rxd;
				elsif cnt=8 then
					tem8 :=rxd;
				elsif cnt=9 then			
					r_shift(0)<=r_shift(1);	
					r_shift(1)<=r_shift(2);
					r_shift(2)<=r_shift(3);
					r_shift(3)<=r_shift(4);
					r_shift(4)<=r_shift(5);
					r_shift(5)<=r_shift(6);
					r_shift(6)<=r_shift(7);
					r_shift(7)<=r_shift(8);
					r_shift(8)<=r_shift(9);
					r_shift(9)<=r_shift(10);
					r_shift(10)<=r_shift(11);
					r_shift(11)<=(tem7 and tem8)or(tem7 and rxd)or(tem8 and rxd);
				end if;
			end if;
		end if;
	end process;
	
	process(rst,clk16)--add cnt
	begin
		if cs ='0' then
			if rst='0' then
				cnt<=(others=>'0');
				receive<='0';
				over<="00";
				sm2<='1';	
			elsif clk16'event and clk16='1' then
				if rd='0' then--当读信号有效时over  复位。 
					over<="00";
				end if;
				if receive='0' then	
					if rxd='0' then
						cnt<=cnt+1;
						if cnt=8 then
							receive<='1';
						end if;
					end if;
				else cnt<=cnt+1;
					if rxdcnt=12 then
						receive<='0';
						cnt<="0000";
						if r_shift(10)='1' then--如果是广播帧
							if (r_shift(8 downto 1) = close_all) then--如果是置位sm2信号
								sm2<='1';
							end if;
							if sm2='1' and (r_shift(8 downto 1) = address) then--如果地址匹配
								sm2<='0';
							end if;
						elsif sm2='0' then--如果是单机通信,则直接接收
							if (r_shift(1)xor r_shift(2)xor r_shift(3)xor r_shift(4)xor r_shift(5)xor r_shift(6)xor r_shift(7)xor r_shift(8)xor r_shift(9))= '0' then
								rbuf <= r_shift(8 downto 1);
								over<="01";	--正常结束    
							else over<="10";--奇偶校验错
							end if;	
							if r_shift(11)='0' or ssr/=s0 then--祯格式错或者发生覆盖
								over<="10";
							end if;								
						end if;
					end if;
				end if;
			end if;
		end if;
	end process;
	
	
	process(rst,clk16)--接收移位寄存器-->接收缓冲器
		begin
		if cs ='0' then
			if rst='0' then
				rxdcnt<=(others=>'0');
			elsif clk16'event and clk16='1' then
				if receive='0' then
					rxdcnt<=(others=>'0');
				elsif cnt=15 then
					rxdcnt<=rxdcnt+1;
				end if;
			end if;
		end if;
	end process;

	data <= rbuf when rd = '0' else "ZZZZZZZZ";	
	tbuf <= data when wr = '0' ;
	
	ti<='1' when sst=s2 else '0';
	ri<='1' when ssr/=s0 else '0';
	err<='1' when ssr=s4 else '0';
	
end behav;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -