Skocz do zawartości
skibos

STM32 F042K6 przerwania obsługa silników

Pomocna odpowiedź

Witam,

czy jest ktoś mi w stanie objaśnić idee przerwań w stm32? Mam czujniki które zmieniają stan pinu z wysokiego na niski kiedy czujnik będzie widział jakiś obiekt, jeśli nie pin będzie w stanie wysokim. Mam napisane funkcje do mostka ustawiające odpowiednio stany pinów aby silniki jechały w odpowiednim kierunku te funkcje to: forward(), right(), left(). Chciałbym aby cały czas wykonywała się funkcja left(), natomiast gdy czujnik zauważy przeszkodę tzn. pin zmieni się ze stanu wysokiego na niski to program się przerwał i jeśli np. zauważy czujnik przedni to wykonał  funkcję  forward(), jeśli  stan  zmieni  się  na  wysoki  na  tym  pinie  to żeby znów  wykonywała  się funkcja left(). Jednakże nie chce aby wykonywało się to ifami bo to ciągłe obciążenie procesora poprzez sprawdzanie stanu pinu milion razy na minute tylko przerwaniami gdzie funkcja wykona się tylko wtedy kiedy nastąpiło przerwanie na pinie a jak  przerwania na tym pinie już nie będzie to żeby funkcja wróciła to programu głównego. Testowałem już miliony rozwiązań jednak wciąż nie doszedłem do właściwej odpowiedzi. Podczas dodawania do pętli głównej programu left() oraz ustawienie przerwań na callbacku, przerwania się nie wykonują tzn cały czas wykonuje się program główny niezależnie od stanu na pinach czujników. Kod:

 

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */
int przodprawo, przodlewo, lewo, prawo;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
void forward();
void left();
void right();
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int 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_TIM2_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  left();
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48;
  RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief TIM2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 5;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 254;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */
  HAL_TIM_MspPostInit(&htim2);

}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

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

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_3, GPIO_PIN_RESET);

  /*Configure GPIO pins : PA4 PA5 PA6 PA7 */
  GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PB0 PB3 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : przod_lewo_Pin przod_prawo_Pin */
  GPIO_InitStruct.Pin = przod_lewo_Pin|przod_prawo_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


  /*Configure GPIO pins : prawo_Pin lewo_Pin */
  GPIO_InitStruct.Pin = prawo_Pin|lewo_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

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

}

/* USER CODE BEGIN 4 */
void forward(){

	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
	  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 70);
	  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 70);
}
void left(){

	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
	  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 70);
	  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 70);
}
void right(){

	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
	  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 70);
	  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 70);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
	if(GPIO_Pin == przod_prawo_Pin || GPIO_Pin == przod_lewo_Pin){
	forward();

	}
	if(GPIO_Pin == prawo_Pin){
		right();

	}
	if(GPIO_Pin == lewo_Pin){
		left();

	}

}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* 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(char *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****/

 

Udostępnij ten post


Link to post
Share on other sites

Cześć,

w STM32 praktycznie każdy pin GPIO może pracować jako zewnętrzne przerwanie, Wystarczy to odpowiednio oznaczyć np. podczas generowania szkieletu programu w STM32CubeMX.

Patrz ten zrzut ekranu:

CubeMX01_.thumb.png.317cbfcfb2868938d79fa3f34dda4edb.png

Pozdrawiam

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Tak wiem, Piny odpowiadające za czujniki zadeklarowałem jako przerwania, przerwania zostały włączone w cubemx. Chodzi o kwestię programową aby program w kółko wykonywał funkcję left() tzn. robot kręcił się w lewo a gdy zobaczy przeszkodę na przednim czujniku przerwanie tak jakby zatrzyma te kręcenie i dopóki będzie na czujniku stan niski to będzie wykonywał funkcję forward(), identycznie z czujnikiem prawym tylko funkcja right(). Jeśli stan urośnie z niskiego na wysoki na przerwaniu to funkcja znów wróci  do pierwotnego działania tzn kręcenia w lewo ( wykonywania funkcji left()).

Udostępnij ten post


Link to post
Share on other sites
9 minut temu, skibos napisał:

Tak wiem, Piny odpowiadające za czujniki zadeklarowałem jako przerwania, przerwania zostały włączone w cubemx. Chodzi o kwestię programową aby program w kółko wykonywał funkcję left() tzn. robot kręcił się w lewo a gdy zobaczy przeszkodę na przednim czujniku przerwanie tak jakby zatrzyma te kręcenie i dopóki będzie na czujniku stan niski to będzie wykonywał funkcję forward(), identycznie z czujnikiem prawym tylko funkcja right(). Jeśli stan urośnie z niskiego na wysoki na przerwaniu to funkcja znów wróci  do pierwotnego działania tzn kręcenia w lewo ( wykonywania funkcji left()).

Cześć,

to teraz musisz zadeklarować odpowiednie zmienne stanu (globalne) i odpowiednio zmieniać je w obsłudze przerwania (ustawiać) a w pętli głównej na podstawie tych zmiennych podejmować odpowiednie decyzje. Graf przejść od stanu do stanu najlepiej zaprogramować jako maszynę stanów skończonych  (FSM) wtedy unikniesz "dziwnych" zachowań systemu.

Patrz np. te linki:

https://pl.wikipedia.org/wiki/Automat_skończony

https://pl.wikipedia.org/wiki/Diagram_maszyny_stanowej

https://ep.com.pl/files/1436.pdf

Pozdrawiam

 

Udostępnij ten post


Link to post
Share on other sites

Cześć Skibos,

i jak tam sobie radzisz? Może wyjaśnię dlaczego tak bym to rozwiązał.Staram się w moich projektach używać już od dłuższego czasu FSM bo to ułatwia programowanie i rozwój programu (szczególnie gdy graf przejść pomiędzy stanami jest skomplikowany). Oprogramowanie takiej maszyny stanowej naprawdę nie jest trudne (jak już sobie rozrysujesz graf przejść pomiędzy stanami i określisz dla jakich warunków mają następować przejścia).

Tutaj masz prosty przykład jak to można zrobić w kodzie programu:

https://yakking.branchable.com/posts/state-machines-in-c/

Procedury obsługi przerwań muszą być maksymalnie krótkie, więc w nich tylko ustawiasz zmienne globalne używane w warunkach przejść między stanami.W pętli głównej masz zaimplementowaną maszynę stanową która na podstawie zmiennych stanu dokonuje przejść między stanami i oczywiście jakieś konkretne akcje np. w momencie wejścia do konkretnego stanu. FSM to sposób na zapanowanie nad działaniem układu według naszych założeń.

Pozdrawiam

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

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!

Gość
Dołącz do dyskusji! Kliknij, aby zacząć 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...