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

news2024/9/24 4:26:29

串口是很常用的一个外设,在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) 

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

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

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

void uart_unregister_driver(struct uart_driver *uart) 

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

  • 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) 

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

  • 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) 

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

  • 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 };

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);

可以看出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 };

示例代码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 };

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

设置串口别名

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

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

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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1143273.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RZMO-A-030/210、HZMO-A-030/315电控比例压力阀控制器

RZMO-A-030/50、RZMO-A-030/210、RZMO-A-030/350、RZMO-A-030/100、RZMO-A-030/315、HZMO-A-030/50、HZMO-A-030/210、HZMO-A-030/350、HZMO-A-030/100、HZMO-A-030/315滑阀型先导式数字型比例溢流阀&#xff0c;用于压力开环控制&#xff0c;可提供板式或叠加式安装。A型&…

web - 前段三剑客

目录 前言 一. HTML 常用标签演示 图片标签 ​编辑 表格标签(重点) ​编辑 表单标签 (重点) 布局标签 其余标签 二. CSS 2.1 . css的三种引入方式 2.2 . 三大选择器 2.3 . css样式 - 浮动 2.4 . css样式 - 定位 1.static 2.absolute(绝对位置) 3.relavite(相…

Binder机制总结笔记

Binder机制总结笔记 什么是Binder&#xff1f; Binder的Android特有的IPC通信机制。Android的四大组件Activity、Service、Broadcast、ContentProvider&#xff0c;不同的App等都运行在不同的进程内&#xff0c;他们之间的通信都需要依靠Binder完成。因此Binder在整个Android系…

好用的ps滤镜插件Portraiture2024

Photoshop 是最常用到的综合性的设计工具&#xff0c;虽然PS一直在迭代升级&#xff0c;但是在细节功能上&#xff0c;PS总是无法完全满足全部所有的用户需求&#xff0c;今天coco玛奇朵推荐一个个截至目前最受欢迎的免费的PS插件&#xff0c;有了这些功能扩展的插件后PS如虎添…

OpenCV C++ 图像处理实战 ——《缺陷检测》

OpenCV C++ 图像处理实战 ——《缺陷检测》 一、结果演示二、缺陷检测算法2.1、多元模板图像2.2、训练差异模型三、图像配准3.1 功能源码3.1 功能效果四、多元模板图像4.1 功能源码五、缺陷检测5.1 功能源码六、源码测试图像下载总结一、结果演示

拓世大模型 | 立足行业所需,发力终端,缔造智能无限可能

蒸汽机的发明为人类工业革命揭开序幕&#xff0c;引领了近现代产业变革。众所周知&#xff0c;而今AI技术的革命性突破&#xff0c;站在了时代舞台的中心&#xff0c;特别是大模型的崛起&#xff0c;无疑是第四次产业革命的焦点&#xff0c;它的地位可与当年的“蒸汽机”相提并…

AndroidSDK下载及安装(Windows)

下载地址&#xff1a;https://www.androiddevtools.cn/ 找到SDK工具并下载安装 都是傻瓜式一键安装 除了注意安装路径应避免选择中文或特殊字符路径&#xff0c;应该没什么大问题。 下载安装Android SDK Android SDK Tools安装后&#xff0c;启动SDK Manager.exe&#xff1a;…

综合OA管理系统源码 OA系统源码

综合OA管理系统源码 OA系统源码 功能介绍&#xff1a; 编号&#xff1a;LQ10 一&#xff1a;系统管理 系统配置&#xff0c;功能模块&#xff0c;功能节点&#xff0c;权限角色&#xff0c;操作日志&#xff0c;备份数据&#xff0c;还原数据 二&#xff1a;基础数据 审批…

Linux-组管理和权限管理

一、组管理—基本介绍 在linux中的每个用户必须属于一个组&#xff0c;不能独立于组外。在linux中每个文件有所有者、所在组、其它组的概念。 1)所有者 2)所在组 3)其它组 4)改变用户所在的组 二、组管理—文件/目录所有者 1、查看文件或者目录的所有者和所在组的指令 所有…

文件加密,数据防泄密软件

文件加密和数据防泄密软件成为了保护信息安全的重要工具&#xff0c;它们可以有效地防止敏感数据的泄露和非法访问。 发展历史 文件加密和数据防泄密软件的发展历程可以追溯到上世纪90年代&#xff0c;当时随着互联网的普及和信息技术的不断发展&#xff0c;人们开始意识到信息…

考虑温度影响的vumat子程序在木材受火后强度分析中的应用

木结构在火灾作用下&#xff0c;木材的化学成分及物理特性会发生复杂的变化&#xff0c;导致其力学性能的改变&#xff0c;木构件承载能力降低。本文编写了考虑温度影响的木材本构vumat子程序&#xff0c;并对子程序的正确性进行了验证。 木材是一种复杂的各向异性复合材料&am…

JavaScript综合案例五

目录 一、实战案例&#xff1a;轮播图案例-完整版 代码实现 二、实战案例&#xff1a;tab栏切换 1.普通版本 代码实现 2.事件委托版本 代码实现 三、实战案例&#xff1a;表单全选反选 代码实现 四、实战案例&#xff1a;哔哩哔哩导航滑动 代码实现 五、实战案例&am…

win10安装Tensorflow(2.10-)使用最新cuda(12+),cudnn(8.9+)

# tensorflow在2.11版本后不再支持原生windows的GPU&#xff1a; https://blog.tensorflow.org/2022/09/whats-new-in-tensorflow-210.html# 1、首先&#xff0c;在windows安装好最新的GPU环境&#xff1a; https://blog.csdn.net/sinat_20174131/article/details/121781420?s…

可以实时监控屏幕的电脑监控软件

电脑已经成为了人们工作和生活不可或缺的工具。然而&#xff0c;这也带来了诸多安全问题。一些人可能会利用电脑进行不恰当的操作&#xff0c;如聊天、游戏、观看视频等&#xff0c;甚至会泄露公司的商业机密。 电脑监控软件的定义 电脑监控软件是一种用于监控电脑使用情况的软…

【CSDN 每日一练 ★★☆】【数学】字符串相乘

###【CSDN Daily Practice】【数学】字符串相乘 数学 模拟 题目 给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 示例 示例 1: 输入: num1 “2”, num2 “3” 输出: “6” 示例 2: …

【SOPHON】算能盒子SE-16的C++模型转换

目录 ONNX转MLIR指定模型的预处理过程转换结果 本文以 arcface 为例, 介绍如何编译迁移一个onnx模型至TPU平台运行。 有疑问具体可参考 TPU-MLIR ONNX转MLIR 如果模型是图片输入, 在转模型之前我们需要了解模型的预处理。如果模型用预处理后的npz文件做输入, 则不需要考虑预处…

01. 嵌入式与人工智能是如何结合的?

CPU是Arm A57的 GPU是128cuda核 一.小车跟踪的需求和设计方法 比如有一个小车跟踪的项目。 需求是&#xff1a;小车识别出罪犯&#xff0c;然后去跟踪他。方法&#xff1a;摄像头采集到人之后传入到开发板&#xff0c;内部做一下识别&#xff0c;然后控制小车去跟随。在人工智…

Linux ———— 管理磁盘

&#xff08;一&#xff09;MBR硬盘与GPT硬盘 硬盘按分区表的格式可以分为MBR硬盘与GPT硬盘两种硬盘格式。 MBR 硬盘&#xff1a;使用的是旧的传统硬盘分区表格式&#xff0c;其硬盘分区表存储在MBR(Master Boot Record&#xff0c;主引导区记录&#xff09;内。MBR位于…

为什么引入偏向锁、轻量级锁,介绍下升级流程

Synchronized Synchronized 在 jdk1.6 版本之前&#xff0c;是通过重量级锁的方式来实现线程之间锁的竞争。之所以称它为重量级锁&#xff0c;是因为它的底层底层依赖操作系统的 Mutex Lock 来实现互斥功能。&#xff08;如图&#xff09;Mutex 是系统方法&#xff0c;由于权限…