我正在尝试为MS5541C压力/温度传感器编写驱动程序,但似乎我无法做到。 数据表提供了一些计算,如果我把它们放入excel似乎工作得很好。 但是,当我尝试为它编写VHDL代码并将其显示在7段显示器上时,它不起作用。
提供的计算是:
UT1 = 8 * C5 + 10000
其中C5是从PROM读取的校准数据
dT = D2 - UT1
其中D2是从DAC读取的温度
TEMP = 200 + dT*(C6+100)/2^11
其中temp是0.1摄氏度的实际温度,C6也是校准温度。
在我的情况下,C5 = 2223(dec),D2 = 28144(dec),C6 = 53。 有了这些数字,我的温度就达到了22.7摄氏度。
我在VHDL中使用的代码(MCVE)是:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
ENTITY MS5541C_CONVERTER IS
PORT(
CLK : IN STD_LOGIC;
RST : IN STD_LOGIC;
T_OUT : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE MS5541C_CONVERTER OF MS5541C_CONVERTER IS
Constant C5 : STD_LOGIC_VECTOR(11 DOWNTO 0) := "100010101111"; -- Reference temperature
Constant C6 : STD_LOGIC_VECTOR( 6 DOWNTO 0) := "0110101"; -- Temp coefficient of the temperature
Constant D2 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"6df0"; -- temperature
BEGIN
PROCESS (CLK,RST)
VARIABLE UT1 : SIGNED(33 DOWNTO 0);
VARIABLE dT : SIGNED(33 DOWNTO 0);
VARIABLE TEMPE : SIGNED(33 DOWNTO 0);
VARIABLE C5_s : SIGNED(33 DOWNTO 0);
VARIABLE C6_s : SIGNED(33 DOWNTO 0);
BEGIN
C5_s := RESIZE(signed(C5),33);
C6_s := RESIZE(signed(C6),33);
IF RST = '1' THEN
ELSIF rising_edge(CLK) THEN
UT1 := 8 * C5_s + 10000;
dT := RESIZE(signed(D2),33) - UT1;
TEMPE := 200 + dT*(C6_s + 100)/ 2048;
T_OUT <= STD_LOGIC_VECTOR(RESIZE(TEMPE,16));
END If;
END PROCESS;
END ARCHITECTURE;
结果是2674(dec)或a72(hex)(实际数字可能与excel有点不同,因为这是两次测量,但这甚至不是很接近)
我已经重读了几次计算,甚至尝试了不同的方法,但结果永远不正确。我认为它与类型的转换有关,但我不知道是什么。
P.S。 对于想要阅读数据表的人:
http://media.digikey.com/pdf/Data%20Sheets/Measurement%20Specialties%20PDFs/MS5541-CM.pdf
答案 0 :(得分:0)
至少有一个问题是,当您对C5执行带符号的转换时,将保留-4984,而不是2223.然后,将此负数扩展为33位宽。
如果这是唯一的问题,那么您的最终结果将是4534,因此可能存在另一个问题,但您转换为签名的其他常量都没有前导'1'
。
C5,C6,D2是否实际签名?它们实际上是从舞会上读取的12/7/16位宽吗?
我希望你的时钟非常慢或者这不是合成,尽管我怀疑你打算在真实的系统中使用它。这种使用变量而不是信号的数学运算将在一个时钟周期内完成所有这些工作。 33位操作数(广泛的一面)加剧了这个问题。
说到操作数长度,如果计算出每个计算和操作数将保持的最大值并使用适当的长度,则数学效率会更高。优化器可以修复其中一些,但它们并不总是完美的。