środa, 18 kwietnia 2018

[22.1] STM32F7 - Moduł GPS FGPMMOP6, zapis danych na kartę SD

Ten post jest kontynuacją wcześniejszego. W nim przedstawię zapis danych z GPS do pliku oraz wprowadzę kilka modyfikacji w stosunku do poprzedniego programu.

[Źródło: http://www.st.com/en/evaluation-tools/32f746gdiscovery.html]


Zapis na kartę SD:


Poniżej przedstawię zestaw funkcji potrzebnych do zapisu danych na kartę SD.

Na samym początku należy uruchomić biblioteki potrzebne do uzyskania dostępu do karty SD. Sama karta, jak i przygotowanie projektu zostało opisane w tym poście.

  1. MX_SDMMC1_SD_Init();
  2. MX_FATFS_Init();
  3. HAL_SD_MspInit(&hsd1);

Następnym krokiem będzie zamontowanie karty oraz sprawdzenie czy plik istnieje. Jeśli nie jest on umieszczony na karcie to jest tworzony nowy plik.

Montaż karty SD w układzie:

  1. static uint8_t mountSDCard()
  2. {
  3.     if(f_mount(&SDFatFs, "", 1) == FR_OK)
  4.     {
  5.         return 0;
  6.     }
  7.     return 1;
  8. }

Wszystkie dane są przechowywane w pliku csv. Na samym początku tworze, bądź otwieram pliki z możliwością zapisu oraz odczytu. Gdy pliki są puste to wprowadzam dane do nagłówków:

  1. uint8_t prepareFilesSdCard(void)
  2. {
  3.     uint8_t operationStatus = mountSDCard();
  4.     uint32_t prim;
  5.     prim = __get_PRIMASK();
  6.     __disable_irq();
  7.     if(operationStatus != 0)
  8.     {
  9.         return 0x01;
  10.     }
  11.     /* Set data for GPGGA */
  12.     if(f_open(&FileSDCard, GPGGA_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
  13.     {
  14.         /* When file was succesfully created check if contains any data */
  15.         if(f_size(&FileSDCard) == 0)
  16.         {
  17.             /* If no data create header */
  18.             f_puts("ReadTime;Latitude;LatitudeDirection;Longitude;LongitudeDirection;FixValue;Satellites;HdopValue;Altitude;GeoidAboveWGS84\n",&FileSDCard);
  19.         }
  20.     }
  21.     f_close(&FileSDCard);
  22.     /* Set data for GPGSA */
  23.     if(f_open(&FileSDCard, GPGSA_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
  24.     {
  25.         /* When file was succesfully created check if contains any data */
  26.         if(f_size(&FileSDCard) == 0)
  27.         {
  28.             /* If no data create header */
  29.             f_puts("WorkMode;FixValue;Satelites;PdopValue;HdopValue;VdopValue\n", &FileSDCard);
  30.         }
  31.     }
  32.     f_close(&FileSDCard);
  33.     /* Set data for GPRMC */
  34.     if(f_open(&FileSDCard, GPRMC_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
  35.     {
  36.         /* When file was succesfully created check if contains any data */
  37.         if(f_size(&FileSDCard) == 0)
  38.         {
  39.             /* If no data create header */
  40.             f_puts("ReadTime;DataValidInfo;Latitude;LatitudeDirection;Longitude;LongitudeDirection;SpeedInKnots;RealCourse;ReadDate;Direction;WorkMode\n",&FileSDCard);
  41.         }
  42.     }
  43.     f_close(&FileSDCard);
  44.     /* Set data for GPVTG */
  45.     if(f_open(&FileSDCard, GPVTG_FILE_NAME , FA_CREATE_ALWAYS | FA_READ | FA_WRITE) == FR_OK)
  46.     {
  47.         /* When file was succesfully created check if contains any data */
  48.         if(f_size(&FileSDCard) == 0)
  49.         {
  50.             /* If no data create header */
  51.             f_puts("RealCourse;DataValidInfo_1;DataValidInfo_2;SpeedInKnots;SpeedInKm;WorkMode\n", &FileSDCard);
  52.         }
  53.     }
  54.     f_close(&FileSDCard);
  55.     f_mount(0, "", 1);
  56.     if (!prim) { __enable_irq(); }
  57.     return 0x00;
  58. }

Funkcje wykonujące zapis do pliku wykonywane są po odebraniu i przetworzeniu danych. Na samym początku wprowadzenie danych z ramki GPGGA:

  1. uint8_t writeGpggaDataToFile(gps_GPGGA_TypeDef *gpggaData_St)
  2. {
  3.     if(gpggaData_St->Latitude == 0.0 || gpggaData_St->Longitude == 0.0)
  4.     {
  5.         return 0xFF;
  6.     }
  7.    
  8.     uint8_t operationStatus = mountSDCard();
  9.    
  10.     if(operationStatus != 0) { return 0xFF; }
  11.    
  12.     uint32_t prim;
  13.     prim = __get_PRIMASK();
  14.     __disable_irq();
  15.     char dataToWrite[255] = {0x00};
  16.     char tmpBuffer[20] = {0x00};
  17.     /* Prepare frame to write ----- */
  18.     sprintf(dataToWrite, "%u:%u:%u;",   gpggaData_St->ReadTime.Hour,
  19.                                         gpggaData_St->ReadTime.Minute,
  20.                                         gpggaData_St->ReadTime.Second);
  21.     //-----
  22.     floatConversionStruct convertedData;
  23.     gps_ConvertFloatToTwoValues(gpggaData_St->Latitude, &convertedData, 3);
  24.     sprintf(tmpBuffer, "%ld.%lu;%c;", convertedData.valueBeforDecimal,
  25.                                         convertedData.valueAfterDecimal,
  26.                                         gpggaData_St->LatitudeDirection);
  27.     strcat(dataToWrite, tmpBuffer);
  28.     //-----
  29.     gps_ConvertFloatToTwoValues(gpggaData_St->Longitude, &convertedData, 3);
  30.     sprintf(tmpBuffer, "%ld.%lu;%c;", convertedData.valueBeforDecimal,
  31.                                     convertedData.valueAfterDecimal,
  32.                                     gpggaData_St->LongitudeDirection);
  33.     strcat(dataToWrite, tmpBuffer);
  34.     //-----
  35.     sprintf(tmpBuffer, "%u;", gpggaData_St->FixValue);
  36.     strcat(dataToWrite, tmpBuffer);
  37.     //-----
  38.     sprintf(tmpBuffer, "%u;", gpggaData_St->Satellites);
  39.     strcat(dataToWrite, tmpBuffer);
  40.     //-----
  41.     gps_ConvertFloatToTwoValues(gpggaData_St->HdopValue, &convertedData, 3);
  42.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  43.                                     convertedData.valueAfterDecimal);
  44.     strcat(dataToWrite, tmpBuffer);
  45.     //-----
  46.     gps_ConvertFloatToTwoValues(gpggaData_St->Altitude, &convertedData, 3);
  47.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  48.                                     convertedData.valueAfterDecimal);
  49.     strcat(dataToWrite, tmpBuffer);
  50.     //-----
  51.     gps_ConvertFloatToTwoValues(gpggaData_St->GeoidAboveWGS84, &convertedData, 3);
  52.     sprintf(tmpBuffer, "%ld.%lu;\n", convertedData.valueBeforDecimal,
  53.                                     convertedData.valueAfterDecimal);
  54.     //-----
  55.     strcat(dataToWrite, tmpBuffer);
  56.     /* ---------------------------- */
  57.     if(f_open(&FileSDCard, GPGGA_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
  58.     {
  59.         f_lseek(&FileSDCard, f_size(&FileSDCard));  /* Go to the end of file */
  60.         f_printf(&FileSDCard, "%s", dataToWrite);
  61.     }
  62.     f_close(&FileSDCard);
  63.     f_mount(0, "", 1);
  64.     if (!prim) { __enable_irq(); }
  65.     return 0;
  66. }

Na samym początku sprawdzamy czy dane umieszczone w strukturze zawierają jakieś informacje. Gdy tak jest następuje montaż karty SD. Po poprawnej operacji wyłączane są przerwania i przygotowywany jest bufor do wpisania do pliku. Gdy te operacje dobiegną końca następuje otwarcie pliku i wyszukanie ostatniej wpisanej informacji. Następnie dane są wprowadzane, plik zamykany, karta od montowana i na końcu ponowne włączenie przerwań. Włączanie i wyłączanie przerwań pozwala na zminimalizowanie ilości błędów podczas obsługi plików na karcie.

Pozostałe pliki przygotowywane są w ten sam sposób.

Przygotowywanie ramki GPGSA:

  1. uint8_t writeGpgsaDataToFile(gps_GPGSA_TypeDef *gpgsaData_St)
  2. {
  3.     if(gpgsaData_St->HdopValue == 0.0 || gpgsaData_St->PdopValue == 0.0)
  4.     {
  5.         return 0xFF;
  6.     }
  7.     uint8_t operationStatus = mountSDCard();
  8.    
  9.     if(operationStatus != 0)
  10.     {
  11.         return 0xFF;
  12.     }
  13.     uint32_t prim;
  14.     prim = __get_PRIMASK();
  15.     __disable_irq();
  16.     char dataToWrite[255] = {0x00};
  17.     char tmpBuffer[40] = {0x00};
  18.     floatConversionStruct convertedData;
  19.     /* Prepare frame to write ----- */
  20.     sprintf(dataToWrite, "%c;",   gpgsaData_St->WorkMode);
  21.     //----------
  22.     sprintf(tmpBuffer, "%u;", gpgsaData_St->FixValue);
  23.     strcat(dataToWrite, tmpBuffer);
  24.     //----------
  25.     sprintf(tmpBuffer, "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u;", gpgsaData_St->Satelites[0],
  26.                                                            gpgsaData_St->Satelites[1],
  27.                                                            gpgsaData_St->Satelites[2],
  28.                                                            gpgsaData_St->Satelites[3],
  29.                                                            gpgsaData_St->Satelites[4],
  30.                                                            gpgsaData_St->Satelites[5],
  31.                                                            gpgsaData_St->Satelites[6],
  32.                                                            gpgsaData_St->Satelites[7],
  33.                                                            gpgsaData_St->Satelites[8],
  34.                                                            gpgsaData_St->Satelites[9],
  35.                                                            gpgsaData_St->Satelites[10],
  36.                                                            gpgsaData_St->Satelites[11]);
  37.     strcat(dataToWrite, tmpBuffer);
  38.     //----------
  39.     gps_ConvertFloatToTwoValues(gpgsaData_St->PdopValue, &convertedData, 3);
  40.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  41.                                     convertedData.valueAfterDecimal);
  42.     strcat(dataToWrite, tmpBuffer);
  43.     //----------
  44.     gps_ConvertFloatToTwoValues(gpgsaData_St->HdopValue, &convertedData, 3);
  45.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  46.                                     convertedData.valueAfterDecimal);
  47.     strcat(dataToWrite, tmpBuffer);
  48.     //----------
  49.     gps_ConvertFloatToTwoValues(gpgsaData_St->VdopValue, &convertedData, 3);
  50.     sprintf(tmpBuffer, "%ld.%lu;\n", convertedData.valueBeforDecimal,
  51.                                     convertedData.valueAfterDecimal);
  52.     strcat(dataToWrite, tmpBuffer);
  53.     /* ---------------------------- */
  54.     if(f_open(&FileSDCard, GPGSA_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
  55.     {
  56.         f_lseek(&FileSDCard, f_size(&FileSDCard));  /* Go to the end of file */
  57.         f_printf(&FileSDCard, "%s", dataToWrite);
  58.     }
  59.     f_close(&FileSDCard);
  60.     f_mount(0, "", 1);
  61.     if (!prim) { __enable_irq(); }
  62.     return 0;
  63. }

Przygotowywanie ramki GPRMC:

  1. uint8_t writeGprmcDataToFile(gps_GPRMC_TypeDef *gprmcData_St)
  2. {
  3.     if(gprmcData_St->DataValidInfo == 'V')        { return 0xFF; }
  4.     if(gprmcData_St->Latitude == 0.0 || gprmcData_St->Longitude == 0.0) {
  5.         return 0xFF;
  6.     }
  7.     uint8_t operationStatus = mountSDCard();
  8.     if(operationStatus != 0)
  9.     {
  10.         return 0xFF;
  11.     }
  12.     uint32_t prim;
  13.     prim = __get_PRIMASK();
  14.     __disable_irq();
  15.     char dataToWrite[255] = {0x00};
  16.     char tmpBuffer[40] = {0x00};
  17.     floatConversionStruct convertedData;
  18.     /* ---------------------------- */
  19.     sprintf(dataToWrite, "%u:%u:%u;",   gprmcData_St->ReadTime.Hour,
  20.                                         gprmcData_St->ReadTime.Minute,
  21.                                         gprmcData_St->ReadTime.Second);
  22.     //----------
  23.     sprintf(tmpBuffer, "%c;", gprmcData_St->DataValidInfo);
  24.     strcat(dataToWrite, tmpBuffer);
  25.     //----------
  26.     gps_ConvertFloatToTwoValues(gprmcData_St->Latitude, &convertedData, 3);
  27.     sprintf(tmpBuffer, "%ld.%lu;%c;", convertedData.valueBeforDecimal,
  28.                                         convertedData.valueAfterDecimal,
  29.                                         gprmcData_St->LatitudeDirection);
  30.     strcat(dataToWrite, tmpBuffer);
  31.     //-----
  32.     gps_ConvertFloatToTwoValues(gprmcData_St->Longitude, &convertedData, 3);
  33.     sprintf(tmpBuffer, "%ld.%lu;%c;", convertedData.valueBeforDecimal,
  34.                                         convertedData.valueAfterDecimal,
  35.                                         gprmcData_St->LongitudeDirection);
  36.     strcat(dataToWrite, tmpBuffer);
  37.     //-----
  38.     gps_ConvertFloatToTwoValues(gprmcData_St->SpeedInKnots, &convertedData, 3);
  39.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  40.                                         convertedData.valueAfterDecimal);
  41.     strcat(dataToWrite, tmpBuffer);
  42.     //-----
  43.     gps_ConvertFloatToTwoValues(gprmcData_St->RealCourse, &convertedData, 3);
  44.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  45.                                         convertedData.valueAfterDecimal);
  46.     strcat(dataToWrite, tmpBuffer);
  47.     //-----
  48.     sprintf(tmpBuffer, "%u/%u/%u;",   gprmcData_St->ReadDate.Day,
  49.                                         gprmcData_St->ReadDate.Month,
  50.                                         gprmcData_St->ReadDate.Year);
  51.     strcat(dataToWrite, tmpBuffer);
  52.     //-----
  53.     gps_ConvertFloatToTwoValues(gprmcData_St->Direction, &convertedData, 3);
  54.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  55.                                         convertedData.valueAfterDecimal);
  56.     strcat(dataToWrite, tmpBuffer);
  57.     //-----
  58.     sprintf(tmpBuffer, "%c;\n", gprmcData_St->WorkMode);
  59.     strcat(dataToWrite, tmpBuffer);
  60.     /* ---------------------------- */
  61.     if(f_open(&FileSDCard, GPRMC_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
  62.     {
  63.         f_lseek(&FileSDCard, f_size(&FileSDCard));  /* Go to the end of file */
  64.         f_printf(&FileSDCard, "%s", dataToWrite);
  65.     }
  66.     f_close(&FileSDCard);
  67.     f_mount(0, "", 1);
  68.     if (!prim) { __enable_irq(); }
  69.     return 0;
  70. }

Przygotowywanie ramki GPVTG:

  1. uint8_t writeGpvtgDataToFile(gps_GPVTG_TypeDef *gpvtgData_St)
  2. {
  3.     if(gpvtgData_St->RealCourse == 0.0 || gpvtgData_St->SpeedInKm == 0.0){
  4.         return 0xFF;
  5.     }
  6.     uint8_t operationStatus = mountSDCard();
  7.     if(operationStatus != 0) { return 0xFF; }
  8.     uint32_t prim;
  9.     prim = __get_PRIMASK();
  10.     __disable_irq();
  11.     char dataToWrite[255] = {0x00};
  12.     char tmpBuffer[40] = {0x00};
  13.     floatConversionStruct convertedData;
  14.     /* ---------------------------- */
  15.     gps_ConvertFloatToTwoValues(gpvtgData_St->RealCourse, &convertedData, 3);
  16.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  17.                                         convertedData.valueAfterDecimal);
  18.     strcat(dataToWrite, tmpBuffer);
  19.     //-----
  20.     sprintf(tmpBuffer, "%c;", gpvtgData_St->DataValidInfo_1);
  21.     strcat(dataToWrite, tmpBuffer);
  22.     //-----
  23.     sprintf(tmpBuffer, "%c;", gpvtgData_St->DataValidInfo_2);
  24.     strcat(dataToWrite, tmpBuffer);
  25.     //-----
  26.     gps_ConvertFloatToTwoValues(gpvtgData_St->SpeedInKnots, &convertedData, 3);
  27.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  28.                                         convertedData.valueAfterDecimal);
  29.     strcat(dataToWrite, tmpBuffer);
  30.     //-----
  31.     gps_ConvertFloatToTwoValues(gpvtgData_St->SpeedInKm, &convertedData, 3);
  32.     sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
  33.                                     convertedData.valueAfterDecimal);
  34.     strcat(dataToWrite, tmpBuffer);
  35.     //-----
  36.     sprintf(tmpBuffer, "%c;\n", gpvtgData_St->WorkMode);
  37.     strcat(dataToWrite, tmpBuffer);
  38.     /* ---------------------------- */
  39.     if(f_open(&FileSDCard, GPVTG_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
  40.     {
  41.         f_lseek(&FileSDCard, f_size(&FileSDCard));  /* Go to the end of file */
  42.         f_printf(&FileSDCard, "%s", dataToWrite);
  43.     }
  44.     f_close(&FileSDCard);
  45.     f_mount(0, "", 1);
  46.     if (!prim) { __enable_irq(); }
  47.     return 0;
  48. }

Czas potrzebny na zdekodowanie ramki razem z wpisaniem danych do pliku i wyświetleniem danych na ekranie:


Czas pomiędzy kolejnym dekodowaniem wynosi:


Cały kod można pobrać z dysku Google pod tym linkiem.