简介
项目开发过程中,采用STM32L151 芯片进行涉及,其中需要使用其片上ADC进行多路ADC数据采样。这里就记录一下实际这块的开发过程,其中涉及工程代码再项目中实际投产使用。STM32L151 多通道ADC DMA循环扫描STM32CubeIDE STM32CubeMX参考设计。
本文使用工程下载
STM32L151多通道ADCDMA循环扫描STM32CubeIDESTM32CubeMX参考设计资源-****文库
设计思路
由于需要采样11路ADC电压,所以采用DMA的方式,并设置ADC循环扫描,来减轻CPU的工作负担。采用STM32CubeIDE、STM32CubeMX+Keil uVision5进行设计验证。
调试过程关键问题
刚开始开发采用STM32CubeIDE,由于版本较低,出现了一个比较难搞的问题,后面切换到STM32CubeMX+Keil uVision5进行开发。该问题记录在博客,有兴趣的同学可以了解一下STM32CubeIDE使用ADC采用DMA重大BUG-****博客。
是否需要打开ADC中断?
我看了很多网上的设计,都没有说清楚这个问题。这里其实没有必要打开ADC中断了,因为已经有使用DMA了,DMA传输完成后会给出DMA中断。如果有需要,可以在DMA中断处理函数,进行处理。
void DMA1_Channel1_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
/* USER CODE END DMA1_Channel1_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_adc);
/* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
/* USER CODE END DMA1_Channel1_IRQn 1 */
}
硬件设计
时钟方面,使能外部8Mhz时钟,时钟配置图如下图所示,从图中可以看出ADC的时钟是由内部高速时钟提供的。
ADC设计,如下图所示,打开11路ADC采样通道。
软件设计
串口打印设置
添加串口打印宏定义如下:
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
//#if (DEBUG_PRINTF_ON == 1)
//HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1 , 0xffff);
while((USART1->SR&0x40)==0){};
USART1->DR = ch;
// while((USART3->SR&0x40)==0);
// USART3->DR = ch;
//#endif
return ch;
}
这里需要提醒的是采用STM32CubeMX+Keil uVision5进行设计的时候,因为使用了printf函数,所以需要将工程的如下设置勾选。
ADC初始化
ADC初始配置如下代码所示,这里针对hadc.Init.ContinuousConvMode = DISABLE;由于DMA数据深度设置为1,也就是说11路采样数据采样完成后,就有DMA中断,所以DMA中断太频繁,如果设置hadc.Init.ContinuousConvMode = ENABLE;会导致MCU一直处于DMA中断中,这里也可以加深DMA采样数据来解决这个问题,由于本项目需求较为简单,就是对采样率没有特别要求。所以无需加深DMA的采样数据。ADC如果采样数据不对,可以尝试调大单个通道sConfig.SamplingTime = ADC_SAMPLETIME_96CYCLES;来进行调试。
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc.Init.LowPowerAutoWait = ADC_AUTOWAIT_DISABLE;
hadc.Init.LowPowerAutoPowerOff = ADC_AUTOPOWEROFF_DISABLE;
hadc.Init.ChannelsBank = ADC_CHANNELS_BANK_A;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.NbrOfConversion = 11;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = ENABLE;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_96CYCLES;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_5;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_6;
sConfig.Rank = ADC_REGULAR_RANK_4;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_7;
sConfig.Rank = ADC_REGULAR_RANK_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = ADC_REGULAR_RANK_6;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_9;
sConfig.Rank = ADC_REGULAR_RANK_7;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_18;
sConfig.Rank = ADC_REGULAR_RANK_8;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_19;
sConfig.Rank = ADC_REGULAR_RANK_9;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_20;
sConfig.Rank = ADC_REGULAR_RANK_10;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_21;
sConfig.Rank = ADC_REGULAR_RANK_11;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
调试记录
STM32CubeIDE 1.7.0工程测试记录:
STM32CubeMX 6.8.1+Keil uVision5测试记录
本文使用工程下载
STM32L151多通道ADCDMA循环扫描STM32CubeIDESTM32CubeMX参考设计资源-****文库