将 DHT22 连接到 FPGA - elbert v2

Interface DHT22 to FPGA - elbert v2

现在我做了一个测量温度和湿度的电路,然后显示在LCD上。这是我的 DHT22 代码,我使用 Elbert V2。 生成我的项目后,它运行不正常。

我测试过,我的程序没有达到"end_sl"(最后状态)。我不知道为什么?对我有什么建议吗?谢谢。

我的代码

----------------------------------------------------------------------------------------------------------------------------------------------------------------
entity DHT11 is
generic (
CLK_PERIOD_NS : positive := 83;    -- 12MHz
N: positive:= 40);
port(
    clk,rst : in std_logic ;
    singer_bus: inout std_logic; 
    dataout: out std_logic_vector (N-1 downto 0);
    tick_done: out std_logic
); 
end DHT11;
architecture Behavioral of DHT11 is

constant DELAY_1_MS: positive := 1*10**6/CLK_PERIOD_NS+1;
constant DELAY_40_US: positive := 40*10**3/CLK_PERIOD_NS+1;
constant DELAY_80_US: positive := 80*10**3/CLK_PERIOD_NS+1;
constant DELAY_50_US: positive := 50*10**3/CLK_PERIOD_NS+1; -- 
constant TIME_70_US: positive := 80*10**3/CLK_PERIOD_NS+1; --bit  > 70 us 
constant TIME_28_uS: positive := 30*10**3/CLK_PERIOD_NS+1; -- bit 0 > 28 us 
constant MAX_DELAY  : positive := 5*10**6/CLK_PERIOD_NS+1; -- 5 ms
type state_type is (reset,start_m,wait_res_sl,response_sl,delay_sl,start_sl,consider_logic,end_sl);
signal  index, next_index : natural range 0 to MAX_DELAY; 
signal  state, next_state : state_type; 
signal  data_out,next_data_out: std_logic_vector (N-1 downto 0);
signal  bit_in, next_bit_in: std_logic; 
signal  number_bit,next_number_bit: natural range 0 to 40; 
signal  oe: std_logic;  -- help to set input and output port.
begin   
--register
regis_state:process (clk,rst) begin
    if rst = '1' then 
        state <= reset; 
        index <= MAX_DELAY; 
        number_bit <= 0;
        bit_in <= '1';
        data_out <= (others => '0');
    elsif rising_edge(clk) then
        state <= next_state; 
        index <= next_index;
        number_bit <= next_number_bit;
        bit_in     <= next_bit_in;
        data_out   <= next_data_out;
    end if; 
end process regis_state; 
proces_state: process (singer_bus,index,state,bit_in,number_bit,data_out) begin 
    tick_done <= '0';
    next_data_out <= data_out;
    next_number_bit <= number_bit;
    next_state <= state;
    next_data_out <= data_out;
    next_index <= index;
    dataout <= (others => '0');
    oe <= '0';
    next_bit_in <= bit_in;
    case(state) is
        when reset =>   -- initial  
            if index = 0 then 
                next_state <= start_m; 
                next_index <= DELAY_1_MS;
                next_number_bit <= N-1;
            else
                next_state <= reset;
                next_index <= index - 1;                    
            end if;     
        when start_m =>  -- master send '1' in 1ms
            if index = 0 then 
                next_state <= wait_res_sl;
                next_index <= DELAY_40_US;
            else 
                oe <= '1'; 
                next_state <= start_m; 
                next_index <= index -1;
            end if ;
        when wait_res_sl => -- wait for slave response in 40us  --
            next_bit_in <= singer_bus;
            if  bit_in ='1' and next_bit_in = '0' then  -- 
                next_state <= response_sl;
            else 
                next_state <= wait_res_sl;  
            end if; 
        when response_sl => -- slave response in 80us 
            next_bit_in <= singer_bus;
            if bit_in ='0' and next_bit_in = '1' then 
                next_state <= delay_sl;
            else 
                next_state <= response_sl;
            end if;
        when delay_sl => -- wait for slave delay in 80us 
            if bit_in = '1' and next_bit_in ='0' then 
                next_state <= start_sl;
            else 
                next_state <= delay_sl;
            end if;
        when start_sl => -- start to prepare in 50us                
            if (bit_in = '0') and (next_bit_in = '1') then
                next_state <= consider_logic;
                next_index <= 0;
            elsif number_bit = 0 then 
                    next_state <= end_sl;
                    next_index <= DELAY_50_US;
                else 
                    next_state <= start_sl;
            end if;
        when consider_logic => -- determine 1 bit-data of slave 
            next_index <= index + 1;
            next_bit_in <= singer_bus;
            if bit_in = '1' and next_bit_in = '0' then -- the end of logic state
                next_number_bit <= number_bit -1;
                if (index < TIME_28_uS) then -- time ~ 28 us - logic = '0'
                    next_data_out <= data_out(N-2 downto 0) & '0';
                elsif (index < TIME_70_US) then -- time ~70 us - logic ='1' 
                    next_data_out <= data_out(N-2 downto 0) & '1'; 
                end if;
                    next_state <= start_sl; 
                    next_index <= DELAY_50_US;  
            elsif bit_in ='1' and next_bit_in ='1' then 
                next_state <= consider_logic;
            end if;
        when end_sl => -- tick_done = '1' then dataout has full 40 bit. 
            if index = 0 then 
                next_index <= MAX_DELAY; 
                next_state <= reset;    
            else 
                tick_done <= '1';
                dataout <= data_out;
                next_index <= index -1; 
                next_state <= end_sl;   
            end if;
    end case;
end process proces_state; 
--tristate IOBUFFER
singer_bus <= '0' when oe ='1' else 'Z';
end Behavioral;

您的代码中有很多错误。你到底是怎么调试的?因为你好像没有。

为什么重置后要等待 60 毫秒?你浪费了(宝贵的)模拟时间。 6毫秒就足够了。

查看模拟输出,您可以看到 state 根本没有前进 :它卡在了 ini wait_res_sl 中。问题是您没有将进程中读取的所有信号添加到敏感列表中。即

bit_in ='1' and next_bit_in = '0'

如果 next_bit_in 不在敏感列表中,则不会检测到更改。

一个问题 - 一个常见的错误 - 是你的 'test bench' 只提供输入刺激....但它实际上并没有测试任何东西。

然后是计数器。为什么延迟计数器叫做index?它没有索引任何东西。

为什么你的时间延迟与他们的标签不符? 70 微秒 -> 80 微秒。 28us -> 30us.

小东西不要叫RTL架构behavioral

我试过清理你的代码,现在似乎可以工作了。

library ieee;
use ieee.std_logic_1164.all;

entity dht2 is
    generic (
        clk_period_ns : positive := 83;    -- 12mhz
        data_width: positive:= 40);
    port(
        clk,rst : in std_logic ;
        singer_bus: inout std_logic; 
        dataout: out std_logic_vector(data_width-1 downto 0);
        tick_done: out std_logic
        ); 
end entity;

architecture rtl of dht2 is
    constant delay_1_ms: positive := 1*10**6/clk_period_ns+1;
    constant delay_40_us: positive := 40*10**3/clk_period_ns+1;
    constant delay_80_us: positive := 80*10**3/clk_period_ns+1;
    constant delay_50_us: positive := 50*10**3/clk_period_ns+1; -- 
    constant time_70_us: positive := 70*10**3/clk_period_ns+1; --bit  > 70 us 
    constant time_28_us: positive := 28*10**3/clk_period_ns+1; -- bit 0 > 28 us 
    constant max_delay  : positive := 5*10**6/clk_period_ns+1; -- 5 ms

    signal input_sync : std_logic_vector(0 to 2); 

    type state_type is (reset,start_m,wait_res_sl,response_sl,delay_sl,start_sl,consider_logic,end_sl);
    signal state : state_type; 
    signal delay_counter : natural range 0 to max_delay; 
    signal data_out : std_logic_vector (data_width-1 downto 0);
    signal bus_rising_edge, bus_falling_edge : boolean;
    signal number_bit : natural range 0 to data_width; 
    signal oe: std_logic;  -- help to set input and output port.
begin
    input_syncronizer : process(clk) begin
        if rising_edge(clk) then
            input_sync <= to_x01(singer_bus)&input_sync(0 to 1);
        end if;
    end process;

    bus_rising_edge <= input_sync(1 to 2) = "10";
    bus_falling_edge <= input_sync(1 to 2) = "01";

    --register
    regis_state:process (clk) begin
        if rising_edge(clk) then
            case(state) is
                when reset =>   -- initial
                    if delay_counter = 0 then 
                        number_bit <= data_width;
                        oe <= '1'; 
                        delay_counter <= delay_1_ms;
                        state <= start_m; 
                    else
                        delay_counter <= delay_counter - 1;                    
                    end if;     
                when start_m =>  -- master send '1' in 1ms
                    if delay_counter = 0 then 
                        oe <= '0'; 
                        delay_counter <= delay_40_us;
                        state <= wait_res_sl;
                    else 
                        delay_counter <= delay_counter -1;
                    end if ;
                when wait_res_sl => -- wait for slave response in 40us  --
                    if bus_falling_edge then  -- 
                        state <= response_sl;
                    end if; 
                when response_sl => -- slave response in 80us 
                    if bus_rising_edge then 
                        state <= delay_sl;
                    end if;
                when delay_sl => -- wait for slave delay in 80us 
                    if bus_falling_edge then 
                        state <= start_sl;
                    end if;
                when start_sl => -- start to prepare in 50us                
                    if bus_rising_edge then
                        delay_counter <= 0;
                        state <= consider_logic;
                    elsif number_bit = 0 then 
                        delay_counter <= delay_50_us;
                        state <= end_sl;
                    end if;
                when consider_logic => -- determine 1 bit-data of slave 
                    if bus_falling_edge then -- the end of logic state
                        number_bit <= number_bit - 1;
                        if (delay_counter < time_28_us) then -- time ~ 28 us - logic = '0'
                            data_out <= data_out(data_width-2 downto 0) & '0';
                        elsif (delay_counter < time_70_us) then -- time ~70 us - logic ='1' 
                            data_out <= data_out(data_width-2 downto 0) & '1'; 
                        end if;
                        delay_counter <= delay_50_us;  
                        state <= start_sl; 
                    end if;
                    delay_counter <= delay_counter + 1;
                when end_sl => -- tick_done = '1' then dataout has full 40 bit. 
                    if delay_counter = 0 then 
                        delay_counter <= max_delay; 
                        state <= reset;    
                    else 
                        tick_done <= '1';
                        dataout <= data_out;
                        delay_counter <= delay_counter - 1; 
                    end if;
            end case;
            if rst = '1' then 
                number_bit <= 0;
                data_out <= (others => '0');
                delay_counter <= max_delay; 
                state <= reset; 
            end if;
        end if; 
    end process regis_state; 
    --tristate iobuffer
    singer_bus <= '0' when oe ='1' else 'Z';
end architecture;

和测试台:我加了一个check,但是你应该做更多的checks:每次你做某事,它应该有一个效果。你应该测试一下这种效果是否真的发生了。

entity dht2_tb is end dht2_tb;

library ieee;
architecture behavior of dht2_tb is 
    use ieee.std_logic_1164.all;
    --inputs
    signal clk : std_logic := '0';
    signal rst : std_logic := '0';
    --bidirs
    signal singer_bus : std_logic := 'H';
    --outputs
    signal tick_done : std_logic;
    -- clock period definitions
    constant clk_period : time := 83.33 ns;    -- 12mhz

    use ieee.math_real.all;
    -- This function generates a 'slv_length'-bit std_logic_vector with
    --  random values.
    function random_slv(slv_length : positive) return std_logic_vector is
        variable output : std_logic_vector(slv_length-1 downto 0);
        variable seed1, seed2 : positive := 65; -- required for the uniform function
        variable rand : real;
        -- Assume mantissa of 23, according to IEEE-754:
        --  as UNIFORM returns a 32-bit floating point value between 0 and 1
        --  only 23 bits will be random: the rest has no value to us.
        constant rand_bits : positive := 23;
        -- for simplicity, calculate remaining number of bits here
        constant end_bits : natural := slv_length rem rand_bits;
        use ieee.numeric_std.all;
    begin
        -- fill sets of 23-bit of the output with the random values.
        for i in 0 to slv_length/rand_bits-1 loop
            uniform(seed1, seed2, rand); -- create random float
            -- convert float to int and fill output
            output((i+1)*rand_bits-1 downto i*rand_bits) :=
                std_logic_vector(to_unsigned(integer(rand*(2.0**rand_bits)), rand_bits));
        end loop;
        -- fill final bits (< 23, so above loop will not work.
        uniform(seed1, seed2, rand);
        if end_bits /= 0 then
            output(slv_length-1 downto slv_length-end_bits) :=
                std_logic_vector(to_unsigned(integer(rand*(2.0**end_bits)), end_bits));
        end if;
        return output;
    end function;

    -- input + output definitions
    constant test_data_length : positive := 32;
    constant test_data : std_logic_vector(test_data_length-1 downto 0) := random_slv(test_data_length);
    signal data_out : std_logic_vector(test_data_length-1 downto 0);
begin
    -- instantiate the unit under test (uut)
    uut: entity work.dht2 -- use entity instantiation: no component declaration needed
        generic map (
            clk_period_ns => clk_period / 1 ns,
            data_width => test_data_length)
        port map (
            clk => clk,
            rst => rst,
            singer_bus => singer_bus,
            dataout => data_out,
            tick_done => tick_done
            );

    -- clock stimuli
    clk_process: process begin
        clk <= '0', '1' after clk_period/2;
        wait for clk_period;
    end process;

    -- reset stimuli
    rst_proc : process begin
        rst <= '1', '0' after 100 us;
        wait;
    end process;

    -- bidir bus pull-up
    -- as you drive the bus from the uut and this test bench, it is a bidir
    -- you need to simulate a pull-up ('H' = weak '1'). slv will resolve this.
    singer_bus <= 'H';

    -- stimulus process
    bus_proc: process
        -- we use procedures for stimuli. Increases maintainability of test bench

        -- procedure bus_init initializes the slave device. (copied this from your code)
        procedure bus_init is begin
    --      singer_bus <= 'Z'; -- initial 
            wait for 6 ms;  
            -- singer_bus <= '0'; -- master send 
            -- wait for 1 ms;
            singer_bus <= 'Z'; -- wait response for slave 
            wait for 40 us; 
            singer_bus <= '0'; -- slave pull low  
            wait for 80 us; 
            singer_bus <= 'Z'; -- slave pull up
            wait for 80 us; 
        end procedure;

        function to_string(input : std_logic_vector) return string is
            variable output : string(1 to input'length);
            variable j : positive := 1;
        begin
            for i in input'range loop
                output(j) := std_logic'image(input(i))(2);
                j := j + 1;
            end loop;
            return output;
        end function;

        -- procedure send_data 
        procedure send_data(data : std_logic_vector) is begin
            -- we can now send a vector of data,length detected automatically
            for i in data'range loop
                singer_bus <= '0';  -- slave start data transmission 
                wait for 50 us;
                singer_bus <= 'Z';  -- slave send bit;
                -- I found the only difference between sending bit '0'
                --  and '1' is the length of the delay after a '0' was send.
                case data(i) is
                    when '0' => wait for 24 us; 
                    when '1' => wait for 68 us;
                    when others =>
                        report "metavalues not supported for bus_proc send_data"
                            severity failure;
                end case;
                singer_bus <= '0';
            end loop;
            -- next is VHDL-2008 (else use ieee.std_logic_textio.all;)
            report "transmitted: "&to_string(data);
        end procedure;
    begin       
        wait until rst = '0';
        bus_init; -- call procedure

        send_data(test_data); -- call procedure

        wait for 100 us; -- final delay
        singer_bus <= 'Z'; -- release bus

        report "received: "&to_string(data_out);
        -- test correctness of output
        assert data_out = test_data
            report "data output does not match send data"
            severity error;

        report "end of simulation" severity failure;
    end process;
end architecture;