1)实验平台:正点原子ATK-DLRK3568开发板
2)平台购买地址:https://detail.tmall.com/item.htm?id=731866264428
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban
第三十二章 Linux RS232/485驱动实验
串口是很常用的一个外设,在Linux下通常通过串口和其他设备或传感器进行通信,根据电平的不同,串口分为TTL和RS232。不管是什么样的接口电平,其驱动程序都是一样的,通过外接RS485这样的芯片就可以将串口转换为RS485信号,正点原子的ATK-DLRK3568开发板就是这么做的。
RS232和RS485接口分别连接到了ATK-DLRK3568的UART3和UART4接口上。本章我们就来学习一下如何驱动ATK-DLRK3568开发板上的UART3和UART4,进而来实现RS232和RS485的实验。
32.1 Linux下UART驱动框架
1、uart_driver注册和注销
与前面的I2C一样,Linux也提供了串口驱动框架,我们只需要按照相应的串口框架编写驱动程序即可。串口驱动没什么主机端和设备端之分,就只有一个串口驱动,而且这个驱动也已经由瑞芯微官方编写好了,我们真正要做的就是在设备树中添加所要使用的串口节点信息。当系统启动以后串口驱动和设备匹配成功,相应的串口就会被驱动起来,生成/dev/ttySx文件,其中x代表数字。
虽然串口驱动不需要我们去写,但是串口驱动框架我们还是要了解,uart_driver结构体代表UART驱动,uart_driver定义在include/linux/serial_core.h文件中,内容如下:
示例代码32.1.1 uart_driver结构体
1 struct uart_driver {
2 struct module *owner; //模块所属者
3 const char *driver_name; //驱动名字
4 const char *dev_name; //设备名字
5 int major; //主设备号
6 int minor; //次设备号
7 int nr; //控制数
8 struct console *cons; //控制台
9
10 /*
11 * these are private; the low level driver should not
12 * touch these; they should be initialised to NULL
13 */
14 struct uart_state *state;
15 struct tty_driver *tty_driver;
16};
每个串口驱动需要定义一个uart_driver,加载驱动的时候通过uart_register_driver函数向系统注册这个uart_driver,函数原型如下:
int uart_register_driver(struct uart_driver *uart)
函数参数和返回值含义如下:
uart:要注册的uart_driver。
返回值:0,成功;负值,失败。
注销驱动的时候也需要注销掉前面注册的uart_driver,需要用到uart_unregister_driver函数原型如下:
void uart_unregister_driver(struct uart_driver *uart)
函数参数和返回值含义如下:
uart:要注销的uart_driver。
返回值:无
2、uart_port的添加与移除
uart_port表示一个具体的port,uart_port定义在include/linux/serial_core.h文件,内容如下(有省略):
示例代码32.1.2 uart_port结构体
1 struct uart_port {
2 spinlock_t lock; /* port lock */
3 unsigned long iobase; /* in/out[bwl] */
4 unsigned char __iomem *membase; /* read/write[bwl] */
......
134 const struct uart_ops *ops;
135 unsigned int custom_divisor;
136 unsigned int line; /* port index */
137 unsigned int minor;
138 resource_size_t mapbase; /* for ioremap */
139 resource_size_t mapsize;
140 struct device *dev; /* parent device */
......
149 };
uart_port中最主要的就是134行的ops,ops包括了串口的具体驱动函数,这个我们稍后再看。每个UART都有一个uart_port,那么uart_port是怎么和uart_driver结合起来的呢。这里要用到uart_add_one_port函数,函数原型如下:
int uart_add_one_port(stuct uart_driver *reg, stuct uart_port *port)
函数参数和返回值含义如下:
reg:要注册的串口驱动程序。
prot:要注册的串口端口。
返回值:0,成功;负值,失败。
卸载UART驱动的时候也需要将uart_port从相应的uart_driver中移除,需要用到uart_remove_one_port函数,函数原型如下:
int uart_remove_one_port(struct uart_driver *reg, struct uart_prot *prot)
reg:要卸载程序。
prot:要卸载口端口。
返回值:0,成功;负值,失败。
3、uart_ops实现
在上面讲解uart_port的时候说过,uart_port中的pos成员变量很重要,因为ops包含了针对UART具体的驱动函数,Linux系统收发数据最终调用的都是ops中的函数。ops是uart_ops类型的结构体指针变量,uart_ops定义在include/linux/serial_core.h文件中,内容如下:
示例代码32.1.3 uart_poat结构体
1 struct uart_ops {
2 unsigned int (*tx_empty)(struct uart_port *);
3 void (*set_mctrl)(struct uart_port *, unsigned int mctrl);
4 unsigned int (*get_mctrl)(struct uart_port *);
5 void (*stop_tx)(struct uart_port *);
6 void (*start_tx)(struct uart_port *);
7 void (*throttle)(struct uart_port *);
8 void (*unthrottle)(struct uart_port *);
9 void (*send_xchar)(struct uart_port *, char ch);
10 void (*stop_rx)(struct uart_port *);
11 void (*enable_ms)(struct uart_port *);
12 void (*break_ctl)(struct uart_port *, int ctl);
13 int (*startup)(struct uart_port *);
14 void (*shutdown)(struct uart_port *);
15 void (*flush_buffer)(struct uart_port *);
16 void (*set_termios)(struct uart_port *, struct ktermios *new,
17 struct ktermios *old);
18 void (*set_ldisc)(struct uart_port *, struct ktermios *);
19 void (*pm)(struct uart_port *, unsigned int state,
20 unsigned int oldstate);
21
22 /*
23 * Return a string describing the type of the port
24 */
25 const char *(*type)(struct uart_port *);
26
27 /*
28 * Release IO and memory resources used by the port.
29 * This includes iounmap if necessary.
30 */
31 void (*release_port)(struct uart_port *);
32
33 /*
34 * Request IO and memory resources used by the port.
35 * This includes iomapping the port if necessary.
36 */
37 int (*request_port)(struct uart_port *);
38 void (*config_port)(struct uart_port *, int);
39 int (*verify_port)(struct uart_port *, struct serial_struct *);
40 int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
41#ifdef CONFIG_CONSOLE_POLL
42 int (*poll_init)(struct uart_port *);
43 void (*poll_put_char)(struct uart_port *, unsigned char);
44 int (*poll_get_char)(struct uart_port *);
45#endif
46};
UATT驱动编写人员需要实现uart_ops,因为uart_ops是最底层的UART驱动接口,是实实在在的和UART寄存器打交道的。关于uart_ops结构体中的这些函数的具体含义请参考Documentation/serial/driver这个文档。
UART驱动框架大概就是这些,接下来我们理论联系实际,看一下瑞芯微官方的UART驱动文件是如何编写的。
32.2 RK3568 UART驱动分析
1、8250串口通用驱动文件
在瑞芯微官方提供的内核可以得知,使用了8250串口通用驱动,以下为主要驱动文件
drivers/tty/serial/8250/8250_core.c # 8250串口驱动核心
drivers/tty/serial/8250/8250_dw.c # Synopsis DesignWare 8250串口驱动
drivers/tty/serial/8250/8250_dma.c # 8250串口DMA驱动
drivers/tty/serial/8250/8250_port.c # 8250串口端口操作
drivers/tty/serial/8250/8250_early.c # 8250串口early console驱动
2、UART的platform驱动框架
下面我们以UART3来分析,打arch/arm64/boot/dts/rockchip/rk3568.dtsi文件,找到UART3对应的子节点,子节点内容如下所示:
示例代码32.2.1 uart3设备节点
1 uart3: serial@fe670000 {
2 compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart";
3 reg = <0x0 0xfe670000 0x0 0x100>;
4 interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
5 clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>;
6 clock-names = "baudclk", "apb_pclk";
7 reg-shift = <2>;
8 reg-io-width = <4>;
9 dmas = <&dmac0 6>, <&dmac0 7>;
10 pinctrl-names = "default";
11 pinctrl-0 = <&uart3m0_xfer>;
12 status = "disabled";
13 };
重点看一下第2行compatible属性值为“snps,dw-apb-uart”。在Linux源码中搜索这个值即可找到对应的UART驱动文件,此文件为drivers/tty/serial/8250/8250_dw.c,在此文件中可以找到如下内容:
示例代码32.2.2 UART platform驱动框架
1 static const struct of_device_id dw8250_of_match[] = {
2 { .compatible = "snps,dw-apb-uart" },
3 { .compatible = "cavium,octeon-3860-uart" },
4 { .compatible = "marvell,armada-38x-uart" },
5 { .compatible = "renesas,rzn1-uart" },
6 { /* Sentinel */ }
7 };
8 MODULE_DEVICE_TABLE(of, dw8250_of_match);
.......
24 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
25
26 static struct platform_driver dw8250_platform_driver = {
27 .driver = {
28 .name = "dw-apb-uart",
29 .pm = &dw8250_pm_ops,
30 .of_match_table = dw8250_of_match,
31 .acpi_match_table = dw8250_acpi_match,
32 },
33 .probe = dw8250_probe,
34 .remove = dw8250_remove,
35};
36
37 module_platform_driver(dw8250_platform_driver);
可以看出瑞芯微的UART本质上是一个platform驱动,第1~7行,设备树所使用的匹配表,第2行的compatible属性值为“snps,dw-apb-uart”。
第25~35行,platform驱动框架结构体dw8250_platform_driver。
接下来,我们继续看文件drivers/tty/serial/8250/8250_core.c。
示例代码32.2.3 驱动的初始化
1 static int __init serial8250_init(void)
2 {
3 int ret;
4
5 if (nr_uarts == 0)
6 return -ENODEV;
7
8 serial8250_isa_init_ports();
9
10 pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
11 nr_uarts, share_irqs ? "en" : "dis");
12
13 #ifdef CONFIG_SPARC
14 ret = sunserial_register_minors(&serial8250_reg, UART_NR);
15 #else
16 serial8250_reg.nr = UART_NR;
17 ret = uart_register_driver(&serial8250_reg);
18 #endif
19 if (ret)
20 goto out;
21
22 ret = serial8250_pnp_init();
23 if (ret)
24 goto unreg_uart_drv;
25
26 serial8250_isa_devs = platform_device_alloc("serial8250",
27 PLAT8250_DEV_LEGACY);
28 if (!serial8250_isa_devs) {
29 ret = -ENOMEM;
30 goto unreg_pnp;
31 }
32
33 ret = platform_device_add(serial8250_isa_devs);
34 if (ret)
35 goto put_dev;
36
37 serial8250_register_ports(&serial8250_reg,
38 &serial8250_isa_devs->dev);
39 ret = platform_driver_register(&serial8250_isa_driver);
40 if (ret == 0)
41 goto out;
42
43 platform_device_del(serial8250_isa_devs);
44 put_dev:
45 platform_device_put(serial8250_isa_devs);
46 unreg_pnp:
47 serial8250_pnp_exit();
48 unreg_uart_drv:
49 #ifdef CONFIG_SPARC
50 sunserial_unregister_minors(&serial8250_reg, UART_NR);
51 #else
52 uart_unregister_driver(&serial8250_reg);
53 #endif
54 out:
55 return ret;
56 }
57
58 static void __exit serial8250_exit(void)
59 {
60 struct platform_device *isa_dev = serial8250_isa_devs;
61
62 /*
63 * This tells serial8250_unregister_port() not to re-register
64 * the ports (thereby making serial8250_isa_driver permanently
65 * in use.)
66 */
67 serial8250_isa_devs = NULL;
68
69 platform_driver_unregister(&serial8250_isa_driver);
70 platform_device_unregister(isa_dev);
71
72 serial8250_pnp_exit();
73
74 #ifdef CONFIG_SPARC
75 sunserial_unregister_minors(&serial8250_reg, UART_NR);
76 #else
77 uart_unregister_driver(&serial8250_reg);
78 #endif
79 }
80
81 #ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
82 rootfs_initcall(serial8250_init);
83 #else
84 module_init(serial8250_init);
85 #endif
86 module_exit(serial8250_exit);
第1~56行,驱动入口函数,第8行此函数用于初始化串口端口的ISA总线驱动程序,主要实现请求端口、添加和注册串口端口,第17行调用uart_register_driver函数向Linux内核注册uart_driver,在这里就是serial8250_reg。
第58~79行,驱动出口函数,第77行调用uart_unregister_driver函数注销掉前面注册的uart_driver,在这里就是serial8250_reg。
3、uart_driver初始化
在serial8250_init函数中向Linux内核注册了serial8250_reg,serial8250_reg就是uart_driver类型的结构体变量,serial8250_reg定于如下:
示例代码32.2.4 serial8250_reg结构体
1 static struct uart_driver serial8250_reg = {
2 .owner = THIS_MODULE,
3 .driver_name = "serial",
4 .dev_name = "ttyS",
5 .major = TTY_MAJOR,
6 .minor = 64,
7 .cons = SERIAL8250_CONSOLE,
8 };
4、uart_port初始化与添加
当UART设备和驱动匹配成功以后dw8250_probe函数就会执行,此函数重点就是初始uart_port,然后将其添加到对应的uart_driver中。接下来看一下dw8250_probe函数,函数内容如下所示:
示例代码32.2.5 dw8250_probe函数
1 static int dw8250_probe(struct platform_device *pdev)
2 {
3 struct uart_8250_port uart = {};
4 struct resource *regs = platform_get_resource(pdev,
IORESOURCE_MEM, 0);
5 int irq = platform_get_irq(pdev, 0);
6 struct uart_port *p = &uart.port;
7 struct device *dev = &pdev->dev;
8 struct dw8250_data *data;
9 int err;
10 u32 val;
.......
23 spin_lock_init(&p->lock);
24 p->mapbase = regs->start;
25 p->irq = irq;
26 p->handle_irq = dw8250_handle_irq;
27 p->pm = dw8250_do_pm;
28 p->type = PORT_8250;
29 p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
30 p->dev = dev;
31 p->iotype = UPIO_MEM;
32 p->serial_in = dw8250_serial_in;
33 p->serial_out = dw8250_serial_out;
34 p->set_ldisc = dw8250_set_ldisc;
35 p->set_termios = dw8250_set_termios;
.......
135 data->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
136 if (IS_ERR(data->rst)) {
137 err = PTR_ERR(data->rst);
138 goto err_pclk;
139 }
140 reset_control_deassert(data->rst);
141
142 dw8250_quirks(p, data);
143
144 /* If the Busy Functionality is not implemented, don't handle it*/
145 if (data->uart_16550_compatible)
146 p->handle_irq = NULL;
147
148 if (!data->skip_autocfg)
149 dw8250_setup_port(p);
150
151 /* If we have a valid fifosize, try hooking up DMA */
152 if (p->fifosize) {
153 data->dma.rxconf.src_maxburst = p->fifosize / 4;
154 data->dma.txconf.dst_maxburst = p->fifosize / 4;
155 uart.dma = &data->dma;
156 }
157
158 data->line = serial8250_register_8250_port(&uart);
159 if (data->line < 0) {
160 err = data->line;
161 goto err_reset;
162 }
.......
187 return err;
188 }
第23行,初始化自旋锁函数
第142行,调用dw8250_quirks函数,它主要通过of_alias_get_id函数从设备树的aliases节点中获取“serial”相关的ID,以及获取对应的串口信息。
第158行,调用serial8250_register_8250_port函数,它主要负责向uart_driver添加uart_port,对应的就是在serial8250_reg添加uart->port。
5、serial8250_pops 结构体变量
serial8250_pops就是uart_ops类型的结构体变量,保存了RK3568串口最底层的操作函数,定义如下:
示例代码32.2.6 serial8250_pops
1 static const struct uart_ops serial8250_pops = {
2 .tx_empty = serial8250_tx_empty,
3 .set_mctrl = serial8250_set_mctrl,
4 .get_mctrl = serial8250_get_mctrl,
5 .stop_tx = serial8250_stop_tx,
6 .start_tx = serial8250_start_tx,
7 .throttle = serial8250_throttle,
8 .unthrottle = serial8250_unthrottle,
9 .stop_rx = serial8250_stop_rx,
10 .enable_ms = serial8250_enable_ms,
11 .break_ctl = serial8250_break_ctl,
12 .startup = serial8250_startup,
13 .shutdown = serial8250_shutdown,
14 .set_termios = serial8250_set_termios,
15 .set_ldisc = serial8250_set_ldisc,
16 .pm = serial8250_pm,
17 .type = serial8250_type,
18 .release_port = serial8250_release_port,
19 .request_port = serial8250_request_port,
20 .config_port = serial8250_config_port,
21 .verify_port = serial8250_verify_port,
22 #ifdef CONFIG_CONSOLE_POLL
23 .poll_get_char = serial8250_get_poll_char,
24 .poll_put_char = serial8250_put_poll_char,
25 #endif
26 };
serial8250_pops中的函数基本都是和RK3568的UART寄存器打交道的,这里就不去详细的分析了。简单的了解了RK3568的UART驱动以后我们再来学习一下,如何驱动正点原子ATK-DLRK3568开发板上的UART3接口和UART4接口。
32.3 硬件原理图分析
本实验要用到ATK-DLRK3568的UART3接口和UART5接口,UART3连接RS232的母头,UART4连接RS485。我们依次来看一下这两个串口的硬件原理图。
1、RS232原理图
RS232原理图如图32.3.1所示:
图32.3.1 RS232原理图
COM1母头连接到UART3接口上,把JP6的1-3和2-4连接起来以后SP232就和UART3连接到一起了,UART3_TX_M1和UART3_RX_M1分别接到了GPIO3_B7和GPIO3_C0这两个引脚上。
2、RS485原理图
RS485原理图如图32.3.2所示:
图32.3.2 RS485原理图
RS485采用SP3485EN这款芯片来实现,RO为数据输出端,DI为数据接收端,RE是接收使能信号(低电平有效),DE是发送使能信号(高电平有效)。把JP2的1-3和2-4连接起来以后SP3485EN就和UART4连接到一起了,UART4_TX_M1和UART4_RX_M1分别接到了GPIO3_B2和GPIO3_B1这两个引脚上。在图32.3.2中RE和DE经过一系列的电路,最终通过RS485_RX来控制,这样我们可以省掉一个RS485收发控制IO,将RS485完全当作一个串口来使用,方便我们写驱动。
32.4 RS232驱动编写
前面我们已经说过了,RK3568的UART驱动RK厂商已经编写好了,所以不需要我们编写。我们要做的就是在设备树中添加UART3对应的设备节点即可。打开rk3568-atk-evb1-ddr4-v10.dtsi文件,因为uart3的节点在rk3568.dtsi已经存在了,我们只要在rk3568-atk-evb1-ddr4-v10.dtsi文件里面向这些节点追加一些内容即可,追加的步骤如下:
1、添加uart3的引脚信息
我们先在rk3568-pinctrl.dtsi文件下看有没有uart3的引脚配置,以及引脚配置是不是我开发板所对应的。默认情况下rk3568-pinctrl.dtsi里面是有uart3的引脚配置,如下图所示:
示例代码32.4.1 要追加的pinmux配置
1 uart3 {
2 /omit-if-no-ref/
3 uart3m0_xfer: uart3m0-xfer {
4 rockchip,pins =
5 /* uart3_rxm0 */
6 <1 RK_PA0 2 &pcfg_pull_up>,
7 /* uart3_txm0 */
8 <1 RK_PA1 2 &pcfg_pull_up>;
9 };
......
24
25 /omit-if-no-ref/
26 uart3m1_xfer: uart3m1-xfer {
27 rockchip,pins =
28 /* uart3_rxm1 */
29 <3 RK_PC0 4 &pcfg_pull_up>,
30 /* uart3_txm1 */
31 <3 RK_PB7 4 &pcfg_pull_up>;
32 };
33 };
第25~32行就是UART3所需的引脚配置。稍后我们向uart3中追加内容会使用到uart3m1_xfer这个节点的。
2、向uart3节点追加内容
在rk3568-atk-evb1-ddr4-v10.dtsi文件中追加相应如下代码:
示例代码32.4.2 串口的节点
1 &usart3 {
2 pinctrl-names = "default";
3 pinctrl-0 = <&uart3m1_xfer>;
4 status = "okay";
5 };
这里追加的内容很简单,第3行就是刚刚我们添加的pinmux配置。
3、设置串口的别名
在前面的UART驱动分析已经得知,驱动会读取aliaser节点,打开文件rk3568.dtsi,添加的别名如下所示:
示例代码32.4.3 串口的别名
1 aliases {
2 csi2dphy0 = &csi2_dphy0;
3 csi2dphy1 = &csi2_dphy1;
4 csi2dphy2 = &csi2_dphy2;
.....
24 serial0 = &uart0;
25 serial1 = &uart1;
26 serial2 = &uart2;
27 serial3 = &uart3;
28 serial4 = &uart4;
29 serial5 = &uart5;
30 serial6 = &uart6;
31 serial7 = &uart7;
32 serial8 = &uart8;
33 serial9 = &uart9;
39 };
serial3就是uart3的别名,表示在系统启动会生成名为“/dev/ttyS3”的设备文件,如此类推,最多是10个。serial2就是我们的调试串口。
启动开发板出厂buildroot系统,系统启动之后就会有如下32.4.4所示设备文件:
图32.4.4 串口的设备文件
使用系统自带的串口调试助手microcom来测试,在开发板上输入“microcom --version”来查看microcom工作是否正常,结果如图32.4.5所示
图32.4.5 microcom信息
32.5 RS232驱动测试
在测试之前要先将ATK-DLRK3568的RS232接口与电脑连接起来,具体接法可以参考开发板光盘A盘-基础资料\10、用户手册\01、测试文档\ ATK-DLRK3568_Buildroot系统快速体验手册/串口测试章节。
接好线之后在开发板中输入命令“microcom /dev/ttyS3 -s 115200”,打开串口功能,启动的是UART3,波特率为115200。这里COM3口是开发板的,COM6口是电脑端的。这里特别说明一下,microcom是没有开启回显功能的。
1、发送数据
图32.5.1 通过UART3向电脑发送“AAA”
图32.5.2 电脑接收开发板数据“AAA”
2、接收数据
图32.5.3 通过UART3向开发板发送“aaa”
图32.5.4 开发板接收电脑数据“aaa”
UART3收发测试都没有问题,说明我们的UART3驱动工作正常。如果要退出microcom功能的话,在开发板界面按下“CRTL+X”。关于microcom的使用我们这里讲的很简单,大家可以在网上查找更加详细的microcom使用教程。
32.6 RS485驱动编写
好了,我们接下来就来学习如何实现RS485,有了前面RS232的学习,RS485就比较轻松的。我们要做的就是在设备树中添加UART4对应的设备节点即可。
1、添加uart4的引脚信息
我们先在rk3568-pinctrl.dtsi文件下看有没有uart4的引脚配置,以及引脚配置是不是我开发板所对应的。默认情况下rk3568-pinctrl.dtsi里面是有uart4的引脚配置,如下图所示:
示例代码32.6.1 要追加的pinmux配置
1 uart4 {
2 /omit-if-no-ref/
3 uart4m0_xfer: uart4m0-xfer {
4 rockchip,pins =
5 /* uart4_rxm0 */
6 <1 RK_PA4 2 &pcfg_pull_up>,
7 /* uart4_txm0 */
8 <1 RK_PA6 2 &pcfg_pull_up>;
9 };
10...
25 /omit-if-no-ref/
26 uart4m1_xfer: uart4m1-xfer {
27 rockchip,pins =
28 /* uart4_rxm1 */
29 <3 RK_PB1 4 &pcfg_pull_up>,
30 /* uart4_txm1 */
31 <3 RK_PB2 4 &pcfg_pull_up>;
32 };
33 };
第25~32行就是UART4所需的引脚配置。稍后我们向uart4中追加内容会使用到uart3m1_xfer这个节点的。
2、向uart4节点追加内容
在rk3568-atk-evb1-ddr4-v10.dtsi文件中追加相应如下代码:
示例代码32.6.2 串口的节点
1 &usart4 {
2 pinctrl-names = "default";
3 pinctrl-0 = <&uart4m1_xfer>;
4 status = "okay";
5 };
这里追加的内容很简单,第3行就是刚刚我们添加的pinmux配置。
32.7 RS485驱动测试
在测试之前要先将ATK-DLRK3568的RS485接口与电脑连接起来,具体接法可以参考开发板光盘A盘-基础资料\10、用户手册\01、测试文档\ ATK-DLRK3568_Buildroot系统快速体验手册/串口测试章节。按32.5步骤测试RS485接口是否正常工作即可。