【问题标题】:rs232 receiver in VHDL doesn't hold data correctly if at allVHDL 中的 rs232 接收器根本无法正确保存数据
【发布时间】:2019-05-08 18:19:40
【问题描述】:

我正在尝试用 VHDL 设计一个 rs232 接收器:我使用 python 脚本发送数字,它必须捕获并显示给一些 LED。我希望了解 RS232 的工作原理并着手进行该设计。该设计的行为与我希望的不同,我想知道是否有人可以帮助我找出我的错误。

当然我去看看串行接收器是如何工作的。但作为一个初学者,我经常对提出的解决方案感到不知所措(例如:VHDL RS-232 Receiver" 或更糟糕的是:https://www.nandland.com/vhdl/modules/module-uart-serial-port-rs232.html),我缺乏理解其中发生的事情的词汇和经验。

我在 quartus II 网页版上做了这个设计:

底部的实体只是锁定到通过 rs232 输入的任何数据,以确保 python 脚本确实在做某事。

使用这两个文件: rs232_test

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity rs232_receiver is 
port (
    clock : in std_logic;
    r     : in std_logic;
    reset : in std_logic;
    data  : out std_logic_vector (7 downto 0)
);
end rs232_receiver;

architecture rs232_receiver_arch of rs232_receiver is
    signal data_buffer : std_logic_vector (12 downto 0); 
    signal state : integer; -- 1000 => idle;
begin

    process
    begin
    wait until rising_edge (clock);
        if (reset = '0') then
            if (state = 1000) then
                if (r = '0') then
                    state <= 0; -- startbit as been detected => time to READ !
                end if;
            elsif (state < 13 and state > -1) then
                data_buffer(state) <= r;
                state <= state + 1;
            else
                state <= 1000; -- go back to idle
                data <= data_buffer(7 downto 0);
                data_buffer <= (others => '0');
            end if;
        else
            data_buffer <= (others => '0');
            data <= (others => '0');
            state <= 1000;
        end if;
    end process;
end rs232_receiver_arch;

时钟调整(原始时钟为 24 MHz,我希望我制作这个分频器的方式,输出为 1200 Hz,我相信波特率为 1200)。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity div1000 is 
port (
    clock : in std_logic;
    clockOut : out std_logic
);
end div1000;

architecture div1000_arch of div1000 is
    signal count : integer;
begin

    clockOut <= '1' when count < 10000 else '0';

    process begin
    wait until rising_edge (clock);
        if (count > 19999 or count < 0) then
            count <= 1;
        else
            count <= count + 1;
        end if;
    end process;
end div1000_arch;

我用这个 python 脚本加载数字:

# -*- coding: utf-8 -*-
"""
Created on Thu May  2 14:52:12 2019

@author: nathan hj ragot
"""

import time
import serial
import serial.tools.list_ports

print ("hello world !")

#  initialisation des variables
port = ""                                                                      # port choisit
ports = []                                                                     # ports listes

#  recherche et choix du port
print ("merci de rentrer le nom d'un port :")
print ("ps : automatiquement, le script a detecte ces ports :")
print ("**************")

ports = serial.tools.list_ports.comports()
for i in range (len(ports)):
    print ("-> [" + str(i) + "] : " + str (ports[i]))

print ("**************")

port = input("? votre choix :")
print ("ok cool")

# open serial port
ser = serial.Serial(
    port=port,
    baudrate=1200,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_TWO,
    bytesize=serial.EIGHTBITS
)
print(ser.isOpen())

#start writing
ser.write(bytearray([255]))
for i in range(15):
    input("press enter to print " + str(i))
    ser.write (bytearray([i]))

#stop writing
ser.close()

print(ser.isOpen())
print ("bye")

我期待每次我在键盘上按 Enter 键时,python 脚本都会向我的 fpga 板发送一个字节,并且设计会锁定数字并将其显示给 LED。相反,LED 会闪烁到一些与发送的数字不对应的随机位置,然后立即关闭。

【问题讨论】:

    标签: python serial-port vhdl intel-fpga


    【解决方案1】:

    我问过我的一位老师,我的设计可能有什么问题。他告诉我:即使两个时钟具有相同的速率,它们也可能不会同步,因为当发射器距离其上升沿或下降沿太近时,接收器可能会尝试读取信号。因此,他建议我添加一个在启动位启动时启动的单独计数器。这将充当时钟分频器,在识别出下降沿和 r = '0' 时启动。

    我自己重写了接收器的 vhdl 代码以获得这个:

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity serial_receiver is 
    port (
        -- clock is 24 MHz
        clock : in std_logic;
        -- data in at 1200 baud rate
        -- two stop bit
        -- no parity check
        -- byte size at 8
        r     : in std_logic;
        -- packet received
        dataOut : out std_logic_vector (7 downto 0)
    );
    end serial_receiver;
    
    architecture serial_receiver_arch of serial_receiver is
        -- state of the process :
        --  idle => waiting for start bit
        --      start => waiting THROUGH the start bit
        --      reading => index and storing bits in data buffer
        --      stop => update up data and go back to idle
        type states is (idle, start, reading, stop);
        signal state : states := idle;
    
        -- clock divider for bit reading, one bit is 16 cycle after first division
        signal counter: integer := 0;
        -- clock divider for process, 1250 divider => clock is now 16*1200 Hz
        signal waiter : integer := 0;
        -- index for incomming data to be store in buffer
        signal index  : integer := 0;
        -- data buffer
        signal data   : std_logic_vector (7 downto 0);
    begin
    
        process begin
            wait until rising_edge(clock);
    
            --first divider
            if waiter < 1250 then
                waiter <= waiter + 1;
            else
                -- time to run process
                -- reset waiter to restart clock divider
                waiter <= 0;
    
                -- switch case for state
                case state is
                    -- receiver is idle
                    when idle =>
                        -- will become ready for start when bit start is received
                        if r = '0' then
                            state <= start;
                            counter <= 0;
                        end if;
                    -- receiver is waiting through start bit, doing nothing
                    when start =>
                        -- not done yet, counter max must be bigger than 16 to insure not too close from rising_edge
                        if counter < 18 then
                            counter <= counter + 1;
                        else
                        -- done, is getting ready for reading
                            state <= reading;
                            -- counter is set to 16 to immediatly read first bit
                            counter <= 16;
                            index <= 0;
                        end if;
                    -- receiver store data inside buffer
                    when reading =>
                        -- clock divider to wait until next bit.
                        if counter < 16 then
                            counter <= counter + 1;
                        else
                            -- store bit in buffer if we can
                            if index < 8 then
                                counter <= 0;
                                data(index) <= r;
                                index <= index + 1;
                            else
                            -- if we can't, time to stop
                                counter <= 0;
                                state <= stop;
                            end if;
                        end if;
                    -- reading is finnished
                    when stop =>
                        -- go back to idle.
                        dataOut <= data;
                        state <= idle;
                        counter <= 0;
                end case;
            end if;
        end process;
    end serial_receiver_arch;
    

    VHDL 在设计中是单独存在的,所有其他实体都不再存在。

    这似乎现在可以使用 python 脚本工作(测试了一些介于 0 到 255 之间的数字)。我试图做一些看起来更像@QuantumRipple 的答案的东西:VHDL RS-232 Receiver。由于我的代码略有不同,我仍然不确定在旧代码中究竟是什么不起作用。我只是假设这是同步的事情。如果有人仍然有想法,我愿意接受更多知识。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-28
      • 1970-01-01
      • 2015-12-05
      • 1970-01-01
      • 2022-08-14
      • 1970-01-01
      相关资源
      最近更新 更多