0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32基于onewire单总线的数据抽象实例简析

STM32嵌入式开发 来源:STM32嵌入式开发 2023-10-27 15:44 次阅读

1.前言

onewire(单总线) 是DALLAS公司推出的外围串行扩展总线技术总线,顾名思义,它是采用一根信号线进行通信,既传输时钟信号又传输数据,而且能够进行双向通信,具有节省I/O口线、资源结构简单、成本低廉、便于总线扩展和维护等诸多优点。

常用到单总线的器件,一般是温度传感器、EEPROM、唯一序列号芯片等,如DS18B20、DS2431。

在使用单总线时,往往很少CPU会提供硬件单总线,几乎都是根据单总线标准的时序图,通过普通IO翻转模拟实现单总线。而在模式实现时序图的过程中,需要根据CPU时钟频率等条件进行时序时间计算,如果更换CPU后,需要重新计算时序时间,如果时序代码和器件外设控制代码集成在一起,则代码改动比较大。

或者同一CPU需要模拟多根单总线时,传统的“复制”方式使得程序显得累赘,还增加ROM占用空间。因此,可以利用“函数指针”的方式,将时序部分抽象出来,达到“复用”代码的效果,减少重复代码编写。

2.onewire 抽象

2.1 onewire 结构体

onewire结构体主要是对与CPU底层相关的操作抽象分离,调用时只需将该结构体地址(指针)作为函数入口参数,通过该指针实现对底层函数的回调。该结构体我们命名为“struct ops_onewire_dev”,其原型如下:


struct ops_onewire_dev
{
    void (*set_sdo)(int8_t state);
    uint8_t (*get_sdo)(void);
    void (*delayus)(uint32_t us);
};
其中: 1)set_sdo:IO输出1bit,包括时钟和数据。 2)get_sdo:IO输入1bit,包括时钟和数据。 3)delayus:时序延时函数,根据CPU频率进行计算。 回调函数相关文章:C语言技巧之回调函数

2.2 onewire 对外接口



extern uint8_t ops_onewire_reset(struct ops_onewire_dev *onewire);
extern int ops_onewire_read(struct ops_onewire_dev *onewire,void *buff,int size);
externintops_onewire_write(structops_onewire_dev*onewire,void*buff,intsize);
1)分别为复位函数、读函数、写函数。

2)入口首参数为“struct ops_onewire_dev”结构体指针,此部分就是硬件层相关,需要后期初始化的.

3)其余入口参数易于理解,读/写缓存及数据大小。

2.3 onewire 抽象接口实现

分别实现上述三者函数接口。

2.3.1 复位函数

复位函数,在单总线初始化外设器件时需要用到,用于判断总线与器件是否通信上,类似“握手”的动作。如图,为DS18B20的复位时序图,以下与单总线相关的时序图,都是以DS18B20为例,因为此芯片为单总线应用的经典。 1643d926-749c-11ee-939d-92fbcf53809c.png 根据时序图,实现复位函数。


/**
  * @brief  单总线复位时序
  * @param  onewire 总线结构体指针
  * @retval 成功返回0
*/
uint8_t ops_onewire_reset(struct ops_onewire_dev *onewire)
{
 uint8_t ret = 0;
 
 onewire->set_sdo(1);
 onewire->delayus(50);
 onewire->set_sdo(0);
 onewire->delayus(500);
 onewire->set_sdo(1);
 onewire->delayus(40);
 ret = onewire->get_sdo();
 onewire->delayus(500);
 onewire->set_sdo(1);
 return ret;
}

2.3.2 读函数

读函数即以该函数,通过单总线从外设上读取数据,至于代码的实现,完全是时序图的实现,无特殊难点。先实现单字节读函数,再通过调用单字节读函数实现多字节读函数。

pYYBAGGSOe-AeFXUAACD9VFIX00147.png


/**
  * @brief  单总线读取一字节数据
  * @param  onewire 总线结构体指针
  * @retval 返回读取的数据
*/
static char ops_onewire_read_byte(struct ops_onewire_dev *onewire)
{
 char data = 0;
 uint8_t i;
 
 for(i=8;i>0;i--)
 {
  data >>= 1;
  onewire->set_sdo(0);
  onewire->delayus(5);
  onewire->set_sdo(1);
  onewire->delayus(5);
  if(onewire->get_sdo())
   data |= 0x80;
  else
   data &= 0x7f;
  onewire->delayus(65);
  onewire->set_sdo(1);
 }
 return data;
}


/**
  * @brief  读取多字节
  * @param  onewire 总线结构体指针
  * @param  buff 存放数据缓存
  * @param  size 数据大小
  * @retval 返回读取到的数据大小
*/
int ops_onewire_read(struct ops_onewire_dev *onewire,void *buff,int size)
{
 int i;
 char *p = (char*)buff; 
 for(i=0;i

2.3.3 写函数

写函数与读函数同理,即以该函数,通过单总线往外设写入数据,至于代码的实现,完全是时序图的实现,无特殊难点。先实现单字节写函数,再通过调用单字节写函数实现多字节写函数。

poYBAGGSOfGAUeEhAADKD-j20k4098.png


/**
  * @brief  单总线写一字节
  * @param  onewire 总线结构体指针
  * @param  data 待写数据
  * @retval 返回读取的数据
*/
static int ops_onewire_write_byte(struct ops_onewire_dev *onewire,char data)
{
 uint8_t i;
 
 for(i=8;i>0;i--)
 {
  onewire->set_sdo(0);
  onewire->delayus(5);
  if(data&0x01)
   onewire->set_sdo(1);
  else
   onewire->set_sdo(0);
  onewire->delayus(65);
  onewire->set_sdo(1);
  onewire->delayus(2);
  data >>= 1;
 }
 return 0;
}


/**
  * @brief  写多字节
  * @param  onewire 总线结构体指针
  * @param  buff 代写数据地址
  * @param  size 数据大小
  * @retval 写入数据大小
*/
int ops_onewire_write(struct ops_onewire_dev *onewire,void *buff,int size)
{
 int i;
 char *p = (char*)buff;
 for(i=0;i
 至此,onewire(单总线)抽象化完成,此部分代码与硬件层分离,亦可单独作为一个模块,移植到不同平台CPU时,也几乎无需改动。剩下部分工作则是实现“struct ops_onewire_dev”中的函数指针原型,即可使用一根单总线。

3.onewire 抽象应用

STM32F1为例,实现上述抽象接口。

3.1 “struct ops_onewire_dev” 实现

此部分即是与硬件相关部分,不同CPU平台改动该部分即可,如从51单片机移植到STM32上。下面涉及到的IO宏,是对应IO的宏定义,如“ONEWIRE1_PORT”、“ONEWIRE1_PIN”,实际使用的是PC13 IO口。

3.1.1 IO输出


static void gpio_set_sdo(int8_t state)
{
    if (state)
  GPIO_SetBits(ONEWIRE1_PORT,ONEWIRE1_PIN); 
    else
  GPIO_ResetBits(ONEWIRE1_PORT,ONEWIRE1_PIN); 
}

3.1.2 IO输入


static uint8_t gpio_get_sdo(void)
{
    return (GPIO_ReadInputDataBit(ONEWIRE1_PORT,ONEWIRE1_PIN));
}

3.1.3 延时函数


static void gpio_delayus(uint32_t us)
{
#if 1  /* 不用系统延时时,开启 */
    volatile int32_t i;
 
    for (; us > 0; us--)
    {
     i = 30;  //mini 17
        while(i--);
    }
#else
  delayus(us);
#endif
}

3.2onewire 总线初始化

3.2.1 onewire 抽象相关

第一步:定义一个“struct ops_onewire_dev”结构体类型变量(全局)——onewire1_dev。


struct ops_onewire_dev onewire1_dev;
第二步:实例化“onewire1_dev”中的函数指针。

onewire1_dev.get_sdo=gpio_get_sdo; onewire1_dev.set_sdo=gpio_set_sdo; onewire1_dev.delayus=gpio_delayus; 第三步:使用时,通过传入“onewire1_dev”地址(指针)即可。

3.2.2 onewire 基础相关

初始基础部分,与使用的CPU硬件相关,如时钟、IO方向等。


/**
  * @brief  初始化单总线
  * @param  none
  * @retval none
*/
void stm32f1xx_onewire1_init(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;          
 RCC_APB2PeriphClockCmd(ONEWIRE1_RCC,ENABLE);  


 GPIO_InitStructure.GPIO_Pin = ONEWIRE1_PIN;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      
   GPIO_Init(ONEWIRE1_PORT, &GPIO_InitStructure);             
 ONEWIRE1_PORT->BSRR = ONEWIRE1_PIN;      
 
 /* device init */
 onewire1_dev.get_sdo = gpio_get_sdo;
 onewire1_dev.set_sdo = gpio_set_sdo;
 onewire1_dev.delayus = gpio_delayus;
}

4.onewire 使用

经过前面的步骤后,我们已经通过IO口翻转,模拟实现了一根单总线——“onewire1_dev”,以DS18B20为例,调用第一部分中三者接口,实现对DS18B20的操作。

4.1 DS18B20操作

对于DS18B20,不陌生,即是温度传感器,不多赘述,使用的功能主要是作为温度检测,另外还有其内部的唯一序列号会作为同一总线上挂多个DS18B20时的“地址”识别。 亦可把DS18B20的唯一序列号作为模块、产品、通信总线等的唯一标识使用。因此,代码也是主要实现这两个功能。


#include "onewire_hw.h"
#include "ds18b20.h"


static uint8_t ds18b20_start(void)
{    
 char reg;
    ops_onewire_reset(&onewire1_dev);     
      
 reg = 0xcc; /* 跳过ROM */
 ops_onewire_write(&onewire1_dev,®,1);
 reg = 0x44; /* 温度转换指令 */
 ops_onewire_write(&onewire1_dev,®,1);        
 return 0;
}


/**
  * @brief  读取温度
  * @param  none
  * @retval 温度值,浮点型
*/
float ds18b20_readtemp(void)
{
    uint8_t  tl,th,sign;
 uint16_t reg_temp; 
 char reg;
 float temp;
 
 ds18b20_start();
 ops_onewire_reset(&onewire1_dev); 
 reg = 0xcc;
 ops_onewire_write(&onewire1_dev,®,1); /* 跳过ROM */
 reg = 0xbe;
 ops_onewire_write(&onewire1_dev,®,1); /* 读取RAM */
 ops_onewire_read(&onewire1_dev,&tl,1);  /* 低8位数据 */
 ops_onewire_read(&onewire1_dev,&th,1);   /* 高8位数据 */
 if(th > 7)
 {/* - */
  th = ~th;
  tl = ~tl + 1; 
  sign = 0;             
 }
 else 
 {/* + */
  sign = 1;   
 }  
 reg_temp = (th<<8) | tl;
 temp = reg_temp * 0.0625f; 
 if(sign)
 {
  return temp;       
 }
 else 
 {
  return -temp;   
 }
}
 
/**
  * @brief  读唯一序列号
  * @param  rom 返回序列号缓存
  * @retval none
*/
void ds18b20_readrom(char *rom)
{
 uint8_t i;
 char reg;
 
 ops_onewire_reset(&onewire1_dev);
 reg = 0x33;
 ops_onewire_write(&onewire1_dev,®,1);
 for (i = 0;i < 8;i++)
 {
  ops_onewire_read(&onewire1_dev,&rom[i],1);  
 } 
}
至此,完成单总线的抽象分层使用。








审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 温度传感器
    +关注

    关注

    48

    文章

    2650

    浏览量

    154302
  • STM32
    +关注

    关注

    2240

    文章

    10674

    浏览量

    348809
  • EEPROM
    +关注

    关注

    9

    文章

    928

    浏览量

    80329
  • DS2431
    +关注

    关注

    0

    文章

    3

    浏览量

    8359
  • OneWire
    +关注

    关注

    0

    文章

    2

    浏览量

    798

原文标题:STM32基于onewire单总线的数据抽象实例

文章出处:【微信号:c-stm32,微信公众号:STM32嵌入式开发】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    单总线技术的原理是什么?

    顾名思义,单总线只有一根数据线系统中的数据交换、控制都在这根线上完成。设备(主机或从机)通过一个漏极开路或三态端口连至该数据线,这样允许设备不发送
    发表于 09-17 09:11

    单总线协议的定义及特点分别是什么呢

    总线上可挂接的从器件数量几乎不受限制。2.特点:这是由达拉斯半导体公司推出的一项通信技术。它采用单根信号线,既可传输时钟,又能传输数据,而且数据传输是双向的。3.优点:单总线技术具有线
    发表于 01-05 06:45

    单总线协议时序对应代码

    一.单总线协议时序对应代码1.延时函数//单总线延时函数,约1~2usvoid Delay_OneWire(unsigned int t){static unsigned char i;while(t--){ for(i=0;i
    发表于 01-17 08:05

    DS18B20芯片用法及代码解析

    :主机和从机通过1根线进行通信,在一条总线上可挂接的从器件数量几乎不受限制。2.特点:这是由达拉斯半导体公司推出的一项通信技术。它采用单根信号线,既可传输时钟,又能传输数据,而且数据传输是双向的。3.优点:
    发表于 01-17 07:37

    总线的基本概念及其分类

    文章目录1.总线的基本概念2.总线的分类2.1 片内总线2.2 系统总线2.2.1 数据总线2.
    发表于 02-16 06:54

    单总线测温系统

    单总线测温系统 1 -Wire Sy tem for Temperature Mea urement 摘要介绍了单总线系统的结构、原理和技术特点,阐述了单总线协议、操作流程以及DS18B20 数字式温度传感器的功能结构,
    发表于 01-12 16:58 9次下载

    二叉树算法在单总线技术中的应用

    介绍了单总线技术和二叉树算法。单总线技术可以将地址线、数据线和控制线合成一根线,并允许在这根线上挂接多个单总线器件。提出了用二叉树算法搜索单总线
    发表于 03-16 09:38 20次下载

    DS2438及其在单总线微网中的应用

    介绍内部集成多种功能部件的单总线器件DS2438, 利用该器件内部丰富的硬件资源, 可构成具有环境温度及单总线供电电压补偿功能的单总线数据采集系统;介绍器件性能特点、内部
    发表于 04-15 11:26 98次下载

    利用单总线传输数据与电源

    利用单总线传输数据与电源
    发表于 05-04 13:33 28次下载

    《振南电子STM32视频教程》第十讲:单总线

    [第10讲] 单总线(33分钟),由何强主讲.本课主要讲解:(1).DS18B20讲解;(2).单总线讲解;(3).工程源程序讲解:使用GPIO来操作DS18B20的各种功能你函数详解.
    发表于 10-09 16:04 830次阅读

    单总线协议详解

    I/O口线、资源结构简单、成本低廉、便于总线扩展和维护等诸多优点。 单总线是DALLAS公司研制开发的种协议由一个总线主节点、或多个从节点组成系统,通过根信号线对从芯片进行数据的读取。
    发表于 10-24 17:50 3.5w次阅读
    <b class='flag-5'>单总线</b>协议详解

    单总线结构

    使用总线时,能迅速放弃总线控制权。 单总线结构 单总线主机或从机设备通过一个漏极开路或三态端口连接至该数据线,这样允许设备在不发送
    发表于 10-25 09:28 8962次阅读
    <b class='flag-5'>单总线</b>结构

    "蓝桥杯单片机设计与开发-底层驱动代码编写(iic,onewire,ds1302)"

    ;stc15f2k60s2.h>sbit DQ = P1^4; //单总线接口//单总线延时函数void Delay_OneWire(unsigned int t) //STC89C52RC{ while(t--);}//通
    发表于 11-21 13:21 0次下载
    "蓝桥杯单片机设计与开发-底层驱动代码编写(iic,<b class='flag-5'>onewire</b>,ds1302)"

    Onewire单总线驱动DS18B20读取温度

    :主机和从机通过1根线进行通信,在一条总线上可挂接的从器件数量几乎不受限制。2.特点:这是由达拉斯半导体公司推出的一项通信技术。它采用单根信号线,既可传输时钟,又能传输数据,而且数据传输是双向的。3.优点:
    发表于 01-18 10:09 4次下载
    <b class='flag-5'>Onewire</b><b class='flag-5'>单总线</b>驱动DS18B20读取温度

    LCS2110R-S的单总线协议分析

    LCS2110R-S的单总线为标准单总线协议,且支持单总线唤醒低功耗等功能。
    发表于 07-21 11:51 593次阅读