terça-feira, 17 de junho de 2025

Lendo o ADC do STM32 na IDE arduino

Olá, neste exemplo vou demonstrar como ler 2 entradas analógicas e imprimir pela serial do microcontrolador STM32F103C6T6 . O pino PA10 é o RX (ligado ao TX do PC) e o pino PA9 o TX (ligado ao RX do PC).Veja que o código é bem simples:


#define LED    PC13

  //#define BOTAO  PA7  não sera usado
  #define A0  PA0
  #define A1  PA1

 bool status_led=0;

void setup() {
Serial.begin(9600);
  pinMode(BOTAO, INPUT);  // botao
  pinMode(LED, OUTPUT);  // led de status
  pinMode(A0, INPUT);  // configura entradas analogicas
  pinMode(A1, INPUT);
}

void loop() {
  // variavei para ler AN0 e AN1
  int canal0 = analogRead(A0);
  int canal1 = analogRead(A1);
  // imprime os valores
  Serial.print("canal_A0:");
  Serial.print(canal0);
  Serial.println(",");
  Serial.print("canal_A1:");
  Serial.println(canal1);

    if(status_led == 0) // pisca led
    {
        digitalWrite(LED, HIGH);
        status_led = 1;
    }
    else
    {
        digitalWrite(LED, LOW);
        status_led = 0;
    }  
  delay(300);

}

segunda-feira, 16 de junho de 2025

Comunicação serial 232 modo DMA usando o CUBE IDE no STM32F103C6T6

     Olá, veja a demonstração como usar o recurso DMA do microcontrolador da STM32, pois este recurso permite que a CPU do microcontrolador não pare de funcionar  a cada recepção de caracteres que chegam pela serial. Vale lembrar que também é possível configurar este recuso para transmissão, ou seja pode se colocar um vetor(array) para transmissão e então habilitar (ou não) para que ao finalizar gere uma interrupção de envio de todos os dados. aqui será usado a interface gráfica do CUBE IDE.

    Aqui estou usando o microcontrolador STM32F103C6T6 da placa de desenvolvimento blue pill.

configurando o CUBE IDE :

    Basta seguir as imagens para configurar corretamente. Na primeira imagem da aba "PINOUT & CONFIGURATION -> NVIC Setting"  deve estar habilitado as 2 interrupção de DMA e global, pois uma e para coletar os caractere e a outra é acionada quando o DMA atingir o numero de caracteres configurado, observe que na interface gráfica os pinos configurados são destacados.

    Na aba DMA Settings habilita USART_RX, mas se quiser habilitar pra transmissão use o USART_TX

    Na aba Parameter Settings configure a porta serial. 

    Neste exemplo usei o cristal externo na aba RCC, porem se quiser usar o clock interno fique a vontade, pois a propria IDE faz os ajuste automaticamente neste parâmetros, quando se seta na aba "CLOCK CONFIGURATION" .

Pronto ! agora é codificar

O código fonte :


    Pra quem usa o CUBE IDE sabe que ele irá gerar automaticamente o código da estrutura "main.c" quando se salva as configurações portanto é necessário acrescentar apenas algumas variáveis e as chamadas de interrupções, neste caso utilizei a de recepção completa(HAL_UART_RxCpltCallback) mas existe a opção de avaliar quando se chega metade dos dados(HAL_UART_RxHalfCpltCallback), caso precise validar um pacote grande pode ser util. 
    Na rotina principal não precisaria ter nada, porém coloquei uma variável para demonstrar caso seja necessário fazer alguma ação depois que recebe o vetor com os dados recebidos.

#include "main.h"

#include <stdio.h>

UART_HandleTypeDef huart1;

DMA_HandleTypeDef hdma_usart1_rx;


/* USER CODE BEGIN PV */

/* USER CODE END PV */


/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_DMA_Init(void);

static void MX_USART1_UART_Init(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */


/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

#define TX_BUFFER_SIZE 128 // Tamanho do buffer de transmissão


uint8_t RxData[20]; //20 bytes de recepção

uint8_t tem_dados = '0';


char txBuffer[TX_BUFFER_SIZE]; // Buffer para enviar mensagens de debug/resposta


void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)

{ //chegou a metade dos dados pode ser util em alguma aplicação

//HAL_UART_Transmit(&huart1,RxData, 10, 50); //imprime a metade coletada

}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{ //chegou a quantidade de dados escolhidos

HAL_UART_Receive_DMA(&huart1,RxData,10); // solicita novamente mais 10 bytes

tem_dados = '1';

HAL_UART_Transmit(&huart1,RxData, 10, 50);

int apaga=0;

while(apaga<20)//limpa pacote

{

RxData[apaga] =' ';

apaga++;

}


}


/* 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_DMA_Init();

MX_USART1_UART_Init();

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

HAL_UART_Receive_DMA(&huart1,RxData,10);

/* Infinite loop */

/* USER CODE BEGIN WHILE */

/* USER CODE END WHILE */

HAL_UART_Transmit(&huart1, (uint8_t*)"Sistema Pronto. Aguardando dados...\n\r", strlen("Sistema Pronto. Aguardando dados...\n\r"), HAL_MAX_DELAY);

for(;;)

{

if(tem_dados == '1')

{

tem_dados = '0';

HAL_UART_Transmit(&huart1, (uint8_t*)"chegou dados!", strlen("chegou dados!"), HAL_MAX_DELAY);

}

}

/* 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};


/** 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_NONE;

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_HSE;

RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;


if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)

{

Error_Handler();

}

}


/**

* @brief USART1 Initialization Function

* @param None

* @retval None

*/

static void MX_USART1_UART_Init(void)

{


/* USER CODE BEGIN USART1_Init 0 */

/* USER CODE END USART1_Init 0 */


/* USER CODE BEGIN USART1_Init 1 */

/* USER CODE END USART1_Init 1 */

huart1.Instance = USART1;

huart1.Init.BaudRate = 9600;

huart1.Init.WordLength = UART_WORDLENGTH_8B;

huart1.Init.StopBits = UART_STOPBITS_1;

huart1.Init.Parity = UART_PARITY_NONE;

huart1.Init.Mode = UART_MODE_TX_RX;

huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;

huart1.Init.OverSampling = UART_OVERSAMPLING_16;

if (HAL_UART_Init(&huart1) != HAL_OK)

{

Error_Handler();

}

/* USER CODE BEGIN USART1_Init 2 */

/* USER CODE END USART1_Init 2 */


}


/**

* Enable DMA controller clock

*/

static void MX_DMA_Init(void)

{


/* DMA controller clock enable */

__HAL_RCC_DMA1_CLK_ENABLE();


/* DMA interrupt init */

/* DMA1_Channel5_IRQn interrupt configuration */

HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);


}


/**

* @brief GPIO Initialization Function

* @param None

* @retval None

*/

static void MX_GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStruct = {0};

/* USER CODE BEGIN MX_GPIO_Init_1 */

/* USER CODE END MX_GPIO_Init_1 */


/* GPIO Ports Clock Enable */

__HAL_RCC_GPIOC_CLK_ENABLE();

__HAL_RCC_GPIOD_CLK_ENABLE();

__HAL_RCC_GPIOA_CLK_ENABLE();


/*Configure GPIO pin Output Level */

HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);


/*Configure GPIO pin : LED_Pin */

GPIO_InitStruct.Pin = LED_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);


/* USER CODE BEGIN MX_GPIO_Init_2 */

/* USER CODE END MX_GPIO_Init_2 */

}


/* USER CODE BEGIN 4 */

/* 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 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 CODE END 6 */

}

#endif /* USE_FULL_ASSERT */


Obrigado pela atenção! e até a próxima postagem. Data: 16/06/2025         








           


terça-feira, 3 de junho de 2025

Exemplo de código com comunicação serial para placa BluePill (STM32F103C6T6) no Arduino. (método polling)

 // Código Exemplo para Comunicação Serial com STM32F1 (ex: Blue Pill) usando Arduino IDE

// Autor: Aguivone M.Fogia
// Data: 03/06/2025
// Descrição: Demonstrar envio e recebimento de dados via porta serial (USART1), lendo um botao e acionando led.
//    modo polling

/*
  material necessario
  1. Placa STM32F103C8T6 ou C6T6 (Blue Pill ou similar).
  2. Programador ST-Link V2 ou conversor USB-Serial (para upload e/ou comunicação).
  3. Core STM32 para Arduino IDE instalado (veja instruções no exemplo blink anterior).
  4. Configuração da Placa no Arduino IDE:
     - Ferramentas > Placa: "Generic STM32F103C series" ou similar.
     - Ferramentas > Variant: "STM32F103C6T6"
     - Ferramentas > Upload method: "STLink" ou "Serial".
     - Ferramentas > Porta: Selecione a porta COM correspondente ao seu conversor USB-Serial ou ST-Link (se aplicável para comunicação).

  --- Conexão Física (para USART1) ---
  - Conecte o pino PA9 (TX1) do STM32 ao pino RX do seu conversor USB-Serial.
  - Conecte o pino PA10 (RX1) do STM32 ao pino TX do seu conversor USB-Serial.
  - Conecte o GND do STM32 ao GND do conversor USB-Serial.
  - Alimente a placa STM32 (via ST-Link, USB ou fonte externa).

  --- Nota sobre Portas Seriais ---
  - O objeto `Serial` no core STM32 para Arduino geralmente se refere à USART1 (pinos PA9/PA10).
  - Algumas configurações de placa/core podem mapear `Serial` para a porta USB CDC (Comunicação via cabo USB direto, se a placa tiver bootloader compatível ou hardware USB nativo configurado).
  - Se você precisar usar outras portas seriais (USART2, USART3), use os objetos `Serial1`, `Serial2`, `Serial3`, etc., e conecte aos pinos correspondentes (verifique o pinout da sua placa e a documentação do core).
    - Serial1: PA9 (TX), PA10 (RX)
    - Serial2: PA2 (TX), PA3 (RX)
    - Serial3: PB10 (TX), PB11 (RX)
*/

// --- Configurações ---
  #define LED    PC13
  #define BOTAO  PA7
  long           baudRate = 9600; // Taxa de comunicação serial (bits por segundo)
  // --- Variáveis Globais ---
  String         pacote = ""; // String para armazenar dados recebidos
  unsigned long  tempo_atual;
  unsigned long  tempo_anterior;
  unsigned long  tempo_led = 100;
  int           comando_botao=0;
 
// --- Função Setup: Executada uma vez ---
void setup()
{
  // Inicializa a comunicação serial (USART1 por padrão)
  Serial.begin(baudRate);
  pinMode(LED, OUTPUT); //LED
  pinMode(BOTAO, INPUT);
  // Espera um pouco para a porta serial estabilizar (opcional, mas útil)
  delay(100);
  Serial.println("Comunicação serial com STM32F103C6T6 \n\r");
  Serial.print("Usando botão pra mudar velocidade do led ou a serial\n\r");
}

// --- Função Loop: Executada repetidamente ---
void loop()
{
  // --- Leitura de Dados da Serial ---
  if (Serial.available() > 0) { // Verifica se há dados chegando
    char caracter = Serial.read(); // Lê um caractere
       if(caracter == 'A')//vel1
       {
          Serial.println("velocidade 1 = 100 \n\r");
          tempo_led = 100;
          comando_botao = 0;
          delay(100);//debounce para botao
       }
       if(caracter == 'B')//vel2
       {
          Serial.println("velocidade 2 = 500 \n\r");
          tempo_led = 500;
          comando_botao = 1;
          delay(100);//debounce para botao
       }
       if(caracter == 'C')//vel3
       {
          Serial.println("velocidade 3 = 1000 \n\r");
          tempo_led = 1000;
          comando_botao = 2;
          delay(100);//debounce para botao
       }
     
  }
  else
  {
    if(digitalRead(BOTAO)== 1)
    {
        comando_botao++;
        if(comando_botao > 2)
        {
            comando_botao = 0;
        }
        if(comando_botao == 0)//vel1
       {
          Serial.println("velocidade 1 = 100 \n\r");
          tempo_led = 100;
       }
       if(comando_botao == 1)//vel2
       {
          Serial.println("velocidade 2 = 500 \n\r");
          tempo_led = 500;
       }
       if(comando_botao == 2)//vel3
       {
          Serial.println("velocidade 3 = 1000 \n\r");
          tempo_led = 1000;
       }
       delay(500);//debounce para botao
    }

    tempo_atual = millis();
    if(tempo_atual - tempo_anterior >= tempo_led)
        {
          digitalWrite(LED, !digitalRead(LED));
          tempo_anterior = tempo_atual;
        }
  }

}