4 一线式串行总线

1、基本概念

一线式串行总线

  • “一线式”:说明CPU和外设之间数据通信只需一根信号线,此信号线必然是数据线并且数据线连接了一个上拉电阻,默认为高电平
  • “串行”:说明CPU和外设的数据通信一个时钟周期传输一个bit位
    问:没有时钟控制信号线,哪来的时钟呢,怎么去传输1个bit位呢?不像I2C总线的"低放高取",因为它有时钟控制信号线
    答:看协议
  • “总线”:说明这根数据线上可以连接挂接多个外设
    在这里插入图片描述

2、DS18B20介绍

2.1 相关概念

  • 1.ROM存储了64bit的串行码:后续对于ROM进行处理
    在这里插入图片描述

DS18B20芯片内部集成了64bit容量的ROM(只读存储器),存储每一个DS18B20唯一的序列码(类似身份证号)所以:CPU将来要想访问某个DS18B20,只需通过ROM中的序列码即可访问,也就是CPU只需向总线发送对应的DS18B20的序列码即可访问某个外设。

  • 温度值
    在这里插入图片描述

temperature = msb << 8 | lsb;

  • 访问DS18B20遵循以下三步骤:
    第一步CPU向总线发送初始化复位信号,类似I2C的START信号,UART的起始位
    第二步CPU向总线发送ROM命令,为了找到要访问的外设,类似I2C总线发送设备地址
    第三步CPU向总线发送功能命令(一旦找到外设以后,下面就是读还是写还是其他功能)

  • 初始化序列
    CPU发送复位脉冲
    DS18B20发送了存在脉冲
    在这里插入图片描述

  • CPU向总线发送ROM命令
    在这里插入图片描述

  • CPU向总线发送功能命令
    在这里插入图片描述

2.2 操作流程

  1. 初始化序列

  2. 发送ROM命令 SKIP ROM 命令
    在这里插入图片描述

  3. 发送 CONVERT T 命令:开始采集温度
    在这里插入图片描述

  4. 初始化序列:进行下一次温度获取

  5. 发送SKIP ROM命令

  6. 发送READ命令

  7. 读取两个字节的温度值

2.3 功能实现

在system目录下,新建DS18B20目录,打开keil工程,新建ds18b20.c和ds18b20.h文件
编辑ds18b20.h

#ifndef __DS18B20_H_
#define __DS18B20_H_

#include "stm32f10x.h"
#include "system.h"

// 定义DS18B20的相关信息  - GPIOG11
#define DS18B20_PORT	 GPIOG
#define DS18B20_PIN 	 GPIO_Pin_11
#define DS18B20_IO_OUT   PGout(11)
#define DS18B20_IO_IN    PGin(11)
// 功能函数
void DS18B20_Init(void);// 初始化
void DS18B20_Reset(void);// 初始化序列
void DS18B20_Write_Byte(u8 data);// 发送单字节函数
u8   DS18B20_Read_Byte(void); // 读取单字节函数
float DS18B20_GetTemperature(void);// 获取读取温度值

void DS18B20_ReadRom();

// 测试函数
void DS18B20_Test(void); // 测试命令

#endif

编辑ds18b20.c

#include "ds18b20.h"
#include "systick.h"
#include "stdio.h"
/** 功能函数*/
// 初始化
void DS18B20_Init(void){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);
	GPIO_InitTypeDef gpio_config;
	gpio_config.GPIO_Mode = GPIO_Mode_Out_PP;
	gpio_config.GPIO_Pin = DS18B20_PIN;
	gpio_config.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DS18B20_PORT,&gpio_config);
}
// 配置输出
void DS18B20_OUT(void){
	GPIO_InitTypeDef gpio_config;
	gpio_config.GPIO_Mode = GPIO_Mode_Out_PP;
	gpio_config.GPIO_Pin = DS18B20_PIN;
	gpio_config.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DS18B20_PORT,&gpio_config);
}
// 配置输入
void DS18B20_IN(void){
	GPIO_InitTypeDef gpio_config;
	gpio_config.GPIO_Mode = GPIO_Mode_IPU;
	gpio_config.GPIO_Pin = DS18B20_PIN;
	gpio_config.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DS18B20_PORT,&gpio_config);
}

根据操作流程实现功能
在这里插入图片描述

// 初始化序列
void DS18B20_Reset(void){
	DS18B20_OUT();
	// 拉低,至少480us
	DS18B20_IO_OUT=0;
	delay_us(500);
	// 拉高,保持15~60us
	DS18B20_IO_OUT = 1;
	delay_us(30);
	// 循环等待240us,在此期间能检测到低电平,则有外设在总线上
	int timeTime=0;
	while(timeTime<240 && DS18B20_IO_IN){
		delay_us(1);
		timeTime++;
	}
	if(timeTime >= 240){
		printf("reset failed\r\n");
	}else{
		printf("reset OK\r\n");
		timeTime=0;
	}
}

// 发送单字节函数 从低位开始数据传输
void DS18B20_Write_Byte(u8 data){
	DS18B20_OUT();
	for(int i=0;i<8;i++){
		int temp = (data>>i)&0x01;
		if(temp){ // 1
			DS18B20_IO_OUT = 0;
			delay_us(2);
			DS18B20_IO_OUT = 1;
			delay_us(60);
		}else{ // 0
			DS18B20_IO_OUT = 0;
			delay_us(60);
			DS18B20_IO_OUT = 1;
			delay_us(2);
		}
	}
}
// 读取单字节函数 从低位开始读取
u8   DS18B20_Read_Byte(void){
	u8 temp=0;
	for(int i=0;i<8;i++){
		DS18B20_OUT();
		DS18B20_IO_OUT=0;
		delay_us(2);
		DS18B20_IN();
		delay_us(8);
		temp |=DS18B20_IO_IN<<i;
		delay_us(50); // 延迟,读取一次数据的整体时间大于60us
	}
	return temp;
} 
// 获取读取温度值
float DS18B20_GetTemperature(void){
	
	float value;
	u8 temp_lsb = 0, temp_msb = 0;
	u16 temp;
	// 初始化序列
	DS18B20_Reset();
	// 发送SKIP ROM命令
	DS18B20_Write_Byte(0xcc);
	// 发送CONVERT命令
	DS18B20_Write_Byte(0x44);
	// 初始化序列
	DS18B20_Reset();
	// 发送SKIP ROM命令
	DS18B20_Write_Byte(0xcc);
	DS18B20_Write_Byte(0xbe);
	// 读取两个字节的温度值
	temp_lsb = DS18B20_Read_Byte();
	temp_msb = DS18B20_Read_Byte();
	temp = temp_msb << 8 | temp_lsb;
	// 将数字转化为温度值
	if((temp & 0xf800) == 0xf800){
		temp = (~temp) + 1;
		value = temp * (-0.0625);
	}else{
		value = temp * 0.0625;
	}
	return value;
}

// 静态数组存储ROM值 - 本地化
static u8 rom[8]={0};

// 获取ROM
void DS18B20_ReadRom(void){
	// 初始化序列
	DS18B20_Reset();
	// 读取ROM值
	DS18B20_Write_Byte(0x33);
	// 循环读8次
	for(int i=0;i<8;i++){
		rom[i] = DS18B20_Read_Byte();
		printf("%#x ",rom[i]);
	}
	printf("\r\n");
}

void DS18B20_MatchRom(void){
	// 先发送MATCH_ROW
	DS18B20_Write_Byte(0x55);
	// 循环将rom值发送到总线上匹配
	for(int i=0;i<8;i++){
		DS18B20_Write_Byte(rom[i]);
	}
}

// 获取读取温度值
float DS18B20_GetROMTemperature(void){

	float value;
	u8 temp_lsb = 0, temp_msb = 0;
	u16 temp;
	// 初始化序列
	DS18B20_Reset();
	// 发送MATCH ROM命令
	DS18B20_MatchRom();// 发送ROM
	// 发送CONVERT命令
	DS18B20_Write_Byte(0x44); // 进行温度转换
	delay_ms(1000);
	// 初始化序列
	DS18B20_Reset();
	// 发送MATCH ROM命令
	DS18B20_MatchRom();
	DS18B20_Write_Byte(0xbe); // 读取温度
	// 读取两个字节的温度值
	temp_lsb = DS18B20_Read_Byte();
	temp_msb = DS18B20_Read_Byte();
	temp = temp_msb << 8 | temp_lsb;
	if((temp & 0xf800) == 0xf800){
		temp = (~temp) + 1;
		value = temp * (-0.0625);
	}else{
		value = temp * 0.0625;
	}
	return value;
}

/* 测试函数 */
void DS18B20_Test(void){// 测试命令
	float temp = DS18B20_GetTemperature();
	// float temp = DS18B20_GetROMTemperature();
	printf("CURRENT TEMP : %.3f\r\n", temp);
} 
  • 24
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

启航zpyl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值