使用混杂设备驱动框架,时序要求比较严格
/*
* @Author: yyh
* @Date: 2023-04-11 00:29:09
* @Last Modified by: yyh
* @Last Modified time: 2023-04-26 16:40:24
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// DS18B20设备节点名称
#define DS18B20_DEV_NAME "ds18b20"
// DS18B20设备资源定义
#define DS18B20_GPIO_PIN (PAD_GPIO_C + 17)
#define GET_DS18B20_VAL_CMD _IOR('s', 1, int)
typedef unsigned char uint8_t;
static void ds18b20_delay_us(int us)
{
ktime_t kt;
u64 pre,last;
kt = ktime_get();
pre = ktime_to_ns(kt);
while(1)
{
kt = ktime_get();
last = ktime_to_ns(kt);
if(last-pre >= us*1000)
{
break;
}
}
}
static int ds18b20_pulse_init(void) {
/* 设置引脚为输出模式 */
gpio_direction_output(DS18B20_GPIO_PIN, 0);
ds18b20_delay_us(500); // 拉低至少480微秒
gpio_direction_input(DS18B20_GPIO_PIN);
ds18b20_delay_us(120); // 等待传感器拉低
if (gpio_get_value(DS18B20_GPIO_PIN) == 0) { // 如果传感器存在
ds18b20_delay_us(120); // 等待传感器完成初始化
return 1;
}
return 0;
}
static void ds18b20_write_bit(int bit) {
gpio_direction_output(DS18B20_GPIO_PIN, 0);
if (bit)
ds18b20_delay_us(10);
else
ds18b20_delay_us(60);
gpio_direction_input(DS18B20_GPIO_PIN);
ds18b20_delay_us(15);
}
static void ds18b20_write_byte(uint8_t data) {
int i;
for (i = 0; i < 8; i++) {
ds18b20_write_bit(data & 0x01);
data >>= 1;
}
}
static uint8_t ds18b20_read_bit(void) {
uint8_t bit;
gpio_direction_output(DS18B20_GPIO_PIN, 0);
ds18b20_delay_us(2);
gpio_direction_input(DS18B20_GPIO_PIN);
ds18b20_delay_us(10);
bit = gpio_get_value(DS18B20_GPIO_PIN);
ds18b20_delay_us(48);
return bit;
}
static uint8_t ds18b20_read_byte(void) {
int i;
uint8_t data = 0;
for (i = 0; i < 8; i++) {
data |= ds18b20_read_bit() << i;
}
return data;
}
/* 执行DS18B20转换命令 */
static void ds18b20_config_temperature(uint8_t data) {
ds18b20_pulse_init(); // 复位
ds18b20_write_byte(0xCC); // 跳过ROM匹配
ds18b20_write_byte(0x4E); // 写入配置寄存器
ds18b20_write_byte(0x00); // 写入配置字节0,保留位为0
ds18b20_write_byte(data);
ds18b20_write_byte(0x48); // 复制到EEPROM
mdelay(5);
}
static float ds18b20_read_temperature(int delay_ms) {
uint8_t temp_l, temp_h;
float temp;
if (!ds18b20_pulse_init()) {
printk(KERN_ERR "DS18B20 sensor not found\n");
return -1.0;
}
ds18b20_write_byte(0xCC); // 跳过ROM指令
ds18b20_write_byte(0x44); // 温度转换命令
mdelay(delay_ms); // 等待转换完成
if (!ds18b20_pulse_init()) {
printk(KERN_ERR "DS18B20 sensor not found\n");
return -1.0;
}
ds18b20_write_byte(0xCC); // 跳过ROM指令
ds18b20_write_byte(0xBE); // 读取scratchpad命令
temp_l = ds18b20_read_byte();
temp_h = ds18b20_read_byte();
temp = ((temp_h << 8) | temp_l) / 16.0;
return temp;
}
static int ds18b20_read_temperature_raw(int delay_ms) {
uint8_t temp_l, temp_h;
int temp;
if (!ds18b20_pulse_init()) {
printk(KERN_ERR "DS18B20 sensor not found\n");
return 1;
}
ds18b20_write_byte(0xCC); // 跳过ROM指令
ds18b20_write_byte(0x44); // 温度转换命令
mdelay(delay_ms); // 等待转换完成
if (!ds18b20_pulse_init()) {
printk(KERN_ERR "DS18B20 sensor not found\n");
return 1;
}
ds18b20_write_byte(0xCC); // 跳过ROM指令
ds18b20_write_byte(0xBE); // 读取scratchpad命令
temp_l = ds18b20_read_byte();
temp_h = ds18b20_read_byte();
temp = ((temp_h << 8) | temp_l);
return temp;
}
static ssize_t ds18b20_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
float temp = ds18b20_read_temperature(200); //开始转换,精度为10位需要延时200ms,获取温度数据
if (copy_to_user(buf, &temp, sizeof(temp)))
{
printk(KERN_ERR "ds18b20: failed to copy data to user\n");
return -EFAULT;
}
*f_pos += sizeof(temp);
return sizeof(temp);
}
static long ds18b20_adc_ioctl (struct file *filp, unsigned int cmd, unsigned long args)
{
int temp = 0;
switch(cmd) {
case GET_DS18B20_VAL_CMD:
temp = ds18b20_read_temperature_raw(200); //开始转换,精度为10位需要延时200ms,获取温度数据
// printk(KERN_ERR "tmp kernel = %d\n",temp);
if(copy_to_user((void *)args,&temp,sizeof(temp)) != 0) {
return -EFAULT;
}
return 0;
break;
default:
printk("IOCTLCMD failed\n");
return -ENOIOCTLCMD;
}
}
static struct file_operations ds18b20_fops = {
.owner = THIS_MODULE,
.read = ds18b20_read,
.unlocked_ioctl = ds18b20_adc_ioctl,
};
static struct miscdevice gec6818_adc_miscdev = {
.minor = MISC_DYNAMIC_MINOR, //MISC_DYNAMIC_MINOR,动态分配次设备号
.name = "ds18b20", //设备名称,/dev/ds18b20
.fops = &ds18b20_fops, //文件操作集
};
static int __init ds18b20_init(void)
{
int ret = -1;
//混杂设备的注册
ret = misc_register(&gec6818_adc_miscdev);
if (ret) {
printk("7""misc_register fail\n");
goto err_misc_register;
}
gpio_free(DS18B20_GPIO_PIN);
ret = gpio_request(DS18B20_GPIO_PIN, "ds18b20");
if(ret < 0) {
printk(KERN_ERR"gpio_request fail\n");
goto err_gpio_request;
}
ds18b20_config_temperature(0x3f);// 写入配置字节0,分辨率为10位
printk(KERN_INFO "ds18b20: ds18b20 init.\n");
return 0;
err_gpio_request:
misc_deregister(&gec6818_adc_miscdev);
err_misc_register:
return ret;
}
static void __exit ds18b20_exit(void)
{
misc_deregister(&gec6818_adc_miscdev);
gpio_free(DS18B20_GPIO_PIN);
printk(KERN_INFO "ds18b20: ds18b20 exit.\n");
}
module_init(ds18b20_init);
module_exit(ds18b20_exit);
MODULE_LICENSE("GPL");
test.c
#include
#include
#include
#include
#include
#define GET_DS18B20_VAL_CMD _IOR('s', 1, int)
#define DS18B20_DEV_NAME "/dev/ds18b20"
#define DHT11_DEV_NAME "/dev/dht11"
int test_ds18b20()
{
int fd;
int ret;
float temp;
int tmp;
// 打开设备节点
fd = open(DS18B20_DEV_NAME, O_RDWR);
if (fd < 0) {
perror("open");
exit(1);
}
while(1) {
// 读取温度值
ret=ioctl(fd,GET_DS18B20_VAL_CMD,&tmp);
if (ret < 0) {
perror("read");
close(fd);
exit(1);
}
printf("tmp = %f\n",(float)tmp/16.0);
usleep(4000);
ret = read(fd, &temp, sizeof(temp));
if (ret < 0) {
perror("read");
close(fd);
exit(1);
}
printf("temp = %f\n",temp);
usleep(4000);
}
// 关闭设备节点
close(fd);
return 0;
}
int main(void) {
test_ds18b20();
return 0;
}
https://cloud.tencent.com/developer/article/1974916
https://blog.csdn.net/qq_36413982/article/details/122674749
https://blog.csdn.net/qq_45661238/article/details/114002415