使用VDHL编写了一个DS18B20的驱动代码,实现12位精度的温度采集,输出使用原始数据输出,需要自己进行符号位及小数位的处理。
时钟50MHz,DATA_RD高电平时,输出有效,这里可以自己再修改一下。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
ENTITY DS18B20 IS
PORT( clk : in std_logic; --50Mhz
rerst : in std_logic;
DQ_OUT : inout std_logic;
data_req : in std_logic;
data_out : out std_logic_vector(11 downto 0);
data_rd : out std_logic
);
END ENTITY DS18B20;
ARCHITECTURE behav OF DS18B20 IS
--SIGNAL Define
SIGNAL div_clk : std_logic;
SIGNAL DQ : std_logic;
SIGNAL data_out_temp : std_logic_vector(11 downto 0);
BEGIN
--Always run
DQ_OUT <= DQ;
data_out <= data_out_temp;
low_clock:PROCESS(clk,rerst)IS
VARIABLE count1 : std_logic_vector(4 downto 0);
BEGIN
if rerst='1' then
div_clk <= '0';
count1 := (others => '0');
elsif rising_edge(clk) then
if(count1 = "11000")then --计数到24 50M时钟分频到1M
div_clk <= not div_clk;
count1 := (others => '0');
else
div_clk <= div_clk;
count1 := count1 + '1';
end if;
end if;
END PROCESS low_clock;
main:PROCESS(div_clk,rerst)IS
--VARIABLE Define
VARIABLE count2 : integer range 0 to 510;
VARIABLE delay : integer range 0 to 1000001;
VARIABLE state : integer range 0 to 31;
VARIABLE state_temp : integer range 0 to 12;
VARIABLE readnum : integer range 0 to 12;
VARIABLE sendnum : integer range 0 to 10;
VARIABLE cmd : std_logic_vector(7 downto 0) := "00000000";
BEGIN
if rerst='1' then
data_rd <= '0';
DQ <= 'Z';
count2 := 0;
delay := 0;
state := 0;
state_temp := 0;
readnum := 0;
sendnum := 0;
elsif rising_edge(div_clk) then
case state IS
--Initialization start
WHEN 0 =>
data_rd <= '0';
count2 := 0;
if(data_req = '1')then
state := 1;
else
state := 0;
end if;
WHEN 1 =>
state_temp := 2;
count2 := 0;
state := 12; --rst and check DS18B20
WHEN 2 =>
cmd := "11001100";
state_temp := 3;
count2 := 0;
state := 17; --send 0xCC
WHEN 3 =>
cmd := "01000100";
state_temp := 4;
count2 := 0;
state := 17; --send 0x44
WHEN 4 =>
if(delay < 1000000)then
delay := delay + 1;
state := state;
else
delay := 0;
state := 5; --delay 1000ms
end if;
WHEN 5 =>
state_temp := 6;
count2 := 0;
state := 12; --rst and check DS18B20
WHEN 6 =>
cmd := "11001100";
state_temp := 7;
count2 := 0;
state := 17; --send 0xCC
WHEN 7 =>
cmd := "10111110";
state_temp := 8;
count2 := 0;
state := 17; --send 0xBE
WHEN 8 =>
state_temp := 9;
count2 := 0;
state := 21; --read data
WHEN 9 =>
data_rd <= '1';
state := 0;
----------------------------------------------------------------------
--rst DS18B20
WHEN 12 =>
if(count2 <= 500)then
DQ <= '0';
count2 := count2 + 1;
state := state;
else
DQ <= 'Z';
count2 := 0;
state := 13;
end if;
WHEN 13 =>
if(count2 <= 30)then
DQ <= 'Z';
count2 := count2 + 1;
state := state;
else
state := 14;
end if;
--check DS18B20
WHEN 14 =>
count2 := count2 + 1;
if(DQ = '0')then
state := 15;
else
state := state;
end if;
WHEN 15 =>
if(count2 = 500)then
count2 := 0;
state := 16;
else
count2 := count2 + 1;
state := state;
end if;
WHEN 16 =>
state := state_temp;
--send BYTE
WHEN 17 =>
DQ <= '0';
count2 := 0;
state := 18;
WHEN 18 =>
state := 19;
WHEN 19 =>
if(count2 <= 60)then --send data
count2 := count2 + 1;
DQ <= cmd(sendnum);
state := state;
elsif(count2 <= 63)then --send gap
count2 := count2 + 1;
DQ <= 'Z';
state := state;
else
sendnum := sendnum + 1;
count2 := 0;
state := 20;
end if;
WHEN 20 =>
if(sendnum <= 7)then
state := 17;
else
sendnum := 0;
state := state_temp;
end if;
--read BYTE
WHEN 21 =>
DQ <= '0';
if(count2 <= 2)then
count2 := count2 + 1;
state := state;
else
count2 := 0;
state := 22;
end if;
WHEN 22 =>
DQ <= 'Z';
state := 23;
WHEN 23 =>
if(count2 <= 10)then
count2 := count2 + 1;
state := state;
else
count2 := 0;
data_out_temp <= DQ & data_out_temp(11 downto 1);
state := 24;
end if;
WHEN 24 =>
if(count2 <= 50)then
DQ <= 'Z';
count2 := count2 + 1;
state := state;
else
count2 := 0;
readnum := readnum + 1;
state := 25;
end if;
WHEN 25 =>
if(readnum <= 11)then
state := 21;
else
readnum := 0;
state := state_temp;
end if;
WHEN OTHERS =>
cmd := "00110011";
state := 0;
end case;
end if;
END PROCESS main;
END ARCHITECTURE behav;