Skocz do zawartości

Kurs STM32L4 – #7 – przerwania sprzętowe, obsługa błędów


Pomocna odpowiedź

Wyjaśnij jeszcze Co to znaczy że nie działa? Czy debugger wchodzi do tej funkcji czy widzisz zmieniające się wartości old value I value?

Kot może szaleć ponieważ uard nie jest szybkim peryferium jak za szybko będziesz wysyłał do niego dane to albo będziesz miał krzaki albo będziesz miał overrun i póki nie skasujesz flagi błędu To nic nie dostaniesz chyba że masz włączone nadpisywanie danych.

Generalnie wstawianie printf do przerwania to nie jest dobra praktyka i najczęściej służy celom dydaktycznym w ramach debugowania. Co do pytania odnośnie realizacji zadania trzeciego to wydaje mi się że o wrapowanie print efa jakoś funkcja nie miałoby już sensu bo i tak print jest realizowany przez wcześniejszą modyfikację putchar i tam siedzi Twój kod od uarta

  • 3 miesiące później...

Witam. Mam problem z odbieraniem danych przez UART. Gdy dodaje breakpoint na funkcji funkcji HAL_UART_RxCpltCallback nic się nie dzieje. Nie mogę również wpisać w konsoli on/off. Czy to wina ustawienia konsoli? Używam PuTTy do komunikacji, ponieważ do programowania korzystam z Ubuntu.

/* USER CODE BEGIN 0 */
#define LINE_MAX_LENGTH 80

static char line_buffer[LINE_MAX_LENGTH + 1];
static uint32_t line_length;

void line_append(uint8_t value)
{
  if (value == '\r' || value == '\n') {
    // odebraliśmy znak końca linii
    if (line_length > 0) {
      // dodajemy 0 na końcu linii
      line_buffer[line_length] = '\0';
      // przetwarzamy dane
      if (strcmp(line_buffer, "on") == 0) {
        HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
      } else if (strcmp(line_buffer, "off") == 0) {
        HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
      }

      // zaczynamy zbieranie danych od nowa
      line_length = 0;
    }
  }
  else {
    if (line_length >= LINE_MAX_LENGTH) {
      // za dużo danych, usuwamy wszystko co odebraliśmy dotychczas
      line_length = 0;
    }
    // dopisujemy wartość do bufora
    line_buffer[line_length++] = value;
  }
}

uint8_t uart_rx_buffer;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart == &huart2) {
    line_append(uart_rx_buffer);
    HAL_UART_Receive_IT(&huart2, &uart_rx_buffer, 1);
  }
}

int message_number = 0;

void send_next_message(void)
{
  static char message[] = "Hello World!\r\n";
  static char message2[] = "Forbot jest super!\r\n";

  switch (message_number)
  {
  case 0:
    HAL_UART_Transmit_IT(&huart2, (uint8_t*)message, strlen(message));
    message_number = 1;
    break;
  case 1:
    HAL_UART_Transmit_IT(&huart2, (uint8_t*)message2, strlen(message2));
    message_number = 2;
    break;
  default:
    break;
  }
}


void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart == &huart2) {
    	send_next_message();
    }
}

volatile uint32_t push_counter;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == USER_BUTTON_Pin) {
	  push_counter++;
  }
}

int __io_putchar(int ch)
{
  if (ch == '\n') {
    __io_putchar('\r');
  }

  HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, HAL_MAX_DELAY);

  return 1;
}


/* USER CODE END 0 */

Główna funkcja

nt main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

  	  send_next_message();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	  uint32_t old_push_counter = push_counter;
  while (1)
  {
	  if(old_push_counter != push_counter) {
		  old_push_counter = push_counter;
		  printf("counter: %lu\n", old_push_counter);
	  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

Ustawienia NVIC obraz.thumb.png.ccae564700c51c98b1aadf683f6a5fa6.png

Dziękuję za pomoc! Pozdrawiam

@erysv rozumiem że to:

int __io_putchar(int ch)

jest nieużywane, chcesz na przerwaniu wysyłać. A z odbieraniem to gdzie masz jakiś fragment kodu do rozpoczęcia odbierania?

  • Lubię! 1
  • 5 miesiące później...

Cześć i czołem.

Jak zwykle świetny materiał. Widzę, że nikt wcześniej o to nie zapytał, więc sam postanowiłem zagaić temat odnośnie fragmentu ze "śmieciami" w miejscu byłej zmiennej. Jak to jest, że zmienna x utworzona w funkcji test trafiła akurat do tego konkretnego miejsca w pamięci? Spodziewałem się, że dysponowanie pamięcią na stosie przez program to bardziej kwestia przypadku, a okazuje się, że twórcy kursu byli w stanie na 100% przewidzieć, że u każdego czytelnika zmienna x pojawi się na miejscu zmiennej message. Jak to działa?

Przy okazji chciałem przypomnieć, że w komentarzach do tej części kursu jeden z autorów zadeklarował się, że wrzuci adnotację odnośnie zmiany przez ST domyślnego priorytetu dla przerwania System Tick Timer. Taka informacja byłaby cenna. Sam dopiero po czasie zauważyłem, że widnieje liczba 15 zamiast 0, ale mimo zdziwienia uznałem, że chyba przypadkowo sam to zmieniłem 😄

Pozdrawiam

@masi23x Bardzo dobre pytanie, stos faktycznie wydaje się nieco magicznym i bardzo losowym zjawiskiem, chociaż w rzeczywistości wcale taki nie jest.

Zacznijmy jednak od wyjaśnienia czegoś innego - celem tego przykładu nie było pokazanie komunikatu jakie zobaczy użytkownik, ale zwrócenie uwagi, że wartości zmiennej lokalnej zostaną nadpisane i w rezultacie wysłany komunikat może być niepoprawny. Faktycznie, dokładna treść komunikatu może być różna w zależności od wersji i ustawień kompilatora. Okazuje się jednak, że skoro użytkownicy kursu używają mniej-więcej tej samej wersji środowiska CubeIDE, czyli bibliotek i kompilatora, więc uruchamiane programy działają bardzo podobnie.

Pojawia się więc kolejne, może nawet ciekawsze pytanie - jak to jest z tym stosem i czy wartości na nim są losowe? Okazuje się, że nie - procesory działają w sposób deterministyczny, więc i zawartość stosu jest przewidywalna. Więc jeśli jedna funkcja tworzy na stosie zmienne lokalne, a następnie kolejna funkcja będzie używała stosu, to nastąpi nadpisanie wartości - i o ile nie wystąpią przerwania używające tego samego stosu, to każde uruchomienie będzie dawało identyczne efekty.

 

  • Lubię! 1
  • 10 miesiące później...

Hej. Bardzo fajny kurs. Trochę czasu zajęło mi uruchomienie licznika drugiego przycisku. Napisałem szybko, ale nie działało. Przyczyna trywialna - Port, który próbowałem: PC14 nie ma sprzętowego PULL_UP, mimo że w MX można to skonfigurować. Pomógł multimetr. W końcu zadziałało na PC10.
Niestety płytki Nucleo nie mają opisów portów i trzeba korzystać z dokumentacji a w takich przypadkach pierwsze podejrzenie pada na wetknięcie kabelka na niewłaściwy port. Brak sprzętowego debounce to makabra i trzeba to zrobić programowo. Chciałem jak najprościej, też dla wbudowanego przycisku  i działa.

volatile uint32_t push_counter;
volatile uint32_t push_counter2;
volatile uint32_t start_time = 0;
volatile uint32_t start_time2 = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == USER_BUTTON_Pin) {
	  if(HAL_GetTick() - start_time >= 200){
	  push_counter++; //Licznik naciśnięć przycisku.
	  start_time = HAL_GetTick();
	  }
  }
  if(GPIO_Pin == USER_BUTTON2_Pin){
	  if(HAL_GetTick() - start_time2 >= 200){
	  push_counter2++; //Licznik naciśnięć przycisku.
	  start_time2 = HAL_GetTick();
	  }
  }
}

Działa też prawidłowo naciśnięcie obydwu przycisków.

Natomiast kompilator nie pozwolił mi wstawić tych deklaracji do wewnątrz funkcji jako static.

volatile uint32_t start_time = 0;
volatile uint32_t start_time2 = 0;

Zawsze mi się to udawało, ale nie w ISR-ach. Pewnie jest jakieś ograniczenie.

Czy można static volatile lub volatile static? Nie próbowałem.

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...