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.
- MX_SDMMC1_SD_Init();
- MX_FATFS_Init();
- 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:
- static uint8_t mountSDCard()
- {
- if(f_mount(&SDFatFs, "", 1) == FR_OK)
- {
- return 0;
- }
- return 1;
- }
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:
- uint8_t prepareFilesSdCard(void)
- {
- uint8_t operationStatus = mountSDCard();
- uint32_t prim;
- prim = __get_PRIMASK();
- __disable_irq();
- if(operationStatus != 0)
- {
- return 0x01;
- }
- /* Set data for GPGGA */
- if(f_open(&FileSDCard, GPGGA_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
- {
- /* When file was succesfully created check if contains any data */
- if(f_size(&FileSDCard) == 0)
- {
- /* If no data create header */
- f_puts("ReadTime;Latitude;LatitudeDirection;Longitude;LongitudeDirection;FixValue;Satellites;HdopValue;Altitude;GeoidAboveWGS84\n",&FileSDCard);
- }
- }
- f_close(&FileSDCard);
- /* Set data for GPGSA */
- if(f_open(&FileSDCard, GPGSA_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
- {
- /* When file was succesfully created check if contains any data */
- if(f_size(&FileSDCard) == 0)
- {
- /* If no data create header */
- f_puts("WorkMode;FixValue;Satelites;PdopValue;HdopValue;VdopValue\n", &FileSDCard);
- }
- }
- f_close(&FileSDCard);
- /* Set data for GPRMC */
- if(f_open(&FileSDCard, GPRMC_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
- {
- /* When file was succesfully created check if contains any data */
- if(f_size(&FileSDCard) == 0)
- {
- /* If no data create header */
- f_puts("ReadTime;DataValidInfo;Latitude;LatitudeDirection;Longitude;LongitudeDirection;SpeedInKnots;RealCourse;ReadDate;Direction;WorkMode\n",&FileSDCard);
- }
- }
- f_close(&FileSDCard);
- /* Set data for GPVTG */
- if(f_open(&FileSDCard, GPVTG_FILE_NAME , FA_CREATE_ALWAYS | FA_READ | FA_WRITE) == FR_OK)
- {
- /* When file was succesfully created check if contains any data */
- if(f_size(&FileSDCard) == 0)
- {
- /* If no data create header */
- f_puts("RealCourse;DataValidInfo_1;DataValidInfo_2;SpeedInKnots;SpeedInKm;WorkMode\n", &FileSDCard);
- }
- }
- f_close(&FileSDCard);
- f_mount(0, "", 1);
- if (!prim) { __enable_irq(); }
- return 0x00;
- }
Funkcje wykonujące zapis do pliku wykonywane są po odebraniu i przetworzeniu danych. Na samym początku wprowadzenie danych z ramki GPGGA:
- uint8_t writeGpggaDataToFile(gps_GPGGA_TypeDef *gpggaData_St)
- {
- if(gpggaData_St->Latitude == 0.0 || gpggaData_St->Longitude == 0.0)
- {
- return 0xFF;
- }
- uint8_t operationStatus = mountSDCard();
- if(operationStatus != 0) { return 0xFF; }
- uint32_t prim;
- prim = __get_PRIMASK();
- __disable_irq();
- char dataToWrite[255] = {0x00};
- char tmpBuffer[20] = {0x00};
- /* Prepare frame to write ----- */
- sprintf(dataToWrite, "%u:%u:%u;", gpggaData_St->ReadTime.Hour,
- gpggaData_St->ReadTime.Minute,
- gpggaData_St->ReadTime.Second);
- //-----
- floatConversionStruct convertedData;
- gps_ConvertFloatToTwoValues(gpggaData_St->Latitude, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;%c;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal,
- gpggaData_St->LatitudeDirection);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gpggaData_St->Longitude, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;%c;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal,
- gpggaData_St->LongitudeDirection);
- strcat(dataToWrite, tmpBuffer);
- //-----
- sprintf(tmpBuffer, "%u;", gpggaData_St->FixValue);
- strcat(dataToWrite, tmpBuffer);
- //-----
- sprintf(tmpBuffer, "%u;", gpggaData_St->Satellites);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gpggaData_St->HdopValue, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gpggaData_St->Altitude, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gpggaData_St->GeoidAboveWGS84, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;\n", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- //-----
- strcat(dataToWrite, tmpBuffer);
- /* ---------------------------- */
- if(f_open(&FileSDCard, GPGGA_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
- {
- f_lseek(&FileSDCard, f_size(&FileSDCard)); /* Go to the end of file */
- f_printf(&FileSDCard, "%s", dataToWrite);
- }
- f_close(&FileSDCard);
- f_mount(0, "", 1);
- if (!prim) { __enable_irq(); }
- return 0;
- }
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:
- uint8_t writeGpgsaDataToFile(gps_GPGSA_TypeDef *gpgsaData_St)
- {
- if(gpgsaData_St->HdopValue == 0.0 || gpgsaData_St->PdopValue == 0.0)
- {
- return 0xFF;
- }
- uint8_t operationStatus = mountSDCard();
- if(operationStatus != 0)
- {
- return 0xFF;
- }
- uint32_t prim;
- prim = __get_PRIMASK();
- __disable_irq();
- char dataToWrite[255] = {0x00};
- char tmpBuffer[40] = {0x00};
- floatConversionStruct convertedData;
- /* Prepare frame to write ----- */
- sprintf(dataToWrite, "%c;", gpgsaData_St->WorkMode);
- //----------
- sprintf(tmpBuffer, "%u;", gpgsaData_St->FixValue);
- strcat(dataToWrite, tmpBuffer);
- //----------
- sprintf(tmpBuffer, "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u;", gpgsaData_St->Satelites[0],
- gpgsaData_St->Satelites[1],
- gpgsaData_St->Satelites[2],
- gpgsaData_St->Satelites[3],
- gpgsaData_St->Satelites[4],
- gpgsaData_St->Satelites[5],
- gpgsaData_St->Satelites[6],
- gpgsaData_St->Satelites[7],
- gpgsaData_St->Satelites[8],
- gpgsaData_St->Satelites[9],
- gpgsaData_St->Satelites[10],
- gpgsaData_St->Satelites[11]);
- strcat(dataToWrite, tmpBuffer);
- //----------
- gps_ConvertFloatToTwoValues(gpgsaData_St->PdopValue, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //----------
- gps_ConvertFloatToTwoValues(gpgsaData_St->HdopValue, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //----------
- gps_ConvertFloatToTwoValues(gpgsaData_St->VdopValue, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;\n", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- /* ---------------------------- */
- if(f_open(&FileSDCard, GPGSA_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
- {
- f_lseek(&FileSDCard, f_size(&FileSDCard)); /* Go to the end of file */
- f_printf(&FileSDCard, "%s", dataToWrite);
- }
- f_close(&FileSDCard);
- f_mount(0, "", 1);
- if (!prim) { __enable_irq(); }
- return 0;
- }
Przygotowywanie ramki GPRMC:
- uint8_t writeGprmcDataToFile(gps_GPRMC_TypeDef *gprmcData_St)
- {
- if(gprmcData_St->DataValidInfo == 'V') { return 0xFF; }
- if(gprmcData_St->Latitude == 0.0 || gprmcData_St->Longitude == 0.0) {
- return 0xFF;
- }
- uint8_t operationStatus = mountSDCard();
- if(operationStatus != 0)
- {
- return 0xFF;
- }
- uint32_t prim;
- prim = __get_PRIMASK();
- __disable_irq();
- char dataToWrite[255] = {0x00};
- char tmpBuffer[40] = {0x00};
- floatConversionStruct convertedData;
- /* ---------------------------- */
- sprintf(dataToWrite, "%u:%u:%u;", gprmcData_St->ReadTime.Hour,
- gprmcData_St->ReadTime.Minute,
- gprmcData_St->ReadTime.Second);
- //----------
- sprintf(tmpBuffer, "%c;", gprmcData_St->DataValidInfo);
- strcat(dataToWrite, tmpBuffer);
- //----------
- gps_ConvertFloatToTwoValues(gprmcData_St->Latitude, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;%c;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal,
- gprmcData_St->LatitudeDirection);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gprmcData_St->Longitude, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;%c;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal,
- gprmcData_St->LongitudeDirection);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gprmcData_St->SpeedInKnots, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gprmcData_St->RealCourse, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //-----
- sprintf(tmpBuffer, "%u/%u/%u;", gprmcData_St->ReadDate.Day,
- gprmcData_St->ReadDate.Month,
- gprmcData_St->ReadDate.Year);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gprmcData_St->Direction, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //-----
- sprintf(tmpBuffer, "%c;\n", gprmcData_St->WorkMode);
- strcat(dataToWrite, tmpBuffer);
- /* ---------------------------- */
- if(f_open(&FileSDCard, GPRMC_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
- {
- f_lseek(&FileSDCard, f_size(&FileSDCard)); /* Go to the end of file */
- f_printf(&FileSDCard, "%s", dataToWrite);
- }
- f_close(&FileSDCard);
- f_mount(0, "", 1);
- if (!prim) { __enable_irq(); }
- return 0;
- }
Przygotowywanie ramki GPVTG:
- uint8_t writeGpvtgDataToFile(gps_GPVTG_TypeDef *gpvtgData_St)
- {
- if(gpvtgData_St->RealCourse == 0.0 || gpvtgData_St->SpeedInKm == 0.0){
- return 0xFF;
- }
- uint8_t operationStatus = mountSDCard();
- if(operationStatus != 0) { return 0xFF; }
- uint32_t prim;
- prim = __get_PRIMASK();
- __disable_irq();
- char dataToWrite[255] = {0x00};
- char tmpBuffer[40] = {0x00};
- floatConversionStruct convertedData;
- /* ---------------------------- */
- gps_ConvertFloatToTwoValues(gpvtgData_St->RealCourse, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //-----
- sprintf(tmpBuffer, "%c;", gpvtgData_St->DataValidInfo_1);
- strcat(dataToWrite, tmpBuffer);
- //-----
- sprintf(tmpBuffer, "%c;", gpvtgData_St->DataValidInfo_2);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gpvtgData_St->SpeedInKnots, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //-----
- gps_ConvertFloatToTwoValues(gpvtgData_St->SpeedInKm, &convertedData, 3);
- sprintf(tmpBuffer, "%ld.%lu;", convertedData.valueBeforDecimal,
- convertedData.valueAfterDecimal);
- strcat(dataToWrite, tmpBuffer);
- //-----
- sprintf(tmpBuffer, "%c;\n", gpvtgData_St->WorkMode);
- strcat(dataToWrite, tmpBuffer);
- /* ---------------------------- */
- if(f_open(&FileSDCard, GPVTG_FILE_NAME , FA_OPEN_EXISTING | FA_READ | FA_WRITE) == FR_OK)
- {
- f_lseek(&FileSDCard, f_size(&FileSDCard)); /* Go to the end of file */
- f_printf(&FileSDCard, "%s", dataToWrite);
- }
- f_close(&FileSDCard);
- f_mount(0, "", 1);
- if (!prim) { __enable_irq(); }
- return 0;
- }
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.