完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、为什么使用DMA
STM32的ADC是一个非常强大且灵活的外设,它有大量的通道,同时具有准确的中性测试情况。 STM32系列32系列的产品ADC属于近型(逐个,时间需要多个正型),每个型号的ADC都可以使用到不同类型的不同类型,多个次系列需要多个正范围。在同事转换的情况下,不同的程序设计对系统产生了很大的影响。 举例来说,假设adc需要1us,采样率8k,每次使用通道需要使用缓冲的方式AD转换,如果这4个通道占用一个ADC,那么AD转换占用约3%的资源,如果这4个通道的系统通道用一个,4个通道的转换可以同时进行,系统资源占用降到1%以下,如果4个通道使用DMA实现,系统资源占用片可以播放。随着通道数量的增加,DMA的优势会出现。 二、使用DMA的连续AD转换 以STM32G4 100脚单为为例,对具体配置方法加以说明。 此处STM32CubeMX版本为5.2.0 首先使能需要采集的若干个通道,并将其配置为单端输入模式(除了单端输入模式外,G4系列芯片还支持差分输入)。 然后具体配置ADC参数如下图。 其中: ADC模式- >模式独立 分辨率- > 12模式位 数据对其方式- >对齐向左向右 扫描模式- >能使 结束标志产生条件- >整个序列转换完 连续转换模式->使能 不连续转换模式->关闭 DMA连续请求->使能 序列转换-> 序列开启时间->关闭 转换序列模式->7外部 触发源 代码触发在排序中配置通道号,排序为每次转换的序列号,然后看门狗不使能对DMA进行配置,DMA模式设置为上传模式,DMA数据方向为外设到内存,外设地址不增加,内存地址自动增加请求,每次数据传输宽度为半字,循环uint16_t型配置完成后生成代码,只需要对代码进行修改即可开始工作。
static void MX_ADC2_Init(void) { /* USER CODE BEGIN ADC2_Init 0 */ /* USER CODE END ADC2_Init 0 */ ADC_AnalogWDGConfTypeDef AnalogWDGConfig = {0}; ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC2_Init 1 */ /* USER CODE END ADC2_Init 1 */ /** Common config */ hadc2.Instance = ADC2; hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; hadc2.Init.Resolution = ADC_RESOLUTION_12B; hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc2.Init.GainCompensation = 0; hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE; hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV; hadc2.Init.LowPowerAutoWait = DISABLE; hadc2.Init.ContinuousConvMode = ENABLE; hadc2.Init.NbrOfConversion = 7; hadc2.Init.DiscontinuousConvMode = DISABLE; hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc2.Init.DMAContinuousRequests = ENABLE; hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc2.Init.OversamplingMode = DISABLE; if (HAL_ADC_Init(&hadc2) != HAL_OK) { Error_Handler(); } /** Configure Analog WatchDog 1 */ AnalogWDGConfig.Channel = ADC_CHANNEL_1; if (HAL_ADC_AnalogWDGConfig(&hadc2, &AnalogWDGConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_4; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_12; sConfig.Rank = ADC_REGULAR_RANK_2; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_6; sConfig.Rank = ADC_REGULAR_RANK_3; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_7; sConfig.Rank = ADC_REGULAR_RANK_4; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_8; sConfig.Rank = ADC_REGULAR_RANK_5; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_9; sConfig.Rank = ADC_REGULAR_RANK_6; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_11; sConfig.Rank = ADC_REGULAR_RANK_7; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC2_Init 2 */ HAL_ADC_Start_DMA(&hadc2,(uint32_t *)adc,7); /* USER CODE END ADC2_Init 2 */ } 三、使用 对进行数据进行修改,在大多数应用中,并不需要进行连续监测,更多的情况是需要在连续监测时触发一次配置。通过触发 ,只需要在AD转换时触发触发信号转换,就可以通过触发信号在触发内部触发。 ,需要在定时器2的2通道产生一个上升沿,此处把定时器2的2通道配置为PWM模式以实现电平变化。 此时不在需要ADC进行转换,把连续转换模式设为关闭 TIM2配置如下,可以通道2,配置为pwm模式,根据想要的频率配置分因子psc以及计数周期。 其他配置保持不变。 根据上述配置,cube生成的ADC初始化代码 static void MX_ADC2_Init(void) { /* USER CODE BEGIN ADC2_Init 0 */ /* USER CODE END ADC2_Init 0 */ ADC_AnalogWDGConfTypeDef AnalogWDGConfig = {0}; ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC2_Init 1 */ /* USER CODE END ADC2_Init 1 */ /** Common config */ hadc2.Instance = ADC2; hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; hadc2.Init.Resolution = ADC_RESOLUTION_12B; hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc2.Init.GainCompensation = 0; hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE; hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV; hadc2.Init.LowPowerAutoWait = DISABLE; hadc2.Init.ContinuousConvMode = DISABLE; hadc2.Init.NbrOfConversion = 7; hadc2.Init.DiscontinuousConvMode = DISABLE; hadc2.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T2_CC2; hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; hadc2.Init.DMAContinuousRequests = ENABLE; hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc2.Init.OversamplingMode = DISABLE; if (HAL_ADC_Init(&hadc2) != HAL_OK) { Error_Handler(); } /** Configure Analog WatchDog 1 */ AnalogWDGConfig.Channel = ADC_CHANNEL_1; if (HAL_ADC_AnalogWDGConfig(&hadc2, &AnalogWDGConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_4; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_12; sConfig.Rank = ADC_REGULAR_RANK_2; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_6; sConfig.Rank = ADC_REGULAR_RANK_3; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_7; sConfig.Rank = ADC_REGULAR_RANK_4; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_8; sConfig.Rank = ADC_REGULAR_RANK_5; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_9; sConfig.Rank = ADC_REGULAR_RANK_6; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_11; sConfig.Rank = ADC_REGULAR_RANK_7; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC2_Init 2 */ HAL_ADC_Start_DMA(&hadc2,(uint32_t *)adc,7); /* USER CODE END ADC2_Init 2 */ } 需要注意的代码生成如下: 用户代码 2 * 中不包含使能,以及能输出代码,需要添加使能配置。 HAL_TIM_Base_Start_IT(&htim2); HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2); |
|
|
|
只有小组成员才能发言,加入小组>>
3314 浏览 9 评论
2995 浏览 16 评论
3494 浏览 1 评论
9059 浏览 16 评论
4088 浏览 18 评论
1180浏览 3评论
605浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
599浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 17:24 , Processed in 2.937114 second(s), Total 78, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号