kaiyun官方注册
您所在的位置: 首页> 嵌入式技术> 其他> Linux驱动开发-编写DS18B20驱动

Linux驱动开发-编写DS18B20驱动

2022-09-29
来源:电子发烧友网

  【摘要】 当前文章介绍如何在Linux系统下编写一个DS18B20温度传感器驱动,测量环境温度,并将DS18B20注册成字符设备,通过文件接口将温度数据传递给应用层。

  1. 前言

  当前文章介绍如何在Linux系统下编写一个DS18B20温度传感器驱动,测量环境温度,并将DS18B20注册成字符设备,通过文件接口将温度数据传递给应用层。

  当前使用的开发板是友善之臂的Tiny4412开发板,CPU是三星的Exynos-4412,主频是4核1.5GHZ,当前运行的Linux内核版本是3.5。使用的温度传感器是DS18B20,是一个数字温度传感器,非常经典的一款温度传感器,常年应用在各大高校毕设、实验室、毕设、课设场景。DS1820接线比较简单,只需要一根线就行,加上两根电源线,一共3根线,并且DS18B20支持硬件序列号寻址,支持一个IO口上挂载多个DS18B20。

  2. DS18B20介绍

  DS18B20特性:

  (1)全数字温度转换及输出。

  (2)先进的单总线数据通信。

  (3)最高 12 位分辨率,精度可达土 0.5 摄氏度。

  (4)12 位分辨率时的最大工作周期为 750 毫秒。

  (5)可选择寄生工作方式。

  (6)检测温度范围为-55° C ~+125° C (-67° F ~+257° F)

  (7)内置 EEPROM,限温报警功能。

  (8)64 位光刻 ROM,内置产品序列号,方便多机挂接。

  (9)多样封装形式,适应不同硬件系统。

13.JPG

  DS18B20引脚功能

  GND 电压地

  DQ 单数据总线

  VDD 电源电压

  NC 空引脚

  DS18B20读取温度的步骤:

  发送复位信号-->

  检测回应信号--->

  发送0xCC-->发送0x44->

  发送复位信号->

  检测回应信号->

  写0xcc--->

  写0xbe--->

  循环8次读取温度低字节--->

  循环8次读取温度高字节---->

  打印温度信息

  DS18B20温度转换示例:

  u16 temp;

  u8 TL,TH;

  u16 intT,decT; //温度值的整数和小数部分

  TL=DS18B20_Read_Byte(); //读取温度低8位LSB

  TH=DS18B20_Read_Byte(); //读取温度高8位MSB

  temp=((u16)TH《8)|TL; //将读出的温度高低位组合成16位的值

  intT = temp 》 4; //分离出温度值整数部分

  decT = temp & 0xF; //分离出温度值小数部分

  printf(“A: %d.%d\r\n”,(int)intT,(int)decT); //打印实际温度值

  3. 硬件接线图

  Tiny4412开发板扩展GPIO口:

14.JPG

捕获.JPG

  4. 示例代码

  复制

  #include

  #include

  #include /*杂项字符设备头文件*/

  #include /*文件操作集合*/

  #include /*延时函数*/

  #include

  #include

  /*DS18B20 GPIO接口: GPB_4*/

  /*定义指针,用于接收虚拟地址*/

  volatile unsigned int *DS18B20_GPBCON;

  volatile unsigned int *DS18B20_GPBDAT;

  #define DS18B20_INPUT() {*DS18B20_GPBCON &= ~(0xf 《 4 * 4);}

  #define DS18B20_OUTPUT() {*DS18B20_GPBCON &= ~(0xf 《 4 * 4);*DS18B20_GPBCON |= (0x1 《 4 * 4);}

  /*

  函数功能:等待DS18B20的回应

  返回1:未检测到DS18B20的存在

  返回0:存在

  */

  unsigned char DS18B20_Check(void)

  {

  unsigned char retry=0;

  DS18B20_INPUT() ///SET PG11 INPUT

  while((*DS18B20_GPBDAT & (1 《 4))&&retry<200)

  {

  retry++;

  udelay(1);

  };

  if(retry>=200)return 1;

  else retry=0;

  while(!(*DS18B20_GPBDAT & (1 《 4))&&retry<240)

  {

  retry++;

  udelay(1);

  };

  if(retry>=240)return 1;

  return 0;

  }

  /*

  从DS18B20读取一个位

  返回值:1/0

  */

  unsigned char DS18B20_Read_Bit(void) // read one bit

  {

  unsigned char data;

  DS18B20_OUTPUT();

  *DS18B20_GPBDAT &= ~(1 《 4);//输出0

  udelay(2);

  *DS18B20_GPBDAT |= (1 《 4);//输出1

  DS18B20_INPUT()

  udelay(12);

  if((*DS18B20_GPBDAT & (1 《 4)))data=1;

  else data=0;

  udelay(50);

  return data;

  }

  /*

  从DS18B20读取一个字节

  返回值:读到的数据

  */

  unsigned char DS18B20_Read_Byte(void) // read one byte

  {

  unsigned char i,j,dat;

  dat=0;

  for(i=1;i<=8;i++)

  {

  j=DS18B20_Read_Bit();

  dat=dat》1;

  if(j) //主机对总线采样的数 判断-------读数据-1就是1,否则就是0

  dat|=0x80; //先收低位数据--一步一步向低位移动》

  }

  return dat;

  }

  /*

  写一个字节到DS18B20

  dat:要写入的字节

  */

  void DS18B20_Write_Byte(unsigned char dat)

  {

  unsigned char j;

  unsigned char testb;

  DS18B20_OUTPUT();

  for(j=1;j<=8;j++)

  {

  testb=dat&0x01;

  dat=dat》1;

  if(testb)

  {

  *DS18B20_GPBDAT &= ~(1 《 4);//输出0// Write 1

  udelay(2);

  *DS18B20_GPBDAT |= (1 《 4);//输出1

  udelay(60);

  }

  else

  {

  *DS18B20_GPBDAT &= ~(1 《 4);//输出0// Write 0

  udelay(60);

  *DS18B20_GPBDAT |= (1 《 4);//输出1

  udelay(2);

  }

  }

  }

  /*

  从ds18b20得到温度值

  精度:0.1C

  返回值:温度值 (-550~1250)

  */

  short DS18B20_Get_Temp(void)

  {

  unsigned short aaa;

  unsigned char temp;

  unsigned char TL,TH;

  DS18B20_OUTPUT();

  *DS18B20_GPBDAT &= ~(1 《 4);//输出0 //拉低DQ

  udelay(750); //拉低750us

  *DS18B20_GPBDAT |= (1 《 4);//输出1 //DQ=1

  udelay(15); //15US

  DS18B20_Check();

  DS18B20_Write_Byte(0xcc);

  DS18B20_Write_Byte(0x44);

  DS18B20_OUTPUT();

  *DS18B20_GPBDAT &= ~(1 《 4);//输出0 //拉低DQ

  udelay(750); //拉低750us

  *DS18B20_GPBDAT |= (1 《 4);//输出1 //DQ=1

  udelay(15); //15US

  DS18B20_Check();

  DS18B20_Write_Byte(0xcc);// skip rom

  DS18B20_Write_Byte(0xbe);// convert

  TL=DS18B20_Read_Byte(); // LSB

  TH=DS18B20_Read_Byte(); // MSB

  aaa=((unsigned short)TH《8)|TL;

  return aaa;

  }

  /*

  杂项字符设备注册示例----->DS18B20

  */

  static int tiny4412_open(struct inode *my_inode, struct file *my_file)

  {

  /*映射物理地址*/

  DS18B20_GPBCON=ioremap(0x11400040,4);

  DS18B20_GPBDAT=ioremap(0x11400044,4);

  printk(“DS18B20初始化成功!\r\n”);

  /*设置ds18b20为输出模式*/

  *DS18B20_GPBCON &= ~(0xf 《 4 * 4);

  *DS18B20_GPBCON |= (0x1 《 4 * 4);

  return 0;

  }

  static int tiny4412_release(struct inode *my_inode, struct file *my_file)

  {

  /*释放虚拟地址*/

  iounmap(DS18B20_GPBCON);

  iounmap(DS18B20_GPBDAT);

  printk(“DS18B20释放成功\r\n”);

  return 0;

  }

  static ssize_t tiny4412_read(struct file *my_file, char __user *buf, size_t len, loff_t *loff)

  {

  /*读取温度信息*/

  short temp=DS18B20_Get_Temp();

  copy_to_user(buf,&temp,2); //拷贝温度至应用层

  return 0;

  }

  static ssize_t tiny4412_write(struct file *my_file, const char __user *buf, size_t len, loff_t *loff)

  {

  return 0;

  }

  /*文件操作集合*/

  static struct file_operations tiny4412_fops=

  {

  .open=tiny4412_open,

  .read=tiny4412_read,

  .write=tiny4412_write,

  .release=tiny4412_release

  };

  /*

  核心结构体

  */

  static struct miscdevice tiny4412_misc=

  {

  .minor=MISC_DYNAMIC_MINOR, /*自动分配次设备号*/

  .name=“DS18B20”, /*设备文件,指定/dev/生成的文件名称*/

  .fops=&tiny4412_fops

  };

  static int __init DS18B20_dev_init(void)

  {

  /*杂项设备注册*/

  misc_register(&tiny4412_misc);

  return 0;

  }

  static void __exit DS18B20_dev_exit(void)

  {

  /*杂项设备注销*/

  misc_deregister(&tiny4412_misc);

  }

  module_init(DS18B20_dev_init);

  module_exit(DS18B20_dev_exit);

  MODULE_LICENSE(“GPL”);




更多信息可以来这里获取==>>电子技术应用-AET<<

mmexport1621241704608.jpg

本站内容除特别声明的原创文章之外,转载内容只为传递更多信息,并不代表本网站赞同其观点。转载的所有的文章、图片、音/视频文件等资料的版权归版权所有权人所有。本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如涉及作品内容、版权和其它问题,请及时通过电子邮件或电话通知我们,以便迅速采取适当措施,避免给双方造成不必要的经济损失。联系电话:010-82306116;邮箱:aet@chinaaet.com。
Baidu
map