Este tutorial contém as informações necessárias para criar um programa simples para monitorar um botão e verificar o resultado através do acendimento de um LED do kit STM32F429-DISCO.
O primeiro passo é a criação do projeto, como visto na Figura 1.
Figura 1. Criando um projeto novo.
Fonte: Adaptado pelo autor de STM32CubeIDE.
O programa exibe a Figura 2, onde o usuário pode selecionar o MCU ou a placa do dispositivo. Neste caso, na aba Board selector, foi inserido a descrição da placa STM32F429. Conforme o usuário digita, a ferramenta filtra as opções existentes
Figura 2. Janela de seleção do MCU/Placa.
Fonte: Adaptado pelo autor de STM32CubeIDE.
A janela da Figura 2, mostra diversas informações da placa selecionada, tais como, especificações, datasheet do MCU, preço etc. Ao pressionar o botão Next, a ferramenta exibe a janela da Figura 3, onde é solicitado o nome do projeto, sendo que o local de gravação do projeto é definido no momento da instalação da ferramenta.
Figura 3. Definição do nome do projeto.
Fonte: Adaptado pelo autor de STM32CubeIDE.
Ao definir o nome do projeto na janela da Figura 3, a ferramenta exibe a janela vista na Figura 4. Na janela da Figura 4, o usuário define a versão do compilador e opções de geração de projeto. É recomendado manter as opções mostradas na Figura 4 e pressionar o botão Finish para iniciar o processo de geração da estrutura do projeto.
Figura 4. Definições do projeto.
Fonte: Adaptado pelo autor de STM32CubeIDE.
A ferramenta exibira mais duas janela perguntando ao usuário sobre a geração do projeto. É recomendado responder Yes para as duas janelas seguintes.
Figura 5. Geração do projeto.
Fonte: Adaptado pelo autor de STM32CubeIDE.
Ao final da geração da estrutura do projeto a ferramenta exibe o que é visto na Figura 5. No lado esquerdo tem-se a janela Project Explorer, que exibe a estrutura do projeto, definida nos passos anteriores deste tutorial. Dentro desta estrutura tem-se a árvore de pastas e arquivos criados que compõe o projeto. Em destaque tem-se a pasta Src, que contém os arquivos principais deste projeto, dentre eles o arquivo main.c.
A Figura 5 também apresenta a janela de configuração do MCU, chamada de Pinout & Configuration. Nesta janela o usuário define o funcionamento dos pinos, como entrada e saída, por exemplo. No lado esquerdo da mesma janela, tem-se os periféricos organizados, sendo possível definir habilitar ou desabilitar cada um deles. Neste projeto, se faz necessário revisar cada grupo de periféricos e desabilitar todos, excetuado o grupo System Core, periféricos, GPIO, NVIC, RCC e SYS.
Figura 5. Janela de perspectiva de programação do projeto.
Fonte: Adaptado pelo autor de STM32CubeIDE.
Na janela central, chamada de Pinout, o usuário pode configurar o comportamento dos pinos individualmente. No caso deste projeto, quando da sua criação, foi escolhida a placa do Kit STM32F429, desta forma a ferramenta já traz a configuração para os pinos, como por exemplo, dos LEDs conectados aos pinos PG13 e PG14, configurados como saídas digitais e a chave USER, conectada ao pino PA0, configurada como entrada. A Figura 6, mostra em detalhes as configurações possíveis para o pino PG13, quando o usuário clicar no pino em questão.
Figura 6. Configurações do pino PG13.
Fonte: Adaptado pelo autor de STM32CubeIDE.
Vencida a configuração dos pinos do MCU, passa-se para a clock. Na figura 7, tem-se a janela de configuração dos clocks do MCU. O usuário pode digitar um valor de clock de funcionamento para o MCU na caixa de texto em destaque ao centro, para em seguida a ferramenta selecionar a configuração interna necessária para o valor informado. Neste exemplo, a fonte de clock é o cristal de 8 MHz, presente na placa e para o valor de saída de 72 MHz a ferramenta ajustou as configurações como exibidas na Figura 7.
Figura 7. Configurações do clock.
Fonte: Adaptado pelo autor de STM32CubeIDE.
Figura 8. Configurações do Project Manager.
Fonte: Adaptado pelo autor de STM32CubeIDE.
Na Figura 8, tem-se a aba de gerenciamento do projeto, chamada de Project Manager, que contém as definições de nome, local de gravação, tamanho de Heap e MCU escolhido pelo usuário. Para este exemplo não há necessidade de alterações nesta aba.
Na Figura 9, tem-se a aba chamada de Tools, que possui uma ferramenta de estimação de energia consumida pelo MCU, e opções de inicialização avançadas mas que também não são necessárias para este exemplo.
Figura 9. Configurações Avançadas.
Fonte: Adaptado pelo autor de STM32CubeIDE.
Com todas estas configurações feitas o usuário deve salvar projeto para que as alterações tenham efeito. Se o usuário necessitar alterar algum configuração no futuro, basta executar dois clicks no arquivo le_tecla_piscaled.ioc para abrir o assistente novamente.
Os passos anteriores foram necessários para gerar o código fonte inicial como mostrado na lista abaixo:
Código do programa
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* 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 ---------------------------------------------------------*/
HCD_HandleTypeDef hhcd_USB_OTG_HS;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USB_OTG_HS_HCD_Init(void);
/* USER CODE BEGIN PFP */
/* 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();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 72;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 3;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
Error_Handler();
}
}
/**
* @brief USB_OTG_HS Initialization Function
* @param None
* @retval None
*/
static void MX_USB_OTG_HS_HCD_Init(void) {
/* USER CODE BEGIN USB_OTG_HS_Init 0 */
/* USER CODE END USB_OTG_HS_Init 0 */
/* USER CODE BEGIN USB_OTG_HS_Init 1 */
/* USER CODE END USB_OTG_HS_Init 1 */
hhcd_USB_OTG_HS.Instance = USB_OTG_HS;
hhcd_USB_OTG_HS.Init.Host_channels = 12;
hhcd_USB_OTG_HS.Init.speed = HCD_SPEED_FULL;
hhcd_USB_OTG_HS.Init.dma_enable = DISABLE;
hhcd_USB_OTG_HS.Init.phy_itface = USB_OTG_EMBEDDED_PHY;
hhcd_USB_OTG_HS.Init.Sof_enable = DISABLE;
hhcd_USB_OTG_HS.Init.low_power_enable = DISABLE;
hhcd_USB_OTG_HS.Init.vbus_sensing_enable = DISABLE;
hhcd_USB_OTG_HS.Init.use_external_vbus = DISABLE;
if (HAL_HCD_Init(&hhcd_USB_OTG_HS) != HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN USB_OTG_HS_Init 2 */
/* USER CODE END USB_OTG_HS_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_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, NCS_MEMS_SPI_Pin | CSX_Pin | OTG_FS_PSO_Pin,
GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(ACP_RST_GPIO_Port, ACP_RST_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, RDX_Pin | WRX_DCX_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOG, LD3_Pin | LD4_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : A0_Pin A1_Pin A2_Pin A3_Pin
A4_Pin A5_Pin SDNRAS_Pin A6_Pin
A7_Pin A8_Pin A9_Pin */
GPIO_InitStruct.Pin = A0_Pin | A1_Pin | A2_Pin | A3_Pin | A4_Pin | A5_Pin
| SDNRAS_Pin | A6_Pin | A7_Pin | A8_Pin | A9_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/*Configure GPIO pins : SPI5_SCK_Pin SPI5_MISO_Pin SPI5_MOSI_Pin */
GPIO_InitStruct.Pin = SPI5_SCK_Pin | SPI5_MISO_Pin | SPI5_MOSI_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI5;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/*Configure GPIO pin : ENABLE_Pin */
GPIO_InitStruct.Pin = ENABLE_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(ENABLE_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : SDNWE_Pin */
GPIO_InitStruct.Pin = SDNWE_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(SDNWE_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : NCS_MEMS_SPI_Pin CSX_Pin OTG_FS_PSO_Pin */
GPIO_InitStruct.Pin = NCS_MEMS_SPI_Pin | CSX_Pin | OTG_FS_PSO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pins : B1_Pin MEMS_INT1_Pin MEMS_INT2_Pin TP_INT1_Pin */
GPIO_InitStruct.Pin = B1_Pin | MEMS_INT1_Pin | MEMS_INT2_Pin | TP_INT1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : B5_Pin VSYNC_Pin G2_Pin R4_Pin
R5_Pin */
GPIO_InitStruct.Pin = B5_Pin | VSYNC_Pin | G2_Pin | R4_Pin | R5_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : ACP_RST_Pin */
GPIO_InitStruct.Pin = ACP_RST_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(ACP_RST_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : OTG_FS_OC_Pin */
GPIO_InitStruct.Pin = OTG_FS_OC_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(OTG_FS_OC_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : R3_Pin R6_Pin */
GPIO_InitStruct.Pin = R3_Pin | R6_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF9_LTDC;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : BOOT1_Pin */
GPIO_InitStruct.Pin = BOOT1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BOOT1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : A10_Pin A11_Pin BA0_Pin BA1_Pin
SDCLK_Pin SDNCAS_Pin */
GPIO_InitStruct.Pin = A10_Pin | A11_Pin | BA0_Pin | BA1_Pin | SDCLK_Pin
| SDNCAS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/*Configure GPIO pins : D4_Pin D5_Pin D6_Pin D7_Pin
D8_Pin D9_Pin D10_Pin D11_Pin
D12_Pin NBL0_Pin NBL1_Pin */
GPIO_InitStruct.Pin = D4_Pin | D5_Pin | D6_Pin | D7_Pin | D8_Pin | D9_Pin
| D10_Pin | D11_Pin | D12_Pin | NBL0_Pin | NBL1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/*Configure GPIO pins : G4_Pin G5_Pin B6_Pin B7_Pin */
GPIO_InitStruct.Pin = G4_Pin | G5_Pin | B6_Pin | B7_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pins : D13_Pin D14_Pin D15_Pin D0_Pin
D1_Pin D2_Pin D3_Pin */
GPIO_InitStruct.Pin = D13_Pin | D14_Pin | D15_Pin | D0_Pin | D1_Pin | D2_Pin
| D3_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure GPIO pin : TE_Pin */
GPIO_InitStruct.Pin = TE_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(TE_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : RDX_Pin WRX_DCX_Pin */
GPIO_InitStruct.Pin = RDX_Pin | WRX_DCX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure GPIO pins : R7_Pin DOTCLK_Pin B3_Pin */
GPIO_InitStruct.Pin = R7_Pin | DOTCLK_Pin | B3_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/*Configure GPIO pins : HSYNC_Pin G6_Pin R2_Pin */
GPIO_InitStruct.Pin = HSYNC_Pin | G6_Pin | R2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : I2C3_SDA_Pin */
GPIO_InitStruct.Pin = I2C3_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
HAL_GPIO_Init(I2C3_SDA_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : I2C3_SCL_Pin */
GPIO_InitStruct.Pin = I2C3_SCL_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
HAL_GPIO_Init(I2C3_SCL_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : STLINK_RX_Pin STLINK_TX_Pin */
GPIO_InitStruct.Pin = STLINK_RX_Pin | STLINK_TX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : G7_Pin B2_Pin */
GPIO_InitStruct.Pin = G7_Pin | B2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure GPIO pins : G3_Pin B4_Pin */
GPIO_InitStruct.Pin = G3_Pin | B4_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF9_LTDC;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/*Configure GPIO pins : LD3_Pin LD4_Pin */
GPIO_InitStruct.Pin = LD3_Pin | LD4_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/*Configure GPIO pins : SDCKE1_Pin SDNE1_Pin */
GPIO_InitStruct.Pin = SDCKE1_Pin | SDNE1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief Period elapsed callback in non blocking mode
* @note This function is called when TIM6 interrupt took place, inside
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param htim : TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM6) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}
/**
* @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 */
__disable_irq();
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,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
O código acima, inicializa os pinos dos Leds e do botão conectados respectivamente nos pinos, PG13, PG14 e PA0. A implementação deste programa pode ser feito de duas formas: usando as funções das bibliotecas que compõe a Hardware Abstraction Layer (HAL) ou as funções do conjunto Lower Layer (LL). As funções da HAL consitem de funções com alto nível de abstração, que agilizam o desenvolvimento de aplicações, uma vez que não utiliza sintaxe de funções especificas ligadas aos registradores de qualquer MCU da família. Desta forma o desenvolvedor não necessita de grandes conhecimentos sobre a arquitetura do MCU em questão. Este nível de abstração utiliza funções genéricas e o código natio do MCU é gerado na compilação. Por outro lado, a camada LL o desenvolvedor configura o dispositivo diretamente escrevendo nos registradores do MCU, sendo esta forma a mais próxima da linguagem nativa do dispositivo e exige amplo conhecimento da arquitetura. Esta forma mantém um código mais limpo do que a HAL porém pode exigir maior tempo para elaboração das aplicações. No código abaixo, contido dentro do laço infinito principal, tem-se a implementação da leitura do botão e acendimento de um LED usando HAL:
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, 1);
else
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, 0);
A função HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) é a função usada para a leitura de pinos quaisquer e recebe como parâmetros: um ponteiro que identifica a porta, neste caso GPIOA, e o número do pino da porta a ser lido, neste caso 0, que especifica o pino PA0. Esta função retorna o estado lógico do pino em questão.
Figura 10. Circuito do botão do usuário.
Fonte: Adaptado pelo autor.
A Figura 10 exibe o circuito do botão do usuário conectado ao pino PA0. Enquanto o botão não estiver pressionado, o nível lógico no pino PA0 é 0. Ao ser pressionado o nível passa para 1. No código do programa o Led permanece aceso enquanto o botão não estiver pressionado e apagado caso contrário.
A função HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState) é usada para escrever um nível lógico para determinado pino. O primeiro parâmetro é um ponteiro que identifica a porta, o segundo identifica o pino da porta e o terceiro parâmetro representa o nível lógico do pino.
A seguir é tratado o uso de interrupções para o monitoramento de entradas que podem ser usadas para monitor chaves, por exemplo.
O trecho de código a seguir representa uma situação em que um LED(PG13) fica constantemente piscando enquanto uma chave (PA0) é monitorada.
Exemplo 2:
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, 1);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, 0);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, 1);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, 0);
HAL_Delay(500);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)) {
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_13);
HAL_Delay(500);
}
}
/* USER CODE END 3 */
A construção acima funciona, porém a chave será avaliada apenas após transcorrer o tempo definido por HAL_Delay(1000), ou seja, 1s. Para contornar tal situação, pode-se fazer uso das interrupções de hardware. O MCU permite monitorar a ocorrência de eventos e fazer com que a execução do programa passe para outra rotina, chama de Rotina de Tratamento de Interrupção (RTI). Neste caso, é necessário configurar que a entrada PA0 gere um evento e que este gere uma interrupção. Primeiro deve-se configurar o pino PA0 para gerar uma interrupção externa na borda de subida, descida ou ambas, neste exemplo, foi selecionado pela geração da borda de subida, como visto na Figura 11.
Figura 11. Configuração do pino PA0.
Fonte: Adaptado pelo autor.
O passo seguinte é a habilitação da interrupção chamada de EXTI line0 interrupt, acessível na opção NVIC, da categoria System Core, vista na Figura 12.
Figura 12. Habilitação da interrupção de PA0.
Fonte: Adaptado pelo autor.
Ao salvar o projeto a ferramenta realiza a alteração do código fonte, adicionando as configurações necessárias. O projetista ainda precisa realizar duas etapas: alterar o código do laço infinito e adicionar a RTI. No trecho abaixo o projetista pode comentar o trecho do código responsável pelo monitoramento da chave.
Exemplo 3
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14);
HAL_Delay(1000);
// if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1) {
// HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_13);
// }
}
/* USER CODE END 3 */
}
O segundo passo é adicionar o trecho visto a seguir no arquivo main.c entre os comentários destacados.
Exemplo 4
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_0) {
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_13);
}
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
/* USER CODE END 4 */
A função HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) é executada quando ocorrer o evento de borda de subida no pino PA0 configurado anteriormente e seu parâmetro recebo o número do pino que gerou o evento. Os diversos pinos do MCU podem ser mapeados para diversas linhas de interrupção, caso haja mais de 1 pino mapeados para a mesma linha este parâmetro deverá ser usado para identificar qual pino foi o gerador do evento, como visto no trecho do código. Esta função deve ser implementada entre os dois comentários para que a ferramenta não apague este trecho caso alguma atualização nas configurações seja feita.
Ao executar este código o projetista perceberá que o estado do LED(PG13) sofrerá alteração a qualquer momento sem a necessidade de aguardar transcorrer o tempo especificado em HAL_Delay().