MS5805-02BA01传感器在开发板ubuntu下实现温度和大气压强的读取

本文详细描述了如何通过C语言在Linux系统中实现MS5805传感器的驱动程序,包括I2C通信的初始化、读写操作以及温度和压力的测量计算。内容涵盖了模块注册、错误处理和用户空间读取示例。
摘要由CSDN通过智能技术生成

MS5805传感器的引脚及封装图如下:

通过C语言实现

内核代码

#include <linux/module.h>       //所有模块都需要的头文件
#include <linux/init.h>         // init和exit相关宏
#include <linux/kernel.h>       // printk(),内核打印函数
#include <linux/delay.h>        // 延时函数头文件
#include <linux/device.h>       // 用于设备创建的函数头文件
#include <linux/fs.h>           //和fops相关的头文件
#include <linux/cdev.h>         //字符设备 初始化相关
#include <linux/version.h>
#include <linux/platform_device.h>  //platform总线设备相关
#include <linux/err.h>          //错误码相关
#include <linux/timer.h>        //定时器相关
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>

#define DEV_NAME                        "ms5805"
// MS5805 device address
#define MS5805_ADDR													0x76 //0b1110110

// MS5805 device commands
#define MS5805_RESET_COMMAND										0x1E
#define MS5805_START_PRESSURE_ADC_CONVERSION						0x40
#define MS5805_START_TEMPERATURE_ADC_CONVERSION						0x50
#define MS5805_READ_ADC												0x00

// MS5805 commands
#define MS5805_PROM_ADDRESS_READ_ADDRESS_0							0xA0
#define MS5805_PROM_ADDRESS_READ_ADDRESS_1							0xA2
#define MS5805_PROM_ADDRESS_READ_ADDRESS_2							0xA4
#define MS5805_PROM_ADDRESS_READ_ADDRESS_3							0xA6
#define MS5805_PROM_ADDRESS_READ_ADDRESS_4							0xA8
#define MS5805_PROM_ADDRESS_READ_ADDRESS_5							0xAA
#define MS5805_PROM_ADDRESS_READ_ADDRESS_6							0xAC
#define MS5805_PROM_ADDRESS_READ_ADDRESS_7							0xAE

struct i2c_client *hi_client;
static struct i2c_board_info hi_info = {
     I2C_BOARD_INFO("ms8858", MS5805_ADDR),
};
struct data_temp_pre
{
	uint16_t C0;
	uint16_t C1;
	uint16_t C2;
	uint16_t C3;
	uint16_t C4;
	uint16_t C5;
	uint16_t C6;
	uint32_t D1;
	uint32_t D2;
};

void ms5805_init(void)
{
    struct i2c_adapter *adapter;
    int ret;

    // 获取I2C适配器
    adapter = i2c_get_adapter(2); // 使用第二个I2C总线
    if (adapter == NULL) {
        printk("Failed to get I2C adapter\n");
        return -ENODEV;
    }

    // 创建I2C客户端
    hi_client = i2c_new_device(adapter, &hi_info);
    if (hi_client == NULL) {
        printk("Failed to create I2C client\n");
        return -ENODEV;
    }
}

void ms5805_exit(void)
{
	//卸载I2C客户端
	if(hi_client != NULL){
        i2c_unregister_device(hi_client);
    }
}

uint16_t read_two_byte_value(struct i2c_client *client , uint8_t cmd)
{
    unsigned char recv_buf[2] = {0, 0};
	char sned_buf[1];
	sned_buf[0] = cmd;
    int ret;

    // 发送命令字节到设备以读取数据
    ret = i2c_master_send(client, sned_buf, 1);
    if (ret < 0) {
        pr_err("Failed to send command byte\n");
        return 0; // 错误返回0
    }

    // 从设备中读取数据到缓冲区
    ret = i2c_master_recv(client, recv_buf, sizeof(recv_buf));
    if (ret < 0) {
        pr_err("Failed to read data from device\n");
        return 0; // 错误返回0
    }

    // 数据转换
    uint16_t value = (uint16_t)(recv_buf[0] << 8 | recv_buf[1]);
    return value;
}

uint32_t read_there_byte_value(struct i2c_client *client , uint8_t cmd)
{
    unsigned char recv_buf[3] = {0, 0, 0};
	char sned_buf[1];
	sned_buf[0] = cmd;
    int ret;

    // 发送命令字节到设备以读取数据
    ret = i2c_master_send(client, sned_buf, 1);
    if (ret < 0) {
        pr_err("Failed to send command byte\n");
        return 0; // 错误返回0
    }

    // 从设备中读取数据到缓冲区
    ret = i2c_master_recv(client, recv_buf, sizeof(recv_buf));
    if (ret < 0) {
        pr_err("Failed to read data from device\n");
        return 0; // 错误返回0
    }

     // 数据转换
    uint32_t value = (uint32_t)(recv_buf[0] << 16) | (uint32_t)(recv_buf[1] << 8) | (uint32_t)(recv_buf[2]);
    return value;
}

int  ms5805_write_command(  struct i2c_client *client,uint8_t cmd)
{
	char buf[1];  // 创建一个包含一个字节数据的缓冲区
    buf[0] = cmd;  // 将命令字节放入缓冲区
	int ret = i2c_master_send(client , buf , 1);
	return ret;
}


struct data_temp_pre ms5805_read_temperature_and_pressure(struct i2c_client *client)
{
	struct data_temp_pre data_temp_pres;
	ms5805_write_command(client,MS5805_RESET_COMMAND);
	udelay(10);
	data_temp_pres.C0 = read_two_byte_value(client,MS5805_PROM_ADDRESS_READ_ADDRESS_0);
	data_temp_pres.C1 = read_two_byte_value(client,MS5805_PROM_ADDRESS_READ_ADDRESS_1);
	data_temp_pres.C2 = read_two_byte_value(client,MS5805_PROM_ADDRESS_READ_ADDRESS_2);
	data_temp_pres.C3 = read_two_byte_value(client,MS5805_PROM_ADDRESS_READ_ADDRESS_3);
	data_temp_pres.C4 = read_two_byte_value(client,MS5805_PROM_ADDRESS_READ_ADDRESS_4);
	data_temp_pres.C5 = read_two_byte_value(client,MS5805_PROM_ADDRESS_READ_ADDRESS_5);
	data_temp_pres.C6 = read_two_byte_value(client,MS5805_PROM_ADDRESS_READ_ADDRESS_6);

	ms5805_write_command(client,MS5805_START_PRESSURE_ADC_CONVERSION);
	udelay(500);
	data_temp_pres.D1 = read_there_byte_value(client,MS5805_READ_ADC);

	ms5805_write_command(client,MS5805_START_TEMPERATURE_ADC_CONVERSION);
	udelay(500);
	data_temp_pres.D2 = read_there_byte_value(client,MS5805_READ_ADC);

	return data_temp_pres;

}
static int ms5805_open(struct inode *inode, struct file *file)
{
	printk(KERN_INFO "Driver: ms5805 open\n");
    return 0;
}

static ssize_t ms5805_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
	printk(KERN_INFO "Driver: ms5805 read\n");
	struct data_temp_pre data_temp_pre_copy;
	data_temp_pre_copy = ms5805_read_temperature_and_pressure(hi_client);
	if (copy_to_user(buff,&data_temp_pre_copy,sizeof(data_temp_pre_copy)))
	{
		printk(KERN_ERR "Failed to copy data to user space\n");
		return -EFAULT;
	}
	
    return count;
}

static struct file_operations ms5805_fops = {
    .owner   =   THIS_MODULE,
    .open    =   ms5805_open,
    .read    =   ms5805_read,
};

static struct miscdevice ms5805_misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name =DEV_NAME,
    .fops = &ms5805_fops,
};

static int __init ms5805_dev_init(void)
{
    int ret = 0;
	printk("insmod ms5805! func:= %s\n", __func__);
    /* register MISC device */
    if ((ret = misc_register(&ms5805_misc)))
    {
		printk("failed add a64_misc_dev_device\n");
        return ret;
    }
	ms5805_init();
    return 0;
}

static void __exit ms5805_dev_exit(void)
{
	ms5805_exit();
    misc_deregister(&ms5805_misc);
	printk("rmmod ms5805! func:= %s\n", __func__);
}
module_init(ms5805_dev_init);
module_exit(ms5805_dev_exit);
MODULE_AUTHOR("liufeng");
MODULE_DESCRIPTION("helpera133 ms5805 Driver");
MODULE_LICENSE("GPL")

用户端读取实现

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

struct data_temp_pre
{
	uint16_t C0;
	uint16_t C1;
	uint16_t C2;
	uint16_t C3;
	uint16_t C4;
	uint16_t C5;
	uint16_t C6;
	uint32_t D1;
	uint32_t D2;
};

int main() {
    int fd = open("/dev/ms5805", O_RDONLY);
    if (fd == -1) {
        perror("Failed to open device");
        return -1;
    }
    while (1)
    {
        struct data_temp_pre data;
    int  ret = read(fd, &data, sizeof(data));
    if (ret == -1) {
        perror("Failed to read from device");
        close(fd);
        return -1;
    }

    int32_t dT = data.D2 - data.C5 * 256;
    int32_t TEMP = 2000 + (int64_t)dT * (int64_t)data.C6 / 8388608;
    int64_t OFF = (int64_t)data.C2 * 131072 + (int64_t)data.C4 * (int64_t)dT / 64;
    int64_t SENS = (int64_t)data.C1 * 65536 + (int64_t)data.C3 * (int64_t)dT / 128;
    int32_t T2 = 0;
    int64_t OFF2 = 0;
    int64_t SENS2 = 0;

    if (TEMP < 2000) {
        T2 = 11 * ((int64_t)dT * (int64_t)dT) / 34359738368;
        OFF2 = 31 * (((int64_t)TEMP - 2000) * ((int64_t)TEMP - 2000)) / 8;
        SENS2 = 63 * (((int64_t)TEMP - 2000) * ((int64_t)TEMP - 2000)) / 32;
    }

    int32_t TEMP2 = TEMP - T2;
    OFF2 = OFF - OFF2;
    SENS2 = SENS - SENS2;
    float pressure = (((((data.D1 * SENS2) / 2097152) - OFF2) / 32768)) / 100.0;
    float cTemp = TEMP2 / 100.0;
    float fTemp = cTemp * 1.8 + 32;

    // 打印结构体中的每个数据
    // printf("C0: %u\n", data.C0);
    // printf("C1: %u\n", data.C1);
    // printf("C2: %u\n", data.C2);
    // printf("C3: %u\n", data.C3);
    // printf("C4: %u\n", data.C4);
    // printf("C5: %u\n", data.C5);
    // printf("C6: %u\n", data.C6);
    // printf("D1: %u\n", data.D1);
    // printf("D2: %u\n", data.D2);
    printf("Pressure: %.2f mbar\n", pressure);
    printf("Temperature : %.2f C\n", cTemp);
    printf("Temperature : %.2f F\n", fTemp);
    printf("----------------------------\n");
    sleep(1);
    }
    close(fd);
    return 0;
}

实现结果截图

通过python代码进行实现

python代码

# Distributed with a free-will license.
# Use it any way you want, profit or free, provided it fits in the licenses of its associated works.
# MS5805_02BA01
# This code is designed to work with the MS5805_02BA01_I2CADC I2C Mini Module available from ControlEverything.com.
# https://www.controleverything.com/products

import smbus
import time

MS5805_02BA01_I2CADDR = 0x76
# Get I2C bus
bus = smbus.SMBus(2)

# MS5805_02BA01 address, 0x76(118)
#		0x1E(30)	Reset command
bus.write_byte(MS5805_02BA01_I2CADDR, 0x1E)

time.sleep(0.3)

# Read 12 bytes of calibration data
# Read pressure sensitivity
data = bus.read_i2c_block_data(MS5805_02BA01_I2CADDR, 0xA0, 2)
C0 = data[0] * 256 + data[1]

data = bus.read_i2c_block_data(MS5805_02BA01_I2CADDR, 0xA2, 2)
C1 = data[0] * 256 + data[1]

# Read pressure offset
data = bus.read_i2c_block_data(MS5805_02BA01_I2CADDR, 0xA4, 2)
C2 = data[0] * 256 + data[1]

# Read temperature coefficient of pressure sensitivity
data = bus.read_i2c_block_data(MS5805_02BA01_I2CADDR, 0xA6, 2)
C3 = data[0] * 256 + data[1]

# Read temperature coefficient of pressure offset
data = bus.read_i2c_block_data(MS5805_02BA01_I2CADDR, 0xA8, 2)
C4 = data[0] * 256 + data[1]

# Read reference temperature
data = bus.read_i2c_block_data(MS5805_02BA01_I2CADDR, 0xAA, 2)
C5 = data[0] * 256 + data[1]

# Read temperature coefficient of the temperature
data = bus.read_i2c_block_data(MS5805_02BA01_I2CADDR, 0xAC, 2)
C6 = data[0] * 256 + data[1]

# MS5805_02BA01 address, 0x76(118)
#		0x40(64)	Pressure conversion(OSR = 256) command
bus.write_byte(MS5805_02BA01_I2CADDR, 0x40)

time.sleep(0.5)

# Read digital pressure value
# Read data back from 0x00(0), 3 bytes
# D1 MSB2, D1 MSB1, D1 LSB
value = bus.read_i2c_block_data(MS5805_02BA01_I2CADDR, 0x00, 3)
D1 = value[0] * 65536 + value[1] * 256 + value[2]

# MS5805_02BA01 address, 0x76(118)
#		0x50(64)	Temperature conversion(OSR = 256) command
bus.write_byte(MS5805_02BA01_I2CADDR, 0x50)

time.sleep(0.5)

# Read digital temperature value
# Read data back from 0x00(0), 3 bytes
# D2 MSB2, D2 MSB1, D2 LSB
value = bus.read_i2c_block_data(MS5805_02BA01_I2CADDR, 0x00, 3)
D2 = value[0] * 65536 + value[1] * 256 + value[2]

dT = D2 - C5 * 256
TEMP = 2000 + dT * C6 / 8388608
OFF = C2 * 131072 + (C4 * dT) / 64
SENS = C1 * 65536 + (C3 * dT ) / 128
T2 = 0
OFF2 = 0
SENS2 = 0

if TEMP < 2000 :
	T2 = 11 *(dT * dT) / 34359738368
	OFF2 = 31 * ((TEMP - 2000) * (TEMP - 2000)) / 8
	SENS2 = 63 * ((TEMP - 2000) * (TEMP - 2000)) / 32

TEMP2 = TEMP - T2
OFF2 = OFF - OFF2
SENS2 = SENS - SENS2
pressure = (((((D1 * SENS2) / 2097152) - OFF2) / 32768)) / 100.0
cTemp = TEMP2 / 100.0
fTemp = cTemp * 1.8 + 32

# Output data to screen
print ("C0 : %.2f " %C0)
print ("C1 : %.2f " %C1)
print ("C2 : %.2f " %C2)
print ("C3 : %.2f " %C3)
print ("C4 : %.2f " %C4)
print ("C5 : %.2f " %C5)
print ("C6 : %.2f " %C6)
print ("D1 : %.2f " %D1)
print ("D2 : %.2f " %D2)
print ("TEMP2 : %.2f " %TEMP2)
print ("OFF2 : %.2f " %OFF2)
print ("SENS2 : %.2f " %SENS2)
print ("Pressure : %.2f mbar" %pressure)
print ("Temperature in Celsius : %.2f C" %cTemp)
print ("Temperature in Fahrenheit : %.2f F" %fTemp)

实现结果截图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值