读/写时序
DS18B20 的数据读写是通过时序处理位来确认信息交换的。
写时序
由两种写时序:写 1 时序和写 0 时序。总线控制器通过写 1 时序写逻辑 1 到DS18B20,写 0 时序写逻辑 0 到 DS18B20。所有写时序必须最少持续 60us,包括两个写周期之间至少 1us 的恢复时间。当总线控制器把数据线从逻辑高电平拉到
低电平的时候,写时序开始。
总线控制器要生产一个写时序,必须把数据线拉到低电平然后释放,在写时序开始后的 15us 释放总线。当总线被释放的时候,5K 的上拉电阻将拉高总线。总控制器要生成一个写 0 时序,必须把数据线拉到低电平并持续保持(至少 60us)。总线控制器初始化写时序后,DS18B20 在一个 15us 到 60us 的窗口内对 I/O 线采样。如果线上是高电平,就是写 1。如果线上是低电平,就是写 0。
void DS18b20_Write_0(void) //写逻辑0码
{
DQ = 0; //输出低电平
Delay60us();
DQ = 1; //输出高电平
Delay1us();
Delay1us();
}
void DS18b20_Write_1(void) //写逻辑1码
{
DQ = 0; //输出低电平
Delay1us();
Delay1us();
DQ = 1; //输出高电平
Delay60us();
}
bit DS18b20_Read(void) //读取电平
{
bit state ;
DQ = 0; //输出低电平
Delay1us();
Delay1us();
DQ = 1; //输出高电平
Delay1us();
Delay1us();
state = DQ; //读取当前电平
Delay60us();
return state;
}
所有读时序必须最少 60us,包括两个读周期间至少 1us 的恢复时间。当总线控制器把数据线从高电平拉到低电平时,读时序开始,数据线必须至少保持 1us,然后总线被释放。在总线控制器发出读时序后,DS18B20 通过拉高或拉低总线上来传输 1 或 0。当传输逻辑 0 结束后,总线将被释放,通过上拉电阻回到上升沿状态。从 DS18B20 输出的数据在读时序的下降沿出现后 15us 内有效。因此,总线控制器在读时序开始后必须停止把 I/O 脚驱动为低电平 15us,以读取I/O 脚状态。
void DS18b20_WriteByte(u8 dat) //写一个字节
{
u8 i;
for( i=0;i<8;i++ ) //循环八次
{
if( dat & 0x01 )
DS18b20_Write_1();
else
DS18b20_Write_0();
dat >>=1;
}
}
// 1000 0000
// x100 0000
// xx10 0000
u8 DS18b20_ReadByte(void) //读取一个字节
{
u8 i;
u8 dat=0;
for( i=0;i<8;i++ ) //循环八次
{
dat >>=1;
if( DS18b20_Read() ) //如果读取到的是1,
dat |= 0x80;
}
return dat;
}
和dht11有点像都是单线的 晓飛飛 发表于 2024-5-18 11:08
别弄DS18B20了,来试试国产的单线温度传感器NST1001吧,精度更高,编程更简单。
https://www.stcaimcu.com/ ...
我买了几颗,还在路上.如果这个有塑封的就好了,我的项目就可以直接替换了,18b20国产的不够好,进口的价格太高. 接着搞开始写代码了
思路:循环扫描2个ds18b20的温度
1.需要首先获取每个ds18b20的唯一标识,获取标识的时候需要只接一个ds18b20一个一个获取(网上找的别人的,我移植过来了)
/**
* @brief读取ROM码
* @param存储DS18B20 ROM码的数组
* @retval None
*/
void ReadRomCode(unsigned char* romcode)
{
bit ack;
unsigned char i;
ack = DS18b20_Reset1(); //复位
if(ack == 0)
{
P20 = 0;
DS18b20_WriteByte(0x33); // 发送读取ROM命令
Delay1ms();
for(i = 0; i < 8; i++)
{
romcode = DS18b20_ReadByte(); // 读取64位ROM码
}
}
}
2.将获取到的DS18B20器件的序列号通过数组保存起来
我代码里是直接把rom码发给串口,获取的
unsigned char ROM_data0 = {0x28,0x8e,0xe2,0x83,0x00,0x00,0x00,0xef}; //存储dsrom码
unsigned char ROM_data1 = {0x28,0x61,0x07,0x85,0x00,0x00,0x00,0xe3}; //存储dsrom码
3.main函数如下:基础就是冲哥课程里的代码
#include "COMM/stc.h" //调用头文件
#include "COMM/stc32_stc8_usb.h"
#include "stdio.h"
#include "stc32g.h"
#include "18b20.h"
#define MAIN_Fosc 22118400L //定义主时钟
unsigned char ROM_data; //存储dsrom码
unsigned char ccc = 0xee;
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
bitTIM_10MS_Flag; //10ms的标志位
void sys_init(); //函数声明
void delay_ms(u16 ms); //unsigned int
void Delay3000ms(void) //@22.1184MHz
{
unsigned long edata i;
_nop_();
_nop_();
i = 16588798UL;
while (i) i--;
}
void main() //程序开始运行的入口
{
int dat = 0; //初始数值
unsigned int wendu;
unsigned int wendu1;
sys_init(); //USB功能+IO口初始化
usb_init(); //usb库初始化
EUSB = 1; //中断允许位
EA = 1; //CPU开放中断,打开总中断。
while( DeviceState != DEVSTATE_CONFIGURED );
while(1) //死循环
{
delay_ms(2);
if( bUsbOutReady )
{
// USB_SendData(UsbOutBuffer,OutNumber);
usb_OUT_done();
}
Delay3000ms();
//读取当前ds18的标识码
// ReadRomCode(ROM_data);
// printf( "当前rom1:%x-", ROM_data);
// printf( "当前rom2:%x-", ROM_data);
// printf( "当前rom3:%x-", ROM_data);
// printf( "当前rom4:%x-", ROM_data);
// printf( "当前rom5:%x-", ROM_data);
// printf( "当前rom6:%x-", ROM_data);
// printf( "当前rom7:%x-", ROM_data);
// printf( "当前rom8:%x\r\n", ROM_data);
P01 = !P01;
wendu = DS18b20_ReadTemp2(0); //300ms到达,读取一次温度
if( MinusFlag==1 )
{
printf( "当前温度0:-%.01f\r\n",(float)((float)wendu/10) );
}
else
{
printf( "当前温度0:%.01f\r\n",(float)((float)wendu/10) );
}
Delay3000ms();
wendu1 = DS18b20_ReadTemp2(1); //300ms到达,读取一次温度
if( MinusFlag==1 )
{
printf( "当前温度1:-%.01f\r\n",(float)((float)wendu1/10) );
}
else
{
printf( "当前温度1:%.01f\r\n",(float)((float)wendu1/10) );
}
}
}
void sys_init() //函数定义
{
WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
P3M0 = 0x00;
P3M1 = 0x00;
P3M0 &= ~0x03;
P3M1 |= 0x03;
USBCON = 0X00; //usb初始化
USBCLK = 0X00;
IRC48MCR = 0X00;
delay_ms(10);
//设置USB使用的时钟源
IRC48MCR = 0x80; //使能内部48M高速IRC
while (!(IRC48MCR & 0x01));//等待时钟稳定
USBCLK = 0x00; //使用CDC功能需要使用这两行,HID功能禁用这两行。
USBCON = 0x90;
}
void delay_ms(u16 ms) //unsigned int
{
u16 i;
do
{
i = MAIN_Fosc/6000;
while(--i);
}while(--ms);
}
大神,请教一下,如果同时使用10个DS18B20,分开10个IO接DS18B20,去控制10个继电器工作?怎么写??代码?{:4_165:}{:4_165:}{:4_165:}{:4_165:}能不能实现? 22.1184MHz,楼主改下吧!22.1184Hz,啥也干不了 lovelong 发表于 2024-11-20 08:37
大神,请教一下,如果同时使用10个DS18B20,分开10个IO接DS18B20,去控制10个继电器工作?怎么写??代码? ...
如果同时使用10个DS18B20,1个IO接DS18B20就可以了。
单线总线可以支持,127个DS18B20理论上。实际上也可以20~30个。
网上的18b20程序,很多是用Delay延时直接去写的,目的更多是让你了解这个芯片的工作原理
但这种程序在现实的量产产品中肯定是不行的,因为单片机可能还要做其它的事
可以用定时器来进行非阻塞式的通讯
D_Works 发表于 2024-11-20 08:55
22.1184MHz,楼主改下吧!22.1184Hz,啥也干不了
标记下 。。
页:
1
[2]