S5PV210之温度传感器DS18B20 linux3.0.8驱动
2024-12-31 来源:cnblogs
一 Ds18b20功能描述
FEATURES(特点)
1) Unique 1-WireTM interface requires only oneport pin for communication
独特的单总线接口,使用一个引脚实现双线通线
2) Multidrop capability simplifies distributed temperature sensing applications
多分功能简化分布式温度传感器的应用
3) Requires no external components
不需要外部器件
4) Can be powered from data line. Power supply range is 3.0V to 5.5V
可以从数据线获得电压。功作电源3-5.5V
5) Zero standby power required
不需要备用电源
6) Measures temperatures from -55°C to +125°C. Fahrenheit equivalent is -67°F to
+257°F
测温范围:-55~+125°C, 等效于华氏温度范围:-67~257°F
7) ±0.5°C accuracy from -10°C to +85°C
-10~85°C范围的分辨率为±0.5°C
8) Thermometer resolution is programmable from 9 to 12 bits
可编程温度计分辨率范围9~12位(测量结果以9~12位数字量存储);
9) Converts 12-bit temperature to digital word in 750 ms (max.)
10) User-definable, nonvolatile temperature alarm settings
11) Alarm search command identifies and addresses devices whose temperature is
outside of programmed limits (temperature alarm condition)
12) Applications include thermostatic controls, industrial systems, consumer products,
thermometers, or any thermally sensitive system
二. Ds18b20时序分析
ds18b20时序分为:复位时序,读时序,写时序。
最好按时序来编程,这样可以增强可移植性。
具体的时序分析,网上或苡片资料上有。
比如:ds18b20写时序
从上图可知,在前15us内首先把数据线拉低然后写0或1,然后ds18b20在15~60us间自动读取数据线的值。写该时序代码时,最好在15内向ds18b20数据线写值,并等待ds18b20反应30us以上。案例二上有说明。
三. 总结
案例一:总结:错在81行return((gpio_get_value(S5PV210_GPE0(3)) >> 3) & 0x01);
导致读的值为0;
原因:因为gpio_get_value(S5PV210_GPE0(3))函数返回的
值为指定引脚的高或低电平,即1或0。
案例二:错误总结:
错误部分:dat >>1;
temp = gpio_get_value(S5PV210_GPE0(3) & 0x01);
if ((ds18b20_back_value & 0x08) >> 3)
ds18b20读写函数中,没有按读写时序来写延时的时间。
正确写法:dat >>=1;
temp = gpio_get_value(S5PV210_GPE0(3)) & 0x01;
if ((init_DS18B20()) //因为gpio_get_value(S5PV210_GPE0(3))函数返回的
值为指定引脚的高或低电平,即1或0。
最后按ds18b20的时序来解决上面时序的延时时间。那么就能在开发板上有正确的结果。
时序是很重要的,如果想这时序代码能在多平台上运用,最好延时取中值以上。
案例一:
mini210_ds18b20.c文件中:
案例二: #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
spinlock_t lock; //加不加这都 可以
#define DEVICE_NAME 'DS18B20'
void set_conIN(void)
{
s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_INPUT);
//gpio_set_value(S5PV210_GPE0(3), 1);
}
void set_conOUT(void)
{
s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_OUTPUT);
}
void set_data(int i)
{
if (i == 0) {
gpio_set_value(S5PV210_GPE0(3), 0);
} else if(i == 1) {
gpio_set_value(S5PV210_GPE0(3), 1);
}
}
unsigned int reset_ds18b20(void)
{
unsigned int retValue;
set_conOUT();
set_data(1);
__udelay(1);
set_data(0);
__udelay(600);
set_data(1);
__udelay(20);
set_conIN();
__udelay(100);
/*稍做延时后 如果x=0则初始化成功
x=1则初始化失*/
//retValue = (gpio_get_value(S5PV210_GPE0(3)) >> 3) & 0x01;
retValue = gpio_get_value(S5PV210_GPE0(3));
printk('init is %dn',retValue);
return retValue;
}
unsigned int read_bit(void)
{
spin_lock(&lock);
set_conOUT();
set_data(0);
__udelay(2);
set_conIN();
__udelay(1);
spin_unlock(&lock);
return(gpio_get_value(S5PV210_GPE0(3)) & 0x01);
//return((gpio_get_value(S5PV210_GPE0(3)) >> 3) & 0x01);
}
/*写一位命令*/
void write_bit(char bitValue)
{
spin_lock(&lock);
set_conOUT();
set_data(0);
__udelay(15);
if( bitValue == 1 ){
set_data(1);
}else{
set_data(0);
}
spin_unlock(&lock);
__udelay(45);
set_conIN();
__udelay(2);
}
/*写命令*/
void write_cmd(char cmd)
{
unsigned char i;
unsigned char temp;
for(i=0; i<8;i++){
temp = cmd>>i;
temp &= 0x01;
write_bit(temp);
}
//__udelay(10);
}
static int ds18b20_open(struct inode *inode, struct file *filp)
{
printk (KERN_INFO 'Device openedn');
spin_lock_init(&lock);
return 0;
}
/*读取数据*/
static int ds18b20_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
{
char lowValue=0,highValue=0;
unsigned int i;
int wendu_value;
//float value;
if(reset_ds18b20()){
printk('init errorn');
}
__udelay(400);
set_conOUT();
set_data(1);
write_cmd(0xCC);
write_cmd(0x44);
__udelay(100000);
if(reset_ds18b20()){
printk('init errorn');
}
__udelay(400);
set_conOUT();
set_data(1);
write_cmd(0xcc);
write_cmd(0xBE);
/*读取温度转化数值*/
for(i=0; i<8; i++){
if( read_bit() ){
lowValue |= (0x01< }
__udelay(62);
}
printk('lowValue is %dn',lowValue);
for(i=0; i<8; i++){
if( read_bit() ){
highValue |= (0x01< }
__udelay(62);
}
printk('highValue is %dn',highValue);
if((highValue & 0xf8) != 0x00) {
lowValue = (~lowValue) + 1;
if (lowValue > 255)
highValue = (~highValue) + 1;
}
wendu_value = (highValue * 16 + lowValue/16) + ((lowValue%16)*10/16);
printk('read_wendu--dat_L: %d dat_H: %d wendu: %d.%dn', lowValue, highValue,
wendu_value - ((lowValue%16)*10/16), ((lowValue%16)*10/16));
#if 0
i = highValue;
i <<= 8;
i = i|lowValue;
value = i*0.0625;
printk('kernel is %dn',value);
#endif
highValue <<= 4;
highValue |= ((lowValue&0xf0)>>4) ;
copy_to_user(buffer, &highValue, sizeof(highValue));
/*拷贝内核数据到用户空间*/
//copy_to_user(buffer, &highValue, sizeof(highValue));
return 0;
}
/*写命令,在此置空*/
static int ds18b20_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
return 0;
}
static int ds18b20_release(struct inode *inode,struct file *filp)
{
printk (KERN_INFO 'device closedn');
return 0;
}
static long ds18b20_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
return 0;
}
static struct file_operations ds18b20_fops = {
.owner = THIS_MODULE,
.open = ds18b20_open,
.read = ds18b20_read,
.write = ds18b20_write,
.unlocked_ioctl = ds18b20_ioctl,
.release = ds18b20_release,
};
static struct miscdevice ds18b20_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &ds18b20_fops,
};
static int __init ds18b20_dev_init(void) {
int ret;
int i;
ret = gpio_request(S5PV210_GPE0(3), 'DS18b20');
if (ret) {
printk('%s: request GPIO %d for LED failed, ret = %dn', DEVICE_NAME,
S5PV210_GPE0(3), ret);
return ret;
s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_OUTPUT);
gpio_set_value(S5PV210_GPE0(3), 1);
}
ret = misc_register(&ds18b20_dev);
printk(DEVICE_NAME'tinitializedn');
return ret;
}
static void __exit ds18b20_dev_exit(void) {
int i;
for (i = 0; i < 1; i++) {
gpio_free(S5PV210_GPE0(3));
}
misc_deregister(&ds18b20_dev);
}
module_init(ds18b20_dev_init);
module_exit(ds18b20_dev_exit);
MODULE_LICENSE('GPL');
MODULE_AUTHOR('mingLi.');
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
spinlock_t lock; //不用也行
#define DEVICE_NAME 'DS18B20'
//********************************
//功能:设置引脚为输入功能
//********************************
void set_con_in(void)
{
s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_INPUT);
//gpio_set_value(S5PV210_GPE0(3), 1);
}
//********************************
//功能:设置引脚为输出功能
//********************************
void set_con_out(void)
{
s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_OUTPUT);
}
//********************************
//功能:引脚输出高或低电平功能,i=1(高)
//********************************
void set_output_data(int i)
{
if (i == 0) {
gpio_set_value(S5PV210_GPE0(3), 0);
} else if(i == 1) {
gpio_set_value(S5PV210_GPE0(3), 1);
}
}
//********************************
//功能:ds18b20复位
//********************************
int init_DS18B20(void)
{
int result = 10;
set_con_out();
__udelay(3); //短时间延迟
set_output_data(1);
__udelay(3); //短时间延迟
set_output_data(0);
__udelay(550); //480-960us
set_output_data(1);
__udelay(20); //15-60us,最好大于15us
set_con_in();
__udelay(100); //60-240us, ds18b20回应值保持时间
result = gpio_get_value(S5PV210_GPE0(3));
printk('init_DS18B20--result:%dn', result);
set_con_out();
__udelay(3);
set_output_data(1);
//__udelay(300);
return result;
}
//*************************************
//功能:从ds18b20读一个字节的数据
//*************************************
unsigned char read_one_char(void)
{
unsigned char i = 0;
unsigned char dat = 0;
unsigned char temp = 0;
spin_lock(&lock);
//苡片手册上说写周期不少于60us
//但时从时序图可知少于60us也行
//或者取中值左右,最好是大于60us
//for (i=8; i > 0; i--) {
for(i=0; i<8; i++) {
set_con_out();
__udelay(3);
set_output_data(1);
dat >>= 1;
/*set_output_data(0); //++
__udelay(3);
set_output_data(1); //将数据线'人为'拉高,为单片机检测DS18B20的输出电平作准备
__udelay(3);
*/
//
set_output_data(0); //该行与下行等效该行上面的4行
__udelay(18); //按时序来延时,不能太小或太大
set_con_in();
__udelay(1);
//temp = gpio_get_value(S5PV210_GPE0(3) & 0x01);
//错在S5PV210_GPE0(3)后面少加')'
temp = gpio_get_value(S5PV210_GPE0(3)) & 0x01;
if (temp)
dat |= 0x80;
else
dat |= 0x00;
printk('read_one_char--temp: %dn', temp);
__udelay(65);
}
spin_unlock(&lock);
printk('read_one_char--dat: %dn', dat);
return dat;
}
//*************************************
//功能:向ds18b20写一个字节的数据
//*************************************
void write_one_char(unsigned char dat)
{
//printk('write_one_char--dat: %dn', dat);
unsigned char i = 0;
spin_lock(&lock);
set_con_out();
for(i=0; i<8; i++) {
set_output_data(1);
__udelay(1);
set_output_data(0);
__udelay(5);
set_output_data(dat & 0x01);
__udelay(55);//延时约55us,DS18B20在拉低后的约
//15~60us期间从数据线上采样
//最好取中值以上,太小可得会出错
//芯片手册上说一个写周期不少于60us
//但我使用时,少于60us也可以,
//但不能太小,一般中值以上
//总结:为能可移值性,
//最好是一个写周期在于60us
set_output_data(1);
__udelay(2);
dat >>= 1;
}
spin_unlock(&lock);
__udelay(30);
}
//********************************
//功能:读取ds18b20的温度
//********************************
unsigned int read_wendu(void)
{
unsigned char dat_L = 0, dat_H = 0;
unsigned int wendu_value;
int ds18b20_back_value;
ds18b20_back_value = init_DS18B20();
//if ((ds18b20_back_value & 0x08) >> 3) //错,init_DS18B20()返回值为0或1
if (ds18b20_back_value)
printk('ds18b20 init error!!!n');
else
printk('ds18b20_back_value %dn', ds18b20_back_value);
write_one_char(0xCC);
write_one_char(0x44);
if (init_DS18B20())
printk('ds18b20 init error!!!n');
else
printk('ds18b20 init ok n');
write_one_char(0xcc);
write_one_char(0xBE);
dat_L = read_one_char();
dat_H = read_one_char();
if((dat_H & 0xf8) != 0x00) {
dat_L = (~dat_L) + 1;
if (dat_L > 255)
dat_H = (~dat_H) + 1;
}
wendu_value = (dat_H * 16 + dat_L/16) * 10 +((dat_L%16)*10/16);
printk('read_wendu--dat_L: %d dat_H: %d wendu: %d.%dn',dat_L, dat_H,
wendu_value/10, wendu_value%10);
return(wendu_value);
//return (dat_H*256 + dat_L);
}
static int ds18b20_open(struct inode *inode, struct file *filp)
{
printk (KERN_INFO 'Device openedn');
spin_lock_init(&lock);
return 0;
}
/*读取数据*/
static int ds18b20_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
{
unsigned int wendu_value = 0;
wendu_value = read_wendu();
printk('wendu_valu is %ldn', wendu_value);
copy_to_user(buffer, &wendu_value, sizeof(wendu_value));
return 0;
}
/*写命令,在此置空*/
static int ds18b20_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
return 0;
}
static int ds18b20_release(struct inode *inode,struct file *filp)
{
printk (KERN_INFO 'device closedn');
return 0;
}
static long ds18b20_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
return 0;
}
static struct file_operations ds18b20_fops = {
.owner = THIS_MODULE,
.open = ds18b20_open,
.read = ds18b20_read,
.write = ds18b20_write,
.unlocked_ioctl = ds18b20_ioctl,
.release = ds18b20_release,
};
static struct miscdevice ds18b20_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &ds18b20_fops,
};
static int __init ds18b20_dev_init(void) {
int ret;
int i;
ret = gpio_request(S5PV210_GPE0(3), 'DS18b20');
if (ret) {
printk('%s: request GPIO %d for GPE0 failed, ret = %dn', DEVICE_NAME,
S5PV210_GPE0(3), ret);
return ret;
s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_OUTPUT);
gpio_set_value(S5PV210_GPE0(3), 1);
}
ret = misc_register(&ds18b20_dev);
printk(DEVICE_NAME'tinitializedn');
return ret;
}
static void __exit ds18b20_dev_exit(void) {
int i;
for (i = 0; i < 1; i++) {
gpio_free(S5PV210_GPE0(3));
}
misc_deregister(&ds18b20_dev);
}
module_init(ds18b20_dev_init);
module_exit(ds18b20_dev_exit);
MODULE_LICENSE('GPL');
MODULE_AUTHOR('mingli.');
上一篇:S5PV210的开发与学习:2.2 UBOOT学习笔记(零距离初体验uboot)
下一篇:tiny210(s5pv210)移植u-boot(基于 2014.4 版本号)——移植u-boot.bin(打印串口控制台)
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 蓝牙信道探测技术原理与开发套件实践
- Microchip 推出生产就绪型全栈边缘 AI 解决方案,赋能MCU和MPU实现 智能实时决策
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析




