如何实现单片机与CPLD通讯

如何实现单片机与CPLD通讯,第1张

1。可以用CPLD模拟一个RS232串口,利用这个串口与单片机通信

下面是用VHDL写的一个串口程序,你可以根据你的通信协议对这个程序略作修改即可使用

-- 本模块的功能是验证实现基本的串口通信的功能。

--

-- 程序实现了一个收发一帧10个bit(即无奇偶校验位)的串口控

--制器,10个bit是1位起始位,8个数据位,1个结束

--位。串口的波特律由程序中定义的div_par参数决定,更改该参数可以实

--现相应的波特率。程序当前设定的div_par 的值是0x104,对应的波特率是

--9600。用一个8倍波特率的时钟将发送或接受每一位bit的周期时间

--划分为8个时隙以使通信同步

:串口处于全双工工作状态,

--字符串(串口调试工具设成按ASCII码接受方式);

library IEEE;

use IEEESTD_LOGIC_1164ALL;

use IEEESTD_LOGIC_ARITHALL;

use IEEESTD_LOGIC_UNSIGNEDALL;

ENTITY UART IS

PORT (

clk : IN std_logic;

rst : IN std_logic;

rxd : IN std_logic; --串行数据接收端

txd : OUT std_logic; --串行数据发送端

en : OUT std_logic; -- 数码管使能

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的波特率,即分频出的时钟频率是96008

SIGNAL txd_xhdl3 : std_logic;

BEGIN

en <='0' ;--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";

WHEN "00110001" =>

seg_data <= "10011111";

WHEN "00110010" =>

seg_data <= "00100101";

WHEN "00110011" =>

seg_data <= "00001101";

WHEN "00110100" =>

seg_data <= "10011001";

WHEN "00110101" =>

seg_data <= "01001001";

WHEN "00110110" =>

seg_data <= "01000001";

WHEN "00110111" =>

seg_data <= "00011111";

WHEN "00111000" =>

seg_data <= "00000001";

WHEN "01000001" =>

seg_data <= "00011001";

WHEN "01000010" =>

seg_data <= "00010001";

WHEN "01000011" =>

seg_data <= "11000001";

WHEN "01000100" =>

seg_data <= "01100011";

WHEN "01000101" =>

seg_data <= "10000101";

WHEN "01000110" =>

seg_data <= "01100001";

WHEN "01000111" =>

seg_data <= "01110001";

WHEN OTHERS =>

seg_data <= "11111111";

END CASE;

END PROCESS;

END arch;

2。可利用单片机的IO口与CPLD实现通信,其他人已经回答过了,我不再赘述。

关于第二个问题,主要现在电路已经做成,有些线已经无法再连接,看能不能从软件方面补救一下。我的FIFO不是靠空满逻辑来读数的,因为我在发送数据给FIFO和从FIFO中读出的数据是一一对应的,有多少数读多少数,不多也不少。但是现在因为FIFO读使能和DMA通道打开之间有个时间差,所以我担心这段时间内没有读到FIFO中的数据,使读上去的数据比预期的要少。

以上就是关于如何实现单片机与CPLD通讯全部的内容,包括:如何实现单片机与CPLD通讯、请教一下关于CPLD和FIFO的问题、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/9320790.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-27
下一篇2023-04-27

发表评论

登录后才能评论

评论列表(0条)

    保存