Skocz do zawartości

STM32 F411 Timer interrupt nie działa


Pomocna odpowiedź

Napisano

Jak w temacie, płytka to blackpill f411, ustawiłem częstotliwość pracy płytki na 16MHz, timer 2 posiada clock source = internal source, prescaler = 1600-1, counter period = 10000-1, auto-reload preload = enable. Powinna wyjść zatem sekunda. W ustawieniach NVIC timer 2 global interrupt zaznaczony, w kodzie w main.c oczywiście wystartowanie timera:

HAL_TIM_Base_Start_IT(&htim2);

w pętli while nic się nie dzieje, za to w user code begin 4 mam to:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
	checkTempAndHumSTH31();
}

void checkTempAndHumSTH31() {
	uint8_t txBuff [2] ={0x24, 0x00};
	uint8_t rxBuff [6];
	uint16_t raw_temp = 0;
	uint16_t raw_hum = 0;
	HAL_I2C_Master_Transmit(&hi2c1, STH31_ADDR, txBuff,	sizeof(txBuff), HAL_MAX_DELAY);
	HAL_Delay(50);
	HAL_I2C_Master_Receive(&hi2c1, STH31_ADDR, rxBuff, sizeof(rxBuff), HAL_MAX_DELAY);
	HAL_Delay(50);
	raw_temp = rxBuff[0] << 8 | rxBuff[1];
	raw_hum = rxBuff[3] << 8 | rxBuff[4];
	temperature = -45.0f + 175.0f * (raw_temp / 65535.0f);
	humidity = 100.0f * (raw_hum / 65535.0f);
}

Kod odczytujący temperaturę oraz wilgotność działał w pętli while z dodanym HAL_Delay(1000);, ale jest to bardzo nieporęczna metoda uzyskiwania danych, zwłaszcza, że będę wpinał inne czujniki. Na chwilę obecną raz przerwanie się pojawi w momencie startu i nie jest prawdopodobnie nawet dokończone - debugger zatrzymuje się na HAL_Delay(50); i przechodzi do działania while od razu.

 

Dodatkowe pytanie - czy ktoś ma pomysł jak mogę usprawnić ten kod? I dodatkowo czy istnieje jakiś prosty w tłumaczeniu poradnik jak zrobić własny plik .c oraz .h? W internecie nie znalazłem nigdzie sensownie działających plików do tego czujnika, to mam ochotę samemu zrobić taki.

Kod zawierający jakiekolwiek "delay-e" nie zadziała poprawnie w procedurze obslugi przerwania (a tak de facto jest wołana HAL_TIM_PeriodElapsedCallback()). Także słowo "delay" to pierwsze zło, które tu dostrzegam.

  • Lubię! 1
(edytowany)

Okej, jak opóźnić zatem odbiór danych z i2c, pozostawienie tego bez żadnej zwłoki powoduje wysypanie się komunikacji - czujnik musi przetworzyć dane oraz je wysłać. Istnieje może wskaźnik jakiś czy w buforze znajdują się dane do odebrania jak jest to w wypadku uarta?

Edytowano przez DeadGeneratio
(edytowany)

W procedurze obsługi przerwania nie może znajdować się kod, który wprowadza jakiekolwiek opóźnienia (wywołania HAL_Delay(), wywołania jakichkolwiek blokujących funkcji API itd.). Przerwanie od timer-a może Ci posłużyć do zainicjowania procesu komunikacji z czujnikiem, ale nie możesz tam umieścić całego "algorytmu", o ile nie jest to operacja "natychmiastowa".

Z lotu ptaka to wygląda tak, że w przerwaniu od timer-a wysyłasz żądanie odczytu, natomiast o tym, że dane są gotowe i można je odebrać, dowiadujesz się za jakiś czas (np. za pięć milisekund) w przerwaniu od urządzenia, które obsługujesz. Tu trzeba by poszperać po kodzie HAL-a i poczytać o trybie przerwaniowym w I2C. Do płytki STM32F4 powstał nawet dokument (UM1725) - dokumentacja driverów HAL. Zbyt wylewny to ten dokument nie jest, ale na szczęście nie jest to tylko lista nagłówków funkcji API:
https://www.st.com/resource/en/user_manual/um1725-description-of-stm32f4-hal-and-lowlayer-drivers-stmicroelectronics.pdf

W prostym projekcie hobbystycznym warto pomyśleć, czy skórka jest warta wyprawki. W pętli głównej możesz zrobić za pomocą kilku zmiennych namiastkę "maszyny stanów". Wkładasz do pętli głównej jeden HAL_Delay(X), gdzie X jest "kwantem czasu", co jaki Twoja pętla budzi się do działania, i w każdym obiegu pętlli, dzięki "zmiennym stanu" sprawdzasz, w którym jesteś kroku i jaką masz podjąć akcję. Można w ten sposób np. prosto obsłużyć cykl komunikacji z kilkoma czujinkami typu:
żadanie1 -> odczyt1 -> żądanie2 -> odczyt2 -> żądanie3 -> odczyt3-> .......... -> żądanie1 -> odczyt1 -> ...                   

 

Edytowano przez ReniferRudolf
13 godzin temu, ReniferRudolf napisał:

W procedurze obsługi przerwania nie może znajdować się kod, który wprowadza jakiekolwiek opóźnienia (wywołania HAL_Delay(), wywołania jakichkolwiek blokujących funkcji API itd.).

To nie do końca prawda w przypadku STM32. HAL_Delay to zwykły polling na rejestrze SysTicku, może być przerwany prze każde inne, o lepszym priorytecie przerwanie. Tam jest wielopoziomowy system priorytetów i wywłaszczeń dzięki, któremu zasada taka znana choćby z AVR nie jest tak ścisła. W AVR _delay wyłącza przerwania, w STM32 tak nie jest. Przy poprawnie zaprojektowanym urządzeniu w przerwaniach mogą być dowolnie długo trwające procedury.

Oczywiście w szczególnych przypadkach należy trzymać się zasady krótkiego "kodu" w przerwaniach i pewnie w tym przypadku, dla mniej wprawionego programisty, będzie to dobra i skuteczna zasada.

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...