基于FPGA的UART串口通信实验(VHDL语言实现)

时间:2019-01-23
本文章向大家介绍基于FPGA的UART串口通信实验(VHDL语言实现),主要包括基于FPGA的UART串口通信实验(VHDL语言实现)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
                                      **基于FPGA的UART串口通信实验(VHDL语言实现)**

一、前言:
最近在做UART串口通信的相关实验,然后在网上查了很多资料,发现网上的大多数代码错误太多且难以理解。故在完成此实验后,起了写一篇博客的心思,以供有想做相关实验的朋友参阅。
二、实验要求:
(1)实现和 PC 双向通信
(2)可通过 FPGA 的键盘扫描,在开发板上设置控制参数,输入发送内容
(3)通信波特率可调
(4)LCD 液晶屏实现菜单、接收到的数据显示

注:关于UART串口通信实验的相关理论网上很多,而且都很详细,我在这里都不赘余了,我的重点是代码及其分析。本次使用到的FPGA开发板为: Cyclone Ⅱ EP2C5Q208C8 核心的MAGIC3200_EP2C5 开发板。

三、引脚分配:

四、代码及其分析:

注:此处代码有两个文件,一个是主文件,另外一个是按键消抖文件。(按键消抖文件可去可不去,影响不大)
先上按键消抖文件,此处代码比较好理解。

------------------------------------------------按键消抖文件---------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity key5 is                      --按键防抖动
	port(
	  CLK,RESET:      in std_logic; --时钟以及有效位
	  din:            in std_logic; --是按键,可能与防抖动有关!
	  dout:           out std_logic --'0'有效	 
	);
end key5;

architecture Behavioral of key5 is

   signal count		    :	integer range 0 to 3000000	;	 --分频器
	signal keyclk		:	std_logic	;	                 --分频器
	type state is(s0,s1);                                    --定义两种状态
	signal pre_s,next_s:state;                               --状态机指针

begin

	process(CLK,RESET)	--时钟进程,产生各种时钟信号
	begin
	 	if RESET='0' then	  keyclk<='0';count<=0;		
		elsif CLK'event and CLK='1' then	 

			count<=count+1;

			if count=3000000 then keyclk<=not keyclk;	count<=0;
			else count<=count+1;
			end if;

		end if;             --毫秒时钟
	end process;
	process(keyclk,RESET)	--状态机激励源
	begin
	 	if RESET='0' then	  pre_s<=s0;		
		elsif keyclk'event and keyclk='1' then	 pre_s<=next_s;	 		
		else null;
		end if;	 	
	end process;

	process(pre_s,next_s,din)	--
	begin
	 	case pre_s is
			when s0=>
						dout<='1';
						if din='0' then next_s<=s1; --检测到按键
						else next_s<=s0;
						end if;

			when s1=>
			         dout<='1';
						if din='0' then dout<='0'; --检测到按键
						else next_s<=s0;
						end if;
		
			when others => next_s<=s0;
		end case;
	end process;
end Behavioral;
------------------------------------------------按键消抖文件---------------------------------------------------------

下面是主程序文件,我们重点来分析这一块。

------------------------------------------------主程序文件-----------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity RS232 is
port
	(
			RESET		    :	in  std_logic;                      --复位信号
			CLK		        :  	in  std_logic;                      --时钟输入,50MHZ
			KeyIn	        :	in  std_logic_vector(3 downto 0);	--column列电平
            KeyOut	        :	out std_logic_vector(3 downto 0);   --row行电平
		
		
		    JX		    :  	in	std_logic;   --改变波特率(键盘上X、Y、Z三个键分别对应波特率9600、19200、38400)
			KEYA		:  	in	std_logic;  
			UART0_RX	:	in	std_logic;
			UART0_TX 	:	out	std_logic;
			
			LCD_RESET   :    out std_logic ;       
            LCD_RW      :    out std_logic ;
            LCD_RS      :    out std_logic ;
            LCD_E       :    out std_logic ;
            LCD_D       :    buffer  std_logic_vector ( 7 downto 0) 
			

	
	);

end RS232;

architecture Behavioral of RS232 is

 type states is ( set ,clr ,set_d ,open1,set_addr,set_ddrom1,
                  set_ddrom2,set_ddrom3,set_ddrom4,set_ddrom5,set_1,
                   set_ddrom6,set_ddrom7,set_ddrom8,set_ddrom9,set_ddrom10,
                   set_ddrom11,set_ddrom12,set_ddrom13,s1,s2,
                   set_addrh4,set_ddrom1h4,
                  set_ddrom2h4,set_ddrom3h4,set_ddrom4h4,set_ddrom5h4,set_1h4,
                   set_ddrom6h4,set_ddrom7h4,set_ddrom8h4);
 signal current_state  : states :=set ;  --上述代码均和LCD显示屏有关

 	Signal timecnt		    :	    integer range 0 to 100000;   --分频计数器,用来得到10ms时钟
	Signal time10ms	        :	    std_logic	;	             --10ms时钟
	Signal scanvalue        :       std_logic_vector(3 downto 0);--记录扫描数据
	Signal combvalue        :       std_logic_vector(7 downto 0);--KeyIn、KeyOut组合值
	Signal cpy_scanvalue    :       std_logic_vector(3 downto 0);--备份扫描数据	
	Signal JX		        :	    std_logic_vector(2 downto 0);
    Signal Data00           :	    std_logic_vector(9 downto 0);	


	Signal	Clock9600	:	std_logic;--9600波特率时钟,发送
	Signal	Clock3		:	std_logic;--9600三倍频采样时钟,用于接收采用

 	Signal Send_data	:	std_logic_vector(9 downto 0);	 --发送寄存器
	Signal Send_en     	:   std_logic;--串口发送使能,0有效
	Signal Send_over    :   std_logic;--串口发送完成,0有效

	Signal Rx_Hold		:   std_logic;--串口接收到起始位标志

	Signal Rx_Valid		:	std_logic;--标志接收到一字节有效数据
	Signal Rx_Data		:	std_logic_vector(7 downto 0);	 --接收寄存器
	Signal Data1		:	std_logic_vector(3 downto 0);
	Signal Data2		:	std_logic_vector(3 downto 0);


	signal count		:	integer range 0 to 100000	;	--分频器,产生毫秒时钟基准
	
	signal dout		    :   std_logic;  --A键
	
	signal clkcnt       : std_logic_vector(13 downto 0);
    signal LCD_Clk      : std_logic;
       
	component key5 	  --按键防抖动
	port(
	  			CLK,RESET:in std_logic;
	  			din:in std_logic;
	  			dout:out std_logic--'0'有效	  
			);
	end component;

 ------------------------------------------------波特率设置部分--------------------------------------------------------     
  begin

	LCD_RESET <='1';LCD_RW <= '0' ;
	
	
	
	process(CLK,RESET,Rx_Hold)  --时钟产生进程
			variable	ClockCount	    :	integer range 0 to 5208 :=0;
			variable	ClockCount_Rx	:	integer range 0 to 314  :=0;
			variable	ClockCount1	    :	integer range 0 to 5208 :=0;
			variable	ClockCount_Rx1	:	integer range 0 to 314  :=0;


	begin
	

							  
							  
		if RESET='0' then	 time10ms<='0';
			
			elsif (rising_edge(CLK)) then	 ClockCount:=ClockCount+1;ClockCount_Rx:=ClockCount_Rx+1	;timecnt<=timecnt+1;
			
                             --产生9600时钟,1/50MHZ*5208=1/9600
                            
                      	case JX is	 	--波特率选择
					when "100" => ClockCount1:=5208;ClockCount_Rx1:=314;
					when "010" => ClockCount1:=2604;ClockCount_Rx1:=157;
					when "001" => ClockCount1:=1302;ClockCount_Rx1:=78;

			 		when others => null;
                       end case;
							  
							if ClockCount=ClockCount1 then	Clock9600<='1'; 
							ClockCount:=0;
			                else	Clock9600<='0';
			                end if;
								 
						  

                            
                             if timecnt=100000 then  time10ms<=not time10ms; timecnt<=0;
			     end if;


			     --16倍超采样,5208/16=325
			     if ClockCount_Rx=ClockCount_Rx1 then	Clock3<='1';ClockCount_Rx:=0;
			     else Clock3<='0';
			     end if;
				
				 
				
				             
							 
							 if(clkcnt="10000000000000")then  clkcnt<="00000000000000";
                             else  clkcnt<=clkcnt+1;
                          	 end if;
			
		 end if;

	end process;
	--注:以上代码注释 均是以波特率9600为例,case语句部分即为波特率选择部分。
 ------------------------------------------------键盘扫描部分--------------------------------------------------------      
 LCD_Clk<=clkcnt(6);
  
	--进程2:键盘扫描输出
	process( time10ms,RESET)
	begin

		if RESET='0' then	 	scanvalue<="0001";combvalue<="00000000";	
	Data00<="0000000000";	--初始化
		elsif time10ms'event and time10ms='1' then	--每10ms进行一次键盘扫描
			KeyOut<=scanvalue; --输出扫描值	 		
			cpy_scanvalue<=scanvalue; 	--备份扫描值,为了进程3对扫描结果进行比较	

			 case scanvalue is	  --扫描值移位
					
					when "0001" => scanvalue<="0010";
					when "0010" => scanvalue<="0100";
					when "0100" => scanvalue<="1000";
					when "1000" => scanvalue<="0001";										
					when others => scanvalue<="0001";
			 end case;	

			combvalue<= (KeyIn & cpy_scanvalue); --组合键盘扫描的输入和输出

			 case combvalue is	  --翻译扫描结果
					
					when "00010001" => Data00<="1000000010"; --对应键盘“1”
					when "00100001" => Data00<="1000000100"; --对应键盘“2”
					when "01000001" => Data00<="1000000110"; --对应键盘“3”
					when "10000001" => JX<="100";               --对应键盘“X”

					when "00010010" => Data00<="1000001000"; --对应键盘“4”
					when "00100010" => Data00<="1000001010"; --对应键盘“5”
					when "01000010" => Data00<="1000001100"; --对应键盘“6”
					when "10000010" => JX<="010";               --对应键盘“Y”

					when "00010100" => Data00<="1000001110"; --对应键盘“7”
					when "00100100" => Data00<="1000010000"; --对应键盘“8”
					when "01000100" => Data00<="1000010010"; --对应键盘“9”
					when "10000100" => JX<="001";               --对应键盘“Z”

					when "00011000" => Data00<="1000001000"; --对应键盘“0”
					when "00101000" => null;               --对应键盘“+”
					when "01001000" => null;               --对应键盘“-”
					when "10001000" => null;               --对应键盘“=”

					when others => null; --无键盘按下
					
			 end case;				


		end if;

	end process;


 ------------------------------------------------串口发送部分--------------------------------------------------------     

	process(Clock9600)	--串口发送程序

		variable Send_count	:	integer range 0 to 9 :=0;	--位发送计数						  
	begin
				  		
		if Send_en='1' then	Send_count:=0;UART0_TX<='1';Send_over<='1';
		elsif rising_edge(Clock9600) then

			if Send_count=9 then  UART0_TX<=Send_data(9);	Send_over<='0';
			else UART0_TX<=Send_data(Send_count);  Send_count:=Send_count+1; 
			end if;
	
		end if;

	end process;

	Key0:key5 port map(CLK=>CLK,RESET=>RESET,din=>KEYA,dout=>dout); --元件例化
	


	process(dout,Clock9600,RESET)  --发送激励
			
	begin
		if RESET='0' then	 Send_en<='1';Send_data<="1000000000";
		else
			if rising_edge(dout) 
			then Send_en<='0'; Send_data<=Data00; 
			end if;

			if Send_over='0'	 then  Send_en<='1';  end if;
		end if;

	end process;
	


 ------------------------------------------------串口接收部分--------------------------------------------------------     

	process(RESET,CLK,Rx_Valid) --串口接收检测起始位
		
	begin
		if RESET='0' then Rx_Hold<='0';
		else 
			if UART0_RX='0' and  Rx_Hold='0' then 	Rx_Hold<='1';  --挂起串口接收
			elsif	 Rx_Valid'event and Rx_Valid='0' then Rx_Hold<='0';
	   	end if;
			
		end if;					  	
	end process;



	process(RESET,Clock3) --
		variable m:integer range 0 to 168 :=0;
	begin
		if RESET='0' then Rx_Valid<='0';m:=0;
		elsif rising_edge(Clock3) and Rx_Hold='1'
		then 	
			case m is
				when 24 =>	Rx_Data(0)<=UART0_RX;
				when 40 =>	Rx_Data(1)<=UART0_RX;
				when 56 =>	Rx_Data(2)<=UART0_RX;
				when 72 =>	Rx_Data(3)<=UART0_RX;
				when 88 =>	Rx_Data(4)<=UART0_RX;
				when 104 =>	Rx_Data(5)<=UART0_RX;
				when 120 =>	Rx_Data(6)<=UART0_RX;
				when 136=>	Rx_Data(7)<=UART0_RX;  
				when 152 =>	Rx_Valid<='1';
				when 168=> m:=0;Rx_Valid<='0';
				when others  => null;
			end case;
		  	
						
			m:=m+1;
		
				end if;
			
	end process;


	process(Rx_Valid,CLK)
	begin

		if RESET='0' then	Data1<="0000";	Data2<="0000";
		else
		

			
		if rising_edge(Rx_Valid) then	
	 		Data1<=Rx_Data(3)&Rx_Data(2)&Rx_Data(1)&Rx_Data(0);
	 		Data2<=Rx_Data(7)&Rx_Data(6)&Rx_Data(5)&Rx_Data(4);
		end if;

		end if;
	end process;
 ---------------------------------------LCD12864基本参数设置---------------------------------------------------------     
control:  process ( LCD_Clk,current_state )
          variable fanwei:integer:=2500;
          variable cnt : integer:=0 ;
    begin
     if LCD_Clk'event and LCD_Clk='1' then     
        case current_state is
         when    set => LCD_RS<='0';                        --功能设定
                        LCD_D<="00110000" ;                 ----30h
                        LCD_E<='0';
                   if cnt=2 then LCD_E<='1' ;cnt:=cnt+1 ;
                      else LCD_E<='0' ; cnt:=cnt+1 ;
                   end if ;
                   if cnt=fanwei*2 then
                      current_state<=clr ;cnt:=0 ;else current_state<=set ;
                   end if ;
         when    clr => LCD_E<='0' ;
                        LCD_RS<='0' ;
                        LCD_D<="00000001";                ---清除显示  ,01H
                   if cnt=2 then LCD_E<='1'; cnt:=cnt+1 ;
                       else LCD_E<='0'; cnt:=cnt+1;
                   end if ;
                   if cnt=fanwei*2 then
                        current_state<=set_d ;cnt:=0 ; else current_state<=clr ;
                   end if ;
         when  set_d => LCD_E<= '0' ;                 -----设定显示的移动方向,06H
                        LCD_RS<= '0' ;
                        LCD_D<="00000110";
                    if cnt=2 then LCD_E<='1';cnt:=cnt+1;
                         else LCD_E<='0';cnt:=cnt+1;
                    end if ;
                    if cnt=fanwei*2 then
                         current_state <=open1; cnt :=0 ;  else current_state<=set_d;
                    end if ;
        
        
          when open1=> LCD_E<='0' ;                   -----显示状态开或关    0FH
                       LCD_RS<='0' ;
                       
						LCD_D<="00001100";
                     if cnt=2 then LCD_E<= '1'; cnt:=cnt+1 ;
                        else LCD_E<='0'; cnt:=cnt+1 ;
                     end if ;
                     if cnt=fanwei*2 then
                         current_state<=set_addr ;cnt:=0 ; else current_state<=open1;
                      end if ;
                      
                      
    --------------------------------第一行 显示“波特率:(波特率数值)”------------------------------------------                  
when set_addr=>LCD_E<='0' ;
                         LCD_RS<='0' ;             
                         LCD_D<=X"80";           --------设定地址 80H
                       if cnt=2 then LCD_E<='1'; cnt:=cnt+1 ;
                           else LCD_E<='0'; cnt :=cnt+1 ;
                       end if ;
                       if cnt=fanwei*2 then
                         current_state<=set_ddrom1 ;cnt:=0;  else current_state<=set_addr;
                       end if ;
          when set_ddrom1=>LCD_E<='0' ;
                         LCD_RS<='1' ;
                         LCD_D<=X"B2";                   ----‘波’高字节
                       if cnt=2 then LCD_E<='1'; cnt:=cnt+1 ;
                           else LCD_E<='0'; cnt :=cnt+1 ;
                       end if ;
                       if cnt=fanwei*2 then
                         current_state<=set_ddrom2 ;cnt:=0; else current_state<=set_ddrom1;
                       end if ;
         
         when set_ddrom2=> LCD_E<='0';
                        LCD_RS<='1';
                        LCD_D<=X"A8";      -----‘波’低字节
                         if cnt=2 then  
                              LCD_E<='1';cnt:=cnt+1;                
                              else LCD_E<='0';cnt:=cnt+1;  
                            end if;
                            if cnt=fanwei*2 then
                              current_state<=set_ddrom3;cnt:=0;  else current_state<=set_ddrom2; 
                      end if;
  when set_ddrom3=> LCD_E<='0';             -----‘特’高字节
                    LCD_RS<='1';
                    LCD_D<=X"CC";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom4;cnt:=0;else current_state<=set_ddrom3;
                        end if;
  when set_ddrom4=> LCD_E<='0';             -----‘特’低字节
                    LCD_RS<='1';
                    LCD_D<=X"D8";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom5;cnt:=0;else current_state<=set_ddrom4;
                        end if;
        
  when set_ddrom5=> LCD_E<='0';                -----‘率’高字节
                    LCD_RS<='1';                    
					LCD_D<=X"C2";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom6;cnt:=0;else current_state<=set_ddrom5;
                        end if;
  when set_ddrom6=> LCD_E<='0';               -----‘率’低字节
                    LCD_RS<='1';                    
					LCD_D<=X"CA";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom7;cnt:=0;else current_state<=set_ddrom6;
                        end if;
  when set_ddrom7=> LCD_E<='0';             -------‘:’高字节
                    LCD_RS<='1';
                    LCD_D<=X"A3";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom8;cnt:=0;else current_state<=set_ddrom7;
                        end if;
  when set_ddrom8=> LCD_E<='0';               -------‘:’低字节
                    LCD_RS<='1';
                    LCD_D<=X"BA";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom9;cnt:=0;else current_state<=set_ddrom8;
                        end if;
       
  when set_ddrom9=> LCD_E<='0';          -----‘9’
                    LCD_RS<='1';
					
					
					 case JX is	  
					when "100" => LCD_D<=X"39";
					when "010" => LCD_D<=X"31";
					when "001" => LCD_D<=X"33";
					when others => null;
					 end case;
                    
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom10;cnt:=0;else current_state<=set_ddrom9;
                        end if;
  when set_ddrom10=> LCD_E<='0';               -----‘6’
                    LCD_RS<='1';
					
					 case JX is	  
					when "100" => LCD_D<=X"36";
					when "010" => LCD_D<=X"39";
					when "001" => LCD_D<=X"38";
					when others => null;
					 end case;
                    
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom11;cnt:=0;else current_state<=set_ddrom10;
                        end if;
        when set_ddrom11=> LCD_E<='0';
                    LCD_RS<='1';                     -------‘0’
					
					 case JX is	  
					when "100" => LCD_D<=X"30";
					when "010" => LCD_D<=X"32";
					when "001" => LCD_D<=X"34";
					when others => null;
					 end case;
					 
                    
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom12;cnt:=0;else current_state<=set_ddrom11;
                        end if;
           when set_ddrom12=> LCD_E<='0';
                    LCD_RS<='1';               -------‘0’
                    LCD_D<=X"30";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom13;cnt:=0;else current_state<=set_ddrom12;
                        end if;
           
         when set_ddrom13=> LCD_E<='0';                ----‘ ’高字节
                    LCD_RS<='1';
                 
					 case JX is	  
					when "100" => LCD_D<=X"D7";
					when "010" => LCD_D<=X"30";
					when "001" => LCD_D<=X"30";
					when others => null;
					 end case;
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_addrh4;cnt:=0;else current_state<=set_ddrom13;
                        end if;
			--注:以上代码注释 均是以波特率9600为例,case语句部分即为波特率选择部分。			
		---------------------------------第二行 显示:“数字:(传送值)”---------------------------------
			when set_addrh4=>LCD_E<='0' ;
                         LCD_RS<='0' ;             
                         LCD_D<=X"8A";                            ----设定地址 8AH
                       if cnt=2 then LCD_E<='1'; cnt:=cnt+1 ;
                           else LCD_E<='0'; cnt :=cnt+1 ;
                       end if ;
                       if cnt=fanwei*2 then
                         current_state<=set_ddrom1h4 ;cnt:=0;  else current_state<=set_addrh4;
                       end if ;
          when set_ddrom1h4=>LCD_E<='0' ;
                         LCD_RS<='1' ;
                         LCD_D<="11001010";                   ----‘数’高字节
                       if cnt=2 then LCD_E<='1'; cnt:=cnt+1 ;
                           else LCD_E<='0'; cnt :=cnt+1 ;
                       end if ;
                       if cnt=fanwei*2 then
                         current_state<=set_ddrom2h4 ;cnt:=0; else current_state<=set_ddrom1h4;
                       end if ;
         
         when set_ddrom2h4=> LCD_E<='0';
                        LCD_RS<='1';
                        LCD_D<="11111101";               ----‘数’低字节
                         if cnt=2 then  
                              LCD_E<='1';cnt:=cnt+1;                
                              else LCD_E<='0';cnt:=cnt+1;  
                            end if;
                            if cnt=fanwei*2 then
                              current_state<=set_ddrom3h4;cnt:=0;  else current_state<=set_ddrom2h4; 
                      end if;
  when set_ddrom3h4=> LCD_E<='0';             ----‘字’高字节
                    LCD_RS<='1';
                    LCD_D<=X"D7";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom4h4;cnt:=0;else current_state<=set_ddrom3h4;
                        end if;
  when set_ddrom4h4=> LCD_E<='0';             ----‘字’低字节
                    LCD_RS<='1';
                    LCD_D<=X"D6";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom5h4;cnt:=0;else current_state<=set_ddrom4h4;
                        end if;
        
  when set_ddrom5h4=> LCD_E<='0';                -----‘:高字节’
                    LCD_RS<='1';
                    LCD_D<=X"A3";
					
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom6h4;cnt:=0;else current_state<=set_ddrom5h4;
                        end if;
  when set_ddrom6h4=> LCD_E<='0';               -----‘:低字节’
                    LCD_RS<='1';
                 
					LCD_D<=X"BA";
                      if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom7h4;cnt:=0;else current_state<=set_ddrom6h4;
                        end if;

 when set_ddrom7h4=> LCD_E<='0';               ----‘传送的代码值前四位’
                    LCD_RS<='1';
					
					LCD_D<=X"20";
			
                  case Data2 is	  
					when "0000" => LCD_D<=X"30";
					when "0001" => LCD_D<=X"31";
					when "0010" => LCD_D<=X"32";
					when "0011" => LCD_D<=X"33";
					when "0100" => LCD_D<=X"34";
					when "0101" => LCD_D<=X"35";
					when "0110" => LCD_D<=X"36";
					when "0111" => LCD_D<=X"37";
					when "1000" => LCD_D<=X"38";
					when "1001" => LCD_D<=X"39";
			 		when others => null;	
						 end case;
    
					 if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                        if cnt=fanwei*2 then
                           current_state<=set_ddrom8h4;cnt:=0;else current_state<=set_ddrom7h4;
                        end if;
  
  
  
  when set_ddrom8h4=> LCD_E<='0';               ----‘传送的代码值后四位’
                    LCD_RS<='1';
					LCD_D<=X"20";
					
					
                  	case Data1 is	 	
					when "0000" => LCD_D<=X"30";
					when "0001" => LCD_D<=X"31";
					when "0010" => LCD_D<=X"32";
					when "0011" => LCD_D<=X"33";
					when "0100" => LCD_D<=X"34";
					when "0101" => LCD_D<=X"35";
					when "0110" => LCD_D<=X"36";
					when "0111" => LCD_D<=X"37";
					when "1000" => LCD_D<=X"38";
					when "1001" => LCD_D<=X"39";
			 		when others => null;
                       end case;
  
					  if cnt=2 then
                               LCD_E<='1';cnt:=cnt+1;
                             else LCD_E<='0';cnt:=cnt+1;
                            end if ;
                       

					   if cnt=fanwei*2 then
                           current_state<=open1;cnt:=0;else current_state<=set_ddrom8h4;
                        end if;
            
  when others=>current_state<=open1;
 
           end case;
           end if;
end process control;	
end Behavioral;
------------------------------------------------主程序文件-----------------------------------------------------------

五、实验结果:
本次试验的波特率通过键盘上的“X”“Y”“Z”分别更改为:“9600、19200、38400”;LCD屏幕第一行显示“波特率: ”,第二行显示:“数字: ”;发送数字时按键盘中“A”键即可,在这里,只能发送和接收两位数的数字。以上功能,读者均可根据自身需求增添删改。在使用LCD12864时,需要知道汉字、数字和标点符号的内码,使用到的汉字内码查询器站内有很多,读者自行下载使用即可。


注明:本文章仅供学习参考之用,代码简单,但贵在易于理解和更改。作者水平有限,不免有错漏之处,如有问题或建议,可留言告之。