我通过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'之后 .
为什么我会看到这种奇怪的行为?我不能只读一个输入信号吗?
我使用'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;
1 回答
完成测试平台的Minimal Complete and Verifiable example之后:
我们看到了问题:
测试平台中添加了几个信号以标记您的延迟 . 它们很容易丢弃 . 使用的模拟器不会将变量输出到波形 . 您没有正确操作双向传感器信号 .
那该怎么办呢?
在前十几个谷歌的热门歌曲中,原始的Single line multiplexing system for sensors and actuators专利出现,在1982年被授予美国专利4,311,986 .
虽然专利很长时间,但它“教导”了这项发明 .
还有MAX6575L/H数据表告诉我们,您希望在FPGA下降trigger_sensor之前操作计数器,直到传感器再次触发触发传感器为止 .
这种方式的工作原理是FPGA将在一个固定的时间间隔内丢弃trigger_sensor,以指示单线总线上的任何传感器或 Actuator 启动 . 多达8个设备可以使用乘法器共享总线,根据两个输入引脚缩放时间,具有两个延迟系列(H和L后缀) .
对于单个传感器,它将在其时间窗口中通过再次丢弃触发传感器来响应一段固定时间,从而发出脉冲宽度调制编码值(通常用于温度) .
Actuator 将由主机端操作(在这种情况下,FPGA通过丢弃触发传感器线再次将脉冲宽度编码数据值发送到致动器 .
只要没有传感器应答重新开始采样间隔,计数器就足够大,可以通过翻转来重新启动 . 我们这里的VHDL模型只读取传感器 .
那么回到双向信号有什么问题 .
它应该被建模为具有两个驱动器和上拉的开放式收集器 . 对于单个传感器,状态机可能有点过度,但可以使其工作 .
这里的诀窍是,两端都不会在线上驱动'1',只有'0'或'Z'(高阻抗) . 上拉将'Z'变为'H'并代表电阻(数据表显示10K欧姆电阻) .
要读取一个,需要过滤为'0'或'1'值,并且std_logic_1164包有一个函数TO_01来执行该操作,添加的输入具有将元值映射为'0'的默认值 . 对于我们使用开放收集器模型的目的,我们希望函数将元值映射为“1” .
对于您没有使用TO-01的情况,这是在std_logic_1164软件包的早期版本中没有的,它已被包含在内 . 对您的VHDL源所做的所有更改都已注释:
这给我们的信号波形起作用:
因为驱动trigger_sensor的传感器是异步的,所以您可以考虑对trigger_sensor上的状态机进行元稳定性过滤 .
如果在显示waitfor10us脉冲的时间之后检查显示的波形,您将看到测试平台与sensor_read设计单元的计数间隔不匹配 . 可能需要一些修修补补 . 另请注意,在测试台发出一个值后,计数器正在运行 . 这里需要进行一些修修补补 .