Skocz do zawartości

Wysyłanie temperatury z stm32F411 na komputer PC Windows


Imilek

Pomocna odpowiedź

Zmieniłem tak jak powiedziałeś.

Dodatkowo jeszcze zmieniłem z tego:

size = sprintf(data, "%d\r\n", Wyjscie);

Na to:

size = sprintf(data, "%.2f\r\n", Wyjscie);

I koniec końców uzyskuję coś takiego:

Dwa wyniki i koniec. Transmisja z mikrokontrolera do komputera już się od tego momentu nie odbywa.

Link do komentarza
Share on other sites

W końcu znalazłem konwerter UART-USB i u mnie taki program działa całkiem dobrze:

/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 ** This notice applies to any and all portions of this file
 * that are not between comment pairs USER CODE BEGIN and
 * USER CODE END. Other portions of this file, whether 
 * inserted by the user or by software development tools
 * are owned by their respective copyright owners.
 *
 * COPYRIGHT(c) 2018 STMicroelectronics
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;

TIM_HandleTypeDef htim10;
TIM_HandleTypeDef htim11;

UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/*Obs�uga dzia�ania przycisk�w*/
int8_t settemp = 20;
uint8_t PinState;
uint32_t timer1ms = 0;
/* Wysy�anie danych przez UART*/
uint8_t data[100];
uint16_t size = 0;
volatile float Wyjscie;
/*Pomiar temperatury przez mikrokontroler*/
uint16_t PomiarADC;
volatile uint32_t Counter = 0;
volatile float Suma = 0;
float Temperature;
float Vsense;
const float V25 = 0.76;
const float Avg_slope = 0.0025;
const float SupplyVoltage = 3.0;
const float ADCResolution = 4096.0;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM10_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_TIM11_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if (hadc->Instance == ADC1)	{
	PomiarADC = HAL_ADC_GetValue(&hadc1);
	Vsense = (SupplyVoltage*PomiarADC)/(ADCResolution-1);
	Temperature = ((Vsense-V25)/Avg_slope)+25;
	Suma = Suma + Temperature;
	++Counter;
	HAL_ADCBITS_1;
 huart1.Init.Parity = UART_PARITY_NONE;
 huart1.Init.Mode = UART_MODE_TX_RX;
 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
 huart1.Init.OverSampling = UART_OVERSAMPLING_16;
 if (HAL_UART_Init(&huart1) != HAL_OK)
 {
   _Error_Handler(__FILE__, __LINE__);
 }

}

/** Configure pins as 
       * Analog 
       * Input 
       * Output
       * EVENT_OUT
       * EXTI
*/
static void MX_GPIO_Init(void)
{

 GPIO_InitTypeDef GPIO_InitStruct;

 /* GPIO Ports Clock Enable */
 __HAL_RCC_GPIOH_CLK_ENABLE();
 __HAL_RCC_GPIOA_CLK_ENABLE();
 __HAL_RCC_GPIOD_CLK_ENABLE();
 __HAL_RCC_GPIOB_CLK_ENABLE();

 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(LED_Blue_GPIO_Port, LED_Blue_Pin, GPIO_PIN_RESET);

 /*Configure GPIO pins : Button_Up_Pin Button_Down_Pin */
 GPIO_InitStruct.Pin = Button_Up_Pin|Button_Down_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
 GPIO_InitStruct.Pull = GPIO_PULLUP;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 /*Configure GPIO pin : LED_Blue_Pin */
 GPIO_InitStruct.Pin = LED_Blue_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(LED_Blue_GPIO_Port, &GPIO_InitStruct);

 /* EXTI interrupt init*/
 HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(EXTI3_IRQn);

 HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(EXTI4_IRQn);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @param  file: The file name as string.
 * @param  line: The line in file as a number.
 * @retval None
 */
void _Error_Handler(char *file, int line)
{
 /* USER CODE BEGIN Error_Handler_Debug */
 /* User can add his own implementation to report the HAL error return state */
 while(1)
 {
 }
 /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t* file, uint32_t line)
{ 
 /* USER CODE BEGIN 6 */
 /* User can add his own implementation to report the file name and line number,
    tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
 /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/**
 * @}
 */

/**
 * @}
 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Co prawda w trybie ciągłym nie powinno być potrzebne ponowne wywoływanie HAL_ADC_Start_IT, więc kolejny krok to poprawienie konfiguracji ADC i wyrzucenie tej funkcji. Chociaż wydaje mi się, że taka jak teraz wersja działa poprawnie.

[ Dodano: 19-05-2018, 23:49 ]

Podpowiem - wystarczy zmienić konfigurację ADC i działa bez HAL_ADC_Start_IT. Ale to już chyba byłoby za łatwo żebym wszystko podpowiadał. Wydaje mi się, że poradzisz sobie bez pomocy.

  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

Dziękuję za pomoc. Trzeba było zmienić opcję w sekcji: End of conversion selection na

EOC Flag on the end of all conversions.

Teraz tylko mam pytanie, dlaczego to pomogło? Dlaczego przy używaniu liczb całkowitych, program mógł się wykonywać, a przy zmianie na zmiennoprzecinkowe już nie? Dlaczego przerwanie generowane po wykonaniu wszystkich konwersji, sprawiło poprawne wykonanie programu<- bo w ten sposób rozumiem tę flagę. I koniec końców skąd program wiedział ile jest tych konwersji, po których generować przerwanie? Jeżeli to są banały, to przepraszam i jeżeli znajdę odpowiedź na nie w literaturze to chętnie bym się dowiedział jakiej.

Pozdrawiam.

Link do komentarza
Share on other sites

To nie są banały, ale bardzo słusznie zadawane pytania. Wbrew pozorom wcale nie jest tak łatwo na nie odpowiedzieć.

Zacznijmy więc od pewnej niepisanej reguły: przerwania powinny być obsługiwane szybko.

Można oczywiście pisać programy inaczej, ale to bywa trudniejsze. W Twoim programie mamy bardzo dużo przerwań od przetwornika ADC - po każdym pomiarze wywoływane jest przerwanie. I nie jest to 4096 na sekundę, tylko ponad 22000 (jako ćwiczenie polecam sprawdzić i przeliczyć).

Biblioteka HAL nakłada na obsługę przerwań pewien "narzut" więc generowanie ich tak często jest już pewnym wyzwaniem. Ale ważniejsze jest coś innego - nie znam STM32F411, ale na szybko przejrzałem notę katalogową i z tego co widzę przetwornik wykrywa wykonanie kolejnego pomiaru bez odczytu poprzedniego. Czyli innymi słowy jeśli któreś z 22000 przerwań nie zostanie obsłużone na czas, w odpowiednim rejestrze zapali się flaga błędu.

Ponieważ nie obsługujesz błędów, nawet o tym nie wiesz... Trochę szkoda, ale czasem lepiej zaimplementować HAL_ADC_ErrorCallback tylko po to żeby wyświetlić "blue-screen" jeśli coś działa inaczej niż zakładamy.

A wracając do przerwań. Problemem jest wywołanie sprintf w procedurze obsługi przerwania od TIM10. Ogólnie printf-y są bardzo rozbudowanymi i mało wydajnymi funkcjami. A jeszcze obsługa float-ów sprawia, że to przerwanie jest obsługiwane dłużej i blokuje odczyty z ADC.

Jak chcesz sprawdzić czy mam rację, najpierw zmień program na niedziałającą wersję z float-ami, EOC jak wcześniej.

Następnie jedyne co zmień do generowanie komunikatu:

    size = sprintf(data, "%d\r\n", (int)Wyjscie);

W takiej wersji obliczenia są na float-ach i u mnie działało poprawnie.

Ostatni "dowód" na teorię o opóźnieniu przerwań to dodanie sztucznego opóźnienia, czyli po sprintf coś jak:

				for (volatile int i=0;i<500;i++);

Program zacznie zachowywać się jak na początku, czyli niepoprawnie.

Ogólnie radziłbym wypisywanie komunikatów przenieść do programu głównego. Przerwania nie powinny być blokowane na dłużej, więc można w nich obliczyć wynik (Wyjscie) i zapalić flagę inforumjącą o gotowości do wysłania, ale samo formatowanie, wysyłanie (i obsługa błędów) powinny być poza tym przerwaniem.

A dlaczego zmiana EOC pomagała - sam nie wiem... Jak napisałem, nie znam modelu F411, więc jedyne co mogę doradzić to dokładne przeczytanie noty katalogowej. Tam jest dokładnie opisane jak przetwornika analogowo-cyfrowy działa w tym układzie.

  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.