一、介绍一下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;//PC1
ADC_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;//PA2
ADC_sConfig.Rank = ADC_REGULAR_RANK_2;
HAL_ADC_ConfigChannel(&g_adc_dma_handle, &ADC_sConfig);
ADC_sConfig.Channel = ADC_CHANNEL_3;//PA3
ADC_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->M
g_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,PA3
GPIO_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=12M
HAL_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和DMA
HAL_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次,所以同一个通道的数据之间位置相差3
sum2+=adc_dma_rec_NumOf_3_buf[(3*i)+1];//因为是CH11->CH2->CH3->CH11->CH2->CH3一直循环50次,所以同一个通道的数据之间位置相差3
sum3+=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); //开启下一次传输
}
}
}