我通过 inout 行触发传感器。之后,我正在等待传感器将 inout 线拉高,但是我在查看 inout 信号时遇到了麻烦,而没有损坏我的输出信号。写作有效,不读。
每当行
elsif state = sensor_answer_0 AND trigger_sensor = '1' then
ouput_signal 设置为' X'。
但是当我评论 trigger_sensor 时:
elsif state = sensor_answer_0 then
output_signal 实际上获取分配给它的值。
我已经尝试过使用内部缓冲信号,该信号在单独的过程中读取,但结果相同。
在下面的代码中我也使用 output_signal 进行调试,我在每个状态下设置它以查看实际执行的状态。 我检查了我的测试平台,似乎没有与 output_signal 的写 - 写冲突。但是,我正在设置 trigger_sensor 。但只有在 trigger_sensor 已经设置为' Z'在我的主要代码中。
为什么我会看到这种奇怪的行为?我不能只读 inout 信号吗?
我正在使用' Quartus II 15.0'和模拟的ModelSim
ibrary ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sensor_read is port(
clk_50: in std_logic;
enable : in std_logic; -- enable sensor read
trigger_sensor: inout std_logic; -- 1. trigger sensor, 2. read sensor value
output_sensor : out std_logic_vector(7 downto 0)
);
end sensor_read;
architecture behavior of sensor_read is
--
type state_type is (init, trigger_0, trigger_1, sensor_answer_0 );
signal state : state_type := init;
signal icnt : std_logic_vector( 18 downto 0 ) := ( others => '0' ); -- counter
----------------------------------------------------------------------
--- wait for enable
--- trigger sensor
--- wait for sensor to pull trigger line HIGH and assign output
----------------------------------------------------------------------
begin
process (clk_50 )
begin
if rising_edge( clk_50 ) then
-- start here
if state = init AND unsigned( icnt ) = 0 then
icnt <= ( others => '0' );
if enable = '1' then -- start trigger process
state <= trigger_0;
trigger_sensor <= '0';
else
state <= init;
trigger_sensor <= 'Z';
end if;
-- TRIGGER SENSOR
elsif state = trigger_0 AND unsigned( icnt ) = 50 then
state <= trigger_1;
trigger_sensor <= '1';
output_sensor <= "00000001"; -- debug
elsif state = trigger_1 AND unsigned( icnt ) = 550 then -- 500 clk cycle
state <= sensor_answer_0;
icnt <= ( others => '0' );
trigger_sensor <= 'Z'; -- set trigger to high impedance to let sensor drive line
output_sensor <= "00001111"; -- debug
-- WAIT FOR SENSOR TO PULL TRIGGER=HIGH
-- ERROR HERE -> when trigger_sensor is used in if statement output_sensor becomes xxx
-- when trigger_sensor = not('1') is commented out, output_sensor is set correctly to "00011111"
elsif state = sensor_answer_0 AND trigger_sensor = '1' then
state <= init;
icnt <= ( others => '0' );
output_sensor <= "00011111"; -- assign final output
else
icnt <= std_logic_vector ( unsigned( icnt ) + 1 );
end if;
end if;
end process;
end behavior;
编辑:根据要求添加测试平台
-- clock generation
process
begin
clk_50 <= '1';
wait for 10 ns;
clk_50 <= '0';
wait for 10 ns;
end process;
-- input data
process
begin
enable <= '0';
trigger_sensor <= 'Z';
wait for 1 ms;
-- start the meassurement
enable <= '1';
-- wait for the trigger signal to be over
while trigger_sensor /= '1' loop wait for 1 us; end loop;
while trigger_sensor = '1' loop wait for 1 us; end loop;
-- now send response
wait for 100 us;
trigger_sensor <= '1';
wait for 1 ms;
trigger_sensor <= '0';
wait for 10 us;
trigger_sensor <= 'Z';
wait;
end process;
答案 0 :(得分:0)
完成测试平台的Minimal Complete and Verifiable example后:
library ieee;
use ieee.std_logic_1164.all;
entity sensor_read_tb is
end entity;
architecture foo of sensor_read_tb is
signal clk_50: std_logic;
signal enable: std_logic;
signal trigger_sensor: std_logic;
signal output_sensor: std_logic_vector (7 downto 0);
--added for visual markers:
signal waitfor100us: bit;
signal waitfor1ms: bit;
signal waitfor10us: bit;
begin
DUT:
entity work.sensor_read
port map (
clk_50 => clk_50,
enable => enable,
trigger_sensor => trigger_sensor,
output_sensor => output_sensor
);
-- clock generation
process
begin
clk_50 <= '1';
wait for 10 ns;
clk_50 <= '0';
wait for 10 ns;
if now > 2.2 ms then
wait;
end if;
end process;
-- input data
process
begin
enable <= '0';
trigger_sensor <= 'Z';
wait for 1 ms;
-- start the meassurement
enable <= '1';
-- wait for the trigger signal to be over
while trigger_sensor /= '1' loop wait for 1 us; end loop;
while trigger_sensor = '1' loop wait for 1 us; end loop;
-- now send response
waitfor100us <= '1';
wait for 100 us;
waitfor100us <= '0';
trigger_sensor <= '1';
waitfor1ms <= '1';
wait for 1 ms;
waitfor1ms <= '0';
trigger_sensor <= '0';
waitfor10us <= '1';
wait for 10 us;
waitfor10us <= '0';
trigger_sensor <= 'Z';
wait;
end process;
end architecture;
我们看到了问题:
在测试平台中添加了几个信号以标记您的延迟。它们很容易丢弃。使用的模拟器不会将输出变量输出到波形。 您没有正确操作双向传感器信号。
那该怎么办呢?
在前十几个谷歌的热门歌曲中,最初的Single line multiplexing system for sensors and actuators专利出现了,1982年被授予美国专利4,311,986。
虽然该专利已经过期,但它已经教授了这项专利。发明。
还有MAX6575L/H数据表告诉我们,您希望在FPGA下降trigger_sensor之前操作计数器,直到传感器再次触发触发传感器为止。
这种方式的工作原理是FPGA会在一个固定的时间间隔内丢失trigger_sensor,从而发出单线总线上任何传感器或执行器的信号。多达8个设备可以使用乘法器共享总线,根据两个输入引脚缩放时间,具有两个延迟系列(H和L后缀)。
对于单个传感器,它将通过再次丢弃触发传感器在一段固定时间内响应其时间窗口,该固定周期用信号通知脉冲宽度调制编码值(通常用于温度)。
执行器将由主机端操作(在这种情况下是FPGA,通过丢弃触发传感器线再次向执行器发送脉冲宽度编码数据值。
当没有传感器应答重新开始采样间隔时,计数器可以大到足以重新启动。 我们这里的VHDL模型只读取传感器。
回到双向信号的错误。
它应该被建模为具有两个驱动器和上拉的开放式收集器。对于单个传感器,状态机可能有点过度,但可以使其工作。
这里的诀窍是,两端都不会驱动一个&#39; 1&#39;在电线上,只有一个&#39; 0&#39; 0或者是&#39; Z&#39; (高阻抗)。上拉将是一个&#39; Z&#39;到了&#39; H&#39;并代表一个电阻器(数据表显示一个10K欧姆的电阻器)。
要阅读一个需要过滤到&#39; 0&#39;或者&#39; 1&#39;值和std_logic_1164包有一个函数TO_01来做到这一点,添加了一个输入,其默认值将元值映射到&#39; 0&#39;。对于使用开放收集器模型的我们的目的,我们希望函数将元值映射到&#39; 1&#39;。
对于您未使用TO-01的情况,这些情况在std_logic_1164软件包的早期版本中不可用,但它已被包含在内。对您的VHDL源所做的所有更改都已注释:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sensor_read is
port (
clk_50: in std_logic;
enable: in std_logic; -- enable sensor read
trigger_sensor: inout std_logic; -- 1. trigger sensor, 2. read sensor value
output_sensor: out std_logic_vector(7 downto 0)
);
end entity sensor_read;
architecture behavior of sensor_read is
type state_type is (init, trigger_0, trigger_1, sensor_answer_0);
signal state: state_type := init;
signal icnt: std_logic_vector( 18 downto 0) := (others => '0');
-- for VHDL revisions prior to -2008:
function TO_01 (s: STD_ULOGIC; xmap: std_ulogic := '0') return std_ulogic is
begin
case s is
when '0' | 'L' =>
return '0';
when '1' | 'H' =>
return '1';
when others =>
return xmap;
end case;
end function TO_01;
begin
process (clk_50)
begin
if rising_edge(clk_50) then
if state = init AND unsigned(icnt) = 0 then
icnt <= ( others => '0' );
if enable = '1' then
state <= trigger_0;
trigger_sensor <= '0';
else
state <= init;
trigger_sensor <= 'Z';
end if;
elsif state = trigger_0 AND unsigned(icnt) = 50 then
state <= trigger_1;
trigger_sensor <= 'Z'; -- WAS '1';
output_sensor <= "00000001";
elsif state = trigger_1 AND unsigned(icnt) = 550 then
state <= sensor_answer_0;
icnt <= (others => '0');
trigger_sensor <= 'Z';
output_sensor <= "00001111";
elsif state = sensor_answer_0 AND
TO_01(trigger_sensor, xmap => '1') = '1' then -- CHANGED
state <= init;
icnt <= ( others => '0' );
output_sensor <= "00011111";
else
icnt <= std_logic_vector (unsigned(icnt) + 1);
end if;
end if;
end process;
end architecture behavior;
library ieee;
use ieee.std_logic_1164.all;
entity sensor_read_tb is
end entity;
architecture foo of sensor_read_tb is
signal clk_50: std_logic;
signal enable: std_logic;
signal trigger_sensor: std_logic;
signal output_sensor: std_logic_vector (7 downto 0);
--added for visual markers:
signal waitfor100us: bit;
signal waitfor1ms: bit;
signal waitfor10us: bit;
-- for VHDL revisions prior to -2008:
function TO_01 (s: STD_ULOGIC; xmap: std_ulogic := '0') return std_ulogic is
begin
case s is
when '0' | 'L' =>
return '0';
when '1' | 'H' =>
return '1';
when others =>
return xmap;
end case;
end function TO_01;
begin
DUT:
entity work.sensor_read
port map (
clk_50 => clk_50,
enable => enable,
trigger_sensor => trigger_sensor,
output_sensor => output_sensor
);
-- clock generation
process
begin
clk_50 <= '1';
wait for 10 ns;
clk_50 <= '0';
wait for 10 ns;
if now > 2.2 ms then
wait;
end if;
end process;
-- input data
process
begin
enable <= '0';
trigger_sensor <= 'Z';
wait for 1 ms;
-- start the meassurement
enable <= '1';
-- wait for the trigger signal to be over
while TO_01(trigger_sensor, '1') /= '1' loop wait for 1 us; end loop;
while TO_01(trigger_sensor, '1') = '1' loop wait for 1 us; end loop;
-- now send response
waitfor100us <= '1';
wait for 100 us;
waitfor100us <= '0';
-- trigger_sensor <= '1';
trigger_sensor <= 'Z'; -- WAS '1';
waitfor1ms <= '1';
wait for 1 ms;
waitfor1ms <= '0';
trigger_sensor <= '0';
waitfor10us <= '1';
wait for 10 us;
waitfor10us <= '0';
trigger_sensor <= 'Z';
wait;
end process;
PULLUP: -- ADDED
trigger_sensor <= 'H'; -- PULLUP
end architecture;
这为我们提供了有效的信号波形:
因为驱动trigger_sensor的传感器是异步的,你可以考虑在trigger_sensor上对状态机进行元稳定性过滤。
如果在显示waitfor10us脉冲的时间之后检查显示的波形,您将看到测试平台与sensor_read设计单元的计数间隔不匹配。可能需要一些修修补补。另请注意,在测试台发出一个值后,计数器正在运行。这里需要进行一些修改。