2025-03-09
串口通信是嵌入式开发的常用通信方式之一。下面就给大家演示一下,如何使用Linux驱动来进行串口通信?下面的例子主要实现了串口通信回显功能,上位机通过USB串口发送数据到raspi3b,pi3b的驱动接收到数据后,直接将数据发送回来。
// testoverlay.dts
/dts-v1/;
/plugin/;
/ {
compatible = "raspberrypi,3-model-bbrcm,bcm2837";
fragment@0 {
target = <&uart1>;
__overlay__ {
echodev {
compatible = "brightlight,echodev";
status = "okay";
};
};
};
};
// simple.c
#include <linux/init.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/serdev.h>
static struct of_device_id my_driver_ids[] = {
{
.compatible = "brightlight,echodev",
},
{},
};
MODULE_DEVICE_TABLE(of, my_driver_ids);
static int _echo_recv(struct serdev_device *serdev,
const unsigned char *buffer, size_t size) {
pr_info("received %ld bytes with \"%s\"\n", size, buffer);
return serdev_device_write_buf(serdev, buffer, size);
}
static const struct serdev_device_ops dops = {
.receive_buf = _echo_recv,
};
static int _dt_probe(struct serdev_device *serdev) {
int status = 0;
const char* prompt = "Type something: ";
pr_info("simple_dt_probe\n");
serdev_device_set_client_ops(serdev, &dops);
status = serdev_device_open(serdev);
if (status) {
pr_err("serdev_device_open failed\n");
return -status;
}
serdev_device_set_baudrate(serdev, 9600);
serdev_device_set_flow_control(serdev, false);
serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
status = serdev_device_write_buf(serdev, prompt, sizeof(prompt));
pr_info("send %d bytes\n", status);
return 0;
}
static void _dt_remove(struct serdev_device *serdev) {
pr_info("simple_dt_remove\n");
serdev_device_close(serdev);
}
static struct serdev_device_driver my_dirver = {
.probe = _dt_probe,
.remove = _dt_remove,
.driver =
{
.name = "my_device_driver",
.of_match_table = my_driver_ids,
},
};
static int __init simple_init(void) {
pr_info("simple_init\n");
if (serdev_device_driver_register(&my_dirver)) {
pr_err("serdev_device_driver_register failed\n");
return -1;
}
return 0;
}
static void __exit simple_exit(void) {
pr_info("simple_exit\n");
serdev_device_driver_unregister(&my_dirver);
}
module_init(simple_init);
module_exit(simple_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("heng30");
MODULE_VERSION("v0.0.1");
MODULE_DESCRIPTION("A simple kernel module");
#!/bin/sh
top-dir = $(shell pwd)
kernel-version = $(shell uname -r)
kernel-dir ?= /lib/modules/$(kernel-version)/build
obj-m += simple.o
all: dt driver
driver:
make -C $(kernel-dir) modules M=$(top-dir)
dt:
dtc -@ -I dts -O dtb -o testoverlay.dtbo testoverlay.dts
clean:
rm -f *.o *.ko *.mod *.mod.c *.order *.symvers *.dtbo
make -C $(kernel-dir) clean m=$(top-dir)
编译:make
复制设备树节点到启动目录:sudo cp testoverlay.dtbo /boot/overlays/
编辑启动配置:sudo vim /boot/config.txt
dtoverlay=testoverlay
配置树莓派串口选项:sudo raspi-config
Interface Options
->Serial Port
The serial login shell is disabled │
The serial interface is enabled
重启:sudo reboot
查看串口信息:ls /proc/device-tree/soc/serial*
安装驱动:insmod simple.ko
向串口发送数据:sudo screen /dev/ttyUSB0 9600
移除驱动:rmmod simple.ko