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

📄 rs422.vhd

📁 FPGA串口界面调试程序,用VHDL语言实现
💻 VHD
字号:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity rs422 is
port(
     reset,clk,clk_serial:in std_logic;
     rxd:in std_logic;                          --the baud rate of serial port is 19.2kbps.
     dsp0_rd:in std_logic;
     dsp0_addr:in std_logic_vector(3 downto 0); --[27..24]&[5..0]
     --dsp0_irq:out std_logic_vector(3 downto 0);
     dsp0_irq:out std_logic;
     dsp0_data:out std_logic_vector(15 downto 8);  --DSP0 external buswidth must be 64 bits.
     Doutp:out std_logic_vector(7 downto 0);
     D_enp:out std_logic;
     D_busyp:out std_logic;
     WPp:out std_logic_vector(3 downto 0);
     STATE_1p:out std_logic_vector(1 downto 0);
     Dsum1p:out std_logic_vector(7 downto 0);
     LENGTH1_1P:out std_logic_vector(3 downto 0);
     LENGTH1_2P:out std_logic_vector(3 downto 0);
     count1_1p:out std_logic_vector(7 downto 0);
     count1_2p:out std_logic_vector(3 downto 0);
     D_valid1_1p:out std_logic;
     D_error1_1p:out std_logic;
     data0:out std_logic_vector(7 downto 0);
     data1:out std_logic_vector(7 downto 0);
     data2:out std_logic_vector(7 downto 0);
     data3:out std_logic_vector(7 downto 0);
     data4:out std_logic_vector(7 downto 0);
     data5:out std_logic_vector(7 downto 0);
     tag0p:out std_logic;
     tag1p:out std_logic
    );
end rs422;

architecture rtl of rs422 is
constant N :integer:=15;     --定义一个常量作为内部FIFO的大小,若要修改,则改此处的值即可

signal temp  : std_logic_vector(7 DOWNTO 0); --数据缓存
signal D_en  : std_logic;--它的下降沿表明一个字节接收完毕
signal D_busy: std_logic;--接收串行数据的标志,为'0'表明正在接收
SIGNAL LENGTH1_1:integer range 0 to 15;
SIGNAL LENGTH1_2:integer range 0 to 15;
SIGNAL WP:INTEGER RANGE 0 TO N;  --这些RAM地址指针范围至少必须比其相应的RAM大小N值大1,原因在
                                          --后面的第401~406行程序中有说明
SIGNAL STATE_1:STD_LOGIC_VECTOR(1 DOWNTO 0);

SIGNAL Dout,Dsum1:std_logic_vector(7 DOWNTO 0);--Dout存放的是串口数据通过串并转换后的并行数据,Dsum1为从串口所接收的一帧数据内数据长度与数据包所有字节累加结果的低8位
SIGNAL D_valid1_1: std_logic:='1';--dsp0中断标志
SIGNAL D_valid1_2: std_logic:='1';--dsp0中断标志
SIGNAL D_error1_1: std_logic:='1';
SIGNAL count1_1:integer range 0 to 255;
SIGNAL count1_2:integer range 0 to 15;
SIGNAL count1_3:integer range 0 to 255;
SIGNAL tag0:std_logic;
SIGNAL tag1:std_logic;

TYPE MEMORY IS ARRAY (0 TO N) OF std_logic_vector(7 DOWNTO 0); --假设RAM1,RAM2大小为N个字节
SIGNAL RAM1,RAM2: MEMORY;

begin

-----------------------------------------------------------------------------------------------------------
--下面的进程实现串行数据的接收和串并转换,串行数据的格式为1位起始位,8位数据位,1位停止位。发送和接收
--数据速率均为19.2kbps,同步时钟频率为19.2k*25Hz=480kHz,内部有16个字节深度的FIFO,用于缓存接收和发送的数据
-----------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------
--进程1完成串行数据的接收和串并转换,串行数据格式为1位起始位'0',8位数据位和一位终止位'1'
---------------------------------------------------------------------------------------
p1:
process(clk_serial,reset,rxd)
variable flag : INTEGER RANGE 0 TO 3;
begin
   
    if(clk_serial'event and clk_serial='1') then   --1
       if reset='0' then             --2
          count1_1<=0;
          flag:=0;
          D_en<='1';
          D_busy<='1';
       else      
          if(flag=0) then           --3等待起始位
             count1_1<=0;
             if(rxd='0') then         --起始位
                flag:=1;
                D_en<='1';
                D_busy<='1';
             end if;   
          elsif(flag=1) then         --检测起始位
             count1_1<=count1_1+1;
             if(count1_1=13) then
                count1_1<=0; 
                if(rxd='0') then
                   flag:=2;         --12个时钟周期后rxd仍为零则开始接收
                   D_en<='1';
                   D_busy<='0';     --D_busy<='0'表明正在接收串口的数据
                else
                   flag:=0;
                   D_en<='1';
                   D_busy<='1';
                end if;
             end if;   
          elsif(flag=2) then
             count1_1<=count1_1+1;
             case count1_1 is
                  when 25 => temp(0)<=rxd;
                  when 50 => temp(1)<=rxd;
                  when 75 => temp(2)<=rxd;
                  when 100=> temp(3)<=rxd;
                  when 125=> temp(4)<=rxd;
                  when 150=> temp(5)<=rxd;
                  when 175=> temp(6)<=rxd;
                  when 200=> temp(7)<=rxd;
                  when 225=>      --检测停止位
                       if(rxd='1') then
                          Dout<=temp;
                       else
                          flag:=0;
                       end if;      
                  when 226 =>   D_en<='0'; --一个字节数据接收完毕,串并转换完成,置D_en为0说明已有数据可读取,缓冲区满   
                                      D_busy<='1'; 
                  when 235 =>         flag:=0; count1_1<=0; D_en<='1'; D_busy<='1';
                  when others => D_en<='1'; D_busy<='1';                           
             end case;                                       
          end if;                    --3
       end if;                       --2
    end if;                         --1
end process;
       Doutp<=temp;
       D_enp<=D_en;
       D_busyp<=D_busy;
       count1_1p<=conv_std_logic_vector(count1_1,8);
-------------------------------------------------------------------------------------------------------------------------------------
--进程2将串口发送过来的数据存储到RAM1中,若数据正确,则向DSP0发中断(D_valid1_1<='0'低有效),若有误则发数据出错标志(D_error1_1<='0'低有效)
--------------------------------------------------------------------------------------------------------------------------------------
p2:
process(clk_serial,reset,Dout,D_en,D_busy)
begin
   if (D_en'EVENT and D_en='0') then --D_en下降沿表明接收了一字节数据,有数据可读取,用它的上升沿来锁存数据,确保数据的稳定与正确
      if (reset='0') then
          WP<=0;                     
          STATE_1<="00";        --CNT1为0说明未接收帧内数据
          Dsum1<="00000000";
          D_valid1_1<='1';
          D_error1_1<='1';
          LENGTH1_1<=0;
          LENGTH1_2<=0;
      elsif (WP=0 and Dout="10101010" and STATE_1="00") then   --检测数据是否为
          RAM1(WP)<=Dout;   --帧头AAH,如果是的话置状态标志STATE_1为"01",
          STATE_1<="01";     --如果WP不为0,则说明此时的Dout一定不是帧头
          WP<=WP+1;         --帧内各数据从RAM1(0)开始顺序存放
          Dsum1<="00000000";
          D_valid1_1<='1'; 
          D_error1_1<='1'; 
          LENGTH1_1<=0;
          LENGTH1_2<=0;  
      elsif (WP=1 and Dout="01010101" and STATE_1="01") then  --检测第二个帧头55H,
                            --如果是的话置状态标志STATE_1为"10",说明下面将接收到数据长度以及真正的数据
          RAM1(WP)<=Dout;   --如果WP不为1,则说明此时的Dout一定不是帧头,在接收数据的过程中状态标志STATE_1一直保持为"10",           
          STATE_1<="10";     
          WP<=WP+1;
          Dsum1<="00000000";
          D_valid1_1<='1';
          D_error1_1<='1'; 
          LENGTH1_1<=0;
          LENGTH1_2<=0;
      elsif(WP=2 and STATE_1="10") then--接收数据长度
          RAM1(WP)<=Dout;    --若是的话置状态标志STATE_1为"11"        
          WP<=WP+1;           --如果WP不为2,则说明此时的DATA2一定不是数据长度
          STATE_1<="11"; --说明下面将接收到数据长度以及真正的数据,在接收数据的过程中状态标志STATE_1一直保持为"11"
          Dsum1<=Dsum1+Dout; 
          D_valid1_1<='1';
          D_error1_1<='1'; 
          LENGTH1_1<=conv_integer(Dout)+4; 
          LENGTH1_2<=conv_integer(Dout)+4; 
      elsif(STATE_1<="11" and WP<=(N-1)) then
         if(WP<LENGTH1_1-1) then                 --STATE_2为"11"说明是需要接收的一帧数据,否则不写入到RAM2中去
           RAM1(WP)<=Dout;
           Dsum1<=Dsum1+Dout;
           WP<=WP+1;
           D_valid1_1<='1';
           D_error1_1<='1'; 
         elsif(Dsum1=Dout) then --校验和正确,说明接收的一帧数据是正确的,一帧数据接收完毕,将指针、状态标志复位,数据有效(D_valid2_1<='0'),既有数据可读
           RAM1(WP)<=Dout;
           STATE_1<="00";
           WP<=0; 
           Dsum1<="00000000";
           D_valid1_1<='0';
           D_error1_1<='1'; 
           LENGTH1_1<=0;
         else --校验和不正确,说明数据有误,将指针、状态标志复位,数据出错标志(D_error2<='0')
           STATE_1<="00";
           WP<=0;  
           D_error1_1<='0'; 
           LENGTH1_1<=1; 
         end if;      
      else   --没有正确检测到帧头,将指针、状态标志复位,数据出错标志(D_error2<='0')  
           STATE_1<="00";
           WP<=0;  
           D_error1_1<='0'; 
           LENGTH1_1<=1;    
      end if;   --RAM1(2)中存放的是不包含帧头和校验和的帧长度
   end if;
end process;     
      D_valid1_1p<=D_valid1_1;
      D_error1_1p<=D_error1_1;
      WPp<=conv_std_logic_vector(WP,4);
      STATE_1p<=STATE_1;
      Dsum1p<=Dsum1;
      LENGTH1_1P<=conv_std_logic_vector(LENGTH1_1,4); 
      LENGTH1_2P<=conv_std_logic_vector(LENGTH1_2,4);
      data0<=RAM1(0);
      data1<=RAM1(1);
      data2<=RAM1(2);
      data3<=RAM1(3);
      data4<=RAM1(4);
      data5<=RAM1(5);
----------------------------------------------------------------------------------------------------------------
p3:
process(clk,reset,D_valid1_1)
begin
   if(clk'event and clk='1') then
      if(reset='0') then
         count1_2<=0;
         tag0<='0';
      elsif(D_valid1_1='1') then
         count1_2<=0;
         tag0<='1';
      elsif(tag0='1' and D_valid1_1='0') then
         if(count1_2<14) then
            count1_2<=count1_2+1;
         else
            count1_2<=14;
            tag0<='0';
         end if;
      end if;
   end if;
end process;
   count1_2p<=conv_std_logic_vector(count1_2,4);
   tag0p<=tag0;
p4:
process(clk,reset,D_valid1_1,count1_2)
begin
   if(clk'event and clk='0') then
      if(reset='0') then
         D_valid1_2<='1';
         tag1<='0';
      elsif(D_valid1_1='1') then
         D_valid1_2<='1';
         tag1<='1';
      elsif(tag1='1' and D_valid1_1='0') then
         if(count1_2<14) then
            D_valid1_2<='0';
         else
            D_valid1_2<='1';
         end if;
      end if;
   end if;
end process;         
   tag1p<=tag1;
   --dsp0_irq(0)<=D_valid1_2;   
   dsp0_irq<=D_valid1_2;  
----------------------------------------------------------------------------------------------------------------
--进程5将RAM1中的数据写入dsp0中
-------------------------------
p5:
process(dsp0_rd,dsp0_addr(3 downto 0),RAM1)
begin
   if(dsp0_rd'event and dsp0_rd='0') then
      case dsp0_addr(3 downto 0) is
           when "0000"  => dsp0_data(15 downto 8)<=RAM1(0);  --帧头AAH
           when "0001"  => dsp0_data(15 downto 8)<=RAM1(1);  --帧头55H
           when "0010"  => dsp0_data(15 downto 8)<=RAM1(2);  --数据长度
           when "0011"  => dsp0_data(15 downto 8)<=RAM1(3);
           when "0100"  => dsp0_data(15 downto 8)<=RAM1(4);
           when "0101"  => dsp0_data(15 downto 8)<=RAM1(5);
           when "0110"  => dsp0_data(15 downto 8)<=RAM1(6);
           when "0111"  => dsp0_data(15 downto 8)<=RAM1(7);
           when "1000"  => dsp0_data(15 downto 8)<=RAM1(8);
           when "1001"  => dsp0_data(15 downto 8)<=RAM1(9);
           when "1010"  => dsp0_data(15 downto 8)<=RAM1(10);
           when "1011"  => dsp0_data(15 downto 8)<=RAM1(11);
           when "1100"  => dsp0_data(15 downto 8)<=RAM1(12);
           when "1101"  => dsp0_data(15 downto 8)<=RAM1(13);
           when "1110"  => dsp0_data(15 downto 8)<=RAM1(14);
           --when "1111"  => dsp0_data(15 downto 8)<=RAM1(15);
           
           when others =>dsp0_data(15 downto 8)<="ZZZZZZZZ"; 
       end case;
   end if;
end process;        


end rtl;

⌨️ 快捷键说明

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