Notas de estudio de STM32CubeMX (8) -Uso de la interfaz ADC

1. Introducción a ADC

ADC (convertidor de analógico a digital) , es decir, convertidor de analógico a digital, puede convertir señales analógicas que cambian continuamente en señales digitales discretas y luego utilizar circuitos digitales para el procesamiento, lo que se denomina procesamiento de señales digitales.

La serie STM32f103 tiene 3 ADC con una precisión de 12 bits y cada ADC tiene hasta 16 canales externos. Entre ellos, ADC1 y ADC2 tienen 16 canales externos y ADC3 varía según la cantidad de canales de los pines de la CPU, generalmente hay 8 canales externos. La conversión A / D de cada canal se puede ejecutar en modo simple, continuo, de escaneo o discontinuo. El resultado de ADC se puede justificar a la izquierda o a la derecha almacenado en el registro de datos de 16 bits. La función de vigilancia analógica permite que la aplicación detecte si el voltaje de entrada excede un umbral alto / bajo definido por el usuario. El reloj de entrada ADC no debe exceder los 14MHz, es generado por PCLK2 después de la división de frecuencia.

2. Selección de canal ADC

El ADC de STM32 tiene hasta 18 canales, de los cuales 16 canales externos son ADCx_IN0, ADCx_IN1 ... ADCx_IN5 en el diagrama de bloques. Estos 16 canales corresponden a diferentes puertos IO, qué puerto IO se puede encontrar en el manual. Entre ellos, ADC1 / 2/3 también tienen canales internos: el canal 16 de ADC1 está conectado al sensor de temperatura dentro del chip, y Vrefint está conectado al canal 17. Los canales analógicos 16 y 17 de ADC2 están conectados al VSS interno. Los canales analógicos 9, 14, 15, 16 y 17 de ADC3 están conectados al VSS interno.

Tres, determinación de pines

Hay un reóstato deslizante de parche en la placa de desarrollo, el pin es PC1, que corresponde al canal 11 de ADC1

4. Nueva construcción

1. Abra el software STM32CubeMX y haga clic en "Nuevo proyecto"

2. Elija MCU y paquete

3. Configure los
ajustes de reloj RCC, seleccione HSE (reloj externo de alta velocidad),

seleccione Configuración de reloj para resonador de cristal / cerámica (oscilador de cristal / resonador de cerámica) , configure el reloj del sistema SYSCLK a 72MHz,
modifique el valor de HCLK a 72, y presiona Enter. Modifica automáticamente todas las configuraciones

4. Es
un paso muy importante configurar el modo de depuración ; de lo contrario, la
configuración SYS del depurador no se reconocerá después del primer programa de programación , seleccione Depurar como cable serial

Cinco, ADC1

5.1 Configuración de parámetros

En el conjunto de Analogselección ADC1, y seleccione IN11el canal 11

o el lado derecho de la FIG PC1, los pines encontrados , la selección de ADC1_IN11

los parámetros de configuración específicos son los siguientes.

  • ADCs_Common_Settings :
    • Modo :
      Independent modmodo ADC independiente, cuando se usa un ADC, es modo independiente, cuando se usan dos ADC, es modo dual.Hay muchos modos de subdivisión disponibles en modo dual, y el bit ADC_CR1: DUALMOD está configurado específicamente.
  • ADC_Settings :
    • Alineación de datos : Los
      Right alignmentdatos del resultado de la conversión se alinean a la derecha. Generalmente, elegimos el modo de alineación correcto.
      Left alignmentLos datos del resultado de la conversión se alinean a la izquierda.
    • Modo de conversión de escaneo :
      Disableddesactive el modo de escaneo. Si se trata de una conversión de AD de un solo canal, use DISABLE.
      EnabledActive el modo de escaneo. Si se trata de una conversión de AD multicanal, utilice ENABLE.
    • Modo de conversión continua :
      Disabledconversión única. Una vez detenida la conversión, se requiere un control manual para reiniciar la conversión.
      EnabledConversión continua automática.
    • DiscontinuousConvMode : el
      Disabledmodo discontinuo está prohibido. Esto es necesario en productos que deben considerar el consumo de energía, es decir, iniciar la conversión cuando se activa por un evento determinado.
      EnabledActiva el modo intermitente.
  • ADC_Regular_ConversionMode :
    Enable Regular Conversionssi habilitar la conversión regular.
    Number Of ConversionLa cantidad de canales de conversión de ADC, simplemente escriba tantos como desee.
    External Trigger Conversion SourceSelección de disparador externo. Hay varias opciones para esto, y generalmente se usa la activación por software.
  • Rango : selección del período de muestreo del
    Channelcanal de conversión de ADC
    Sampling Time. Cuanto más corto sea el período de muestreo, más corto será el período de salida de datos de conversión de ADC, pero menor será la precisión de los datos. Cuanto más largo sea el período de muestreo, más largo será el período de salida de datos de conversión de ADC y mayor será la precisión de los datos .
  • ADC_Injected_ConversionMode :
    Enable Injected Conversionssi habilitar la conversión de inyección. El canal de inyección solo aparece cuando existe el canal regular.
  • WatchDog :
    Enable Analog WatchDog Modesi se debe habilitar la interrupción del perro guardián analógico. Cuando el voltaje analógico convertido por el ADC es menor que el umbral bajo o mayor que el umbral alto, se genera una interrupción.

5.2 Configurar NVIC

Habilitar la interrupción de ADC

5.3 Configuración del reloj ADC

El tiempo de conversión de ADC está relacionado con el reloj de entrada de ADC y el tiempo de muestreo.
La fórmula es: Tconv = tiempo de muestreo + 12,5 ciclos . Cuando ADCLK = 14MHZ (el más alto) y el tiempo de muestreo se establece en 1.5 ciclos (el más rápido), entonces el tiempo de conversión total (el más corto) Tconv = 1.5 ciclos + 12.5 ciclos = 14 ciclos = 1us.
Generalmente, establecemos PCLK2 = 72M. El único reloj que puede dividir el preescalador ADC a la frecuencia máxima es 12Mestablecer el período de muestreo en 1.5 ciclos y calcular el tiempo de conversión más corto como 1.17us. Este es el más comúnmente utilizado.

5.4 Generar código

Nombres de elementos de ruta y

selección de entrada de elementos de un entorno de desarrollo de aplicaciones IDE MDK-ARM V5

cada periférico genera un ’.c/.h’archivo separado ,
no un gancho: Todo el código de inicialización se genera en main.c
verificado: archivo de código de inicialización generado en el periférico asociado. Por ejemplo, el código de inicialización GPIO se genera en gpio.c.

Haga clic en GENERAR CÓDIGO para generar código

Seis modos independientes de interrupción de adquisición de un solo canal

单通道采集适用 AD 转换完成中断,在中断服务函数中读取数据,不使用 DMA 传输,在多通道采集时才使用 DMA 传输。

6.1 Modificar la función de devolución de llamada de interrupción

Abra el stm32f1xx_it.carchivo de rutina del servicio de interrupción, busque la función de servicio de ADC1_2_IRQHandler()
interrupción de la rutina del servicio de interrupción ADC1 que se denomina manejador de interrupciones ADCHAL_ADC_IRQHandler()

Abra el stm32f1xx_hal_adc.carchivo, busque el prototipo del controlador de interrupciones de ADC HAL_ADC_IRQHandler(), su función principal es determinar qué ADC genera una interrupción, borrar el indicador de interrupción y luego llamar a la función de devolución de llamada de interrupción HAL_ADC_ConvCpltCallback().

/ * NOTA: Esta función no debe modificarse, cuando se necesita la devolución de llamada,
la HAL_GPIO_EXTI_Callback podría implementarse en el archivo de usuario
* /
Esta función no debe cambiarse, si necesita usar la función de devolución de llamada, vuelva a implementar la función en el archivo de usuario.

HAL_ADC_ConvCpltCallback()De acuerdo con el indicador oficial, deberíamos definir la función nuevamente, que __weakes una bandera debilitada. La función con esta es una función debilitada, es decir, puede escribir una función con exactamente el mismo nombre y parámetros en otro lugar, y el compilador ignorará esta función. En su lugar UNUSED(hadc), ejecute la función que escribió; y , esta es una definición a prueba de errores. Cuando el número ADC pasado no realiza ningún procesamiento, el compilador no informará una advertencia. De hecho, ya no necesitamos preocuparnos por la función de servicio de interrupción cuando estamos desarrollando. Solo necesitamos encontrar la función de devolución de llamada de interrupción y reescribirla. Hay otro aspecto muy conveniente de esta función de devolución de llamada que no se refleja aquí. Cuando se habilitan múltiples interrupciones, STM32CubeMX organizará automáticamente las funciones de servicio de varias interrupciones juntas y llamará a una función de devolución de llamada, es decir, no importa cuántas interrupciones, solo necesitamos reescribir una función de devolución de llamada y juzgar el número del temporizador entrante.

Luego solo stm32f1xx_it.cagregamos la parte inferior de este documentoHAL_ADC_ConvCpltCallback()

/* USER CODE BEGIN EV */
extern __IO uint32_t ADC_ConvertedValue;
/* USER CODE END EV */

/* USER CODE BEGIN 1 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    
    
    ADC_ConvertedValue = HAL_ADC_GetValue(hadc);
}
/* USER CODE END 1 */

Leer datos en una función de devolución de llamada de interrupción, los datos se almacenan en una variable ADC_ConvertedValueen formato .

6.2 Agregar variables globales

Definir variables relevantes en main.c.

// ADC转换值
__IO uint32_t ADC_ConvertedValue;
// 用于保存转换计算后的电压值 	 
float ADC_Vol;

6.3 Agregar función de inicio de interrupción ADC

En main.c, antes del ciclo while y después de que se inicialice el ADC, agregue la función de habilitación de interrupciones del ADC, de modo que la interrupción se active cuando los datos se reciban por primera vez.

/**
  * @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_USART1_UART_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */
  HAL_ADCEx_Calibration_Start(&hadc1);    //AD校准
  HAL_ADC_Start_IT(&hadc1); //开启ADC中断转换
  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

6.4 Agregar conversión de valor de voltaje

Después de que el ADC convierte el voltaje analógico, es un valor digital de 12 bits. Si se imprime en formato hexadecimal a través del puerto serie, la legibilidad es relativamente baja. Entonces, a veces necesitamos convertir el voltaje digital en un voltaje analógico , que también puede seguir la comparación real del voltaje analógico (medido con un multímetro) para ver si la conversión es precisa.
Al diseñar el diagrama esquemático, generalmente establecemos el rango de voltaje de entrada del ADC en:, 0~3.3vporque el ADC es de 12 bits, entonces la escala completa de 12 bits corresponde a 3.3V, y la escala completa de 12 bits corresponde al valor digital: 2 ^ 12. El valor 0 corresponde a 0V. Si el valor convertido es X y el voltaje analógico correspondiente a X es Y, entonces se establecerá una ecuación: 2 ^ 12 / 3.3 = X / Y, => Y = (3.3 * X) / 2 ^ 12 .

Vista de la función de impresión del puerto serie Notas de estudio de STM32CubeMX (6) -Uso del puerto serie USART

/* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    
      ADC_Vol =(float) ADC_ConvertedValue/4096*3.3; // 读取转换的AD倿
      printf("The current AD value = 0x%04X \r\n", ADC_ConvertedValue); 
      printf("The current AD value = %f V \r\n\r\n",ADC_Vol); //实际电压倿
      HAL_Delay(1000); 
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

6.5 Comparación de la biblioteca HAL y el código de biblioteca estándar

STM32CubeMX usa el código generado por la biblioteca HAL:

__IO uint32_t ADC_ConvertedValue;

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

/**
  * @brief This function handles ADC1 and ADC2 global interrupts.
  */
void ADC1_2_IRQHandler(void)
{
    
    
  /* USER CODE BEGIN ADC1_2_IRQn 0 */

  /* USER CODE END ADC1_2_IRQn 0 */
  HAL_ADC_IRQHandler(&hadc1);
  /* USER CODE BEGIN ADC1_2_IRQn 1 */

  /* USER CODE END ADC1_2_IRQn 1 */
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    
    
    ADC_ConvertedValue = HAL_ADC_GetValue(hadc);
}

HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_IT(&hadc1);

Utilice el código de biblioteca estándar STM32:

__IO uint16_t ADC_ConvertedValue;

/**
  * @brief  ADC GPIO 初始化
  * @param  无
  * @retval 无
  */
static void ADCx_GPIO_Config(void)
{
    
    
	GPIO_InitTypeDef GPIO_InitStructure;
	
	// 打开 ADC IO端口时钟
	ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE );
	
	// 配置 ADC IO 引脚模式
	// 必须为模拟输入
	GPIO_InitStructure.GPIO_Pin = ADC_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	
	// 初始化 ADC IO
	GPIO_Init(ADC_PORT, &GPIO_InitStructure);				
}

/**
  * @brief  配置ADC工作模式
  * @param  无
  * @retval 无
  */
static void ADCx_Mode_Config(void)
{
    
    
	ADC_InitTypeDef ADC_InitStructure;	

	// 打开ADC时钟
	ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
	
	// ADC 模式配置
	// 只使用一个ADC,属于独立模式
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	
	// 禁止扫描模式,多通道才要,单通道不需要
	ADC_InitStructure.ADC_ScanConvMode = DISABLE ; 

	// 连续转换模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

	// 不用外部触发转换,软件开启即可
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

	// 转换结果右对齐
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	
	// 转换通道1个
	ADC_InitStructure.ADC_NbrOfChannel = 1;	
		
	// 初始化ADC
	ADC_Init(ADCx, &ADC_InitStructure);
	
	// 配置ADC时钟为PCLK2的8分频,即9MHz
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); 
	
	// 配置 ADC 通道转换顺序和采样时间
	ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, 
	                         ADC_SampleTime_55Cycles5);
	
	// ADC 转换结束产生中断,在中断服务程序中读取转换值
	ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);
	
	// 开启ADC ,并开始转换
	ADC_Cmd(ADCx, ENABLE);
	
	// 初始化ADC 校准寄存器  
	ADC_ResetCalibration(ADCx);
	// 等待校准寄存器初始化完成
	while(ADC_GetResetCalibrationStatus(ADCx));
	
	// ADC开始校准
	ADC_StartCalibration(ADCx);
	// 等待校准完成
	while(ADC_GetCalibrationStatus(ADCx));
	
	// 由于没有采用外部触发,所以使用软件触发ADC转换 
	ADC_SoftwareStartConvCmd(ADCx, ENABLE);
}

static void ADC_NVIC_Config(void)
{
    
    
  NVIC_InitTypeDef NVIC_InitStructure;
  // 优先级分组
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  // 配置中断优先级
  NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

/**
  * @brief  ADC初始化
  * @param  无
  * @retval 无
  */
void ADCx_Init(void)
{
    
    
	ADCx_GPIO_Config();
	ADCx_Mode_Config();
	ADC_NVIC_Config();
}

void ADC_IRQHandler(void)
{
    
    	
	if (ADC_GetITStatus(ADCx,ADC_IT_EOC)==SET) 
	{
    
    
		// 读取ADC的转换值
		ADC_ConvertedValue = ADC_GetConversionValue(ADCx);
	}
	ADC_ClearITPendingBit(ADCx,ADC_IT_EOC);
}

MX_ADC1_Init();Correspondiente al ADCx_GPIO_Config();ADCx_Mode_Config();ADC_NVIC_Config();
HAL_ADC_Init(&hadc1)correspondiente ADC_Init(ADCx, &ADC_InitStructure)
HAL_ADCEx_Calibration_Start(&hadc1);correspondiente a ADC_StartCalibration(ADCx);
HAL_ADC_Start_IT(&hadc1);un correspondiente ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);
HAL_ADC_GetValue(hadc);a correspondienteADC_GetConversionValue(ADCx);

Siete, asuntos que necesitan atención

El código de usuario se agregará USER CODE BEGIN Ny USER CODE END Nentre, de lo contrario, el próximo uso después de que STM32CubeMX vuelva a generar el código, se eliminará.


Escrito por Leung el 19 de enero de 2021

• Referencia: Tutorial 7 de la serie STM32CubeMX : Conversión de analógico a digital (ADC)
    "Guía de desarrollo de STM32 integrado" Parte dos Conceptos básicos: Capítulo 8 Entrada y salida analógica-ADC (Biblioteca HAL)

Supongo que te gusta

Origin blog.csdn.net/qq_36347513/article/details/112850329
Recomendado
Clasificación