STM32F1与STM32CubeIDE快速入门-ADC中断方式实现PWM调光器

中断方法是一种以非阻塞方式进行 ADC 转换的有效方法,因此 CPU 可以继续执行主代码例程,直到 ADC 完成转换并触发中断信号,以便 CPU 可以切换到 ISR 上下文并保存 用于进一步处理的转换结果。

然而,当以循环模式处理多个通道时,将收到来自 ADC 的周期性中断,这些中断对于 CPU 来说是无法处理的。 这会给系统带来抖动注入和中断延迟以及各种时序问题。 这可以通过使用 DMA 来避免。
在这里插入图片描述

本次实例将实现通过ADC中断式采样,并转换成PWM方式输出,从而达到LED调光效果。

1、ADC中断配置

创建工程及系统时钟配置请参考前面文章,在这里不再做介绍。

2)ADC中断配置

在这里插入图片描述

3)定时器TIM2配置

在这里插入图片描述
保存配置,并生成代码。

2、代码生成与功能实现

STM32Cube IDE生成的主要代码如下:

1)ADC初始化

main.c文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/\*\*
\* @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 = DISABLE;
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_7;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL\_ADC\_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
Error\_Handler();
}
/\* USER CODE BEGIN ADC1\_Init 2 \*/

/\* USER CODE END ADC1\_Init 2 \*/

}


2)ADC中断初始化

stm32f1xx_hal_msp.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/\*\*
\* @brief ADC MSP Initialization
\* This function configures the hardware resources used in this example
\* @param hadc: ADC handle pointer
\* @retval None
\*/
void HAL\_ADC\_MspInit(ADC_HandleTypeDef\* hadc)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hadc->Instance==ADC1)
{
/\* USER CODE BEGIN ADC1\_MspInit 0 \*/

/\* USER CODE END ADC1\_MspInit 0 \*/
/\* Peripheral clock enable \*/
\_\_HAL\_RCC\_ADC1\_CLK\_ENABLE();

\_\_HAL\_RCC\_GPIOA\_CLK\_ENABLE();
/\*\*ADC1 GPIO Configuration
PA7 ------> ADC1\_IN7
\*/
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL\_GPIO\_Init(GPIOA, &GPIO_InitStruct);

/\* ADC1 interrupt Init \*/
HAL\_NVIC\_SetPriority(ADC1_2_IRQn, 0, 0);
HAL\_NVIC\_EnableIRQ(ADC1_2_IRQn);
/\* USER CODE BEGIN ADC1\_MspInit 1 \*/

/\* USER CODE END ADC1\_MspInit 1 \*/
}

}

3)定时器TIM2初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/\*\*
\* @brief TIM2 Initialization Function
\* @param None
\* @retval None
\*/
static void MX\_TIM2\_Init(void) {

/\* USER CODE BEGIN TIM2\_Init 0 \*/

/\* USER CODE END TIM2\_Init 0 \*/

TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
TIM_MasterConfigTypeDef sMasterConfig = { 0 };
TIM_OC_InitTypeDef sConfigOC = { 0 };

/\* USER CODE BEGIN TIM2\_Init 1 \*/

/\* USER CODE END TIM2\_Init 1 \*/
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 65535;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL\_TIM\_Base\_Init(&htim2) != HAL_OK) {
Error\_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL\_TIM\_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
Error\_Handler();
}
if (HAL\_TIM\_PWM\_Init(&htim2) != HAL_OK) {
Error\_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL\_TIMEx\_MasterConfigSynchronization(&htim2, &sMasterConfig)
!= HAL_OK) {
Error\_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL\_TIM\_PWM\_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1)
!= HAL_OK) {
Error\_Handler();
}
/\* USER CODE BEGIN TIM2\_Init 2 \*/

/\* USER CODE END TIM2\_Init 2 \*/
HAL\_TIM\_MspPostInit(&htim2);

}

4)程序入口及功能实现

a)中断功能实现

stm32f1xx_it.c文件中

1
2
3
4
5
6
/\* USER CODE BEGIN 1 \*/
void HAL\_ADC\_ConvCpltCallback(ADC_HandleTypeDef \*hadc) {
// Read & Update The ADC Result
AD_RES = HAL\_ADC\_GetValue(&hadc1);
}

b)程序入口及功能实现

main.c文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/\* Private typedef -----------------------------------------------------------\*/
/\* USER CODE BEGIN PTD \*/
uint16_t AD_RES = 0;
/\* USER CODE END PTD \*/

/\*\*
\* @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();
MX\_TIM2\_Init();
/\* USER CODE BEGIN 2 \*/
HAL\_TIM\_PWM\_Start(&htim2, TIM_CHANNEL_1);
// Calibrate The ADC On Power-Up For Better Accuracy
HAL\_ADCEx\_Calibration\_Start(&hadc1);

/\* USER CODE END 2 \*/

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

/\* USER CODE BEGIN 3 \*/
// Start ADC Conversion
HAL\_ADC\_Start\_IT(&hadc1);
// Update The PWM Duty Cycle With Latest ADC Conversion Result
TIM2->CCR1 = (AD_RES << 4);
HAL\_Delay(1);
}
/\* USER CODE END 3 \*/
}

文章来源: https://iotsmart.blog.csdn.net/article/details/123470275