常见的通信方式及线路数量(常见四大类线路或协议)
UART: VCC GND TXD RXD ——通用串行数据总线,用于异步双向通信
USART: VCC GND TXD RXD SCK ——同步单向通信,半双工单线通信
SPI: VCC GND CS MOSI MISO SCK ——串行外设接口,同步高速全双工总线
I2C: VCC GND SDA SCK ——双向二线制同步串行总线
1-wrie: VCC+GND+SDA+SCK合并为单线
在串行通信系统中通常具备:
1.时钟信号线 2.数据信号线 3.控制信号线 4.设备电源线、
RXD– 接受数据串行输入 TXD– 发送数据输出
SCK/SCLK/SCL– 时钟信号线 SDA– 数据信号线
SDO/MOSI – 主设备数据输出,从设备数据输入 SDI/MISO – 主设备数据输入,从设备数据输出
SCLK – 时钟信号,由主设备产生;
1-wrie协议
达拉斯半导体公司提出的一种技术,将时钟线,数据线,控制线和电源线合并为一根线,只要符合单总线协议的器件都能以从机的身份挂接到单总线上与主机进行通信,这种串行总写是半双工通信方式,要求总线上所有器件都遵“一套规则”。
————————————————————————————————————————————————————————————
DS18B20
单线式数字温度传感器,测温范围为+125℃— -55℃。每个设备都有唯一的64位光刻ROM序列,用于区别对象;宽电压器件支持供电3.0v-5.5v,支持外部供电和“寄生”,测温的分辨率可由用户设置,可实现高精度测量具有温度报警功能,用户可根据需要设置上下限,设定的限值掉电后不丢失。测量结果直接输出数字温度信号,同时可传输CRC校验码。支持多网点功能,可用于多点布置系统。
1.寄生接法
DS18B20的寄生方式是在DQ引脚为高电平时“窃取”电源,同时将部分能量存储在内部的电容里。(见图寄生电源电路单元)
所以,上拉电阻!!一定要接上,使电平多处于高电平蓄电。
B、为了使DS18B20准确完成温度转换,当温度转换发生时,IO口必须提供足够大的功率。
DS18B20的工作电流高达1mA,5K的上拉电阻使得IO口没有足够的驱动能力。
正常接法
DS18B20内部结构
64位光刻ROM
即每个DS18B20的身份证号码,如果你只用到了一个DS181B20,你可以不关注它。
DS18B20设备ROM指令一览
DS18B20的功能指令
是用来实现设备功能操作的,比如启动温度转换,配置转换的分辨率,配置设备的温度限制报警功能。
转换分辨率问题
分辨率的配置实际时通过配置高速暂存器中的byte4配置寄存器来实现的,配置寄存器的R0(位5)和R1(位6)的取值就决定了设备当前的温度转换分辨率,温度转换分辨率越高,最大转换时间就越长,繁殖最大转换时间就越短。部分断电记忆。
温度值放置
1.装载在Byte0和Byte1中。在高字节中的高5位是符号位,用S表示。如果温度值位正数,则S位均为0;若为负数,则S位均为1。
2.如果DS18B20配置为12位转换分辨率,温度寄存器的所有位都是有效的,对于11位分辨率,位0未定义。对于10位分辨率,位0和位1未定义,对于9位分辨率,位2,位1和位0未定义。12=S+11,11=S+10;
3.若温度为+125℃转换为二进制数位(1111101)B,将这二进制数按照DS18B20温度数值的存储格式依次填入,由于+125℃是正温度,所有符号位S都是0,小数部分2e-1至2e-4(温度值低位LSB位0至位3)位也为0,可以按照如图所示方式装入温度值数据:
4。若温度为负数,需转换为二进制码将二进制码依次填入DS18B20的高低两个字节中,并且符号位S全为1的形式,我们将该带有符号位的二进制码取反得到反码,并且在反码的基础+1得到补码。
5.实际计算温度=分数最小份值。若我们从单总线上取回温度数据(11111010000)B,将其转换为十进制为(2000)D,2000*0.0625=125。 12位分辨率为0.0625,11位0.125,10位0.25。
温度限值
“温度限值”就是高温阙值和低温阙值。当实际采样测量的温度值超过高温限值或者低于低温限值,对应的DS18B20就会发出报警信号,只可设置整数阙值。高速暂存器中的Byte2和Byte3这两个字节用来存储高温限值Th和低温限值Tl,EEPROM也有两个字节与之对应用来保存配置值,以防断电丢失。
以上为DS18B20的数据格式及转换,指令,结构,数据组织,转换都清楚后,接下来是DS18B20读写及时序编程。
ds18b20采集数据的过程
- 1.发送初始化时序——主机发送复位脉冲且从机正确回复应答脉冲的过程
请求: 主机通过拉低单线480us以上, 产生复位脉冲, 然后释放该线, 进入Rx接收模式. 主机释放总线时, 会产生一个上升沿脉冲.
DQ : 1 -> 0(480us+) -> 1
响应: DS18B20检测到该上升沿后, 延时15~60us, 通过拉低总线60~240us来产生应答脉冲.
DQ: 1(15~60us) -> 0(60~240us)
接收响应: 主机接收到从机的应答脉冲后, 说明有单线器件在线. 至此, 初始化完成.
DQ: 0
初始化DS18B20
/*******************************************************************************
函数名:DS18B20_reset
功能:初始化DS18B20
返回值:初始化成功为0,不成功为1
备注:
*******************************************************************************/
int DS18B20_reset(void)
{
int x = 0;
//改变DQ引脚为输出
DS18B20_DQ_DDR(1);
//先置高
DS18B20_DQ_H;
//延时700us,使总线稳定
delay_us(1400);
//复位脉冲,低电位
DS18B20_DQ_L;
//保持至少480us,这里500us
delay_us(1000);
//改变DQ引脚为输入
DS18B20_DQ_DDR(0);
//拉高数据线,释放总线
DS18B20_DQ_H;
//等待15-60us,这里33us
delay_us(60);
//等待35us,这里33us
delay_us(60);
//聆听,判断有没有初始化成功(DS18B20有没有发送应答脉冲)
x = DS18B20_DQ_ReadPin;
printf("DS18B20 waiting....\n");
//等待应答脉冲出现
while(x);
printf("DS18B20 OK\n");
//至少480us后进入接收状态,这里500us
delay_us(1000);
return x;
}
发送ROM操作指令——当有多个DS18B20连接在同一个IO口上时,通过ROM指令指定DS18B20
初始化玩完成后,按照DS18B20操作顺序,主机发送ROM指令,发送相关指令到单总线上就是“写”的过程,由于单总线上读写都必须是逐位操作,即把待写的命令写过程也分为了写“1”过程和写“0”过程,只要按照时序要求的“写时隙”将总线置高或置低即可。
而只有一个DS18B20时,我们通常直接发送“跳过ROM”
- 2.写数据时序
写时隙
写“0” 最小采样时间15us用于从机反应,在60us后从机反应主机写0;
写“1”时主机拉高数据线DQ恢复高电平,接着将数据线DQ先拉低保持15us后, 将数据线DQ拉高;
写一个字节(1Byte=8bit,循环8次写1个位时序,字节从最低位到最高位)
写“0” 写“1” ——分析时序写
/*******************************************************************************
函数名:DS18B20_Wbyte
功能:写一个字节
输入:uint8_t xbyte
******************************************************************************/
void DS18B20_Wbyte(uint8_t xbyte)
{
int8_t i ,x = 0; //i:循环控制变量,x:取位运算变量
DS18B20_DQ_DDR(1); // 改变DQ引脚为输出状态
for(i = 1; i <= 8; i++) //8次循环实现逐位写入
{
x = xbyte & 0x01; //先取低位到最高位
if(x) //写1
{
DS18B20_DQ_H; //回复高电平状态 ,使DQ数据线稳定
DS18B20_DQ_L; //DQ拉低总线
delay_us(30); //延时15us
DS18B20_DQ_H; //总线写1
delay_us(100); //延时45us
DS18B20_DQ_H; //最终保持高电平
delay_us(10);
}
else //写0
{
DS18B20_DQ_H; //恢复高电平状态
DS18B20_DQ_L; //总线拉低
delay_us(30); //延时15us
DS18B20_DQ_L; //总线写0,DS18B20采样
delay_us(100); //延时45us
DS18B20_DQ_H; //最终保持高电平
delay_us(4);
}
xbyte = xbyte >> 1; //xbyte右移一位
}
}
- 3.写数据时序
读时隙
从机收到相关指令后也应该“回答”,这时候就要设计到读时隙,之际只有在发出读时隙时1-wire总线上的相关设备才能向主机逐位传输数据。所以,当主机已经发送ROM指令和相关功能指令后,必须马上产生读时序将DS18B20的结果数据取回。
读一个字节
/*******************************************************************************
函数名:DS18B20_Rbit
功能:从DS18B20读一个位
返回值:读取到的位
备注:释放总线 释放到空闲状态,DQ为高电平是总线的空闲状态,当总线传输数据时(高低电平变化)处理完数据后要把总线释放以等待下一次总线传输数据
*******************************************************************************/
uint8_t DS18B20_Rbit(void)
{
uint8_t rbit = 0x00,x = 0; //rbit是最终位数据,x是取状态变量 0和1
DS18B20_DQ_DDR(1); //改变DQ为输出模式
DS18B20_DQ_H;
DS18B20_DQ_L; //DQ单总线写0
delay_us(30); //延时15us以内
DS18B20_DQ_H; //释放总线
DS18B20_DQ_DDR(0); //改变DQ为输入模式
//delay_us(30); //延时大约15us
x = DS18B20_DQ_ReadPin; //获取总线电平状态
if(x)
rbit = 0x80; //若位高电平则最高位为1返回0x80,否则返回0x00 (10000 0000)B
delay_us(130); //延时大约60us
return rbit; //返回最终位数据
}
/*******************************************************************************
函数名:DS18B20_Rbyte
功能:从DS18B20读一个字节
返回值:读取到的字
*******************************************************************************/
uint8_t DS18B20_Rbyte(void)
{
uint8_t rbyte = 0,i = 0, tempbit =0; //rbyte:最终得到的字节 tempbit:中间运算变量
for (i = 1; i <= 8; i++) //i位循环控制变量,8次循环实现逐位拼合
{
tempbit = DS18B20_Rbit(); //读取单个位
rbyte = rbyte >> 1; //右移实现高低位排序
rbyte = rbyte|tempbit; //或运算移入数据
}
return rbyte; //返回最终字节
}
- 4.获取温度流程
- 复位(初始化) 2.是否读取ID 3.发送温度转换命令(0x44) 4. 延时 5. 复位(初始化)
- 是否读取ID 7. 读取温度的高、低字节 8. 计算
int ReadTemperature(void)
{
int fg; //fg:符号位
int data; //data:温度的整数部分
DS18B20_reset(); //DS18B20复位
DS18B20_Wbyte(0xcc); //跳过读序列号
DS18B20_Wbyte(0x44); //启动温度转换
HAL_Delay(1); //等待温度转换
DS18B20_reset();
DS18B20_Wbyte(0xcc);
DS18B20_Wbyte(0xbe); //读温度寄存器
uint8_t TempL = DS18B20_Rbyte();
uint8_t TempH = DS18B20_Rbyte();
if(TempH > 0x70) //符号位为负
{
TempL = ~TempL;
TempH = ~TempH;
fg = 0;
}
else
fg = 1;
//整数部分
data = TempH; //获得高八位
data <<= 8;
data += TempL; //左移的高8位加上低8位合成一个16位数据
data = (float)data*0.625; //转换
data = data / 10.0;
if(fg)
return data;
else
return -data;
}
配置DS18B20的GPIO接口
/*******************************************************************************
函数名:DS18B20_DQ_DDR
功能:配置IO输入/输出状态
输入:0/1 输入0配置为输入,输入1配置为输出
输出:
返回值:
备注:我用的是PB15,其他GPIO口需自己看手册修改相应的寄存器
*******************************************************************************/
void DS18B20_DQ_DDR(uint8_t ddr) //配置寄存器方法
{
if(ddr == 1)
{
GPIOB->CRH&=0X1FFFFFFF;
GPIOB->CRH|=0X10000000;
}
else
{
GPIOB->CRH&=0X8FFFFFFF;
GPIOB->CRH|=0X80000000;
}
}
//void DS18B20_DQ_DDR(uint8_t ddr)
//{
// GPIO_InitTypeDef GPIO_InitStruct;
// //使能GPIO时钟
// __HAL_RCC_GPIOB_CLK_ENABLE();
// //配置为输出
// if(ddr == 1)
// {
// GPIO_InitStruct.Pin = GPIO_PIN_15;
// GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
// HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// }
// //配置为输入
// else
// {
// GPIO_InitStruct.Pin = GPIO_PIN_15;
// GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
// GPIO_InitStruct.Pull = GPIO_NOPULL;
// HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// }
//}