基于stm32实现adc的双通道采集HAL库DMA方式
本文目标:基于stm32实现adc的双通道采集HAL库DMA方式实验
按照本文的描述,应该可以跑通实验并举一反三。
先决条件:装有编译和集成的开发环境,比如:Keil uVision5、STM32CubeMX
使用外设:USART1、GPIO、ADC、DMA
前言
这篇文章是使用了双通道的adc进行验证而积累,属于自我笔记类型,供初学者进行学习验证。
实验目的
基于stm32实现adc的双通道采集HAL库DMA方式实验,顺便记录一下使用自己所理解的点。
关于ADC的特点
功能框图:
关于ADC的模式
扫描模式: 使用STM32CUBEMX配置了多通道后,这一项默认开启且无法设置成关闭。这个模式就是自动扫描你开启的所有通道进行转换,直至转换完。例如你开启了CH0、CH1、CH2、CH3这四个通道,启动转换后ADC会自动将这4个通道全部转换完,但是这种连续性是可以被打断的,所以就引出了间断模式。
连续模式: 在CUBE中选中ENABLE就是连续模式,DISABLE就是单次模式。开启连续模式后,ADC的转换不由其他控制。例如将ADC设置为了定时器的TGRO触发采样,如果开启连续模式,ADC将忽略定时器的触发采样。(连续转换模式开启后其实就是满频率的采样)。
间断模式: 可以将多个通道进行分组采集,例如你开启了CH0~3这4个通道,假如你设置了间断次数为4,就相当于将4个通道分成了4组,每组1个通道,那么要想采集完这4个通道就需要手动触发4次ADC采集;如果设置了间断次数为2,那么采集完4个通道就需要手动触发2次ADC采集。
关于采样时间
ADC采样两点间隔的时间一定要大于ADC的采样时间! 采样时间怎么算,下面就细说一下。
STM32F103一般将时钟配置主频为72M、APB2为72M。ADC挂在APB2时钟总线上,且ADC的时钟不能超过14M。所以一般将ADC的分频设置为6,ADC的时钟主频就为72/6=12MHz。那么一个周期就是:1/12MHz=0.0833us。
上图的意思是:ADC对输入电压采样若干个ADC_CLK周期,这些周期可通过ADC_SMPR1和ADC_SMPR2寄存器中的SMP[2:0]位进行修改。每个通道都可以用不同的采样时间进行采样。
ADC转换时间 = 采样时间 + 12.5个周期
示例:
当ADC时钟主频为14MHz并且采样时间为1.5个周期时:采样时间 = 1.5 + 12.5 = 14个周期;一个周期的时间为1/14MHz,一共14个周期,1 / 14MHz * 14个周期 = 1us,那么此时ADC的采样频率就是1/1us=1000KHz=1MHz,这也是理论上ADC的最大采样频率。
STM32F1系列的时钟主频一般设置为了12M,采样时间的设置所对应采样频率如下图所示:
知道了最短时间后,当ADC时钟主频为12M并且采样时间为1.5个周期时,ADC采样两点的时间必须大于1.17us。
基于上面的描述,接下来进行工程实验。
搭建工程
使用STM32CubeMX配置stm32的基本配置。基本的配置如下:开启swd调试,开启外部时钟。
- 配置USART1,用于printf调试
- 配置ADC1,用于本次实验的测试
- 时钟界面选项卡:
- 工程选项卡:
点击右上角的的生成代码:
使用keil打开工程,编译工程,一切都是ok
编写代码实现需求
开始编写代码,首先要把串口的打印映射好,使用下面的代码片段可用正常使用printf打印
int fputc( int ch, FILE *f )
{
USART_TypeDef* USARTx = USART1;
while ((USARTx->SR & (1<<7)) == 0);
USARTx->DR = ch;
return ch;
}
接下来定义数组用于接收数据
uint16_t g_sensor_adc_value[2] = {0};
在main函数中简单进行测试一下
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1); // 启动ADC转换
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)g_sensor_adc_value,2); // 开启DMA
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&g_sensor_adc_value[0],2); // 开启DMA
}
}
实验现象
总结
这里我外接了两个感应器,可以看到单片机此时能够正常获取数据,能根据传感器采集的数据变化而变化,综上所述本次实验取得预期效果。