引言
- 部分GPS模组使用的是串口,对接GPS模块,调通串口就可以了
- 如果使用的是GPS芯片,接口可能是I2C、SPI、UART等,就需要对接
- 我这里单独注册一个gps设备,用于对接各类接口的GPS芯片,GPS对上层来讲,就算是一个字符设备而已
GPS模块验证
- 硬件使用:【ART-Pi】,当然其他的STM32相关的MCU,依旧可以。为何使用ART-Pi,因为这是我的验证环境
- 我使用的是UBLOX GPS模组:这个模组是串口的,对外4根线:VCC(+3V~+5V,我使用+3.3V),GND,RX、TX
- 首先让GPS模组先能定到位,电脑使用USB转串口,能获取到GPS模组吐出的数据
- 验证下来,串口的收发要正确,尤其是USB转串口能配置电平的,配置为+3.3V的。这个GPS模组,耗电较大,大概有70mA左右的电流,再就是室内定位很难,使用GPS长的天线,放在窗户旁边,注意GPS天线的朝向,朝外效果会更好。
开发环境
- GPS模组验证OK,就要使用【ART-Pi】串口接收解析数据了
- 查看ART-Pi的原理图,找个合适的串口,最终选择了UART6(USART6)
config BSP_USING_UART6
bool "Enable UART6"
select RT_USING_SERIAL
default n
- 配置UART6的引脚,可以使用:STM32CubeMX图形配置好,生成,然后更新到工程的
stm32h7xx_hal_msp.c 文件 void HAL_UART_MspInit(UART_HandleTypeDef* huart) 函数增加:
else if(huart->Instance==USART6)
{
__HAL_RCC_USART6_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_USART6;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) 增加
else if(huart->Instance==USART6)
{
__HAL_RCC_USART6_CLK_DISABLE();
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_7|GPIO_PIN_6);
}
- 配置 UART6的时钟,这里修改:board.c 中的:
system_clock_config ,增加UART6相关的:
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC|RCC_PERIPHCLK_USART3
|RCC_PERIPHCLK_UART4|RCC_PERIPHCLK_SPI4
|RCC_PERIPHCLK_UART5|RCC_PERIPHCLK_USART6
|RCC_PERIPHCLK_SPI1|RCC_PERIPHCLK_SDMMC
|RCC_PERIPHCLK_ADC|RCC_PERIPHCLK_USB
|RCC_PERIPHCLK_FMC;
PeriphClkInitStruct.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
软件调试
- menuconfig 配置并使能UART6,
scons --target=mdk5 生成Keil MDK5工程,然后编译下载 - 没用,还需要开启串口做GPS的接收操作
- 测试一下uart6是否正常的工作:
#include <rtthread.h>
#ifndef GPS_UART_DEVICE_NAME
#define GPS_UART_DEVICE_NAME "uart6"
#endif
#define DBG_TAG "gps.uart"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
static rt_device_t gps_uart_dev = RT_NULL;
static rt_thread_t gps_uart_thread = RT_NULL;
static rt_err_t gps_uart_rx_ind(rt_device_t dev, rt_size_t size)
{
LOG_E("%s", __func__);
return RT_EOK;
}
rt_err_t gps_uart_open(void)
{
gps_uart_dev = rt_device_find(GPS_UART_DEVICE_NAME);
if (gps_uart_dev != RT_NULL)
{
rt_device_open(gps_uart_dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
rt_device_set_rx_indicate(gps_uart_dev, gps_uart_rx_ind);
return RT_EOK;
}
else
{
LOG_E("%s : gps uart error!", __func__);
return -RT_ERROR;
}
}
void gps_uart_thread_entry(void *param)
{
rt_thread_mdelay(5000);
gps_uart_open();
while (1)
{
rt_thread_mdelay(5000);
rt_device_write(gps_uart_dev, 0, "gps uart ok", rt_strlen("gps uart ok"));
}
}
int gps_uart_test(void)
{
if (gps_uart_thread != RT_NULL)
{
LOG_I("%s gps uart thread already!", __func__);
return -RT_ERROR;
}
gps_uart_thread = rt_thread_create("gps_uart", gps_uart_thread_entry, RT_NULL,
1024, 20, 30);
if (gps_uart_thread != RT_NULL)
{
rt_thread_startup(gps_uart_thread);
LOG_D("%s gps uart thread ok!", __func__);
}
else
{
LOG_E("%s gps uart thread failed!", __func__);
}
return 0;
}
MSH_CMD_EXPORT(gps_uart_test, gps_uart_test);
串口需要使能【接收中断】,需要在open 时,增加标志位 : RT_DEVICE_FLAG_INT_RX rt_device_open(gps_uart_dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX); 这样,串口驱动才会配置串口接收中断,接收数据后,会调用: rt_device_set_rx_indicate(gps_uart_dev, gps_uart_rx_ind); 设置的回调函数:gps_uart_rx_ind ,我开始没在意,发现串口能发送,不能接收,我以为引脚配 置错了,后来软件一步步调试,发现忘了这个标志位:RT_DEVICE_FLAG_INT_RX
#include "drv_gps.h"
#include "board.h"
#ifndef BSP_GPS_DEVICE_NAME
#define BSP_GPS_DEVICE_NAME "gps"
#endif
#ifndef GPS_UART_DEVICE_NAME
#define GPS_UART_DEVICE_NAME "uart6"
#endif
#define GPS_UART_BAUDRATE BAUD_RATE_9600
static struct rt_device _gps_dev;
static rt_device_t gps_uart_dev = RT_NULL;
static rt_bool_t gps_uart_open_flag = RT_FALSE;
static rt_err_t _gps_dev_init(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t gps_uart_rx_ind(rt_device_t dev, rt_size_t size)
{
RT_ASSERT(dev != RT_NULL);
if (_gps_dev.rx_indicate != RT_NULL)
{
_gps_dev.rx_indicate(&_gps_dev, size);
}
return RT_EOK;
}
static rt_err_t _gps_dev_open(rt_device_t dev, rt_uint16_t oflag)
{
struct serial_configure gps_uart_config = RT_SERIAL_CONFIG_DEFAULT;
if (dev == RT_NULL)
return -RT_ERROR;
gps_uart_dev = rt_device_find(GPS_UART_DEVICE_NAME);
if (gps_uart_dev != RT_NULL)
{
if (gps_uart_open_flag == RT_FALSE)
{
gps_uart_config.baud_rate = GPS_UART_BAUDRATE;
rt_device_control(gps_uart_dev, RT_DEVICE_CTRL_CONFIG, &gps_uart_config);
rt_device_open(gps_uart_dev, oflag);
rt_device_set_rx_indicate(gps_uart_dev, gps_uart_rx_ind);
gps_uart_open_flag = RT_TRUE;
}
}
return RT_EOK;
}
static rt_err_t _gps_dev_close(rt_device_t dev)
{
rt_err_t ret = RT_EOK;
if (gps_uart_open_flag == RT_TRUE)
{
ret = rt_device_close(gps_uart_dev);
gps_uart_open_flag = RT_FALSE;
}
return ret;
}
rt_size_t _gps_dev_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
return rt_device_read(gps_uart_dev, pos, buffer, size);
}
rt_size_t _gps_dev_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
return rt_device_write(gps_uart_dev, pos, buffer, size);
}
static rt_err_t _gps_dev_control(rt_device_t dev, int cmd, void *args)
{
if (dev == RT_NULL)
return -RT_ERROR;
switch (cmd)
{
default:
break;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops gps_dev_ops =
{
_gps_dev_init,
_gps_dev_open,
_gps_dev_close,
_gps_dev_read,
_gps_dev_write,
_gps_dev_control
};
#endif
static int gps_device_register(const char *name, void *user_data)
{
_gps_dev.type = RT_Device_Class_Char;
_gps_dev.rx_indicate = RT_NULL;
_gps_dev.tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
_gps_dev.ops = &gps_dev_ops;
#else
_gps_dev.init = _gps_dev_init;
_gps_dev.open = _gps_dev_open;
_gps_dev.close = _gps_dev_close;
_gps_dev.read = _gps_dev_read;
_gps_dev.write = _gps_dev_write;
_gps_dev.control = _gps_dev_control;
#endif
_gps_dev.user_data = user_data;
rt_device_register(&_gps_dev, name, RT_DEVICE_FLAG_RDWR);
return 0;
}
int gps_device_init(void)
{
return gps_device_register(BSP_GPS_DEVICE_NAME, RT_NULL);
}
INIT_BOARD_EXPORT(gps_device_init);
- 这里使用【套娃】方式,注册一个gps 设备,实际调用:uart6 串口设备
- 【小结2】GPS串口波特率的调整方法,默认初始化为:115200,这里GPS模块默认是:9600,更改的方法如下
struct serial_configure gps_uart_config = RT_SERIAL_CONFIG_DEFAULT;
gps_uart_config.baud_rate = GPS_UART_BAUDRATE;
rt_device_control(gps_uart_dev, RT_DEVICE_CTRL_CONFIG, &gps_uart_config);
RT_DEVICE_CTRL_CONFIG control命令,最终会调用drv_usart.c 中的 configure函数,重新配置串口
调试
- 底层的UART6 已经搭建好,上层只需要做好接收,并解析GPS接收的数据即可。
- 上层的接收,可以参考:虚拟GPS设备的实现那篇文章
小结
- 熟悉了一下uart串口的接收配置、波特率设置方法
- 熟悉了GPS的调试
|