Cube生成定时器2触发双ADC同步采集并用DMA传输

前言

用cube生成一个用定时器触发ADC1,ADC2同步采集的程序,单片机选择的是STM32L476RGT6,用定时器2进行ADC采集触发,更改定时器2的定时周期便可以更改ADC的采样周期,ADC1和ADC2使用同步规则模式,并用DMA进行数据的传输。

STM32的ADC采样完成总共需要的时间是
ADC完成采样时间=采样周期+12个转换周期
举个例子,假如ADC的时钟是15MHz,采样周期是3个周期,3个采样周期加上12个转换周期,一共是15个周期,因为时钟是15MHz,所以完成一次ADC转换总共需要的时间就是1us。

STM32L476RGT6的ADC时钟是32MHZ,采样周期最短是2.5个周期,最快完成一次采集的时间大约是0.45us,因此,定时器触发的周期一定要大于这个时长

参考 STM32参考手册 里面对于ADC同步规则模式的介绍。
Cube生成定时器2触发双ADC同步采集并用DMA传输_第1张图片

Cube生成的过程

时钟源配置

首先时钟源选择 晶体/陶瓷谐振器,
Cube生成定时器2触发双ADC同步采集并用DMA传输_第2张图片

调试方式配置

然后在sys里面选择调试方式为Serial Wire
Cube生成定时器2触发双ADC同步采集并用DMA传输_第3张图片

定时器配置

定时器1选择PWM输出模式,定时器的时钟是80MHz,进行2分频,计数周期是80,生成一个频率是500KHz,占空比为50%的PWM波,用于验证ADC的采样速率。
Cube生成定时器2触发双ADC同步采集并用DMA传输_第4张图片
定时器2的时钟源选择内部时钟,2分频,40计数周期,实现1MHz的ADC触发。Trigger Event Selection TRGO 一定要选择 Update Event ,不然不会触发ADC。
Cube生成定时器2触发双ADC同步采集并用DMA传输_第5张图片

ADC配置

ADC1的通道是12,ADC1和ADC2都有通道打开的情况才会出现双通道的模式选择,如果只有一个独立模式,可以先打开一个ADC2的通道,再来ADC1里面进行模式选择。模式选择双通道同步规则模式,触发源选择定时器2上升沿触发,采样周期是2.5个周期,其余的选项默认设置就行。
Cube生成定时器2触发双ADC同步采集并用DMA传输_第6张图片
ADC2的通道是15,配置默认,ADC2一定要与ADC1的采样周期相同
Cube生成定时器2触发双ADC同步采集并用DMA传输_第7张图片

DMA配置

DMA只需要给ADC1添加一个DMA通道,ADC2不用配置。ADC1添加的DMA模式选择循环传输,数据长度都选择Word。
Cube生成定时器2触发双ADC同步采集并用DMA传输_第8张图片

串口配置

串口选择串口2,配置默认
Cube生成定时器2触发双ADC同步采集并用DMA传输_第9张图片

中断配置

Cube生成定时器2触发双ADC同步采集并用DMA传输_第10张图片

配置完成后的引脚图

Cube生成定时器2触发双ADC同步采集并用DMA传输_第11张图片

时钟树配置

单片机运行的频率是80MHz,ADC采集频率是32MHz。
Cube生成定时器2触发双ADC同步采集并用DMA传输_第12张图片

生成工程代码

上述都配置完成后便可以生成代码啦,
Cube生成定时器2触发双ADC同步采集并用DMA传输_第13张图片
Cube生成定时器2触发双ADC同步采集并用DMA传输_第14张图片

添加程序

main.cl里面需要添加的程序

在初始化完成后,while循环之前添加该段代码,

/* USER CODE BEGIN 2 */
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1);     // 开启频率500KHz占空比为50%的PWM波

HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);  // 对ADC进行校准,如果没有进行校准采集到的数据会有偏差
HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED);	

HAL_TIM_Base_Start(&htim2);	 // 开启定时器2 用于触发ADC采集, 更改定时器2的频率便可以更改ADC的采样速率
HAL_ADC_Start(&hadc2);       // 开启ADC2 
/* USER CODE END 2 */

在while循环里面添加下段代码

/* USER CODE BEGIN 3 */	
printf("开始数据采集\r\n");
adc_complete = 0;  // ADC采集完成标志 置零
HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&ADC_Value, sample_point);  //开始同步采集ADC	
while(adc_complete == 0){HAL_Delay(5);}	//等待ADC采集完成
printf("数据采集完成\r\n");
		
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);   // 对ADC进行校准
HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED);
		
for(i = 0, ad1 = 0, ad2 = 0; i<sample_point; i++)   //分解数据, ADC_Value的高16位是ADC2的数据,ADC_Value的低16位是ADC1的数据
{
	ADC_1[ad1++] =  (uint16_t)ADC_Value[i];
	ADC_2[ad2++] =  (uint16_t)(ADC_Value[i]>>16);
}
for(i = 0; i<sample_point; i++){printf("ADC[%02d] = %x  \r\n", i, ADC_Value[i]);}
printf("\r\n");
for(i = 0; i<sample_point; i++){printf("AD1[%02d] = %d  \r\n", i, ADC_1[i]);}
printf("\r\n");
for(i = 0; i<sample_point; i++){printf("AD2[%02d] = %d  \r\n", i, ADC_2[i]);}
printf("\r\n");
		
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(8000);
/* USER CODE END 3 */

usart.c里面添加代码

/* USER CODE BEGIN 1 */
#ifdef __GNUC__
/*** With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/*** @brief  Retargets the C library printf function to the USART.
* @param  None
* @retval None*/

PUTCHAR_PROTOTYPE

{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */

  HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);  //printf使用串口2输出
  return ch;
}
/* USER CODE END 1 */

adc.c里面添加代码

/* USER CODE BEGIN 1 */
/* ADC采集完成后会进入该回调函数,
   标记ADC转换完成并停止转换,
   以免之前采集到的数据被覆盖*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)  
{
  if(hadc->Instance==ADC1)
  {
    adc_complete = 1;     // 标记ADC采集完成
	HAL_ADCEx_MultiModeStop_DMA(&hadc1);  // 停止ADC采集
  }
}
/* USER CODE END 1 */

验证

由于在家里没有信号源,也没有其他的单片机,验证就简单的输出了一个PWM波给ADC1,2进行采集来看现象。

将程序编译下载到单片机上,由于ADC1的12通道直接连在了定时器1输出PWM波的引脚上,PWM频率是500KHz,占空比是50%,所以ADC1应该采集到的的数据,是一个4095,之后一个0,ADC2的15通道悬空,所以ADC2的数据应该是乱的,串口显示的数据如图所示。
Cube生成定时器2触发双ADC同步采集并用DMA传输_第15张图片
Cube生成定时器2触发双ADC同步采集并用DMA传输_第16张图片
Cube生成定时器2触发双ADC同步采集并用DMA传输_第17张图片
**现在将ADC2的15通道与ADC1的12通道连接在一起,采集到的数据ADC1和ADC2应该保持一致。**串口输出的数据如下图所示。
Cube生成定时器2触发双ADC同步采集并用DMA传输_第18张图片
Cube生成定时器2触发双ADC同步采集并用DMA传输_第19张图片
Cube生成定时器2触发双ADC同步采集并用DMA传输_第20张图片
可以看出ADC1和ADC2采集到的数据保持一致。
现在更改定时器1的PWM波的频率和占空比,频率改为250KHz,占空比改为25%,ADC1和ADC2同时连接到该引脚,采集到的数据应该是1个4095, 3个0,并且ADC1和ADC2采集到的数据保持一致。串口输出的数据如下图所示。
Cube生成定时器2触发双ADC同步采集并用DMA传输_第21张图片
Cube生成定时器2触发双ADC同步采集并用DMA传输_第22张图片
Cube生成定时器2触发双ADC同步采集并用DMA传输_第23张图片
从采集到的数据可以看出,验证基本成功。

完整的工程代码

完整的工程代码放到下面的链接里面了。工程代码

你可能感兴趣的:(Cube生成定时器2触发双ADC同步采集并用DMA传输)