• 正点原子嵌入式linux驱动开发——Linux 串口RS232/485/GPS 驱动


    串口是很常用的一个外设,在Linux下通常通过串口和其他设备或传感器进行通信,根据
    电平的不同,串口分为TTL和RS232
    。不管是什么样的接口电平,其驱动程序都是一样的,通过外接RS485这样的芯片就可以将串口转换为RS485信号,正点原子的STM32MP1开发板就是这么做的。对于正点原子的STM32MP1开发板而言有8个串口,四个同步串口(USART1、USART2、USART3和USART6),四个异步串口(UART4、UART5、UART7和UART8)

    RS232和RS485接口连接到了STM32MP1的USART3接口上,通过跳线帽选择USART3作为RS232还是RS485。GPS模块是连接到UART5接口上,因此这些外设最终都归结为USART3和UART5的串口驱动。本章就来学习一下如何驱动STM32MP1开发板上的USART3串口和UART5,进而实现RS232、RS485以及GPS驱动

    Linux下UART驱动框架

    uart_driver注册/注销

    同I2C、SPI一样,Linux也提供了串口驱动框架,只需要按照相应的串口框架编写驱动程序即可。串口驱动没有什么主机端和设备端之分,就只有一个串口驱动,而且这个驱动也
    已经由ST官方编写好了,真正要做的就是在设备树中添加所要使用的串口节点信息
    。当
    系统启动以后串口驱动和设备匹配成功,相应的串口就会被驱动起来,生成/dev/ttySTMX(X=0….n)文件。

    虽然串口驱动不需要自行实现,但是串口驱动框架还是需要了解的,uart_driver结构体表示UART驱动,uart_driver定义在 include/linux/serial_core.h文件中,内容如下:

    uart_driver结构体

    每个串口驱动都需要定义一个uart_driver,加载驱动的时候通过uart_register_driver函数向系统注册这个uart_driver,此函数原型如下:

    int uart_register_driver(struct uart_driver *uart) 
    
    • 1

    函数参数和返回值含义如下:

    • uart:要注册的uart_driver。
    • 返回值:0,成功;负值,失败。

    注销驱动的时候也需要注销掉前面注册的uart_driver,需要用到uart_unregister_driver函数,函数原型如下:

    void uart_unregister_driver(struct uart_driver *uart) 
    
    • 1

    函数参数和返回值含义如下:

    • uart:要注销的uart_driver。
    • 返回值:无。

    uart_port添加/移除

    uart_port表示一个具体的port,uart_port定义在 include/linux/serial_core.h文件,内容如下(有省略):

    uart_port结构体

    uart_port中最主要的就是第240行的ops,ops包含了串口的具体驱动函数。每个UART都有一个uart_port,那么uart_port是怎么和uart_driver结合起来的呢?这里要用到uart_add_one_port函数,函数原型如下:

    int uart_add_one_port(struct uart_driver *reg, struct uart_port *port) 
    
    • 1

    函数参数和返回值含义如下:

    • reg:此port对应的uart_driver。
    • port:要添加到uart_driver中的port。
    • 返回值:0,成功;负值,失败。

    卸载UART驱动的时候也需要将uart_port从相应的uart_driver中移除,需要用到uart_remove_one_port函数,函数原型如下:

    int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port) 
    
    • 1

    函数参数和返回值含义如下:

    • reg:要卸载的port所对应的uart_driver。
    • port:要卸载的uart_port。
    • 返回值:0,成功;负值,失败。

    uart_ops实现

    在上面讲解uart_port的时候说过,uart_port中的ops成员变量很重要,因为ops包含了针对UART具体的驱动函数,Linux系统收发数据最终调用的都是ops中的函数 。ops是uart_ops类型的结构体指针变量,uart_ops定义在include/linux/serial_core.h文件中,内容如下:

    示例代码 46.1.3 uart_port 结构体
    37 struct uart_ops {
    38     unsigned int (*tx_empty)(struct uart_port *);
    39     void (*set_mctrl)(struct uart_port *, unsigned int mctrl);
    40     unsigned int (*get_mctrl)(struct uart_port *);
    41     void (*stop_tx)(struct uart_port *);
    42     void (*start_tx)(struct uart_port *);
    43     void (*throttle)(struct uart_port *);
    44     void (8unthrottle)(struct uart_port *);
    45     void (*send_xchar)(struct uart_port *, char ch);
    46     void (*stop_rx)(struct uart_port *);
    47     void (*enable_ms)(struct uart_port *);
    48     void (*break_ctl)(struct uart_port *, int ctl);
    49     int (*startup)(struct uart_port *);
    50     void (*shutdown)(struct uart_port *);
    51     void (*flush_buffer)(struct uart_port *);
    52     void (*set_termios)(struct uart_port  *, struct ktermios *new, 
    53                 struct ktermios *old);
    54     void (*set_ldisc)(struct uart_port *, struct ktermios *);
    55     void (*pm)(struct uart_port *, unsigned int state, 
    56                     unsigned int oldstate);
    57
    58     /*
    59      * Return a string describing the type of the port
    60      */
    61     const char *(*type)(struct uart_port *);
    62
    63     /*
    64      * Release IO and memory resources used by the
    65      * This includes iounmap if
    66      */
    67     void (*release_port)(struct uart_port *);
    68
    69     /*
    70      * Request IO and memory resources used by the
    71      * This includes iomapping the port if
    72      */
    73     int (*request_port)(struct uart_port *);
    74     void (*config_port)(struct uart_port  *, int);
    75     int (*verify_port)(struct uart_port *, struct serial_struct );
    76     int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
    77 #ifdef CONFIG_CONSOLE_POLL
    78     int (*poll_init)(struct uart_port *);
    79     void (*poll_put_char)(struct uart_port *, unsigned char);
    80     int (*poll_get_char)(struct uart_port *);
    81 #endif
    82 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    UART驱动编写人员需要实现uart_ops,因为uart_ops是最底层的UART驱动接口,是实实在在的和UART寄存器打交道的。关于uart_ops结构体中的这些函数的具体含义请参考Documentation/serial/driver这个文档

    UART驱动框架大概就是这些,接下来理论联系实际,看一下ST官方的UART驱动文件是如何编写的。

    STM32MP1 UART驱动分析

    UART的platform驱动框架

    打开stm32mp151.dtsi文件,找到USART3对应的子节点,子节点内容如下所示:

    usart3设备节点

    重点看一下第2行的compatible属性值为“st,stm32h7-uart”。在linux源码中搜索这个值即可找到对应的UART驱动文件,此文件为drivers/tty/serial/stm32-usart.c,在此文件中可以找到如下内容:

    示例代码 46.2.2 UART platform 驱动框架
    1218 static const struct of_device_id stm32_match[] = {
    1219     { .compatible = "st,stm32 uart", .data = &stm32f4_info},
    1220     { .compatible = "st,stm32f7 uart", .data = &stm32f7_info},
    1221     { .compatible = "st,stm32h7 uart", .data = &stm32h7_info},
    1222     {},
    1223 };
    ......
    1668 static struct platform_driver stm32_serial_driver = {
    1669     .probe = stm32_usart_serial_probe,
    1670     .remove = stm32_usart_serial_remove,
    1671     .driver = {
    1672         .name = DRIVER_NAME,
    1673         .pm = &stm32_serial_pm_ops,
    1674         .of_match_table = of_match_ptr(stm32_match),
    1675     },
    1676 };
    1677
    1678 static int __init stm32_usart_init(void)
    1679 {
    1680 static char banner[] __initdata = "STM32 USART driver initialized";
    1681     int ret;
    1682
    1683     pr_info("%s\n", banner);
    1684
    1685     ret = uart_register_driver(&stm32_usart_driver);
    1686     if (ret)
    1687         return ret;
    1688
    1689     ret = platform_driver_register(&stm32_serial_driver);
    1690     if (ret)
    1691         uart_unregister_driver(&stm32_usart_driver);
    1692
    1693     return ret;
    1694 }
    1695
    1696 static void __exit stm32_usart_exit(void)
    1697 {
    1698     platform_driver_unregister(&stm32_serial_driver);
    1699     uart_unregister_driver(&stm32_usart_driver);
    1700 }
    1701
    1702 module_init(stm32_usart_init);
    1703 module_exit(stm32_usart_exit);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    可以看出STM32MP1的UART本质上是一个platform驱动,第1218-1223行,设备树所
    使用的匹配表,第1221行的compatible属性值为“st,stm32h7-uart”。

    第1668-1676行,platform驱动框架结构体stm32_serial_driver。

    第1678-1694行,驱动入口函数,第1685行调用uart_register_driver函数向Linux内核注册uart_driver,在这里就是stm32_usart_driver。

    第1696-1700行,驱动出口函数,第1699行调用uart_unregister_driver函数注销掉前面注册的uart_driver,也就是stm32_usart_driver。

    uart_driver初始化

    在stm32_usart_init函数中向Linux内核注册了stm32_usart_driver,stm32_usart_driver就是uart_driver类型的结构体变量,stm32_usart_driver定义如下:

    stm32_usart_driver结构体

    uart_port初始化与添加

    当UART设备和驱动匹配成功以后stm32_usart_serial_probe函数就会执行,此函数的重点工作就是初始化uart_port,然后将其添加到对应的uart_driver中。在看stm32_usart_serial_probe函数之前先来看一下stm32_port结构体,stm32_port是ST为STM32MP1系列SOC定义的一个设备结构体,此结构体内部就包含了uart_port成员变量,stm32_port结构体内容如下所示(有
    缩减):

    stm32_port结构体

    第258行,uart_port结构体成员变量:port。

    第279行,这里定义了一个数组为stm32_ports,数组的类型为stm32_port结构体,数组的长度为8。这是因为STM32MP157最多只有8个串口,一个串口对应一个stm32_port,因此数组长度就是8。

    接下来看一下stm32_usart_serial_probe函数,函数内容如下:

    stm32_usart.c文件代码段

    第1312行,调用stm32_usart_of_get_port函数,它主要是负责配置stm32_ports数组。

    第1322行,调用stm32_usart_init_port函数,它主要是负责获取SOC UART外设首地址、
    中断号、注册中断函数同时还设置uart_ops为stm32_uart_ops,stm32_uart_ops就是STM32MP1最底层的驱动函数集合。

    第1374行,使用uart_add_one_port向uart_driver添加uart_port,在这个就是向stm32_usart_driver添加stm32port->port。

    接下来看一下stm32_usart_of_get_port函数,因为stm32_usart_serial_probe函数会调用此函数来获取串口信息,这些串口信息会放到示例代码46.2.4中的stm32_ports数组里面。stm32_usart_of_get_port函数源码如下:

    stm32_usart_of_get_port函数

    第1197行,通过of_alias_get_id函数从设备树的aliases节点中获取“serial”相关的ID。打开stm32mp157d-atk.dts文件,当前此文件里面的aliases节点内容如下图所示:

    aliases节点

    从上图可以看出,此时alases节点里面只有一个serial0,对应STM32MP157的uart4。所以stm32_usart_of_get_port函数只能得到uart4这一个串口的信息,如果要使用其他的串口,那就必须向alases节点里面按照如下格式添加对应的串口信息

    serialX=&串口名字;

    这个X表示0-7,那是因为STM32MP1的串口只有8个。&后面的串口名字一定要对应设备树中具体的串口名,比如usart3、uart5等

    第1206-1213行,获取对应的串口信息,然后保存到stm32_ports数组中,获取到的串口ID就是串口在数组中的索引。

    第1214行,返回得到的串口信息。

    接下来再来看一下stm32_usart_init_port函数,stm32_usart_serial_probe函数会调用此函数来初始化串口!函数源码如下所示:

    stm32_usart_init_port函数

    stm32_usart_init_port函数主要是负责获取SOC UART外设首地址、中断号、注册中断函数。重点是1149行设置uart_ops为stm32_uart_ops,stm32_uart_ops就是 STM32MP1最底层的驱动函数集合

    stm32_uart_ops结构体变量

    stm32_uart_ops就是uart_ops类型的结构体变量,保存了STM32MP1串口最底层的操作函
    数,stm32_uart_ops定义如下:

    stm32_uart_ops

    stm32_uart_ops中的函数基本都是和STM32MP1的UART寄存器打交道的,这里就不去详细的分析了。简单的了解了STM32MP1的UART驱动以后再来学习一下,如何驱动正点原子STM32MP1开发板上的USART3接口和UART5接口。

    硬件原理图分析

    本实验要用到的STM32MP1的USART3接口和UART5接口,USART3连接RS485和RS232的公头,UART5连接GPS和RS232的母头。依次来看一下这个两个串口的硬件原理图。

    RS232原理图

    RS232原理图如下图所示:

    RS232原理图

    正点原子STM32MP157开发板一共有2个RS232串口,上图中COM1是母头,COM2为公头,这两个RS232串口都是通过SP3232这个芯片来实现

    COM1母头连接到STM32MP1的UART5接口上,COM1和正点原子的ATK模块共用USART5,把JP5的1-3和2-4连接起来以后SP3232就和URAT5连接到一起了。 UART5_TX和UART5_RX分别接到了PB13和PB12这两个引脚上

    COM2公头连接到了STM32MP1的USART3接口上,COM2和RS485共用USART3,把JP4的3-5和4-6连接起来以后SP3232就和USRAT3连接到一起了USART3_TX和USART3_RX分别接到了PD8和PD9这两个引脚上

    RS485原理图

    RS485和COM2共用USART3,将上图中JP4的3-5和4-6连接起来,这时候RS485就连接到了USART3上。RS485原理图如下图所示:

    RS485原理图

    RS485采用SP3485这颗芯片来实现,RO为数据输出端,RI为数据输入端,RE是接收使能信号(低电平有效),DE是发送使能信号(高电平有效)。在上图中RE和DE经过一系列的电路,最终通过RS485_RX来控制,这样可以省掉一个RS485收发控制IO,将RS485完全当作一个串口来使用,方便写驱动。

    GPS原理图

    正点原子有一款GPS+北斗定位模块,型号为ATK1218-BD,STM32MP157开发板留出了这款GPS定位模块的接口,接口原理图如下图所示:

    ATK MODULE模块

    前面讲解RS232原理图的时候说了,COM1和正点原子的ATK模块共用USART5接口,正点原子的ATK1218-BD这个模块用的就是ATK模块接口。如果要使用GPS模块,就要将RS232原理图中JP5的3-5和4-6连接起来。这样GPS模块就连接到了USART5上,USART5驱动成功以后就可以直接读取GPS模块数据了。从上图可以看出,ATK模块还有两个引脚GBC_KEY和GBC_LED分别连接到了STM32MP157的PC13和PI8上,这两个引脚是给其他模块准备的,GPS模块并没有用到。

    RS232驱动编写

    前面已经说过了,STM32MP1的UART驱动ST已经编写好了,所以不需要自行编写。要做的就是在设备树中添加USART3和UART5对应的设备节点即可。打开stm32mp157d-atk.dts文件,因为usart3和uasrt5的节点在stm32mp151.dtsi已经存在了,只要在stm32mp157d-atk.dts文件里面向这些节点追加一些内容即可,追加步骤如下:

    添加usart3和uart5引脚信息

    先在stm32mp15-pinctrl.dtsi文件看下没有usart3和uart5的引脚配置,以及引脚配置是
    否是开发板对应的。默认情况下stm32mp15-pinctrl.dtsi里面是有usart3的引脚配置,但是
    不是正点原子开发板所使用的PD8和PD9,所以不能使用。直接在stm32mp15-pinctrl.dtsi里面添加usart3和uart5这两个串口对应的引脚信息,内容如下:

    示例代码 46.4.1 要追加的 pinmux 配置
    1 usart3_pins_c: usart3-2 {
    2     pins1 {
    3         pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */
    4         bias-disable;
    5         drive-push-pull;
    6         slew-rate = <0>;
    7     };
    8     pins2 {
    9         pinmux = <STM32_PINMUX('D', 9, AF7)>; /* USARTS_RX */
    10         bias-disable;
    11     };
    12 };
    13
    14 uart5_pins_a: uart5-0 {
    15     pins1 {
    16         pinmux = <STM32_PINMUX('B', 13, AF14)>; /* UART5_TX */
    17         bias-disable;
    18         drive-push-pull;
    19         slew-rate = <0>;
    20     };
    21     pins2 {
    22         pinmux = <STM32_PINMUX('B', 12, AF14)>; /* UART5_RX */
    23         bias-disable;
    24     };
    25 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    示例代码46.4.1里配置了两个pinmux分别为usart3_pins_c和uart5_pins_a。稍后向usart3和uart5中追加内容的时候就会用到这两个节点。

    向usart3和uart5节点追加内容

    还是在stm32mp157d-atk.dts文件中,在不是根节点下追加如下代码:

    示例代码 46.4.2 串口的节点
    1  &usart3 { 
    2      pinctrl-names = "default"; 
    3      pinctrl-0 = <&usart3_pins_c>; 
    4      status = "okay"; 
    5  }; 
    6 
    7  &uart5 { 
    8     pinctrl-names = "default";
    9       pinctrl-0 = <&uart5_pins_a>; 
    10     status = "okay"; 
    11 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这里追加了两个串口,分别为uart5和usart3,追加的内容很简单都是使用了刚刚添加的pinmux配置。把status属性原来为“disabled”改为“okay”。

    设置串口别名

    之前UART驱动分析已经知道,驱动会读取aliases节点,添加的别名如下所示:

    示例代码 46.4.3 串口的别名
    1 aliases {
    2     serial0 = &uart4;
    3     serial1 = &uart5;
    4     serial2 = &usart3;
    5 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    serial0是uart4的别名,表示在系统启动生成一个名为“/dev/ttySTM0”的设备文件serial1就会生成“/dev/ttySTM1”如此类推,最多8个。serial0就是调试串口。

    修改完成以后重新编译设备树并使用新的设备树启动Linux,如果设备树修改成功的话系统启动以后就会有如下图所示设备文件:

    串口设备文件

    ttySTM0为serial0,对应uart4;ttySTM1为serial1,对应uart5;ttySTM2为serial2,对应usart3。

    移植minicom

    minicom类似常用的串口调试助手,是Linux下很常用的一个串口工具,将minicom移植到开发板中,这样就可以借助minicom对串口进行读写操作

    buildroot已经集成了minicom,所以只需要重新配置buildroot,使能minicom即可。首先跳转到buildroot的源码目录下,打开buildroot的图形化配置界面里配置以下选项:

    -> Target packages
    -> Hardware handling
    [*] minicom

    配置如下图所示:

    使能minicom

    保存buildroot的配置文件,输入命令“sudo make”重新编译文件系统。编译的时候要联网,因为buildroot在编译的时候需要从网上下载 minicom源码。当编译完成后,进入output/images目录,运行以下命令把文件系统替换进去:

    cd output/images/ //进入到 output/images目录
    sudo tar -axvf rootfs.tar -C /home/zuozhongkai/linux/nfs/rootfs //解压到 nfsroot目录

    上述命令将buildroot中output/images/rootfs.tar这个压缩包解压到/home/zuozhongkai/linux/nfs/rootfs这个目录中,这个目录就是当前nfsroot目录,需要根据自己的实际情况解压到对应的目录文件中。

    完成以后重启开发板!重启以后在开发板中输入“minicom -v”来查看minicom工作是否正常,结果如下图所示:

    minicom版本号

    从上图可以看出,此时minicom版本号为2.7.90,minicom版本号查看正常。输入如下命令打开minicom配置界面:

    minicom -s

    此时minicom配置界面就可以打开了,如下图所示:

    minicom配置界面

    如果出现如上图所示的界面,那么minicom就已经能够正常工作了。

    RS232驱动测试

    RS232连接设置

    在测试之前要先将STM32MP1开发板的RS232接口与电脑连接起来,正点原子STM32MP1开发板上两个RS232接口如下图所示:

    RS232接口

    从上图中可以看出,正点原子开发板上有2个 RS232接口。这里要注意的是这两个RS232接口一个为公头,一个为母头,方便外接自己的设备。上图中左边的COM2为公头,可以通过JP4跳接到USART3上。右边的COM1为母头,可以通过JP5跳接到UART5上。本实验使用右边的COM1,所以需要将JP5的两个跳线帽接到上方,也就是将UART5与COM1连接起来

    跳线帽设置好以后使用RS232线将开发板与电脑连接起来,这里建议使用USB转DB9(RS232)数据线,比如正点原子的CH340方案的USB转DB9数据线,如下图所示:

    USB转DB9数据线

    上图中所示的数据线是带有CH340芯片的,因此当连接到电脑以后就会出现一个COM口,这个COM口就是要使用的COM口。比如在正点原子教程中的电脑上就是COM11,在MobaXterm上新建一个连接,串口为COM11,波特率为115200。

    minicom设置

    在开发板中输入“minicom -s”,打开minicom配置界面,选中“Serial port setup”,如下图所示:

    选中串口设置项

    选中“Serial port setup”点击回车,进入设置菜单,如下图所示:

    串口设置项

    上图中有14个设置项目,分别对应A、B……N,比如第一个是选中串口UART5的串口文件为/dev/ttySTM1(因为设备别名serial1=&UART5),因此串口设置要设置为/dev/ttySTM1。设置方法就是按下键盘上的‘A’,然后输入“/dev/ttySTM1”即可,如下图所示:

    串口设置文件设置

    设置完以后按下回车键确认,确认完以后就可以设置其他的配置项。比如‘E’设置波特率、数据位和停止位的、‘F’设置硬件流控的,设置方法都一样,设置完以后如下图所示:

    UART5设置

    都设置完成以后按下回车键确认并退出,这时候会退回到之前的界面,按下ESC键退出配置界面,退出以后如下图所示:

    minicom串口界面
    上图就是串口调试界面,可以看出当前的串口文件为/dev/ttySTM1,按下CTRL-A,然后再按下Z就可以打开minicom帮助信息界面,如下图所示:

    minicom帮助信息界面

    从上图可以看出,minicom有很多快捷键,本实验打开minicom的回显功能,回显功能配置项为“local Echo on/off…E”,因此按下E即可打开/关闭回显功能。

    RS232收发测试

    发送测试

    首先测试开发板通过UART5向电脑发送数据的功能,需要打开minicom的回显功能(不打开也可以,但是在minicom中看不到自己输入的内容),回显功能打开以后输入“AAAA”,如下图所示:

    通过UART5向电脑发送“AAAA”

    上图中的“AAAA”就是开发板通过UART5向电脑发送的数据,那么电脑的COM11就会接收到“AAAA”,MobaXterm中COM11收到的数据如下图所示:

    电脑接收到开发板发送的数据

    可以看出,开发板通过UART3向电脑发送数据正常,接下来测试开发板数据接收功能。

    接收测试

    接下来测试开发板的UART5接收功能,同样的,要先打开MobaXterm上COM11的本地回显,正点原子教程里面没有指导该功能,但是开发板是可以接收到在COM11上输入的字符。比如,这里输入‘123456’,此时开发板接收到的数据如下图所示:

    开发板接收到发送的数据

    UART5收发测试都没有问题,说明UART5驱动工作正常。如果要退出minicom,在minicom通信界面按下CRTL+A,然后按下X来关闭minicom。

    RS485测试

    前面已经说过了,STM32MP1开发板上的RS485接口连接到了USART3上,因此本质上就是个串口。 RS232实验已经将USART3的驱动编写好了,所以RS485实验就不需要编写任何驱动程序,可以直接使用minicom来进行测试

    RS485连接设置

    首先是设置JP4跳线帽,将1-3、2-4连接起来, RS485接口如下图所示:

    RS485接口设置

    一个板子是不能进行RS485通信测试的,还需要另一个RS485设备,比如另外一块STM32MP1开发板。这里可以使用正点原子出品的USB三合一串口转换器,支持USB转TTL、RS232和RS485,如下图所示:

    正点原子USB三合一川口转换器

    使用杜邦线将USB串口转换器的RS485接口和STM32MP157开发板的RS485连接起来,A接A,B接B,不能接错了!连接完成以后如下图所示:

    串口转换器和开发板RS485连接示意图

    串口转换器通过USB线连接到电脑上,用的是 CH340版本的,因此就不需要安装驱动,如果使用的是FT232版本的就需要安装相应的驱动。连接成功以后电脑就会有相应的COM口,比如教程中电脑上就是COM6,接下来就是测试。

    RS485收发测试

    RS485的测试和RS232一模一样!电脑上USB多合一转换器对应COM12。因为MobaXterm没有找到回显设置,因此这里为了方便观察,USB多合一转换器使用SecureCRT这个终端软件。使用SecureCRT创建一个COM12的连接,开发板使用USART3,对应的串口设备文件为/dev/ttySTM2,因此开发板使用minicom创建一个/dev/ttySTM2的串口连接。串口波特率都选择115200 8位数据位,1位停止位,关闭硬件和软件流控

    RS485发送测试

    首先测试开发板通过RS485发送数据,设置好minicom以后,同样输入“AAAA”,也就是通过RS485向电脑发送一串“AAAA”。如果RS485驱动工作正常的话,那么电脑就会介绍到开发板发送过来的“AAAA”,如下图所示:

    RS485数据发送测试

    从上图可以看出开发板通过RS485向电脑发送“AAAA”成功,说明RS485数据发送正常。

    RS485接收测试

    接下来测试一下RS485数据接收,电脑通过RS485向开发板发送“BBBB”,然后观察minicom是否能接收到“BBBB”。结果如下图所示:

    RS485数据接收测试

    从上图中可以看出开发板接收到电脑通过RS485发送过来的“BBBB”,说明RS485数据接收正常。

    GPS测试

    GPS连接设置

    GPS模块大多数都是串口输出的,这里以正点原子出品的ATK118-BD模块为例,这是一款GSP+北斗的定位模块,如下图所示:

    正点原子ATK1218-BD定位模块

    首先要设置STM32MP1开发板上的JP5跳线帽,将UART5与ATK模块接口上的串口连接起来,如下图所示:

    UART5跳线帽连到GPS

    此时UART5_TX和UART5_RX已经连接到了开发板上的ATK MODULE上,直接将ATK1218-BD模块插到开发板上的ATK MODULE接口即可,开发板上的ATK MODULE接口是6脚的,而 ATK1218-BD模块是5脚的,因此需要靠下插(VCC对应 5V)!然后GPS需要接上天线,天线的接收头一定要放到户外,因此室内一般是没有GPS信号的。连接完成以后如下图所示:

    GPS模块连接示意图

    GPS数据接收测试

    GPS都是被动接收定位数据的,模块接收定位卫星数据,然后计算出位置信息通过串口输出。所以要先设置minicom,UART5对应/dev/ttySTM1,串口设置要求如下:

    1. 波特率设置为38400,因为正点原子的ATK1218-BD模块默认波特率就是38400。
    2. 8位数据位,1位停止位。
    3. 关闭硬件和软件流控。

    设置好以后如下图所示:

    串口设置

    设置好以后就可以静静的等待GPS数据输出,GPS模块第一次启动可能需要几分钟搜星,
    等搜到卫星以后才会有定位数据输出。搜到卫星以后GPS模块输出的定位数据如下图所示:

    GPS数据

    总结

    这一篇实验,其实就是对于STM32MP157开发板的串口的使用,这里驱动也是ST官方已经写好的,我们需要做的就是直接在pinctrl加节点写好GPIO的复用,然后在设备树里面添加对应的串口节点,并关联上pinctrl。还有就是在buildroot里面要配置一下minicom这个串口调试,方便测试串口。

    之后的测试,RS485个人觉得可以关注一下,至于RS232可以看到其实现在用的已经很少了,就直接都是RS232转串口就可以了,比如精英板就是串口直接Type-C了,不会再用RS232。

  • 相关阅读:
    必背积分表
    DSPE-PEG-MMPs; PEG-MMPs-DSPE ;聚乙二醇-基质金属蛋白酶-磷脂 ;磷脂-聚乙二醇-基质金属蛋白酶
    Mybatis总结--传参二
    Linux--进程创建(fork)-退出--孤儿进程
    uniapp点击事件在小程序中无法传参
    clickHouse基础语法
    设置docker启动项目
    第3阶段-运维线上实战-3.2企业级nginx使用
    好玩的调度技术
    transformer系列2---transformer架构详细解析
  • 原文地址:https://blog.csdn.net/xhj12138/article/details/134071235