使用内核API函数找到I2C和串口控制器发送数据

文章讲述了在Linux系统中,如何在shutdown/reboot时通过内核API向I2C和串口发送数据,解决因设备断电导致的应用层无法操作的问题,给出了四个实际编程代码片段作为参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们一般操作I2C或者串口都是编写应用程序调用内核硬件提供的设备节点操作这些硬件的,但是在某个项目中,需要在shutdown的时候往i2c和tty发送数据,发送数据给外置的mcu,mcu几秒内就会给cpu断电,所以,这个动作无法在应用层中完成,需要在内核的reboot这个系统调用中实现了,但是在这个时候根文件系统已经umount了,无法使用call_usermodehelpere调用应用层的可执行程序了,会报找不到设备的错误。只能利用内核的API找到对应的apdter来发送数据了。这里记录一下自己的代码,方便自己下次参考。下面是4个例子:分别是I2C和串口的应用程序和内核程序。

1. I2C应用程序代码例子:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c-dev.h>

#define I2C_ADDR 0x68

int main(int argc, char *argv[]) {
    int file;
    char *bus = "/dev/i2c-1"; // 更换为您的 I2C 总线
    if ((file = open(bus, O_RDWR)) < 0) {
        printf("Failed to open the bus. \n");
        exit(1);
    }
    if (ioctl(file, I2C_SLAVE, I2C_ADDR) < 0) {
        printf("Failed to acquire bus access and/or talk to slave. \n");
        exit(1);
    }
    // 写操作
    static char data[] = "\x01\x02\x03\x04\x05\x06\x07\x08"; 
    if (write(file, data, 2) != 2) {
        printf("Failed to write to the i2c bus. \n");
        exit(1);
    }
    usleep(5000); // 等待一段时间,并发起读操作

    // 读操作
    char buf_read[8] = {0};
    if (read(file, buf_read, 2) != 2) {
        printf("Failed to read from the i2c bus. \n");
        exit(1);
    } else {
        printf("Read: %02x %02x \n", buf_read[0], buf_read[1]);
    }
    close(file);
    return 0;
}

2. 串口应用程序代码例子:

#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fd = open("/dev/ttyS4", O_WRONLY); /* Open serial port for writing */
    if (fd == -1) {
        perror("Failed to open serial port");
        return -1;
    }

    char data[] = "\xfd\xfc\x05\x05\x11\x11\xff\xfe"; /* Specify data to write */
    ssize_t n = write(fd, data, sizeof(data)-1); /* Write data to serial port */
    if (n == -1) {
        perror("Failed to write to serial port");
        return -1;
    }

    close(fd);
}

3. 使用i2c2发送数据到0x7f这个设备的例子:

int i2c_send(void)
{
    // 创建 I2C 消息结构
    struct i2c_msg msg;
    u8 data[] = {0x01, 0x02, 0x03}; // 要发送的数据
    msg.addr = 0x7f << 1;        	// 目标设备的I2C地址
    msg.flags = 0;                 	// 写入标志,表示发送数据
    msg.len = sizeof(data);        	// 数据长度
    msg.buf = data;                	// 数据缓冲区
	
	struct i2c_adapter *adap = i2c_get_adapter(2);
	i2c_transfer(adap, msg, 1);
	return 0;
}

4. 使用ttyS4发送数据的例子:

#include <linux/tty.h>
int shixin_uart_send(void)
{
	static char data[] = "\x01\x02\x03\x04\x05\x06\x07\x08"; /* Specify data to write */
	struct file *file;
	int ret;

	file = filp_open("/dev/ttyS4", O_RDWR | O_NOCTTY, 0);
	if (IS_ERR(file)) {
		printk(KERN_ERR "Failed to open /dev/ttyS6\n");
		return PTR_ERR(file);
	}

	// 发送数据到 ttyS4
	ret = kernel_write(file, data, strlen(data), 0);
	if (ret < 0) {
		printk(KERN_ERR "Failed to send data to /dev/ttyS6\n");
		filp_close(file, NULL);
		return ret;
	}
	
	// 关闭设备文件
	filp_close(file, NULL);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小坚学Linux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值