转载1 http://blog.chinaunix.net/uid-24515821-id-2129103.html
友善之臂Tiny6410 开发板下的DS18B20驱动程序,参考了http://hi.baidu.com/ppln/blog/item/7e3991f57c308067dcc47476.html的代码,在此表示感谢。
//驱动程序#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <mach/s3c6410.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <plat/cpu.h>
#include <plat/devs.h>
#include <mach/gpio-bank-n.h>
#include <mach/gpio-bank-l.h>
#define DEVICE_NAME "Digital Thermometer DS18B20"
static char data[2];
static int reset(void)
{
gpio_direction_output(S3C64XX_GPN(8), 0);
gpio_set_value(S3C64XX_GPN(8),1);
udelay(100);
gpio_set_value(S3C64XX_GPN(8),0);
udelay(600);
gpio_set_value(S3C64XX_GPN(8),1);
udelay(100);
gpio_direction_output(S3C64XX_GPN(8), 1);
if(gpio_get_value(S3C64XX_GPN(8)))
{
// printk("kernel: DS18B20 initilize failed!\n");
return 0;
}
return 1;
}
void write_byte(unsigned char byte)
{
unsigned char i;
gpio_direction_output(S3C64XX_GPN(8), 0);
for(i=0; i<8; i++)
{
gpio_set_value(S3C64XX_GPN(8),0);
udelay(1);
if(byte & 0x01)
{
gpio_set_value(S3C64XX_GPN(8),1);
}
udelay(60);
gpio_set_value(S3C64XX_GPN(8),1);
udelay(15);
byte >>= 1;
}
gpio_set_value(S3C64XX_GPN(8),1);
}
unsigned char read_byte(void)
{
unsigned char i=0;
unsigned char byte=0;
for(i=0; i<8; i++)
{
gpio_direction_output(S3C64XX_GPN(8), 0);
gpio_set_value(S3C64XX_GPN(8),0);
udelay(1);
byte >>=1;
gpio_set_value(S3C64XX_GPN(8),1);
gpio_direction_output(S3C64XX_GPN(8), 1);
if(gpio_get_value(S3C64XX_GPN(8)))
byte |= 0x80;
udelay(60);
}
return byte;
}
static void proc(void)
{
while(reset());
udelay(120);
write_byte(0xcc);
write_byte(0x44);
udelay(5);
while(reset());
udelay(200);
write_byte(0xcc);
write_byte(0xbe);
data[0] = read_byte();
data[1] = read_byte();
}
static int ds18b20_open(struct inode *inode, struct file *file)
{
printk("open DS18B20.\n");
if(gpio_request(S3C64XX_GPN(8), "GPN") < 0)
{
return -1;
}
return 0;
}
static int ds18b20_close(struct inode *inode, struct file *file)
{
printk("close DS18B20.\n");
return 0;
}
static ssize_t ds18b20_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
return 0;
}
static int ds18b20_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
proc();
buff[0] = data[0];
buff[1] = data[1];
return 1;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = ds18b20_open,
.release = ds18b20_close,
.read = ds18b20_read,
.write = ds18b20_write,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{
int ret;
ret = misc_register(&misc);
printk (DEVICE_NAME " initialized\n");
return ret;
}
static void __exit dev_exit(void)
{
printk("DS18B20 module exit.\n");
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("centaur");
//测试程序
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/mman.h>
int main()
{
int fd,t=0;
unsigned char buf[2]={0,0};
float result=0;
if ((fd=open("/dev/ds18b20",O_RDWR)) < 0)
{
printf("Open Device DS18B20 failed.\r\n");
exit(1);
}
while(1)
{
read(fd, buf, 1);
t=(int)buf[1];
t<<=8;
t=t|buf[0];
result=t*0.0625;
printf("%.1f \n", result);
sleep(1);
}
close(fd);
return 0;
}
注意事项:
操作GPIO前如果没有使用gpio_request(S3C64XX_GPN(8), "GPN")函数申请资源,系统会打印出如下信息。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
相信玩过51的童鞋应该都玩过DS18B20吧,虽然用在ARM11上面,但是操作还是一样,多了一点就是读写IO前需要切换IO方向,其实51在读取之前需要切换到高电平的,这个一般由编译器完成的,
- /*************************************************************************************************************
- * 文件名: ds18b20.c
- * 功能: S3C6410 DS18B20驱动
- * 作者: cp1300@139.com
- * 创建时间: 2012年9月17日22:45
- * 最后修改时间:2012年9月17日
- * 详细: 需要延时函数支持
- * 注意延时精度尽可能的高
- * 读取的时候不要长时间的被中断,因为1wire对时间要求很严格
- *************************************************************************************************************/
- #include "system.h"
- #include "timer.h"
- #include "delay.h"
- #include "ds18b20.h"
- //DS18B20使用的是GPIOE0
- #define Set18b20IOout() (rGPECON |= 1) //设置DS18B20 IO为输出,
- #define Set18b20IOin() (rGPECON &= (~0xf)) //设置DS18B20 IO为浮空输入,
- #define Read18b20IO() ((rGPEDAT & BIT0) ? 1 : 0) //读取DS18B20 IO
- #define Write18b20IO(x) (x ? (rGPEDAT |= BIT0) : (rGPEDAT &= ~BIT0)) //写DS18B20 IO
- /*************************************************************************************************************************
- *函数 : u8 DS18B20_Reset(void)
- *功能 : 复位DS18B20
- *参数 : 无
- *返回 : 0:成功;1:失败
- *依赖 : 底层宏定义
- *作者 : cp1300@139.com
- *时间 : 20120917
- *最后修改时间: 20120917
- *说明 :无
- *************************************************************************************************************************/
- u8 DS18B20_Reset(void)
- {
- u8 i = 0;
- Set18b20IOout(); //主机端口推挽输出模式
- Write18b20IO(1);
- Delay_US(1);
- Write18b20IO(0); //拉低总线480us~240us
- Delay_US(500); //>480US延时
- Write18b20IO(1);
- Delay_US(2); //复位完成
- Set18b20IOin(); //主机端口浮空输入模式
- while(Read18b20IO()) //等待低电平应答信号
- {
- i ++;
- Delay_US(1);
- if(i > 100)
- return 1; //等待超时,初始化失败,返回1;
- }
- Delay_US(250); //跳过回复信号
- return 0x00; //检测到DS18B20,并且初始化成功
- }
- /*************************************************************************************************************************
- *函数 : u8 DS18B20_ReadData(void)
- *功能 : 读取DS18B20数据
- *参数 : 无
- *返回 : 数据
- *依赖 : 底层宏定义
- *作者 : cp1300@139.com
- *时间 : 20120917
- *最后修改时间: 20120917
- *说明 :无
- *************************************************************************************************************************/
- u8 DS18B20_ReadData(void)
- {
- u8 i,data = 0;
- for(i = 0;i < 8;i ++)
- {
- Set18b20IOout(); //主机端口推挽输出模式
- Write18b20IO(0); //拉低总线10-15us
- data >>= 1;
- Delay_US(12);
- Write18b20IO(1); //释放总线
- Set18b20IOin(); //主机端口浮空输入模式
- Delay_US(1);
- if(Read18b20IO()) //读取数据,读取后大约延时40-45us
- data |= 0x80;
- Delay_US(42);
- }
- return data;
- }
- /*************************************************************************************************************************
- *函数 : void DS18B20_WriteData(u8 data)
- *功能 : 向DS18B20写数据
- *参数 : 数据
- *返回 : 无
- *依赖 : 底层宏定义
- *作者 : cp1300@139.com
- *时间 : 20120917
- *最后修改时间: 20120917
- *说明 :无
- *************************************************************************************************************************/
- void DS18B20_WriteData(u8 data)
- {
- u8 i;
- Set18b20IOout(); //主机端口推挽输出模式
- for(i = 0;i < 8;i ++)
- {
- Write18b20IO(0); //拉低总线10-15us
- Delay_US(12);
- Write18b20IO(data & 0x01); //写入数据位,保持20-45us
- Delay_US(30);
- Write18b20IO(1); //释放总线
- data >>= 1;
- Delay_US(2);
- }
- }
- /*************************************************************************************************************************
- *函数 : s16 DS18B20_ReadTemper(void)
- *功能 : 读取DS18B20温度
- *参数 : 无
- *返回 : 温度值
- *依赖 : 底层宏定义
- *作者 : cp1300@139.com
- *时间 : 20120917
- *最后修改时间: 20120917
- *说明 :温度值扩大了100倍,温度值是个有符号数.
- *************************************************************************************************************************/
- s16 DS18B20_ReadTemper(void)
- {
- u8 th, tl;
- s16 data;
- if(DS18B20_Reset())
- {
- return 0xffff; //返回错误
- }
- DS18B20_WriteData(0xcc); //跳过读序列号
- DS18B20_WriteData(0x44); //启动温度转换
- DS18B20_Reset();
- DS18B20_WriteData(0xcc); //跳过读序列号
- DS18B20_WriteData(0xbe); //读取温度
- tl = DS18B20_ReadData(); //读取低八位
- th = DS18B20_ReadData(); //读取高八位
- data = th;
- data <<= 8;
- data |= tl;
- data *= 6.25; //温度值扩大100倍,精确到2位小数
- return data;
- }
- DS18B20.H
- #ifndef DS18B20_H_
- #define DS18B20_H_
- s16 DS18B20_ReadTemper(void); //读取DS18B20温度
- #endif /*DS18B20_H_*/
DELAY.C
- /*************************************************************************************************************
- * 文件名: delay.c
- * 功能: 延时函数,调用定时器1进行延时的
- * 作者: cp1300@139.com
- * 创建时间: 2012年9月17日22:32
- * 最后修改时间:2012年9月17日
- * 详细: 延时误差1-2us,使用定时器1
- * 不能在中断服务程序中使用
- *************************************************************************************************************/
- #include "system.h"
- #include "timer.h"
- #include "delay.h"
- /*************************************************************************************************************************
- *函数 : void Delay_US(u32 Delay)
- *功能 : US延时
- *参数 : Delay:延时时间,单位US
- *返回 : 无
- *依赖 : 底层宏定义
- *作者 : cp1300@139.com
- *时间 : 20120917
- *最后修改时间: 20120917
- *说明 :调用定时器0进行延时的,那么定时器0就不能使用了,延时误差1US
- *************************************************************************************************************************/
- void Delay_US(u32 Delay)
- {
- rTCFG0 |= 65; //定时器0预分频65+1,由PCLK=66提供时钟,66分频产生1MHz的定时器时钟
- rTCON &= (~0xff); //清除设置
- rTCON |= BIT3; //定时器0自动更新使能
- rTCNTB0 = Delay; //重装值
- rTINT_CSTAT |= BIT5; //清除中断标志
- rTINT_CSTAT &= ~BIT0; //关闭定时器0中断
- //以下操作启动定时器0
- rTCON |= BIT1; //手动更新
- rTCON &= ~BIT1; //结束手动更新
- rTCON |= BIT0; //启动定时器0
- while(!(rTINT_CSTAT & BIT5)); //等待延时到达
- rTINT_CSTAT |= BIT5; //清除中断标志
- }
- /*************************************************************************************************************************
- *函数 : void Delay_MS(u32 Delay)
- *功能 : MS延时
- *参数 : Delay:延时时间,单位US
- *返回 : 无
- *依赖 : 底层宏定义
- *作者 : cp1300@139.com
- *时间 : 20120918
- *最后修改时间: 20120918
- *说明 :调用定时器0进行延时的,那么定时器0就不能使用了,延时误差<1ms
- *************************************************************************************************************************/
- void Delay_MS(u32 Delay)
- {
- while(Delay --)
- {
- Delay_US(1000);
- }
- }
后面将这个程序移植到LINUX上面当做DS18B20驱动