我们一般操作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;
}