STM32 F429 DMA传输2-ADC多通道采集DMA传输
前言
这篇主要是和上一篇DMA串口传输做对比学习,上一篇是储存器到串口DMA传输,这篇是adc采集到存储器的DMA传输,两个对比学习,方便理解。和上篇一样,我们在配置中学习参数以及函数原理。
配置
1)使能 DMA、ADC 时钟。 2) 初始化 DMA、ADC参数。 3)将DAM与ADC联系起来(这个上篇忘着重提了) 4)使能 ADC、DMA ,启动传输。
以下是具有配置代码 DMA相关配置
void myDMA_init(DMA_Stream_TypeDef *DMAa_Streamb, u32 chx )
{
if((u32)DMAa_Streamb>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
{
__HAL_RCC_DMA2_CLK_ENABLE();//DMA2时钟使能
}else
{
__HAL_RCC_DMA1_CLK_ENABLE();//DMA1时钟使能
}
DAM_Handal.Instance = DMAa_Streamb;
DAM_Handal.Init.Channel = chx;
DAM_Handal.Init.Direction = DMA_PERIPH_TO_MEMORY; //外设到内存
DAM_Handal.Init.PeriphInc = DMA_PINC_DISABLE; //外设(非)增量模式
DAM_Handal.Init.MemInc = DMA_MINC_ENABLE; //内存增量模式
DAM_Handal.Init.PeriphDataAlignment = DMA_MDATAALIGN_BYTE;//字节(8位)
DAM_Handal.Init.MemDataAlignment =DMA_MDATAALIGN_BYTE;
DAM_Handal.Init.Mode =DMA_CIRCULAR; //外设循环模式
DAM_Handal.Init.Priority =DMA_PRIORITY_MEDIUM; //中等优先级
DAM_Handal.Init.FIFOMode =DMA_FIFOMODE_DISABLE;
DAM_Handal.Init.FIFOThreshold =DMA_FIFO_THRESHOLD_FULL;
DAM_Handal.Init.MemBurst =DMA_MBURST_SINGLE; //存储器突发单次传输
DAM_Handal.Init.PeriphBurst =DMA_PBURST_SINGLE; //外设突发单次传输
__HAL_LINKDMA(&ADC1_Handler,DMA_Handle,DAM_Handal); //将DMA与ADC1联系起来(发送DMA)
HAL_DMA_DeInit(&DAM_Handal);
HAL_DMA_Init(&DAM_Handal);
}
需要注意的是ADC采集DMA输出是外设到内存的传输,另外为了能一直获得采集数据还需要打开循环模式,其他配置与第一篇基本无异,有需要的可以参考DMA串口传输。 ADC配置
ADC_HandleTypeDef ADC1_Handler;
static uint8_t ADC_Data_Buff[2] = {0}; //ADC数据缓存区
void my_ADC_init()
{
ADC1_Handler.Instance =ADC1;
ADC1_Handler.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=90/4=22.5MHZ
ADC1_Handler.Init.Resolution =ADC_RESOLUTION_8B; //8位模式
ADC1_Handler.Init.DataAlign =ADC_DATAALIGN_RIGHT;//右对齐
ADC1_Handler.Init.ScanConvMode =ENABLE; //扫描模式
ADC1_Handler.Init.EOCSelection =DISABLE; //关闭EOC中断
ADC1_Handler.Init.ContinuousConvMode=ENABLE; //连续转换
ADC1_Handler.Init.NbrOfConversion=2; //1个转换在规则序列中 也就是只转换规则序列1
ADC1_Handler.Init.DiscontinuousConvMode=DISABLE; //禁止不连续采样模式
ADC1_Handler.Init.NbrOfDiscConversion=0; //不连续采样通道数为0
ADC1_Handler.Init.ExternalTrigConv=ADC_SOFTWARE_START; //软件触发
ADC1_Handler.Init.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_NONE;//使用软件触发
ADC1_Handler.Init.DMAContinuousRequests=ENABLE; //DMA请求
HAL_ADC_Init(&ADC1_Handler); //初始化
Get_Adc ( ) ;
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); //开启GPIOB时钟
GPIO_Initure.Pin=GPIO_PIN_7; //PA7
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=GPIO_PIN_0; //PB0
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}
//获得ADC值
//ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
//返回值:转换结果
void Get_Adc ( )
{
ADC_ChannelConfTypeDef ADC1_ChanConf;
ADC1_ChanConf.Channel = ADC_CHANNEL_7; //通道
ADC1_ChanConf.Rank =2; //第1个序列,序列1
ADC1_ChanConf.SamplingTime =ADC_SAMPLETIME_480CYCLES; //采样时间
ADC1_ChanConf.Offset =0;
HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
ADC1_ChanConf.Channel = ADC_CHANNEL_8;
ADC1_ChanConf.Rank = 1;
ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;
ADC1_ChanConf.Offset = 0;
HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);
HAL_ADC_Start(&ADC1_Handler); //开启ADC
myDMA_init(DMA2_Stream4,DMA_CHANNEL_0);
HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)ADC_Data_Buff, 2); //开启ADC,数据传输方式为DMA传输
}
void Get_Adc_Data(uint8_t *buf)
{
buf[0] = ADC_Data_Buff[0];
buf[1] = ADC_Data_Buff[1];
}
ADC配置主要是时钟配置、参数配置、以及通道配置。 比较需要注意的是ADC数据宽度应与DMA外设数据宽度保证一致,在这里设置的都是8bit,同时一般也设置传输源地址(ADC)和目的地址(缓冲区)的数据宽度相同,当然传输源地址和目的地址的数据宽度也可以不同,但要保证传输的数据成块即保证由外设向存储器搬移的存储器的传输数目( = NDT * 外设端口宽度 / 存储器端口宽度)为整数必须配置 PSIZE、MSIZE 和 NDT[15:0],以确保最后一次传输的完整性。当外设端口的数据 宽度(PSIZE 位)小于存储器端口的数据宽度(MSIZE 位)时,可能会发生数据传输不完整 的情况可以参考下面39和40两个表。其中NDT是要传输数据项数目位,可以通过HAL_XXX_Start_DMA 函数的第三个参数设置。例如PSIZE设置为8位,MSIZE设置为16位传输时必须保证NDT*8/16为正整数,即NDT为2的倍数。 由于设置多通道采集 ,ADC应设置扫描模式
`ADC1_Handler.Init.ScanConvMode =ENABLE;`
和使能连续转换
ADC1_Handler.Init.ContinuousConvMode=ENABLE;
另外不要忘了把DMA和外设连接和开启ADCDMA传输,
__HAL_LINKDMA(&ADC1_Handler,DMA_Handle,DAM_Handal);
HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)ADC_Data_Buff, 2);
设置完整后主函数调用即可:
Get_Adc_Data(ADC_DMA);//获取通道5的转换值,20次取平均
LCD_ShowxNum(134,130,ADC_DMA[0],4,16,0); //显示ADCC采样后的原始值
LCD_ShowxNum(150,150,ADC_DMA[1],4,16,0);
|