DS18B20分析和VHDL代码实现
DS18B20简介DS18B20是一种单总线数字温度传感器。测试温度范围-55℃-125℃,温度数据位可配置为9、10、11、12位,对应的刻度值分别为0.5℃、0.25℃、0.125℃、0.0625℃,对应的最长转换时间分别为93.75ms、187.5ms、375ms、750ms。出厂默认配置为12位数据,刻度值为0.0625℃,最长转换时间为750ms。从以上数据可以看出,DS18B20数据位越低、转换时间越短、反应越快、精度越低。
单总线,意味着没有时钟线,只有一根通信线。单总线读写数据是靠控制起始时间和采样时间来完成,所以时序要求很严格,这也是DS18B20驱动编程的难点。
作为一个传感器来说,对于MCU或者FPGA大都是通过设备地址和寄存器地址来访问我们想要读取的数据,但是DS18B20这个芯片这里没有地址,下面给出DS18B20 的寄存器及地址,只要照着datasheet上的时序对DS18B20进行读寄存器的内容,DS18B20就会自动完成温度的模数转化,更新到寄存器。下面是DS18B20面向MCU的寄存器内容
DSfile:///C:/Users/yao/AppData/Local/Temp/msohtmlclip1/01/clip_image002.gif
18B20重要寄存器
Configuration Register
对于一个器件,一般都会有可以配置的寄存器,DS18B20也不例外。这个寄存器就是配置转化时间间隔和位数的这里不进行配置,使用默认的模式。file:///C:/Users/yao/AppData/Local/Temp/msohtmlclip1/01/clip_image004.gif
Temperature Register
高位字节前5位为符号位,其余的权重和16进制数使用方法一致。
代码实现:
Temperature_1
读取到的高字节(前面定义读取);
temperature_buf_low
读取到的低字节(前面定义读取);
neg_flag
负温度指示(输出)
if(temperature_1and "11111000") = "11111000"then --如果温度是负数则需要转换下,高字节
temperature_buf_low<=(nottemperature_buf_low )+1;--低字节取反再加1
temperature_1:=(not temperature_1);
iftemperature_buf_low="0000000" then --低字节取反时进位处理
temperature_1:=temperature_1+1;
end if;
neg_flag<='1';--负温度指示
else neg_flag<='0';
end if;
temperature<=temperature_1(2 downto0)&temperature_buf_low;--温度值是templ_value2的低3位和templ_value1
DS18B20使用过程:
(1)初始化;
(2)发送ROMCommand(33h:只读rom,不用寻址过程);
(3)发送FunctionCommand(22h: 开始转换温度);
(4)初始化;
(5)发送ROMCommand(33h:只读rom,不用寻址过程);
(6)发送FunctionCommand(7dh: 开始读暂存器);
(7)读取温度寄存器低字节;
(8)读取温度寄存器高字节;
时序实现:file:///C:/Users/yao/AppData/Local/Temp/msohtmlclip1/01/clip_image006.gif
(1)初始化时序:
a.主机拉低480us总线,
b.主机释放总线,输出高阻,或者输出高电平60us
c.DS18B20会拉低总线240us,主机等待240us时间后拉高就完成了初始化过程。
代码实现:同样使用把时序整合到状态机里面的想法。
wheninitial_1 =>
initial_count <=initial_count + '1';
if initial_count=10#50# then
dq<='1';
elsif initial_count=10#100# then --拉低
dq<='0';
elsif initial_count= 10#25100#then --初始化时要求,低电平至少保持480us,这里取500us
dq<='1';
elsif initial_count=10#26500# then --要求15us~60us,拉高,这里取30us(530),再释放总线,以让DS18B20发出存在脉冲
dq<='Z';
elsif initial_count= 10#41500#then --存在脉冲为60us~240us,取 300 再拉高
dq<='1';
elsif initial_count>=10#51000#then --整个时序要求960us,这里取1020us
initial_count<=(others =>'0'); --释放总线电阻拉高,初始化标志置1,即下次不进行初始化,计数器归零
current_state<=wr_cmd1;
dq<='Z';
(2)写一位的时序:写时序分写0和写“1”
a.主机拉低总线15us;
b.主机根据输出0和1来决定拉低或者拉高总线至少60us;
c.最后主机总线至少拉高1us;
file:///C:/Users/yao/AppData/Local/Temp/msohtmlclip1/01/clip_image008.gif
代码实现:
whenwr_cmd1 =>
wr_count<= wr_count +1;
if wr_count = 10#50# then
dq <= '0';--将总线拉低
elsif wr_count = 10#500# then--在15us内向总线写一比特数值
dq <= cmd1(cmd_bit_cnt);
elsif wr_count=10#4500# then --在写时序的15us~60us内,DS18B20对总线采样,所以取90us
dq<='1';
elsif wr_count = 10#4600# then
--在大于1us之后,总线拉低,产生下一写时序 取2us
dq<='0';
wr_count<=(others =>'0');--计数器归零
cmd_bit_cnt := cmd_bit_cnt-1;--写下一bit 的命令
if cmd_bit_cnt = -1 then --写完命令,命令计数值“归零”(倒数),状态转为1,即将写命令2
cmd_bit_cnt :=15;
current_state <=initial_2;
end if;
end if;
(3)读取一位的时序:
a.主机拉低总线至少1us;
b.主机释放总线file:///C:/Users/yao/AppData/Local/Temp/msohtmlclip1/01/clip_image010.gif
c.最后主机在15us时刻读取总线电平;
代码实现:
whenrd_temp_1=>--读取第一字节温度(低字节)
rd_count<=rd_count+1;
if rd_count = 10#50# then
dq <= '0';
elsif rd_count = 10#200# then --低电平至少1us,在释放总线
dq <= 'Z';
elsif rd_count = 10#650# then --要求在15us内读取温度
temperature_1(rd_temp_bit_cnt):=dq;
elsif rd_count = 10#4000# then--读时序至少60us,这里取80us
dq<='1';
elsif rd_count = 10#4100# then
rd_count <= (others =>'0');
rd_temp_bit_cnt:=rd_temp_bit_cnt+1;--读取下个比特
if(rd_temp_bit_cnt = 8) then--读取完第一个字节
rd_temp_bit_cnt:=0;--归零
current_state<=rd_temp_2;
temperature_buf_low<=temperature_1;
end if;
end if;
3.3.5DS18B20驱动设计总结
只要按照上述的时序拼合,经验证,可以读取到温度的温度数据。由于需要给数码管显示,需要把数据转化为BCD码,这里使用整数转化的方法,使用STD_LOGIC_ARITH库的转化运算:
CONV_INTEGER:把向量转化为整数
Conv_Std_Logic_Vector:把整数转化为向量
代码实现: --温度转化为BCD码
process(temperature)
begin
--if(neg_flag = '0') then --温度为正数
var4<=CONV_INTEGER(temperature)/1600; --百位
var3<=CONV_INTEGER(temperature)/160rem 10; --十位
var2<=CONV_INTEGER(temperature)/16rem 10; --个位
var1<=CONV_INTEGER(temperature)*10/16rem 10; --小数点后一位
--end if;
bcd_data(15 downto12)<=Conv_Std_Logic_Vector(var4,4);
bcd_data(11 downto8)<=Conv_Std_Logic_Vector(var3,4);
bcd_data(7 downto4)<=Conv_Std_Logic_Vector(Var2,4);
bcd_data(3 downto0)<=Conv_Std_Logic_Vector(Var1,4);
end process; 对于上述的图片,请自行查看datasheet,我黏贴时黏贴不上来,不好意思 对于上述的图片,请自行查看datasheet,我黏贴时黏贴不上来,不好意思 对于上述的图片,请自行查看datasheet,我黏贴时黏贴不上来,不好意思
页:
[1]