/* USER CODE BEGIN Header */
/*
* Atividade 02 - Termostato Digital com STM32F103C8
*
* Versão ajustada para o diagram.json enviado:
*
* - Sensor NTC em PB0 / ADC_CHANNEL_8
* - Display 7 segmentos em PA0 até PA7
* - Dígitos do display em PB12 até PB15
* - Botões em PC13, PC14 e PC15
* - LED de resfriamento em PA8
* - LED de aquecimento em PA9
*
* IMPORTANTE SOBRE OS LEDs:
* No hardware do Wokwi, os LEDs estão ligados assim:
*
* 3V3 -> resistor -> LED -> pino do STM32
*
* Portanto, eles são ativos em nível baixo:
* GPIO_PIN_RESET = acende
* GPIO_PIN_SET = apaga
*/
/* USER CODE END Header */
/* Bloco de includes: importa as bibliotecas necessárias para usar a HAL do STM32 e recursos matemáticos. */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <math.h>
/* USER CODE END Includes */
/* Bloco de tipos privados: define tipos auxiliares usados apenas neste arquivo. */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* Enumeração dos modos de operação do termostato: normal, configuração de Tmin e configuração de Tmax. */
typedef enum
{
MODE_NORMAL = 0,
MODE_CONFIG_TMIN,
MODE_CONFIG_TMAX
} SystemMode_t;
/* USER CODE END PTD */
/* Bloco de defines: concentra constantes, limites, níveis lógicos e mapeamento de pinos usados no projeto. */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* Configurações gerais do display multiplexado de 4 dígitos. */
#define DISPLAY_DIGIT_COUNT 4
#define DISPLAY_REFRESH_TICKS 2
/* Níveis lógicos usados para ligar e desligar cada dígito do display. */
#define DIGIT_ON_LEVEL GPIO_PIN_RESET
#define DIGIT_OFF_LEVEL GPIO_PIN_SET
/* Índices usados para acessar a tabela de códigos do display de 7 segmentos. */
#define DIGIT_0 0
#define DIGIT_1 1
#define DIGIT_2 2
#define DIGIT_3 3
#define DIGIT_4 4
#define DIGIT_5 5
#define DIGIT_6 6
#define DIGIT_7 7
#define DIGIT_8 8
#define DIGIT_9 9
#define DIGIT_OFF 10
#define DIGIT_L 11
#define DIGIT_H 12
#define DIGIT_MINUS 13
/* Constantes usadas no cálculo da temperatura a partir do NTC pelo ADC. */
#define ADC_MAX_VALUE 4095.0f
#define NTC_NOMINAL_RESISTANCE 10000.0f
#define NTC_NOMINAL_TEMPERATURE_K 298.15f
#define NTC_BETA 3950.0f
/* Limites permitidos para os valores de temperatura configurados no sistema. */
#define TEMP_MIN_LIMIT 0
#define TEMP_MAX_LIMIT 99
/* Tempo mínimo entre leituras de botão para evitar múltiplos acionamentos por ruído mecânico. */
#define BUTTON_DEBOUNCE_MS 180
/* Mapeamento dos pinos usados para os LEDs/saídas de resfriamento e aquecimento. */
#define COOLER_LED_PORT GPIOA
#define COOLER_LED_PIN GPIO_PIN_8
#define HEATER_LED_PORT GPIOA
#define HEATER_LED_PIN GPIO_PIN_9
/* Máscaras que agrupam os pinos dos segmentos e dos dígitos para facilitar escritas em conjunto. */
#define SEGMENT_MASK (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \
GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7)
#define DIGIT_MASK (GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15)
/* LEDs ativos em nível baixo no diagram.json */
#define LED_ON_LEVEL GPIO_PIN_RESET
#define LED_OFF_LEVEL GPIO_PIN_SET
/* USER CODE END PD */
/* Bloco de macros privadas: reservado para macros auxiliares do usuário. */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Bloco de variáveis privadas geradas pelo CubeMX/HAL. */
/* Private variables ---------------------------------------------------------*/
/* Estrutura de controle do ADC1 usada pelas funções HAL para configurar e ler o conversor analógico-digital. */
ADC_HandleTypeDef hadc1;
/* Bloco de variáveis do usuário: guarda tabelas, estados e valores usados pela aplicação. */
/* USER CODE BEGIN PV */
/* Segmentos do display em GPIOA: a, b, c, d, e, f, g, dp */
/* Vetor que relaciona cada segmento do display aos pinos PA0..PA7. */
static const uint16_t segmentPins[8] = {
GPIO_PIN_0,
GPIO_PIN_1,
GPIO_PIN_2,
GPIO_PIN_3,
GPIO_PIN_4,
GPIO_PIN_5,
GPIO_PIN_6,
GPIO_PIN_7
};
/*
* Pelo diagram.json:
* DIG4 -> PB12
* DIG3 -> PB13
* DIG2 -> PB14
* DIG1 -> PB15
*
* O vetor abaixo mantém a ordem:
* digitos[0] = unidade
* digitos[1] = dezena
* digitos[2] = centena
* digitos[3] = milhar/letra
*/
/* Vetor que relaciona cada posição lógica do display ao pino físico que seleciona o dígito. */
static const uint16_t digitSelectPins[DISPLAY_DIGIT_COUNT] = {
GPIO_PIN_12,
GPIO_PIN_13,
GPIO_PIN_14,
GPIO_PIN_15
};
/*
* Tabela do display:
* bit0=a, bit1=b, bit2=c, bit3=d,
* bit4=e, bit5=f, bit6=g, bit7=dp
*/
/* Tabela com os códigos binários para desenhar números, letras e símbolos no display de 7 segmentos. */
static const uint8_t seg7Codes[14] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F, // 9
0x00, // apagado
0x38, // L
0x76, // H
0x40 // -
};
/* Buffer do display: armazena o que será mostrado em cada um dos 4 dígitos durante a multiplexação. */
volatile uint8_t digitos[DISPLAY_DIGIT_COUNT] = {0, 0, 0, 0};
/* Estado atual do sistema, indicando se está mostrando temperatura ou configurando limites. */
volatile SystemMode_t modo = MODE_NORMAL;
/* Valores principais do termostato: temperatura lida e limites mínimo/máximo configuráveis. */
volatile int16_t temperaturaAtual = 0;
volatile int16_t Tmin = 20;
volatile int16_t Tmax = 30;
/* Flag levantada periodicamente pelo SysTick para avisar o loop principal que deve atualizar leitura e controle. */
volatile uint8_t flagAtualizarControle = 0;
/* USER CODE END PV */
/* Protótipos de funções: declara as funções antes de elas serem implementadas. */
/* Private function prototypes -----------------------------------------------*/
/* Funções de inicialização geradas/configuradas para clock, GPIO e ADC. */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
/* Protótipos das funções criadas pelo usuário para display, termostato, botões e saídas. */
/* USER CODE BEGIN PFP */
/* Funções responsáveis por escrever no display de 7 segmentos e controlar sua multiplexação. */
static void Display_WriteCode(uint8_t codeIndex);
static void Display_DisableAllDigits(void);
static void Display_EnableDigit(uint8_t digitIndex);
static void Display_Update(void);
static void Display_ShowNumber(int16_t value);
static void Display_ShowConfig(uint8_t prefix, int16_t value);
static void Display_InitState(void);
/* Funções do termostato: conversão do sensor, atualização visual, controle das saídas e limites. */
static float Thermistor_AdcToCelsius(uint32_t adcValue);
static void Thermostat_UpdateDisplay(void);
static void Thermostat_UpdateOutputs(void);
static void Thermostat_LimitValues(void);
static void Button_Process(uint16_t GPIO_Pin);
/* Funções simples para ligar/desligar individualmente aquecimento, resfriamento ou ambos. */
static void Heater_On(void);
static void Heater_Off(void);
static void Cooler_On(void);
static void Cooler_Off(void);
static void Both_Outputs_Off(void);
/* USER CODE END PFP */
/* Início da implementação das funções de usuário. */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* Liga o LED/saída de aquecimento usando o nível ativo configurado. */
static void Heater_On(void)
{
HAL_GPIO_WritePin(HEATER_LED_PORT, HEATER_LED_PIN, LED_ON_LEVEL);
}
/* Desliga o LED/saída de aquecimento. */
static void Heater_Off(void)
{
HAL_GPIO_WritePin(HEATER_LED_PORT, HEATER_LED_PIN, LED_OFF_LEVEL);
}
/* Liga o LED/saída de resfriamento usando o nível ativo configurado. */
static void Cooler_On(void)
{
HAL_GPIO_WritePin(COOLER_LED_PORT, COOLER_LED_PIN, LED_ON_LEVEL);
}
/* Desliga o LED/saída de resfriamento. */
static void Cooler_Off(void)
{
HAL_GPIO_WritePin(COOLER_LED_PORT, COOLER_LED_PIN, LED_OFF_LEVEL);
}
/* Garante que aquecimento e resfriamento fiquem desligados ao mesmo tempo. */
static void Both_Outputs_Off(void)
{
Heater_Off();
Cooler_Off();
}
/* Recebe um índice da tabela seg7Codes e acende os segmentos correspondentes no GPIOA. */
static void Display_WriteCode(uint8_t codeIndex)
{
if (codeIndex > DIGIT_MINUS)
{
codeIndex = DIGIT_OFF;
}
uint8_t segmentCode = seg7Codes[codeIndex];
uint16_t pinsToTurnOn = 0;
/*
* Primeiro apaga TODOS os segmentos PA0..PA7.
* Depois liga apenas os segmentos necessários.
*
* Fazer isso em escrita por máscara evita sobrar um segmento aceso
* durante a multiplexação do display.
*/
HAL_GPIO_WritePin(GPIOA, SEGMENT_MASK, GPIO_PIN_RESET);
for (uint8_t i = 0; i < 8; i++)
{
if (segmentCode & (1U << i))
{
pinsToTurnOn |= segmentPins[i];
}
}
if (pinsToTurnOn != 0)
{
HAL_GPIO_WritePin(GPIOA, pinsToTurnOn, GPIO_PIN_SET);
}
}
/* Desliga todos os dígitos do display antes de trocar os segmentos, evitando ghosting. */
static void Display_DisableAllDigits(void)
{
HAL_GPIO_WritePin(GPIOB, DIGIT_MASK, DIGIT_OFF_LEVEL);
}
/* Liga apenas o dígito selecionado no vetor digitSelectPins. */
static void Display_EnableDigit(uint8_t digitIndex)
{
HAL_GPIO_WritePin(GPIOB, digitSelectPins[digitIndex], DIGIT_ON_LEVEL);
}
/* Atualiza um dígito por chamada, criando a multiplexação rápida do display. */
static void Display_Update(void)
{
static uint8_t currentDigit = 0;
/*
* Sequência antighosting:
* 1) desliga todos os dígitos
* 2) apaga todos os segmentos
* 3) escreve o próximo valor
* 4) liga apenas o dígito atual
*/
Display_DisableAllDigits();
HAL_GPIO_WritePin(GPIOA, SEGMENT_MASK, GPIO_PIN_RESET);
Display_WriteCode(digitos[currentDigit]);
Display_EnableDigit(currentDigit);
currentDigit++;
if (currentDigit >= DISPLAY_DIGIT_COUNT)
{
currentDigit = 0;
}
}
/* Converte um número inteiro para os quatro dígitos do buffer do display. */
static void Display_ShowNumber(int16_t value)
{
if (value < 0)
{
value = 0;
}
if (value > 9999)
{
value = 9999;
}
digitos[0] = value % 10;
digitos[1] = (value / 10) % 10;
digitos[2] = (value / 100) % 10;
digitos[3] = (value / 1000) % 10;
if (value < 1000)
{
digitos[3] = DIGIT_OFF;
}
if (value < 100)
{
digitos[2] = DIGIT_OFF;
}
if (value < 10)
{
digitos[1] = DIGIT_OFF;
}
}
/*
* Mostra configuração:
* L020 = Tmin 20
* H030 = Tmax 30
*/
/* Monta a tela de configuração com uma letra de prefixo e o valor escolhido. */
static void Display_ShowConfig(uint8_t prefix, int16_t value)
{
if (value < 0)
{
value = 0;
}
if (value > 999)
{
value = 999;
}
digitos[0] = value % 10;
digitos[1] = (value / 10) % 10;
digitos[2] = (value / 100) % 10;
digitos[3] = prefix;
}
/* Inicializa o display em estado conhecido: dígitos apagados e valor zerado. */
static void Display_InitState(void)
{
Display_DisableAllDigits();
Display_WriteCode(DIGIT_OFF);
Display_ShowNumber(0);
}
/*
* Para o sensor wokwi-ntc-temperature-sensor ligado no PB0:
*
* O módulo do Wokwi usa divisor com NTC 10k e resistor 10k.
* Nesta ligação, a resistência do NTC pode ser obtida por:
*
* Rntc = Rfixo * ADC / (4095 - ADC)
*
* Equação Beta:
*
* 1/T = 1/T0 + (1/B) * ln(R/R0)
*
* T em Kelvin.
*/
/* Converte a leitura bruta do ADC para temperatura em Celsius usando divisor resistivo e equação Beta do NTC. */
static float Thermistor_AdcToCelsius(uint32_t adcValue)
{
if (adcValue == 0)
{
adcValue = 1;
}
if (adcValue >= 4095)
{
adcValue = 4094;
}
float adc = (float)adcValue;
float resistance = NTC_NOMINAL_RESISTANCE * adc / (ADC_MAX_VALUE - adc);
float temperatureK = 1.0f / (
(1.0f / NTC_NOMINAL_TEMPERATURE_K) +
(1.0f / NTC_BETA) * logf(resistance / NTC_NOMINAL_RESISTANCE)
);
return temperatureK - 273.15f;
}
/* Mantém Tmin e Tmax dentro dos limites permitidos e impede que Tmin fique maior ou igual a Tmax. */
static void Thermostat_LimitValues(void)
{
if (Tmin < TEMP_MIN_LIMIT)
{
Tmin = TEMP_MIN_LIMIT;
}
if (Tmin > TEMP_MAX_LIMIT)
{
Tmin = TEMP_MAX_LIMIT;
}
if (Tmax < TEMP_MIN_LIMIT)
{
Tmax = TEMP_MIN_LIMIT;
}
if (Tmax > TEMP_MAX_LIMIT)
{
Tmax = TEMP_MAX_LIMIT;
}
if (Tmin >= Tmax)
{
if (modo == MODE_CONFIG_TMIN)
{
Tmin = Tmax - 1;
}
else
{
Tmax = Tmin + 1;
}
}
if (Tmin < TEMP_MIN_LIMIT)
{
Tmin = TEMP_MIN_LIMIT;
}
if (Tmax > TEMP_MAX_LIMIT)
{
Tmax = TEMP_MAX_LIMIT;
}
}
/* Decide o que o display deve mostrar conforme o modo atual do sistema. */
static void Thermostat_UpdateDisplay(void)
{
if (modo == MODE_NORMAL)
{
Display_ShowNumber(temperaturaAtual);
}
else if (modo == MODE_CONFIG_TMIN)
{
Display_ShowConfig(DIGIT_L, Tmin);
}
else
{
Display_ShowConfig(DIGIT_H, Tmax);
}
}
/* Compara a temperatura atual com Tmin/Tmax e aciona aquecimento ou resfriamento quando necessário. */
static void Thermostat_UpdateOutputs(void)
{
/*
* PA9 = aquecimento vermelho.
* PA8 = resfriamento cyan.
*
* Como os LEDs estão ligados ao 3V3 pelo resistor,
* o pino do STM32 precisa ir para 0 para acender.
*/
if (modo != MODE_NORMAL)
{
Both_Outputs_Off();
return;
}
if (temperaturaAtual < Tmin)
{
/* Frio: liga aquecimento */
Heater_On(); // PA9 acende
Cooler_Off(); // PA8 apaga
}
else if (temperaturaAtual > Tmax)
{
/* Quente: liga resfriamento */
Heater_Off(); // PA9 apaga
Cooler_On(); // PA8 acende
}
else
{
/* Dentro da faixa: ambos desligados */
Both_Outputs_Off();
}
}
/* Processa os botões com debounce: incrementa, decrementa ou alterna o modo de configuração. */
static void Button_Process(uint16_t GPIO_Pin)
{
static uint32_t lastButtonTick = 0;
uint32_t now = HAL_GetTick();
if ((now - lastButtonTick) < BUTTON_DEBOUNCE_MS)
{
return;
}
lastButtonTick = now;
if (GPIO_Pin == GPIO_PIN_13)
{
if (modo == MODE_CONFIG_TMIN)
{
Tmin++;
}
else if (modo == MODE_CONFIG_TMAX)
{
Tmax++;
}
}
else if (GPIO_Pin == GPIO_PIN_14)
{
if (modo == MODE_CONFIG_TMIN)
{
Tmin--;
}
else if (modo == MODE_CONFIG_TMAX)
{
Tmax--;
}
}
else if (GPIO_Pin == GPIO_PIN_15)
{
if (modo == MODE_NORMAL)
{
modo = MODE_CONFIG_TMIN;
}
else if (modo == MODE_CONFIG_TMIN)
{
modo = MODE_CONFIG_TMAX;
}
else
{
modo = MODE_NORMAL;
}
}
Thermostat_LimitValues();
/* Atualiza display e saídas uma primeira vez com os valores iniciais. */
Thermostat_UpdateDisplay();
Thermostat_UpdateOutputs();
}
/* Callback chamada pela HAL quando ocorre interrupção externa nos botões PC13..PC15. */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if ((GPIO_Pin == GPIO_PIN_13) ||
(GPIO_Pin == GPIO_PIN_14) ||
(GPIO_Pin == GPIO_PIN_15))
{
Button_Process(GPIO_Pin);
}
}
/* Callback do SysTick: controla a frequência de atualização do display e agenda a atualização do termostato. */
void HAL_SYSTICK_Callback(void)
{
static uint8_t displayTickCount = 0;
static uint16_t controlTickCount = 0;
displayTickCount++;
if (displayTickCount >= DISPLAY_REFRESH_TICKS)
{
displayTickCount = 0;
Display_Update();
}
controlTickCount++;
if (controlTickCount >= 250)
{
controlTickCount = 0;
flagAtualizarControle = 1;
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
/* Função principal: inicializa hardware, prepara estados iniciais e executa o loop infinito da aplicação. */
int main(void)
{
/* Inicializa a biblioteca HAL, configura SysTick e prepara a base do sistema. */
HAL_Init();
/* Configura o clock principal do microcontrolador. */
SystemClock_Config();
/* Inicializa os pinos GPIO usados por botões, display e LEDs. */
MX_GPIO_Init();
/* Inicializa o ADC1 usado para ler o sensor NTC. */
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
/* Deixa display e saídas em estados conhecidos antes de começar o controle. */
Display_InitState();
Display_DisableAllDigits();
HAL_GPIO_WritePin(GPIOA, SEGMENT_MASK, GPIO_PIN_RESET);
Both_Outputs_Off();
/* Inicia o ADC em modo contínuo para disponibilizar leituras do sensor. */
HAL_ADC_Start(&hadc1);
Thermostat_UpdateDisplay();
Thermostat_UpdateOutputs();
/* USER CODE END 2 */
while (1)
{
/* USER CODE BEGIN WHILE */
/* Quando a flag periódica é acionada, o sistema lê o ADC e recalcula o controle. */
if (flagAtualizarControle)
{
flagAtualizarControle = 0;
/* Verifica se há uma nova conversão do ADC pronta para ser lida. */
if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
{
/* Lê o valor bruto do ADC e converte para temperatura em Celsius. */
uint32_t adcValue = HAL_ADC_GetValue(&hadc1);
float temperatura = Thermistor_AdcToCelsius(adcValue);
/* Limita a temperatura exibida entre 0 e 99 e arredonda o valor convertido. */
if (temperatura < 0.0f)
{
temperaturaAtual = 0;
}
else if (temperatura > 99.0f)
{
temperaturaAtual = 99;
}
else
{
temperaturaAtual = (int16_t)(temperatura + 0.5f);
}
/* Depois da leitura, atualiza a informação no display e o estado das saídas. */
Thermostat_UpdateDisplay();
Thermostat_UpdateOutputs();
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
/* Configura o sistema de clock para usar HSE com PLL, gerando o clock principal da aplicação. */
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
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();
}
}
/* Configura o ADC1 para fazer uma conversão contínua no canal 8, ligado ao PB0/NTC. */
static void MX_ADC1_Init(void)
{
/* Estrutura usada para configurar o canal específico do ADC. */
ADC_ChannelConfTypeDef sConfig = {0};
/* Parâmetros gerais do ADC: modo contínuo, alinhamento à direita e uma conversão por sequência. */
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/* Seleciona o canal físico ADC_CHANNEL_8 e define tempo de amostragem. */
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
/* Configura todos os GPIOs: botões com interrupção, segmentos, dígitos e LEDs como saída. */
static void MX_GPIO_Init(void)
{
/* Estrutura reutilizada para configurar grupos de pinos GPIO. */
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Habilita os clocks dos bancos GPIO usados no projeto. */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*
* Estado inicial antes de configurar:
* segmentos apagados, dígitos desligados e LEDs desligados.
*/
HAL_GPIO_WritePin(GPIOA, SEGMENT_MASK, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA,
COOLER_LED_PIN | HEATER_LED_PIN,
LED_OFF_LEVEL);
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15,
DIGIT_OFF_LEVEL);
/*
* Botões:
* Pelo diagram.json, o outro lado dos botões vai para GND.
* Então o pino fica em 1 normalmente e vai para 0 quando aperta.
* Por isso a interrupção correta é borda de descida.
*/
GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* Segmentos do display em PA0..PA7 + LEDs PA8 e PA9 */
GPIO_InitStruct.Pin = SEGMENT_MASK | GPIO_PIN_8 | GPIO_PIN_9;
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);
/* Dígitos do display em PB12..PB15 */
GPIO_InitStruct.Pin = DIGIT_MASK;
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);
Display_DisableAllDigits();
Both_Outputs_Off();
/* Habilita a interrupção EXTI15_10, compartilhada pelos botões nos pinos PC13..PC15. */
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
/* Tratamento de erro: desabilita interrupções e trava em loop infinito para facilitar depuração. */
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
/* Função chamada em falhas de assert quando a verificação completa da HAL está habilitada. */
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif /* USE_FULL_ASSERT */
PA8