赞
踩
1)实验平台:正点原子ATK-DLRK3568开发板
2)平台购买地址:https://detail.tmall.com/item.htm?id=731866264428
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban
串口是很常用的一个外设,在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接口是否正常工作即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。