STM32模拟GPS输出PPS、GPRMC与VLP16时钟同步

1.VLP16与GPS相关的管脚:

  1. GPS-RECEIVE
    接收GPS的GPRMC语句,注意是RS232电平(high 3-15V,low 1.2V以下),如TTL电平输出需要进行信号反转,没有RS232芯片的可以使用反相电路。NPN电平反向
  2. GPS PULSE
    接收GPS的PPS信号,上升沿触发持续10us-200ms,与下一个PPS要大于300ms以上
    在这里插入图片描述
  3. GROUND
    信号地

2.利用GPS信息完成时间同步 TimeSynchronization

  1. VLP16的TOH时间戳
    VLP16有一个用于记录着TOH(top of hour)的定时器,默认根据VLP16的内部时钟自加累积,当收到一个有效的PPS信号时,会把每一个PPS的上升沿与TOH对齐,在data/position数据包里都会存在4个Byte的TOH时间戳。TOH的结构分为’TOH number of minutes and seconds‘和 ’sub-second‘,时间戳分为秒和微秒。这个4Byte能记录的最大时间是3,599,999,999μs,也就是最多能记录一小时的时间戳。在这里插入图片描述
  2. TOH时间戳结构
    sub-second:无PPS时定时器使用内部时钟给sub-second赋值,当检测到有效的PPS信号时,sub-second会在每一秒的PPS上升沿到来时进行调整。
    minutes and seconds:当接受到有效GPRMS数据时,由GPRMS里的时间戳进行调整,如果没有收到GPRMS时也会每秒自加。
    注意:当GPS突然显示无效定位时,此时由VLP16内部时钟接管驱动sub-second,就会出现一些偏移量。
  3. GPS GPRMC含义
    实例:GPRMC,161050.00,A,3042.94310,N,10358.95564,E,0.057,020513,A*7A
    $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
    <1> UTC时间,hhmmss.sss(时分秒.毫秒)格式
    <2> 定位状态,A=有效定位,V=无效定位
    <3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
    <4> 纬度半球N(北半球)或S(南半球)
    <5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)
    <6> 经度半球E(东经)或W(西经)
    <7> 地面速率(000.0~999.9节,前面的0也将被传输)
    <8> 地面航向(000.0~359.9度,以正北为参考基准,前面的0也将被传输)
    <9> UTC日期,ddmmyy(日月年)格式
    <10> 磁偏角(000.0~180.0度,前面的0也将被传输)
    <11> 磁偏角方向,E(东)或W(西)
    <12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
  4. web配置参数含义
    – PPS:Lock
    当VLP16检测到一个稳定持续的PPS信号,会在web页面显示“PPS: Locked”以及在 position packet at offset 0xF4的位置写入0x02。
    – PPS Qualifier:Require GPS Receiver Valid
    On:VLP16在使用PPS上升沿给sub-second调整时,首先验证GPS是否提供了有效的位置信息,检测定位状态(A=有效定位,V=无效定位)是否为A
    – PPS Qualifier:Require PPS Lock
    On:VLP16将会使用Delay值的周期去鉴定PPS信号是否有效
    OFF:VLP16会有两个周期去鉴定PPS信号是否有效
    – Delay值
    单位秒,值0-65535,默认5秒,它的作用是有一个{Delay}秒的滚动窗口不断地去检测PPS的有效性,在开始检测时PPS被认定为不稳定模式(free-running),由内部时钟驱动sub-second,当检测PPS稳定后由PPS的上升沿驱动sub-second
    – GPS Qualifier
    On:当GPS有效时,将会由接收的GPRMC来调整TOH的minutes and seconds值
    OFF:将会由接收的GPRMC来调整TOH的minutes and seconds值,不会去检测GPS定位状态(A=有效定位,V=无效定位)
    在这里插入图片描述
    在这里插入图片描述

3.查找同步关系

  1. STM32模拟GPS发送消息
    通过STM32定时器从GPIO输出1HZ的PPS脉冲,示波器检测GPIO的上升沿jitter抖动在5us左右。从PPS上升沿开始,200ms之后发送GPRMC数据,在264ms之后数据传速完毕。
    在这里插入图片描述
  2. 抓取数据计算时间同步关系
    在这里插入图片描述
    – 上图wireshark抓取几秒的位置包,每秒内的位置包大概100多包,左侧红线中4Byte为TOH时间戳(0x96 84 77 27->2525.263655s)
    – 右侧红线是stm32模拟发送的GPRMC时间004205(00时42分05秒->2525s),与TOH的秒级时间对应
    – 下表是通过记录每次GPRMC改变时的集合:
      1.秒级:TOH的秒级部分是与GPRMC的秒级时间相同
      2.sub秒级:TOH的sub秒级部分大概都在264ms左右,对比示波器从PPS上升沿到GPRMC数据发完的时间264ms左右。VLP16所发送的UDP位置包中,每当GPRMC更新时,根据TOH时间戳往前(sub-second)的时间就是上一次PPS所到达的时间,从而使VLP16的时间与Stm32的时间建立时间同步关系。
    在这里插入图片描述

4.修改ROS代码

  1. velodyne_driver下的gps_time_为是否用GPS信息,同时需要修改velodyne_pointcloud的GPS_TIME为true,然后catkin_make运行
    在这里插入图片描述
    在这里插入图片描述

结论

  1. 关系:根据header的时间戳
    在这里插入图片描述
以下是基于STM32GPS模块实现时间同步和PPS检测的示例代码: 首先,需要配置STM32的UART和外部中断来接收GPS模块的NMEA协议数据和PPS信号。 ```c #include "stm32f4xx.h" #include "stdio.h" /* GPS串口定义 */ #define GPS_USART USART1 #define GPS_USART_CLK RCC_APB2Periph_USART1 #define GPS_USART_CLK_INIT RCC_APB2PeriphClockCmd #define GPS_USART_IRQn USART1_IRQn #define GPS_USART_IRQHandler USART1_IRQHandler #define GPS_USART_BAUDRATE 9600 /* GPS定位信息结构体定义 */ typedef struct { float latitude; // 纬度 float longitude; // 经度 float altitude; // 海拔高度 float speed; // 速度 float course; // 航向 int date; // 日期(YYYYMMDD) int time; // 时间(HHMMSS.SSS) } gps_info_t; /* GPS定位信息变量定义 */ gps_info_t gps_info = {0}; /* PPS信号检测变量定义 */ volatile uint32_t pps_count = 0; volatile uint32_t last_pps_time = 0; volatile uint8_t is_pps_detected = 0; /* GPS定位信息解析函数 */ void gps_parse(char *str) { float lat_degree, lat_minute, lon_degree, lon_minute; char lat_direction, lon_direction; int year, month, day, hour, minute, second; if (sscanf(str, "$GPGGA,%*f,%2d%2d.%*f,%c,%3d%2d.%*f,%c,%*d,%*d,%.1f,%*f,M,%.1f,M,,", &year, &month, &lat_degree, &lat_minute, &lat_direction, &gps_info.altitude, &gps_info.latitude) == 7) { // 解析纬度 gps_info.latitude = (float)lat_degree + lat_minute / 60.0; if (lat_direction == 'S') { gps_info.latitude = -gps_info.latitude; } if (sscanf(str, "$GPRMC,%2d%2d%2d.%*f,A,%3d%2d.%*f,%c,%4d%2d%2d,,,%*s*%*s", &hour, &minute, &second, &lon_degree, &lon_minute, &lon_direction, &year, &month, &day) == 9) { // 解析经度 gps_info.longitude = (float)lon_degree + lon_minute / 60.0; if (lon_direction == 'W') { gps_info.longitude = -gps_info.longitude; } // 解析时间 gps_info.time = hour * 10000 + minute * 100 + second; // 解析日期 gps_info.date = year * 10000 + month * 100 + day; } } } /* GPS串口接收中断处理函数 */ void GPS_USART_IRQHandler(void) { if (USART_GetITStatus(GPS_USART, USART_IT_RXNE) != RESET) { static char gps_buffer[128] = {0}; static uint8_t gps_index = 0; char ch = USART_ReceiveData(GPS_USART) & 0xff; if (ch == '$') { gps_index = 0; memset(gps_buffer, 0, sizeof(gps_buffer)); } gps_buffer[gps_index++] = ch; if (ch == '\n') { gps_parse(gps_buffer); } USART_ClearITPendingBit(GPS_USART, USART_IT_RXNE); } } /* PPS信号检测外部中断处理函数 */ void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) != RESET) { uint32_t current_time = TIM_GetCounter(TIM2); if (current_time - last_pps_time > 1000) { pps_count++; is_pps_detected = 1; } last_pps_time = current_time; EXTI_ClearITPendingBit(EXTI_Line0); } } /* 定时器2初始化函数 */ void TIM2_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; TIM_TimeBaseStructure.TIM_Prescaler = 84 - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_Cmd(TIM2, ENABLE); } /* 外部中断初始化函数 */ void EXTI_Init(void) { EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } int main(void) { USART_InitTypeDef USART_InitStructure; /* GPS串口初始化 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(GPS_USART_CLK, ENABLE); GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = GPS_USART_BAUDRATE; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(GPS_USART, &USART_InitStructure); USART_ITConfig(GPS_USART, USART_IT_RXNE, ENABLE); USART_Cmd(GPS_USART, ENABLE); /* PPS检测定时器和外部中断初始化 */ TIM2_Init(); EXTI_Init(); while (1) { if (is_pps_detected) { is_pps_detected = 0; // 在这里添加PPS信号检测后的处理代码 } // 在这里添加GPS定位信息处理代码 } } ``` 在主函数中,通过解析GPS模块发送的NMEA协议数据,可以获取到GPS定位信息。同时,使用定时器和外部中断来检测PPS信号,计算出两个PPS信号之间的时间差,从而实现时间同步。 需要注意的是,PPS信号的检测精度和稳定性对于时间同步的准确性有很大的影响,因此需要根据实际需求进行优化和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值