一、介绍一下HAL库函数
1.ADC
2.DMA
二、实验思路
1.根据数据手册直到PC1,PA2,PA3分别为ADC123的通道11,2,3,我们就用这三个通道来采集,每一个通道采集 50 次,即一共需要DMA传输150个数据
2.由于我们是DMA直接得到的ADC的原始数据,若是我们不进行处理就继续下一次传输,那么数据就会被覆盖,所以我们还打开DMA传输中断,在里面用标志位,用来判断是否传输完成,然后在main里面进行数据的处理
三、HAL具体操作
1.初始化ADC和DMA结构体,然后用__HAL_LINKDMA();函数连接DMA和ADC的句柄
2.初始化ADC通道结构体,配置转换顺序
3.开启DMA的中断,开启ADC的DMA请求
4.编写MSP函数,配置GPIO,ADC和DMA的时钟,记得配置ADC的采样时钟
5.编写ADC_DMA传输启动函数
#define ADC_DMA_REC_NumOf_3_BUFFSIZE 50*3
uint16_t adc_dma_rec_NumOf_3_buf[ADC_DMA_REC_NumOf_3_BUFFSIZE];
uint8_t g_adc_dma_sta=0;
DMA_HandleTypeDef g_dma_adc_handle;
ADC_HandleTypeDef g_adc_dma_handle;void ADC_DMA_NumOf_3_Init(uint32_t rec_buf)
{__HAL_RCC_DMA1_CLK_ENABLE();ADC_ChannelConfTypeDef ADC_sConfig;g_adc_dma_handle.Instance = ADC1;g_adc_dma_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;//右对齐g_adc_dma_handle.Init.ScanConvMode = ADC_SCAN_ENABLE;//由于我们是多通道,所以用扫描模式g_adc_dma_handle.Init.ContinuousConvMode = ENABLE;//开启连续转换g_adc_dma_handle.Init.NbrOfConversion = 3;//转换通道个数g_adc_dma_handle.Init.DiscontinuousConvMode = DISABLE;//不用(不连续采用模式,只适用于扫描模式)间断模式g_adc_dma_handle.Init.NbrOfDiscConversion = 0;g_adc_dma_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;//软件触发HAL_ADC_Init(&g_adc_dma_handle);HAL_ADCEx_Calibration_Start(&g_adc_dma_handle);//开启校准ADC_sConfig.Channel = ADC_CHANNEL_11;//PC1ADC_sConfig.Rank = ADC_REGULAR_RANK_1;ADC_sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;HAL_ADC_ConfigChannel(&g_adc_dma_handle, &ADC_sConfig);ADC_sConfig.Channel = ADC_CHANNEL_2;//PA2ADC_sConfig.Rank = ADC_REGULAR_RANK_2;HAL_ADC_ConfigChannel(&g_adc_dma_handle, &ADC_sConfig);ADC_sConfig.Channel = ADC_CHANNEL_3;//PA3ADC_sConfig.Rank = ADC_REGULAR_RANK_3;HAL_ADC_ConfigChannel(&g_adc_dma_handle, &ADC_sConfig);g_dma_adc_handle.Instance = DMA1_Channel1;g_dma_adc_handle.Init.Direction = DMA_PERIPH_TO_MEMORY;//P->Mg_dma_adc_handle.Init.PeriphInc = DMA_PINC_DISABLE;//地址不自增g_dma_adc_handle.Init.MemInc = DMA_MINC_ENABLE;//地址自增g_dma_adc_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;g_dma_adc_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;g_dma_adc_handle.Init.Mode = DMA_NORMAL;//不循环转换,即开启一次DMA,转换一次g_dma_adc_handle.Init.Priority = DMA_PRIORITY_MEDIUM;HAL_DMA_Init(&g_dma_adc_handle);/*连接ADC和DMA句柄*/__HAL_LINKDMA(&g_adc_dma_handle,DMA_Handle,g_dma_adc_handle);//我们这里开启DMA的中断,在里面用标志位来表示数据传输完成HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,3);HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);HAL_DMA_Start_IT(&g_dma_adc_handle, (uint32_t)&ADC1->DR, rec_buf, 0);//传输0个,即先不传输HAL_ADC_Start_DMA(&g_adc_dma_handle,&rec_buf,0);//传输0个,即先不传输}void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{if(hadc->Instance == ADC1){RCC_PeriphCLKInitTypeDef ADC_PeriphClkInit={0};__HAL_RCC_GPIOC_CLK_ENABLE();//PC1__HAL_RCC_ADC1_CLK_ENABLE();//开时钟GPIO_InitTypeDef GPIO_Init;GPIO_Init.Pin = GPIO_PIN_1;GPIO_Init.Mode = GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOC,&GPIO_Init);/*多通道配置*/__HAL_RCC_GPIOA_CLK_ENABLE();//PA2,PA3GPIO_Init.Pin = GPIO_PIN_2 | GPIO_PIN_3;GPIO_Init.Mode = GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOA,&GPIO_Init);ADC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;//选择配置ADC时钟ADC_PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;//6分频,即72/6=12MHAL_RCCEx_PeriphCLKConfig(&ADC_PeriphClkInit);}
}/*转换开始函数*/
// 参数:cndtr,传输的个数,寄存器是低16位有效,所以设置16位
/*数据传输数量为0至65535。这个寄存器只能在通道不工作(DMA_CCRx的EN=0)时写入。通
道开启后该寄存器变为只读,指示剩余的待传输字节数目。*/
void ADC_DMA_Transfer(uint16_t cndtr)
{__HAL_ADC_DISABLE(&g_adc_dma_handle);__HAL_DMA_DISABLE(&g_dma_adc_handle);//先关闭ADC和DMA,以写入CNDTR要传输的数据个数while (DMA1_Channel1->CCR & (1 << 0));//检测是否DMA关闭了 DMA1_Channel1->CNDTR = cndtr;//设置传输数目__HAL_ADC_ENABLE(&g_adc_dma_handle);__HAL_DMA_ENABLE(&g_dma_adc_handle);//使能ADC和DMAHAL_ADC_Start(&g_adc_dma_handle);//软件触发ADC,开始ADC转换和DMA传输
}/*DMA中断处理函数*/
void DMA1_Channel1_IRQHandler(void)
{if(__HAL_DMA_GET_FLAG(&g_dma_adc_handle,DMA_FLAG_TC1))//传输完成{g_adc_dma_sta = 1;//标志位置1__HAL_DMA_CLEAR_FLAG(&g_dma_adc_handle,DMA_FLAG_TC1);//清除传输完成标志位}
}
主函数
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "led.h"
#include "usart.h"
#include "dma.h"
#include "adc.h"
#include "stdio.h"#define ADC_DMA_REC_NumOf_3_BUFFSIZE 50*3
extern DMA_HandleTypeDef g_dma_adc_handle;
extern ADC_HandleTypeDef hadc1,g_adc_dma_handle;
extern uint16_t adc_dma_rec_NumOf_3_buf[ADC_DMA_REC_NumOf_3_BUFFSIZE];
extern uint8_t g_adc_dma_sta;int main(void)
{uint16_t adc_temp,i;uint32_t sum1,sum2,sum3;float adc_value;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */LED_Init(); /* LED初始化 */USART_Init(115200);ADC_DMA_NumOf_3_Init((uint32_t)&adc_dma_rec_NumOf_3_buf);ADC_DMA_Transfer(ADC_DMA_REC_NumOf_3_BUFFSIZE);while(1){ if(g_adc_dma_sta==1){sum1=sum2=sum3=0;for(i=0;i<50;i++){sum1+=adc_dma_rec_NumOf_3_buf[(3*i)+0];//因为是CH11->CH2->CH3->CH11->CH2->CH3一直循环50次,所以同一个通道的数据之间位置相差3sum2+=adc_dma_rec_NumOf_3_buf[(3*i)+1];//因为是CH11->CH2->CH3->CH11->CH2->CH3一直循环50次,所以同一个通道的数据之间位置相差3sum3+=adc_dma_rec_NumOf_3_buf[(3*i)+2];//因为是CH11->CH2->CH3->CH11->CH2->CH3一直循环50次,所以同一个通道的数据之间位置相差3}adc_temp=sum1/50;adc_value = adc_temp*3.3/4096;printf("PC1\nadc_temp->%d\nadc_value->%.5f v\n\n\n\n",adc_temp,adc_value);adc_temp=sum2/50;adc_value = adc_temp*3.3/4096;printf("PA2\nadc_temp->%d\nadc_value->%.5f v\n\n\n\n",adc_temp,adc_value);adc_temp=sum3/50;adc_value = adc_temp*3.3/4096;printf("PA3\nadc_temp->%d\nadc_value->%.5f v\n\n\n\n",adc_temp,adc_value);delay_ms(2000);g_adc_dma_sta=0;ADC_DMA_Transfer(ADC_DMA_REC_NumOf_3_BUFFSIZE); //开启下一次传输}}
}