STM32-单总线通讯学习
STM32-单总线通讯学习
/**
* @file BSP_1_WIRE.c
* @author ydm
* @version V1.0
* @date 14-Dec-2021
* @brief 单总线协议驱动文件
* @attention
* 单总线协议的驱动文件,使用GPIO发出单总线的通讯时序,为单总线的设备提供基本驱动接口 \n
* @htmlonly
* <span style="font-weight: bold">History</span>
* @endhtmlonly
* Version|Auther|Date|Describe
* ------|----|------|--------
* V1.0|ydm|14-Dec-2021|Create File
* <h2><center>©COPYRIGHT 2017 WELLCASA All Rights Reserved.</center></h2>
*/
#include "BSP_1_Wire.h"
#include "delay.h"
/** 定义1_Wire的GPIO CLK */
#define ONE_WIRE_GPIO_CLKENABLE __HAL_RCC_GPIOA_CLK_ENABLE()
/** 1-wire总线输出高电平 */
#define ONE_WIRE_HIGH(One_Wire_bus_temp) HAL_GPIO_WritePin(One_Wire_bus_temp->ONE_WIRE_PORT, One_Wire_bus_temp->ONE_WIRE_PIN, GPIO_PIN_SET)
/** 1-wire总线输出低电平 */
#define ONE_WIRE_LOW(One_Wire_bus_temp) HAL_GPIO_WritePin(One_Wire_bus_temp->ONE_WIRE_PORT, One_Wire_bus_temp->ONE_WIRE_PIN, GPIO_PIN_RESET)
/**
* @brief 单总线BUS的初始化函数.
* @details 将对应的单总线BUS进行初始化.
* @param[in] ONE_WIRE_BUS 要将GPIO初始化的BUS
* @retval 1 初始化成功
* @retval 0 初始化失败
* @par 修改日志
* ydm于2021-12-14创建
*/
uint8_t BSP_1_WIRE_Init(PT_ONE_WIRE ONE_WIRE_BUS)
{
BSP_1_WIRE_GPIO_Init(ONE_WIRE_BUS);
BSP_1_WIRE_RST(ONE_WIRE_BUS);
return BSP_1_WIRE_Check(ONE_WIRE_BUS);
}
/**
* @brief 单总线BUS的读取GPIO电平函数.
* @details 读取GPIO的电平.
* @param[in] ONE_WIRE_BUS 要读取的BUS
* @retval 1 高电平
* @retval 0 低电平
* @par 修改日志
* ydm于2021-12-14创建
*/
uint8_t BSP_Ds18B20_Pin_Read(PT_ONE_WIRE ONE_WIRE_BUS)
{
if(HAL_GPIO_ReadPin(ONE_WIRE_BUS->ONE_WIRE_PORT,ONE_WIRE_BUS->ONE_WIRE_PIN) == GPIO_PIN_RESET)
{
return 0;
}
else
{
return 1;
}
}
/**
* @brief 单总线BUS的GPIO初始化函数.
* @details 将对应的单总线BUS使用的GPIO进行初始化.
* @param[in] ONE_WIRE_BUS 要将GPIO初始化的BUS
* @retval
* @par 修改日志
* ydm于2021-12-14创建
*/
static void BSP_1_WIRE_GPIO_Init(PT_ONE_WIRE ONE_WIRE_BUS)
{
ONE_WIRE_GPIO_CLKENABLE;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pin = ONE_WIRE_BUS->ONE_WIRE_PIN;
HAL_GPIO_Init(ONE_WIRE_BUS->ONE_WIRE_PORT, &GPIO_InitStructure);
}
/**
* @brief 设置GPIO方向.
* @details 设置GPIO是输出状态还是输入状态.
* @param[in] ONE_WIRE_BUS 要输出复位时序的BUS
* @param[in] mode 状态是输入还是输出
* @retval
* @par 修改日志
* ydm于2021-12-14创建
*/
static void ONE_WIRE_PinMode(PT_ONE_WIRE ONE_WIRE_BUS,int mode)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(mode == ONE_WIRE_PinMode_IN)
{
GPIO_InitStruct.Pin = ONE_WIRE_BUS->ONE_WIRE_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(ONE_WIRE_BUS->ONE_WIRE_PORT, &GPIO_InitStruct);
}
else if(mode == ONE_WIRE_PinMode_OUT)
{
GPIO_InitStruct.Pin = ONE_WIRE_BUS->ONE_WIRE_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(ONE_WIRE_BUS->ONE_WIRE_PORT, &GPIO_InitStruct);
}
}
/**
* @brief 单总线复位时序输出.
* @details 将对应的单总线BUS输出复位时序.
* @param[in] ONE_WIRE_BUS 要输出复位时序的BUS
* @retval
* @par 修改日志
* ydm于2021-12-14创建
*/
void BSP_1_WIRE_RST(PT_ONE_WIRE ONE_WIRE_BUS)
{
ONE_WIRE_PinMode(ONE_WIRE_BUS,ONE_WIRE_PinMode_OUT);
//拉低单总线480 ~ 960 us产生复位脉冲
ONE_WIRE_LOW(ONE_WIRE_BUS);
Delay_us(520);
ONE_WIRE_HIGH(ONE_WIRE_BUS);
Delay_us(15);
}
/**
* @brief 检测单总线检测是否有从设备相应.
* @details 检测单总线上是否有从设备相应.
* @param[in] ONE_WIRE_BUS 要输出复位时序的BUS
* @retval 0 检测失败
* @retval 1 检测成功
* @par 修改日志
* ydm于2021-12-14创建
*/
uint8_t BSP_1_WIRE_Check(PT_ONE_WIRE ONE_WIRE_BUS)
{
int i = 0;
ONE_WIRE_PinMode(ONE_WIRE_BUS,ONE_WIRE_PinMode_IN);
while((BSP_Ds18B20_Pin_Read(ONE_WIRE_BUS)) && (i<200))
{
i++;
Delay_us(1);
}
if(i >= 200)
{
return 0;
}
else
{
i= 0;
}
//主机至少接收480us
while((!BSP_Ds18B20_Pin_Read(ONE_WIRE_BUS)) && (i<240))
{
i++;
Delay_us(1);
}
if(i >= 240)
{
return 0;
}
else
{
return 1;
}
}
/**
* @brief 向单总线上写一个字节.
* @details 向单总线上写一个字节.
* @param[in] ONE_WIRE_BUS 要进行写操作的BUS
* @param[in] data 要写入BUS的数据.
* @retval
* @par 修改日志
* ydm于2021-12-14创建
*/
void BSP_OneWire_Write_Byte(PT_ONE_WIRE ONE_WIRE_BUS,uint8_t data)
{
int i = 0;
ONE_WIRE_PinMode(ONE_WIRE_BUS,ONE_WIRE_PinMode_OUT);
for(i = 0 ; i < 8 ; i++)
{
ONE_WIRE_LOW(ONE_WIRE_BUS);
Delay_us(2);
if(data & 0x01)
{
ONE_WIRE_HIGH(ONE_WIRE_BUS);
}
else
{
ONE_WIRE_LOW(ONE_WIRE_BUS);
}
Delay_us(60);
ONE_WIRE_HIGH(ONE_WIRE_BUS);
Delay_us(2);
data >>= 1;
}
}
/**
* @brief 从单总线上读取一个bit.
* @details 从单总线上读取一个bit.
* @param[in] ONE_WIRE_BUS 要读取bit的BUS
* @retval 0 读取到bit为0
* @retval 1 读取到bit为1
* @par 修改日志
* ydm于2021-12-14创建
*/
static uint8_t BSP_OneWire_Read_bit(PT_ONE_WIRE ONE_WIRE_BUS)
{
uint8_t data = 0;
ONE_WIRE_PinMode(ONE_WIRE_BUS,ONE_WIRE_PinMode_OUT);
ONE_WIRE_LOW(ONE_WIRE_BUS);
Delay_us(2);
ONE_WIRE_PinMode(ONE_WIRE_BUS,ONE_WIRE_PinMode_IN);
Delay_us(5);
if(BSP_Ds18B20_Pin_Read(ONE_WIRE_BUS))
{
data = 1;
}
else
{
data = 0;
}
Delay_us(50);
return data;
}
/**
* @brief 从单总线上读取一个字节.
* @details 从单总线上读取一个字节.
* @param[in] ONE_WIRE_BUS 要读取字节的BUS
* @retval data 读取到的data
* @par 修改日志
* ydm于2021-12-14创建
*/
uint8_t BSP_OneWire_Read_Byte(PT_ONE_WIRE ONE_WIRE_BUS)
{
uint8_t i,data;
data = 0;
for (i=0;i<8;i++)
{
data >>= 1;
ONE_WIRE_LOW(ONE_WIRE_BUS);
Delay_us(3);
ONE_WIRE_HIGH(ONE_WIRE_BUS);
Delay_us(3);
if(BSP_Ds18B20_Pin_Read(ONE_WIRE_BUS) == 0)
{
;
}
else
{
data |= 0x80;
}
Delay_us(60);
}
return data;
}
/**
* @file BSP_1_WIRE.h
* @author ydm
* @version V1.0
* @date 14-Dec-2021
* @brief 单总线协议驱动文件
* @attention
* 单总线协议的驱动文件,使用GPIO发出单总线的通讯时序,为单总线的设备提供基本驱动接口 \n
* @htmlonly
* <span style="font-weight: bold">History</span>
* @endhtmlonly
* Version|Auther|Date|Describe
* ------|----|------|--------
* V1.0|ydm|14-Dec-2021|Create File
* <h2><center>©COPYRIGHT 2017 WELLCASA All Rights Reserved.</center></h2>
*/
#ifndef __BSP_1_WIRE_H
#define __BSP_1_WIRE_H
#include "main.h"
/** 定义单总线引脚方向为输出方向 */
#define ONE_WIRE_PinMode_OUT 0x01
/** 定义单总线引脚方向为输入方向 */
#define ONE_WIRE_PinMode_IN 0x00
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief 单总线BUS结构体.
* @details 记录单总线的基础信息.
*/
typedef struct One_Wire_Opr
{
uint16_t ONE_WIRE_PIN; /*!< 使用到的GPIO的PIN */
GPIO_TypeDef* ONE_WIRE_PORT; /*!< 使用到的GPIO的PORT */
}ONE_WIRE , *PT_ONE_WIRE;
/**
* @brief 单总线BUS的初始化函数.
* @details 将对应的单总线BUS进行初始化.
* @param[in] ONE_WIRE_BUS 要将GPIO初始化的BUS
* @retval 1 初始化成功
* @retval 0 初始化失败
* @par 修改日志
* ydm于2021-12-14创建
*/
uint8_t BSP_1_WIRE_Init(PT_ONE_WIRE ONE_WIRE_BUS);
/**
* @brief 单总线BUS的读取GPIO电平函数.
* @details 读取GPIO的电平.
* @param[in] ONE_WIRE_BUS 要读取的BUS
* @retval 1 高电平
* @retval 0 低电平
* @par 修改日志
* ydm于2021-12-14创建
*/
uint8_t BSP_Ds18B20_Pin_Read(PT_ONE_WIRE ONE_WIRE_BUS)
/**
* @brief 单总线BUS的GPIO初始化函数.
* @details 将对应的单总线BUS使用的GPIO进行初始化.
* @param[in] ONE_WIRE_BUS 要将GPIO初始化的BUS
* @retval
* @par 修改日志
* ydm于2021-12-14创建
*/
static void BSP_1_WIRE_GPIO_Init(PT_ONE_WIRE ONE_WIRE_BUS);
/**
* @brief 设置GPIO方向.
* @details 设置GPIO是输出状态还是输入状态.
* @param[in] ONE_WIRE_BUS 要输出复位时序的BUS
* @param[in] mode 状态是输入还是输出
* @retval
* @par 修改日志
* ydm于2021-12-14创建
*/
static void ONE_WIRE_PinMode(PT_ONE_WIRE ONE_WIRE_BUS,int mode);
/**
* @brief 单总线复位时序输出.
* @details 将对应的单总线BUS输出复位时序.
* @param[in] ONE_WIRE_BUS 要输出复位时序的BUS
* @retval
* @par 修改日志
* ydm于2021-12-14创建
*/
void BSP_1_WIRE_RST(PT_ONE_WIRE ONE_WIRE_BUS);
/**
* @brief 检测单总线检测是否有从设备相应.
* @details 检测单总线上是否有从设备相应.
* @param[in] ONE_WIRE_BUS 要输出复位时序的BUS
* @retval 0 检测失败
* @retval 1 检测成功
* @par 修改日志
* ydm于2021-12-14创建
*/
uint8_t BSP_1_WIRE_Check(PT_ONE_WIRE ONE_WIRE_BUS);
/**
* @brief 向单总线上写一个字节.
* @details 向单总线上写一个字节.
* @param[in] ONE_WIRE_BUS 要进行写操作的BUS
* @param[in] data 要写入BUS的数据.
* @retval
* @par 修改日志
* ydm于2021-12-14创建
*/
void BSP_OneWire_Write_Byte(PT_ONE_WIRE ONE_WIRE_BUS,uint8_t data);
/**
* @brief 从单总线上读取一个bit.
* @details 从单总线上读取一个bit.
* @param[in] ONE_WIRE_BUS 要读取bit的BUS
* @retval 0 读取到bit为0
* @retval 1 读取到bit为1
* @par 修改日志
* ydm于2021-12-14创建
*/
static uint8_t BSP_OneWire_Read_bit(PT_ONE_WIRE ONE_WIRE_BUS);
/**
* @brief 从单总线上读取一个字节.
* @details 从单总线上读取一个字节.
* @param[in] ONE_WIRE_BUS 要读取字节的BUS
* @retval data 读取到的data
* @par 修改日志
* ydm于2021-12-14创建
*/
uint8_t BSP_OneWire_Read_Byte(PT_ONE_WIRE ONE_WIRE_BUS);
#ifdef __cplusplus
}
#endif
#endif // !__BSP_1_WIRE_H
/**
* @file BSP_DS18B20.h
* @author ydm
* @version V1.0
* @date 14-Dec-2021
* @brief DS18B20驱动文件
* @attention
* DS18B20驱动文件,提供DS18B20需要的操作接口 \n
* @htmlonly
* <span style="font-weight: bold">History</span>
* @endhtmlonly
* Version|Auther|Date|Describe
* ------|----|------|--------
* V1.0|ydm|14-Dec-2021|Create File
* <h2><center>©COPYRIGHT 2017 WELLCASA All Rights Reserved.</center></h2>
*/
#include "BSP_DS18B20.h"
#include "delay.h"
#include "string.h"
static PT_DS18B20 g_ptds18b20OprHead;
uint8_t Ds18b20Init(PT_DS18B20 pDs18b20)
{
int i = 0;
RegisterDs18b20Opr(pDs18b20);
while((!BSP_1_WIRE_Init(pDs18b20->pDS18B20_OneWire)) && i<50)
{
i++;
Delay_us(1);
}
if(i >= 50)
{
return 0;
}
else
{
return 1;
}
}
static void RegisterDs18b20Opr(PT_DS18B20 pDs18b20)
{
PT_DS18B20 ptTmp;
if (!g_ptds18b20OprHead)
{
g_ptds18b20OprHead = pDs18b20;
pDs18b20->ptNext = NULL;
}
else
{
ptTmp = g_ptds18b20OprHead;
while (ptTmp->ptNext)
{
ptTmp = ptTmp->ptNext;
}
ptTmp->ptNext = pDs18b20;
pDs18b20->ptNext = NULL;
}
}
PT_DS18B20 GetDs18b20Opr(const char *pcName)
{
PT_DS18B20 ptTmp = g_ptds18b20OprHead;
while (ptTmp)
{
if (strcmp(ptTmp->name, pcName) == 0)
{
return ptTmp;
}
ptTmp = ptTmp->ptNext;
}
return NULL;
}
static void BSP_DS18B20_Start(PT_DS18B20 pDs18b20)
{
BSP_1_WIRE_RST(pDs18b20->pDS18B20_OneWire);
BSP_1_WIRE_Check(pDs18b20->pDS18B20_OneWire);
Delay_us(1000);
BSP_OneWire_Write_Byte(pDs18b20->pDS18B20_OneWire,0xcc); //skip rom
BSP_OneWire_Write_Byte(pDs18b20->pDS18B20_OneWire,0x44); //convert
}
float BSP_DS18B20_GetTemp(const char *pcName)
{
uint8_t TL = 0,TH = 0;
int temp = 0;
uint8_t CRC_Temp = 0;
uint8_t buf[10] = {'\0'};
float tem = 0.0f;
PT_DS18B20 ptTmp = GetDs18b20Opr(pcName);
BSP_DS18B20_Start(ptTmp);
BSP_1_WIRE_RST(ptTmp->pDS18B20_OneWire);
BSP_1_WIRE_Check(ptTmp->pDS18B20_OneWire);
Delay_us(1000);
BSP_OneWire_Write_Byte(ptTmp->pDS18B20_OneWire,0xcc); //skip rom
BSP_OneWire_Write_Byte(ptTmp->pDS18B20_OneWire,0xbe); //read
// TL=BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // LSB
// TH=BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // MSB
buf[0] =BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // LSB
buf[1] =BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // MSB
buf[2] = BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // Byte2
buf[3] = BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // Byte3
buf[4] = BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // Byte4
buf[5] = BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // Byte5
buf[6] = BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // Byte6
buf[7] = BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // Byte7
buf[8] = BSP_OneWire_Read_Byte(ptTmp->pDS18B20_OneWire); // CRC
CRC_Temp = buf[8];
temp=buf[1];
temp <<= 8;
temp|=buf[0];//拼接为16位数据
if(BSP_DS18B20_CheckCRC(buf,8,CRC_Temp))
{
//校验成功
if(temp < 0)//DS18B20存储数据为补码形式,当temp<0时需要转为原码
{
temp = ~temp;
temp += 1;
}
tem = temp;
tem = tem * 0.0625f;
return tem;
}
else
{
return 0;
}
}
static uint8_t BSP_DS18B20_CheckCRC(uint8_t* temp,uint8_t size,uint8_t CRC_Temp)
{
uint8_t test = crcCalc(temp,size);
if(test == CRC_Temp)
{
//校验成功
return 1;
}
else
{
return 0;
}
}
static uint8_t crcCalc(void *src, uint8_t size)
{
uint8_t ret = 0;
uint8_t *p;
int i = 0;
uint8_t pBuf = 0;
p = (uint8_t*)src;
while(size--)
{
pBuf = *p ++;
for ( i = 0; i < 8; i ++ )
{
if ((ret ^ (pBuf)) & 0x01)
{
ret ^= 0x18;
ret >>= 1;
ret |= 0x80;
}
else
{
ret >>= 1;
}
pBuf >>= 1;
}
}
return ret;
}
/**
* @file BSP_DS18B20.h
* @author ydm
* @version V1.0
* @date 14-Dec-2021
* @brief DS18B20驱动文件
* @attention
* DS18B20驱动文件,提供DS18B20需要的操作接口 \n
* @htmlonly
* <span style="font-weight: bold">History</span>
* @endhtmlonly
* Version|Auther|Date|Describe
* ------|----|------|--------
* V1.0|ydm|14-Dec-2021|Create File
* <h2><center>©COPYRIGHT 2017 WELLCASA All Rights Reserved.</center></h2>
*/
#ifndef __BSP_DS18B20_H
#define __BSP_DS18B20_H
#include "main.h"
#include "BSP_1_Wire.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief DS18B20结构体.
* @details 记录DS18B20的基础信息.
*/
typedef struct Ds18B20Opr
{
char *name; /*!< DS18B20名称 */
float temperature;
struct One_Wire_Opr *pDS18B20_OneWire;
struct Ds18B20Opr *ptNext; /*!< 链表指针 */
}DS18B20 , *PT_DS18B20;
uint8_t Ds18b20Init(PT_DS18B20 pDs18b20);
static void RegisterDs18b20Opr(PT_DS18B20 ptds18b20);
PT_DS18B20 GetDs18b20Opr(const char *pcName);
static void BSP_DS18B20_Start(PT_DS18B20 ptds18b20);
float BSP_DS18B20_GetTemp(const char *pcName);
static uint8_t BSP_DS18B20_CheckCRC(uint8_t* temp,uint8_t size,uint8_t CRC_Temp);
static uint8_t crcCalc(void *src, uint8_t size);
#ifdef __cplusplus
}
#endif
#endif // !__BSP_DS18B20_H
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律