基于VHDL的串口程序.docx
《基于VHDL的串口程序.docx》由会员分享,可在线阅读,更多相关《基于VHDL的串口程序.docx(22页珍藏版)》请在冰豆网上搜索。
基于VHDL的串口程序
在quartus里面没找到SCI的LPM部件,又不想自己从头编写,在网上找到了一个verilog的程序,也找到了和这个实现方法相同的VHDL程序。
都是接收到按键按下时候,启动串口发送,发送welcom但是都是发现一个,并延时重新读取按键,然后再重新启动发送。
数据格式是9600boudrate、8数据位、1启动位、1停止位,每16个bit周期发送一个byte,接收程序,没有中间多位判断部分,考虑接收的有效性和可靠性,对程序进行了修改,改为每11个bit周期发送一个byte,这样也可以兼容接收2个停止位的接收程序,在接收程序中进行了多相判断。
程序和截图如下:
--本模块的功能是验证实现和PC机进行基本的串口通信的功能。
需要在PC机上安装一个串口调试工具来验证程序的功能。
--程序实现了一个收发一帧10个bit(即无奇偶校验位)的串口控制器,10个bit是1位起始位,8个数据位,1个结束位。
--串口的波特律由程序中定义的div_par参数决定,更改该参数可以实现相应的波特率。
程序当前设定的div_par的值
--是0x145,对应的波特率是9600。
用一个8倍波特率的时钟将发送或接受每一位bit的周期时间划分为8个时隙以使通
--信同步.
--程序的基本工作过程是,按动一个按键key1控制器向PC的串口发送“welcome",
--PC机接收后显示验证数据是否正确(串口调试工具设成按ASCII码接受方式).
--PC可随时向FPGA发送0-F的十六进制数据,FPGA接受后显示在7段数码管上.
libraryieee;--designbyjiaolonglan
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
useieee.std_logic_arith.all;
entitymyserialis
generic(boud_rate:
integer:
=9600;
clk_rate:
integer:
=50_000_000);
port(clk:
instd_logic;
rstn:
instd_logic;
rxd:
instd_logic;--receivebit
txd:
outstd_logic;--sendbit
--txd_buff:
instd_logic_vector(7downto0);--bufferwritein
--write_data:
instd_logic;--writedata
en:
outstd_logic_vector(7downto0);
seg_data:
outstd_logic_vector(7downto0);
--rxd_buff:
outstd_logic_vector(7downto0);
key_input:
instd_logic
--testout:
outstd_logic
--read_data:
instd_logic
);
endentitymyserial;
architecturebhvofmyserialis
SIGNALdiv_reg:
integerrange0to2**16-1;--分频计数器,分频值由波特率决定。
分频后得到频率8倍波特率的时钟
SIGNALdiv8_tras_reg:
std_logic_vector(2DOWNTO0);--该寄存器的计数值对应发送时当前位于的时隙数
SIGNALdiv8_rec_reg:
std_logic_vector(2DOWNTO0);--寄存器的计数值对应接收时当前位于的时隙数
SIGNALstate_tras:
std_logic_vector(3DOWNTO0);--发送状态寄存器
SIGNALstate_rec:
std_logic_vector(3DOWNTO0);--接受状态寄存器
SIGNALclkbaud_tras:
std_logic;--以波特率为频率的发送使能信号
SIGNALclkbaud_rec:
std_logic;--以波特率为频率的接受使能信号
SIGNALclkbaud8x:
std_logic;--以8倍波特率为频率的时钟,它的作用是将发送或接受一个bit的时钟周期分为8个时隙
SIGNALrecstart:
std_logic;--开始发送标志
SIGNALrecstart_tmp:
std_logic;--开始接受标志
SIGNALtrasstart:
std_logic;--
SIGNALrxd_reg:
std_logic_vector(7downto0);--接收寄存器1
SIGNALtxd_reg:
std_logic;--发送寄存器
SIGNALrxd_buf:
std_logic_vector(7DOWNTO0);--接受数据缓存
SIGNALtxd_buf:
std_logic_vector(7DOWNTO0);--发送数据缓存
SIGNALsend_state:
std_logic_vector(2DOWNTO0);--每次按键给PC发送"Welcome"字符串,这是发送状态寄存器
SIGNALcnt_delay:
integerrange0to2**20-1;--std_logic_vector(19DOWNTO0);--延时去抖计数器
SIGNALstart_delaycnt:
std_logic;--开始延时计数标志
SIGNALkey_entry1:
std_logic;--确定有键按下曛?
SIGNALkey_entry2:
std_logic;--确定有键按下标志
CONSTANTdiv_par:
integer:
=8;--fortest:
=clk_rate/(8*boud_rate);
--分频参数,其值由对应的波特率计算而得,按此参数分频的时钟频率是波倍特率的8倍,此处值对应9600的波特率,即分频出的时钟频率是9600*8
begin
en<="01010101";--7段数码管使能信号赋值
txd<=txd_reg;
PROCESS(clk,rstn)--delaycounter
BEGIN
IF(rstn='0')THEN
cnt_delay<=0;
start_delaycnt<='0';--
key_entry1<='0';
ELSIF(clk'EVENTANDclk='1')THEN
IF(key_entry2='1')THEN--starttransmitandclearkey_entry1
key_entry1<='0';--
ELSE
IF(cnt_delay=98)THEN
IF(key_input='1')THEN
key_entry1<='1';
ENDIF;
ENDIF;
ENDIF;
IF(start_delaycnt='1')THEN--keypress
IF(cnt_delay<99)THEN--20D800000
cnt_delay<=cnt_delay+1;
ELSE--rejudgekey
cnt_delay<=0;
start_delaycnt<='0';
ENDIF;
ELSE
IF((key_input='1')AND(cnt_delay=0))THEN--judgekeypressstart
start_delaycnt<='1';
ENDIF;
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(clk,rstn)--recyclecounter分频得到8倍波特率的时钟div_par
BEGIN
IF(rstn='0')THEN
div_reg<=0;
clkbaud8x<='0';
ELSIF(clk'EVENTANDclk='1')THEN
IF(div_reg=div_par-1)THEN
div_reg<=0;
clkbaud8x<=NOTclkbaud8x;
ELSE
div_reg<=div_reg+1;
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(clkbaud8x,clkbaud8x,rstn)
BEGIN
IF(rstn='0')THEN
div8_rec_reg<="000";
div8_tras_reg<="000";
ELSEIF(clkbaud8x'EVENTANDclkbaud8x='1')THEN
IF(recstart='1')THEN--接收开始标志
div8_rec_reg<=div8_rec_reg+"001";--接收开始后,时隙数在8倍波特率的时钟下加1循环
ENDIF;
IF(trasstart='1')THEN
div8_tras_reg<=div8_tras_reg+"001";--发送开始后,时隙数在8倍波特率的时钟下加1循环
ENDIF;
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(div8_rec_reg,div8_tras_reg)--creatreceiveandtransmitdataclk
BEGIN
IF(div8_rec_reg="111")THEN
clkbaud_rec<='1';--在第7个时隙,接收
ELSE
clkbaud_rec<='0';
ENDIF;
IF(div8_tras_reg="111")THEN
clkbaud_tras<='1';--在第7个时隙,发送使能信号有效,将数据发出
ELSE
clkbaud_tras<='0';
ENDIF;
ENDPROCESS;
PROCESS(clkbaud8x,rstn)--trsnsmitdata
BEGIN
IF(rstn='0')THEN
txd_reg<='1';
trasstart<='0';
txd_buf<="00000000";
state_tras<="0000";
send_state<="000";
key_entry2<='0';
ELSEIF(clkbaud8x'EVENTANDclkbaud8x='1')THEN
IF(key_entry2='0')THEN
IF(key_entry1='1')THEN
key_entry2<='1';
txd_buf<="01110111";--"w"
ENDIF;
ELSE--key_entry2='1';havekeypressstarttransmit
CASEstate_trasIS
WHEN"0000"=>--发送起始位
IF((trasstart='0')AND(send_state<"111"))THEN--haven'tsendalldatathencontinuetransmit
trasstart<='1';
ELSE
IF(send_state<"111")THEN--send_stateischarcounter
IF(clkbaud_tras='1')THEN--enabletransmiteverydatabitflag
txd_reg<='0';--startbit
state_tras<=state_tras+"0001";--state_trasisbitcounter
ENDIF;
ELSE--=7
key_entry2<='0';
state_tras<="0000";
ENDIF;
ENDIF;
WHEN"0001"=>--发送第1位
IF(clkbaud_tras='1')THEN
txd_reg<=txd_buf(0);--undersendregis
txd_buf(6DOWNTO0)<=txd_buf(7DOWNTO1);
state_tras<=state_tras+"0001";--bitaddone
ENDIF;
WHEN"0010"=>--发送第2位
IF(clkbaud_tras='1')THEN
txd_reg<=txd_buf(0);
txd_buf(6DOWNTO0)<=txd_buf(7DOWNTO1);
state_tras<=state_tras+"0001";
ENDIF;
WHEN"0011"=>--发送第3位
IF(clkbaud_tras='1')THEN
txd_reg<=txd_buf(0);
txd_buf(6DOWNTO0)<=txd_buf(7DOWNTO1);
state_tras<=state_tras+"0001";
ENDIF;
WHEN"0100"=>--发送第4位
IF(clkbaud_tras='1')THEN
txd_reg<=txd_buf(0);
txd_buf(6DOWNTO0)<=txd_buf(7DOWNTO1);
state_tras<=state_tras+"0001";
ENDIF;
WHEN"0101"=>--发送第5位
IF(clkbaud_tras='1')THEN
txd_reg<=txd_buf(0);
txd_buf(6DOWNTO0)<=txd_buf(7DOWNTO1);
state_tras<=state_tras+"0001";
ENDIF;
WHEN"0110"=>--发送第6位
IF(clkbaud_tras='1')THEN
txd_reg<=txd_buf(0);
txd_buf(6DOWNTO0)<=txd_buf(7DOWNTO1);
state_tras<=state_tras+"0001";
ENDIF;
WHEN"0111"=>--发送第7位
IF(clkbaud_tras='1')THEN
txd_reg<=txd_buf(0);
txd_buf(6DOWNTO0)<=txd_buf(7DOWNTO1);
state_tras<=state_tras+"0001";
ENDIF;
WHEN"1000"=>--发送第8位
IF(clkbaud_tras='1')THEN
txd_reg<=txd_buf(0);
txd_buf(6DOWNTO0)<=txd_buf(7DOWNTO1);
state_tras<=state_tras+"0001";
ENDIF;
WHEN"1001"=>--发送停止位
IF(clkbaud_tras='1')THEN
txd_reg<='1';
txd_buf<="01010101";
state_tras<=state_tras+"0001";
ENDIF;
WHEN"1010"=>--1111runto15
IF(clkbaud_tras='1')THEN
state_tras<="0000";--state_tras+"0001";--nextis0000
send_state<=send_state+"001";--judgesendbyte
trasstart<='0';
CASEsend_stateIS
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"
WHENOTHERS=>
txd_buf<="00000000";
ENDCASE;
ENDIF;
WHENOTHERS=>--runto10and14
IF(clkbaud_tras='1')THEN
--state_tras<=state_tras+"0001";//old
state_tras<="0000";
trasstart<='1';
ENDIF;
ENDCASE;
ENDIF;
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(clkbaud8x,rstn)--receivePC机的数据
variabletemp:
integerrange0to8;
variablercv_data:
std_logic;
BEGIN
IF(rstn='0')THEN
rxd_reg<=(others=>'0');
rxd_buf<="00000000";--everyphase
state_rec<="0000";
recstart<='0';
recstart_tmp<='0';
ELSEIF(clkbaud8x'EVENTANDclkbaud8x='1')THEN
rxd_reg<=rxd_reg(6downto0)&rxd;
IF(state_rec="0000")THEN
IF(recstart_tmp='1')THEN--havecapturestartbit
recstart<='1';
recstart_tmp<='0';
state_rec<=state_rec+"0001";
ELSE
IF(rxd_reg(7downto4)="1100")THEN--检测到起始位的下降沿,进入接受状态
recstart_tmp<='1';--setcapturestartbitflag
ENDIF;
ENDIF;
ELSE--detectotherbit
IF(state_rec>="0001"ANDstate_rec<="1000")THEN
IF(clkbaud_rec='1')THEN
temp:
=0;
foriin1to3loop--data6,7012345
temp:
=temp+conv_integer(rxd_reg(i));
iftemp>=2then
rcv_data:
='1';
else
rcv_data:
='0';
endif;
endloop;
rxd_buf(7)<=rcv_data;
rxd_buf(6DOWNTO0)<=rxd_buf(7DOWNTO1);
state_rec<=state_rec+"0001";
ENDIF;
ELSE--stopbit
IF(state_rec="1001")THEN
IF(clkbaud_rec='1')THEN
IFrxd_reg
(2)='0'THEN--stopbiterror
rxd_buf<=(others=>'0');
ENDIF;
state_rec<="0000";
recstart<='0';
ENDIF;
ENDIF;
ENDIF;
ENDIF;
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(rxd_buf,clk)--将接受的数据用数码管显示出来
BEGIN
ifclk'eventandclk='1'then
CASErxd_bufIS
WHEN"00110000"=>
seg_data<="00000011";--00x30
WHEN"00110001"=>
WHEN"00110010"=>
seg_data<="00100101";--2
WHEN"00110011"=>
seg_data<="00001101";--3
WHEN"00110100"=>
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