原文:洛洛晨风
用到的为GPG111即GPIO对应的EINT19,它好像连到的是摄像头管脚的,由于没有CMOS摄像头,故拿来用一下,其他的管脚也是可以的。驱动的加载同以前一样,在内核中添加对应动态模式M等,然后make SUBDIR=driver\char\ modules生成.ko文件,发送到开发板上,加载。说明以下,insmod没问题,就是rmmod执行不了。这个问题现在没有解决,但不影响使用。./测试文件名,就会显示温度。
------已验证,可正常执行及显示。开发板TQ2440
TQ2440内核为2.6.30.4下DS18B20的驱动程序:
###############DS18B20的驱动程序############
#include<linux/platform_device.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include<mach/regs-gpio.h>
#include <mach/io.h>
#include <mach/map.h>
#include<mach/regs-clock.h>
#define DQ S3C2410_GPG11
#define CPG_IN S3C2410_GPG11_INP
#define CPG_OUT S3C2410_GPG11_OUTP
#define DEVICE_NAME "tq18b20" //自定义驱动称为“tq18b20”。
#define DS18B20_MAJOR 210
static int opencount = 0;
static char data[2];
//ds18b20复位,返回0成功,返回1失败
static unsigned char init_ds18b20(void)
{
unsigned char ret =0;
s3c2410_gpio_cfgpin(DQ,CPG_OUT); // 配置GPG11输出模式
//s3c2410_gpio_pullup(DQ,0);
s3c2410_gpio_setpin(DQ,1); // 向18B20发送一个上升沿,并保持高电平状态约100微秒
udelay(100);
s3c2410_gpio_setpin(DQ,0); // 向18B20发送一个下降沿,并保持低电平状态约500微秒
udelay(500);
s3c2410_gpio_setpin(DQ,1); //将18b20总线拉高,以便在15~60us后接收18b20发出的存在脉冲
udelay(50);
s3c2410_gpio_cfgpin(DQ,CPG_IN); //通过再次配置GPG11引脚成输入状态,可以检测到DS18B20是否复位成功
//若存在脉冲是一个60~240us的低电平信号,则通信双方已达成基本的协议
ret =s3c2410_gpio_getpin(DQ); //接下来是控制器与18b20的数字通信
udelay(200);
return ret;
}
//向18b20写一个字节
static void write_onechar(char data)
{
unsigned char i = 0;
s3c2410_gpio_cfgpin(DQ, CPG_OUT); //配置GPG11输出模式
s3c2410_gpio_pullup(DQ, 1);
for(i=0; i<8; i++)
{
s3c2410_gpio_setpin(DQ, 0); //每一位的发送前至少15us低电平起始位
udelay(15);
s3c2410_gpio_setpin(DQ,data&0x01); //在采样时间内,如果控制器将总线拉高,表示写1,拉低表示写0
udelay(60);
s3c2410_gpio_setpin(DQ, 1);
udelay(2);
data >>=1;
}
}
//从18b20读一个字节
static unsigned char read_onechar(void)
{
unsigned char i;
unsigned chardata=0;
for(i=0;i<8; i++)
{
s3c2410_gpio_cfgpin(DQ,CPG_OUT); // 配置GPG11输出模式
s3c2410_gpio_setpin(DQ, 0); //读时间间隙时也是必须先有主机产生至少1us的低电平,表示读时间的起始
udelay(1);
data >>= 1;
s3c2410_gpio_setpin(DQ, 1);
s3c2410_gpio_cfgpin(DQ, CPG_IN);
if(s3c2410_gpio_getpin(DQ)) // 若总线在我们设它为低电平之后若1微秒之内变为高
// 则认为从DS18B20处收到一个“1”信号
data |= 0x80;
udelay(50);
}
return data;
}
//18b20的读函数,读出温度
static ssize_t read_ds18b20(struct file *filp, char*buffer,
size_t count, loff_t *ppos)
{
if(init_ds18b20())//初始化成功,init_ds18b20()返回值为0,否则为1
return-1;
write_onechar(0x0cc);//跳过读序列号的操作
write_onechar(0x44);//启动温度转换
udelay(5);
while(init_ds18b20());
udelay(200);
write_onechar(0x0cc);//跳过读序列号的操作
write_onechar(0x0be);//读取温度寄存器
data[0] = read_onechar();//读低8位
data[1] = read_onechar();//读高8位
// copy_to_user(buffer,&data, 2);
buffer[0]=data[0];
buffer[1]=data[1];
return 1;
}
//对应应用程序的open函数
static int open_ds18b20(struct inode *node, struct file*file)
{
unsigned char flag;
if(opencount == 1)
return-EBUSY;
flag =init_ds18b20();
if(flag&0x01)
{
printk("uable to open device!\n");
return -1;
}
else
{
opencount++;
printk("device opened!\n");
return 0;
}
}
static int release_ds18b20(struct inode *node, struct file*file)
{
opencount--;
printk("devicereleased!\n");
return 0;
}
static struct file_operations ds18b20_fops = {
.owner = THIS_MODULE,
.read =read_ds18b20,
.release =release_ds18b20,
.open =open_ds18b20,
};
static char __initdata banner[] = "TQ2440/SKY2440ds18b20\n";//打印信息
static struct class *ds18b20_class;
static int __init ds18b20_init(void)
{
int ret;
printk(banner);
ret = register_chrdev(DS18B20_MAJOR,DEVICE_NAME, &ds18b20_fops);
if (ret < 0)
{
printk(DEVICE_NAME " can'tregister major number\n");
return ret;
}//错误处理
ds18b20_class = class_create(THIS_MODULE,DEVICE_NAME);
if(IS_ERR(ds18b20_class))
{
printk("Err: failed intope-leds class. \n");
return -1;
}
device_create(ds18b20_class, NULL,MKDEV(DS18B20_MAJOR, 0), NULL,DEVICE_NAME);//创建一个设备节点,节点名为DEVICE_NAME
printk(DEVICE_NAME "initialized\n");//打印信息,内核中的打印用printk函数
return 0;
}
static void __exit ds18b20_exit(void)
{
printk(DEVICE_NAME "exit\n");//打印信息,内核中的打印用printk函数
unregister_chrdev(DS18B20_MAJOR,DEVICE_NAME);//取消注册设备
device_destroy(ds18b20_class,MKDEV(DS18B20_MAJOR, 0)); //删掉设备节点
class_destroy(ds18b20_class); //注销类
}
module_init(ds18b20_init);
module_exit(ds18b20_exit);
MODULE_LICENSE("GPL");//遵循的协议
############以上DS18B20的驱动程序#######################
###############以下为TQ2440下DS18B20的测试程序###########################
#include "stdio.h"
#include "sys/types.h"
#include "sys/ioctl.h"
#include "stdlib.h"
#include "termios.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "sys/time.h"
main()
{
intfd;
unsigned char buf[2];
floatresult;
if((fd=open("/dev/tq18b20",O_RDWR | O_NDELAY | O_NOCTTY))< 0)
{
printf("Open Device DS18B20failed.\r\n");
exit(1);
}
else
{
printf("Open Device DS18B20successed.\r\n");
while(1)
{
read(fd, buf, 1);
result = (float)buf[0];
result /= 16;
result += ((float)buf[1] * 16);
if(result<100)
{
printf("%f .C\r\n", result);
sleep(1);
}
}
close(fd);
}
}
###########################################################################
http://blog.sina.com.cn/s/blog_67d069a90100p7q6.html