Está en la página 1de 22

Instituto Politécnico Nacional

Escuela Superior de Ingeniería Mecánica y


Eléctrica “Unidad Zacatenco”

PRÁCTICA 1
Programación básica del
microcontrolador
STM32F103Cx – GPIO y ADC

Alumno: Santillán Ramírez Bryan Eduardo

Grupo: 7SM2

Asignatura: Microcontroladores e Interfaces


Objetivo de la Práctica

Encender dos LEDs externos de manera continua y que parpadee


el LED conectado en PC_13, cuando se detecten las siguientes
condiciones:

• Se encuentre presionado un botón en Pull-Up y se


encuentre un nivel de señal mayor que 1.6 V en una
entrada analógica del ADC: encender un led cuyo cátodo
esté conectado a GND mediante una resistencia.
• Se encuentre presionado un botón en Pull-Down y se
encuentre un nivel de señal mayor que 1.6 V en una
entrada analógica del ADC: encender un led cuyo ánodo
esté conectado a Vcc mediante una resistencia.
• Cuando se deje de presionar cualquiera de los botones o se
tenga un nivel menor que 1.6 V en el ADC, los dos LEDs
externos y el LED de la tarjeta deben apagarse.

Material

• Microcontrolador STM32F103C8T6
• Cable mini USB
• Programador ST Link
• Dos LEDs (de cualquier color),
• Dos botones (push button),
• Cuatro resistencias de 1 k,
• Un potenciómetro de 10 k
• Un protoboard, telefónico y pinzas de corte.
Equipo
• Computadora con el software:

- CubeIDE
- CubeProgrammer/ST-Link Utility,
- CubeMonitor
- Conexión a Internet.

Introducción

El microcontrolador STM32F103C8T6 cuenta con periféricos


GPIO y ADC, los cuales permiten que dicho microcontrolador
pueda registrar señales de entrada digitales y ejecutar procesos
que resulten en la activación de señales digitales de salida, así
mismo pueden registrar señales de entrada analógicas y ejecutar
procesos que resulten en la activación de señales digitales de
salida.
El compilador del CubeIDE, hace uso del paradigma orientado a
objetos, cuenta con la clase GPIO y ADC, ideales para programar
dichos periféricos del microcontrolador, dichas clases cuentan
con diferentes métodos para adquirir señales digitales o
analógicas de entrada y también para activar señales digitales de
salida.
Desarrollo de la Práctica

• Para comenzar con la práctica, ocuparemos los programas previamente


instalados para la práctica pasada: Programmer, CubeIDE y en esta
usaremos por 1ra vez el Monitor

• También previamente para la práctica deberemos realizar el siguiente


circuito en nuestra protoboard con el material requerido
• Con todo lo previo, comenzaremos un nuevo proyecto en nuestro
programa CubeIDE ocupando, de igual forma que la práctica pasada, el
STM32F103C8T6 en su versión estándar, y en este caso llevará por
nombre “Práctica 1 – Final”

• Ahora bien, continuamos con la configuración básica de nuestro STM32


configurando nuestro reloj a su máxima frecuencia y habilitando algunos
puertos internos desde el menú RCC y SYS
• Continuamos configurando los puertos que serán nuestras entradas y
nuestras salidas a las cuales irán conectados directamente los
componentes correspondientes, activando las opciones GPIO_Input y
GPIO_Output y cambiando el nombre de estos mismos
• Una vez configuradas nuestras entradas y nuestras salidas,
directamente en el apartado de system core, en la opción de GPIO,
continuaremos con laconfiguración de nuestros puertos de la STM32, ya
que para la práctica necesitaremos que nuestros puertos de entrada
tengan activada las funciones Pull-Up o Pull-Down respectivamente y en
otros solo sería cambiar la función de velocidad de salida
• Como última configuración, en el apartado de Analog, entraremos a la
opción ADC1 y en Parameter Settings habilitaremos la función
Continuous Conversion Mode y subiremos a 55.5 ciclos en la función
Sampling time. Esto nos llevará al apartado de Clock Configuration
donde tendremos que cambiar en la opción de ADC Prescaler a: /6

• Una vez terminada la configuración de todos nuestros puertos de la


STM32, procedemos a guardar todas las configuraciones y generaremos
nuestro código. Con el código ya generado lo primero será transformar
nuestro archivo a .hex en el apartado de settings directamente en el
proyecto y yéndonos hacia la opción de Propperties
• Con el código generado y el archivo convertido en .hex procedemos a
modificar el código. Primeramente, declararemos las variables
necesarias con relación a los puertos previamente configurados

• Después ingresamos la función que dará el funcionamiento real


necesario para la práctica con los componentes y el circuito previamente
hecho

• Por último, agregaremos el código que nos ayudará a poder tomar las
lecturas necesarias con el programa de CubeMonitor

• Con el código ya terminado, procedemos a compilarlo para corroborar


que no tenga ningún error, para después poder cargarlo hacia nuestra
tarjeta STM32. Para este punto, nuestro circuito ya tendría que estar en
perfecto funcionamiento
• Circuito funcionando correctamente

- Presionando Boton 0

- Presionando Boton 1
• Con nuestro circuito funcionando de forma correcta, lo siguiente será
abrir nuestro programa de CubeMonitor para la lectura de datos
digitales en tiempo real, donde el primer paso será importar el siguiente
archivo desde el apartado Local

c
c

c
c

• Después de realizar este paso podremos comenzar a configurar nuestro


espacio de trabajo, donde el primer paso será agregar los archivos de
donde se extraerán y seleccionarán las variables que utilizaremos para
nuestras mediciones
• Después en los recuadros myProbe_In y myProbe_Out, los
configuraremos para que sea desde nuestro ST-LINK donde se obtengan
y procesen los valores proporcionados por nuestro circuito

• Lo siguiente será agregar al espacio de trabajo 2 recuadros extras, un


“Single Value” y un “Gauge”, ambos modificándoles el nombre a “V_ADC”
y serán conectados al recuadro de Mis Variables como se muestra
• Importante también modificar en el nodo Gauge, para que los valores
que obtengamos sean en Volts y tengamos solo un máximo de 3.3 que
serán los proporcionados por nuestra STM32

• Continuamos agregando un último nodo tipo “White Panel”, el cuál será


conectado a los nodos “myVariables” y “myProbe_Out”, a este le
cambiaremos el nombre a “miPanel” para posteriormente guardar todas
las modificaciones con la opción “Deploy” y cargar todo para la lectura
de datos como se muestra a continuación
• Una vez hechas todas las conexiones y ajustes finales, podemos
seleccionar la opción “Dashboard” donde podremos visualizar todos los
datos análogos obtenidos en tiempo real, pero de forma gráfica y digital

• Los valores que nos interesa observar son aquellos que podemos
modificar al momento, como lo son el Valor ADC y los valores de Boton_1
y Boton_0
Código Fuente

/* USER CODE BEGIN Header */


/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 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 ---------------------------------------------------------*/


ADC_HandleTypeDef hadc1;

/* USER CODE BEGIN PV */


volatile uint16_t adc_val,adc_res=4095;
volatile uint16_t tiempo = 50;
volatile float vcc_in = 3.3, vcc_out;
volatile uint8_t boton0_val, boton1_val;

/* USER CODE END PV */


/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_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();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
adc_val = HAL_ADC_GetValue(&hadc1);
vcc_out = adc_val * vcc_in/adc_res;

boton0_val = HAL_GPIO_ReadPin(BOTON_0_GPIO_Port, BOTON_0_Pin);


boton1_val = HAL_GPIO_ReadPin(BOTON_1_GPIO_Port, BOTON_1_Pin);

if((boton0_val == 0 || boton1_val == 1) && vcc_out > 1.6)


{
if(boton0_val == 0)
{
HAL_GPIO_WritePin(LED_e0_GPIO_Port, LED_e0_Pin,
GPIO_PIN_SET);
HAL_GPIO_TogglePin(LED_i_GPIO_Port, LED_i_Pin);
HAL_Delay(tiempo);
}
else if(boton1_val == 1)
{
HAL_GPIO_WritePin(LED_e0_GPIO_Port, LED_e1_Pin,
GPIO_PIN_RESET);
HAL_GPIO_TogglePin(LED_i_GPIO_Port, LED_i_Pin);
HAL_Delay(tiempo);
}
}
else
{
HAL_GPIO_WritePin(LED_e0_GPIO_Port, LED_e0_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_e1_GPIO_Port, LED_e1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_i_GPIO_Port, LED_i_Pin, GPIO_PIN_SET);
}
/* 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};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {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.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();
}

/** 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();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}

/**
* @brief ADC1 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC1_Init(void)
{

/* USER CODE BEGIN ADC1_Init 0 */

/* USER CODE END ADC1_Init 0 */

ADC_ChannelConfTypeDef sConfig = {0};

/* USER CODE BEGIN ADC1_Init 1 */

/* USER CODE END ADC1_Init 1 */

/** Common config


*/
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();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_5;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */

/* USER CODE END ADC1_Init 2 */


HAL_ADC_Stop(&hadc1);
while(HAL_ADCEx_Calibration_Start(&hadc1));
HAL_ADC_Start(&hadc1);
}

/**
* @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_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();

/*Configure GPIO pin Output Level */


HAL_GPIO_WritePin(LED_i_GPIO_Port, LED_i_Pin, GPIO_PIN_RESET);

/*Configure GPIO pin Output Level */


HAL_GPIO_WritePin(GPIOB, LED_e1_Pin|LED_e0_Pin, GPIO_PIN_RESET);

/*Configure GPIO pin : LED_i_Pin */


GPIO_InitStruct.Pin = LED_i_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LED_i_GPIO_Port, &GPIO_InitStruct);

/*Configure GPIO pins : LED_e1_Pin LED_e0_Pin */


GPIO_InitStruct.Pin = LED_e1_Pin|LED_e0_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/*Configure GPIO pin : BOTON_0_Pin */


GPIO_InitStruct.Pin = BOTON_0_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(BOTON_0_GPIO_Port, &GPIO_InitStruct);

/*Configure GPIO pin : BOTON_1_Pin */


GPIO_InitStruct.Pin = BOTON_1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(BOTON_1_GPIO_Port, &GPIO_InitStruct);

/* 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 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 */
Conclusiones

Fue interesante como en esta práctica no solo tuvimos


interacción con la placa STM32 y sus componentes internos, sino
que también pudimos adicionar componentes externos para los
cuales requerimos un nuevo tipo de configuración tanto en los
puertos de nuestra placa, como para nuestro código fuente.
Y sobre todo lo más interesante fue poder descubrir, al menos de
forma básica, una nueva interfaz como la del CubeMonitor y
cómo es que esta nos ayuda a entender el concepto de la
obtención y transformación de datos en tiempo real.

También podría gustarte