PPM из PPS и NMEA c GPS модуля

Имеется Arduino Uno R3 и GPS модуль u-Blox NEO-6M, как видно из названия темы конечна цель получить устройство выдающие минутные метки реального времени (PPM).

Как я понимаю алгоритм должен быть примерно такой. Из протокола NMEA достаю время, для меня важны секунды, т.е. на 59 секунде, спустя ~950 мс, в идеале надо продублировать PPS сигнал с GPS модуля, но при этом чтобы фронт не завалился. Или просто сгенерировать сигнал?

Уважаемые форумчане, прощу помощи как лучше это реализовать? Заранее благодарю!

Почему просто не подвесить PPS на прерывание и каждый N-ый импульс не давать свой?

1 лайк

можно даже замутить таймер с внешним тактированием от сигнала PPS и делителем 60 :slight_smile:
Хотя это от контроллера зависит, не знаю, на чем там ТС все это собирает

1 лайк

Да, это интересней было бы. Единственная задача - это TCNT правильно заинитить, а потом просто сидеть и курить.

С какого бодуна ему валиться? Ты точно понимаешь, что это значит?

ATmega328P-PU на плате Arduino Uno R3.
GPS модуль NEO-6M.
Подскажите пожалуйста)

‘’’
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1

#define PPS_PIN 4 // Pin for PPS signal from GPS module
#define PPM_PIN 5 // Pin for PPM signal output
#define PPM_TRIGGER_SECOND 59 // NMEA protocol second to trigger PPM output

volatile unsigned long ppsTime; // Variable to store PPS signal time
volatile bool ppsDetected; // Flag to indicate PPS signal detection
volatile bool ppmTriggered; // Flag to indicate PPM output triggered

void init_UART() {
UBRR0H = (MYUBRR >> 8);
UBRR0L = MYUBRR;
UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
}

void send_char(char c) {
while (!(UCSR0A & (1 << UDRE0)));
UDR0 = c;
}

void send_string(char *str) {
while (*str) {
send_char(*str++);
}
}

void setup() {
pinMode(PPS_PIN, INPUT);
pinMode(PPM_PIN, OUTPUT);
digitalWrite(PPM_PIN, LOW); // Initial state of PPM output pin is LOW

init_UART();

// Configure Timer1 for external clock from PPS signal
TCCR1A = 0; // Disable Timer1 comparison and PWM modes
TCCR1B = (1 << CS12) | (1 << CS10); // Set prescaler to 1024 and start the timer
TIMSK1 = (1 << TOIE1) | (1 << ICIE1); // Enable interrupt on Timer1 overflow and external input capture
sei(); // Enable interrupts
}

void loop() {
if (ppsDetected) { // If PPS signal is detected
unsigned long minutes = (ppsTime / 1000 / 60) % 60; // Calculate number of minutes passed since start of day
if (minutes == 0) { // If a minute has passed
if (!ppmTriggered && TCNT1 >= (PPM_TRIGGER_SECOND * 15625)) { // If PPM output trigger has not been triggered and current time is at or past trigger time
digitalWrite(PPM_PIN, HIGH); // Set PPM output pin high
ppmTriggered = true; // Set flag to indicate PPM output trigger has been triggered
}
send_char(‘P’); // Send ‘P’ character to serial port
} else {
digitalWrite(PPM_PIN, LOW); // Set PPM output pin low
ppmTriggered = false; // Reset PPM output trigger flag
}
ppsDetected = false; // Reset PPS detection flag
}
}

ISR(TIMER1_CAPT_vect) {
ppsTime = ICR1; // Save Timer1 capture register value as PPS time
ppsDetected = true; // Set PPS detection flag
}

ISR(TIMER1_OVF_vect) {
TCNT1 = 0; // Reset Timer1 counter on overflow
}
‘’’

Ошибка в строке № 100500 !!!
Прежде чем что то писать на форуме - ПОЧИТАЙТЕ правила !!!
Тройные кавычки надо ставить те что с буквой Ё на одной клавише.

#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1

#define PPS_PIN 4 // Pin for PPS signal from GPS module
#define PPM_PIN 5 // Pin for PPM signal output
#define PPM_TRIGGER_SECOND 59 // NMEA protocol second to trigger PPM output

volatile unsigned long ppsTime; // Variable to store PPS signal time
volatile bool ppsDetected; // Flag to indicate PPS signal detection
volatile bool ppmTriggered; // Flag to indicate PPM output triggered

void init_UART() {
UBRR0H = (MYUBRR >> 8);
UBRR0L = MYUBRR;
UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
}

void send_char(char c) {
while (!(UCSR0A & (1 << UDRE0)));
UDR0 = c;
}

void send_string(char *str) {
while (*str) {
send_char(*str++);
}
}

void setup() {
pinMode(PPS_PIN, INPUT);
pinMode(PPM_PIN, OUTPUT);
digitalWrite(PPM_PIN, LOW); // Initial state of PPM output pin is LOW

init_UART();

// Configure Timer1 for external clock from PPS signal
TCCR1A = 0; // Disable Timer1 comparison and PWM modes
TCCR1B = (1 << CS12) | (1 << CS10); // Set prescaler to 1024 and start the timer
TIMSK1 = (1 << TOIE1) | (1 << ICIE1); // Enable interrupt on Timer1 overflow and external input capture
sei(); // Enable interrupts
}

void loop() {
if (ppsDetected) { // If PPS signal is detected
unsigned long minutes = (ppsTime / 1000 / 60) % 60; // Calculate number of minutes passed since start of day
if (minutes == 0) { // If a minute has passed
if (!ppmTriggered && TCNT1 >= (PPM_TRIGGER_SECOND * 15625)) { // If PPM output trigger has not been triggered and current time is at or past trigger time
digitalWrite(PPM_PIN, HIGH); // Set PPM output pin high
ppmTriggered = true; // Set flag to indicate PPM output trigger has been triggered
}
send_char(‘P’); // Send ‘P’ character to serial port
} else {
digitalWrite(PPM_PIN, LOW); // Set PPM output pin low
ppmTriggered = false; // Reset PPM output trigger flag
}
ppsDetected = false; // Reset PPS detection flag
}
}

ISR(TIMER1_CAPT_vect) {
ppsTime = ICR1; // Save Timer1 capture register value as PPS time
ppsDetected = true; // Set PPS detection flag
}

ISR(TIMER1_OVF_vect) {
TCNT1 = 0; // Reset Timer1 counter on overflow
}

Почему так ? Там нет ICP !

Спасибо, 8 пин надо, верно?

Это не единственная ошибка !
PPM_TRIGGER_SECOND * 15625 это не влезет в 16 битный таймер !!!
По ходу дела этот код создал ChatGPT или какой другой ИИ ???
Алгоритм БРЕДОВЫЙ.
Почему не считать сами импульсы PPS.
Это можно даже в автоматическом режиме сделать, если подать на T0 или T1 и правильно настроить регистры сравнения…

#define PPS_PIN 5 // Pin for PPS signal from GPS module
//#define PPM_PIN 9 // Pin for PPM signal output
#define PPM_PIN 10 // Pin for PPM signal output

void setup () {
  pinMode(PPS_PIN, INPUT);          //optional command can be removed
  pinMode(PPM_PIN, OUTPUT);
  digitalWrite(PPM_PIN, LOW); // Initial state of PPM output pin is LOW           optional command can be removed
#if PPM_PIN == 9
  TCCR1A = (1<<COM1A1) | (1<<COM1A0) | (1<<WGM11);
  OCR1A=29;
#elif PPM_PIN == 10
  TCCR1A = (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11);
  OCR1B=29;
#else
  #error PPM_PIN must be 9 or 10
#endif
  TCNT1=0;
  ICR1=30;
  TCCR1B = (1<<WGM13) | (1<<CS12) | (1<<CS11)| (1<<CS10);
}

void loop() {
  while (1);
}

На каждые 60 импульсов на входе - будет один 2х секундный импульс на выходе…
PPS-PPM
Вопрос только в том, как привязать PPM именно к 0 секунде реального времени (если это вообще надо ТС). Тут уже без общения с самим модулем по вопросу точного времени не обойтись, но и это вполне решаемо …

1 лайк

Здравствуйте, многоуважаемый! Спасибо вам большое! А не подскажите название программы(скрин ппс и ппм меток) , это какой то эмулятор осциллографа? Не ругайтесь, пару дней как только начал заниматься с мк. Да, это был код с чат гпт(

Из GPS модуля по UART с протокола NMEA парсим секунды и…подскажите, пожалуйста.

#include <SoftwareSerial.h>

SoftwareSerial gpsSerial(3, 4); // RX, TX

void setup() {
  Serial.begin(9600);
  gpsSerial.begin(9600);
}

void loop() {
  if (gpsSerial.available()) {
    String nmea = gpsSerial.readStringUntil('\n');
    if (nmea.startsWith("$GPGGA")) {
      int commaIndex = nmea.indexOf(',');
      int timeIndex = commaIndex + 1;
      commaIndex = nmea.indexOf(',', timeIndex);
      String utcTime = nmea.substring(timeIndex, commaIndex);

      // Извлечение секунд из времени UTC
      String seconds = utcTime.substring(4, 6);

      Serial.println(seconds);
    }
  }
}

Это Proteus.

на 02 секунде запускаем таймер из моего кода - через 58 секунд поднимется PPM на 2 секунды и пойдёт дальше автоматически …

С каких то левых источников он берет информацию и собирает АБСОЛЮТНО не рабочий код !
Восстание машин отменяется …

Так это он усыпляет бдительность кожаных мешков.

Здравствуйте, снова вынужден обратиться к Вам за помощью, если на 2 секунде запускать таймер то PPM генерируется на 32 сек… Поэтому запускаю таймер на 30 секунде.

#include <SoftwareSerial.h>

#define PPS_PIN 5 // Pin for PPS signal from GPS module
#define PPM_PIN 9 // Pin for PPM signal output

SoftwareSerial gpsSerial(3, 4); // RX, TX
bool timerStarted = false;

void setup() {
  pinMode(PPS_PIN, INPUT);
  pinMode(PPM_PIN, OUTPUT);
  digitalWrite(PPM_PIN, LOW); // Initial state of PPM output pin is LOW
#if PPM_PIN == 9
  TCCR1A = (1<<COM1A1) | (1<<COM1A0) | (1<<WGM11);
  OCR1A=29;
#elif PPM_PIN == 10
  TCCR1A = (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11);
  OCR1B=29;
#else
  #error PPM_PIN must be 9 or 10
#endif
  TCNT1=0;
  ICR1=30;
  TCCR1B = (1<<WGM13) | (1<<CS12) | (1<<CS11)| (1<<CS10);
  Serial.begin(9600);
  gpsSerial.begin(9600);
  Serial.println("Waiting data of GPS...");
}

void loop() {
    if (gpsSerial.available()) {
    String nmea = gpsSerial.readStringUntil('\n');
    if (nmea.startsWith("$GPGGA")) {
      int commaIndex = nmea.indexOf(',');
      int timeIndex = commaIndex + 1;
      commaIndex = nmea.indexOf(',', timeIndex);
      String utcTime = nmea.substring(timeIndex, commaIndex);

      // Извлечение секунд из времени UTC
      String seconds = utcTime.substring(4, 6);
      
      Serial.println(seconds);
      if (atoi(seconds.c_str()) == 30 && !timerStarted) {
        setup();
        Serial.println("PPM output started!");
        timerStarted = true;
      }
    }
  }
}

Поправьте что не так, пожалуйста. Мне важно чтобы начало генерации PPM совпадало с началом минуты UTC.

Всё может быть !
Подберите нужную секунду для старта …