目录

一、工程依赖的硬件及背景

二、设计目的

三、 建立工程

1.选择时钟源和Debug模式

2.配置系统时钟和ADC时钟

3.配置串口

4.配置ADC

5.设置TIM3

6.设置TIM4 

7.配置中断

8.GPIO

四、代码修改

1.重新定义ADC回调函数

2.在主程序中编写数据发送代码

3.使能ADC和开启定时器

4.查看结果


        在细说MCU的ADC模块单通道连续采样的实现方法-CSDN博客  https://blog.csdn.net/wenchm/article/details/140008718细说MCU用定时器控制ADC采样频率的实现方法-LMLPHPhttp://xn--https-rfa//blog.csdn.net/wenchm/article/details/140008718中,通过使能AD配置参数中的连续转换模式(Continuous Conversion Mode),并结合ADC中断,实现了连续采样。该例中,ADC的采样频率约为1.58 kHz,是通过设置ADC的时钟频率和采样时间得到的。实际中,有时希望ADC以给定的采样频率转换数据,譬如1 kHz。在这种情况下靠配置ADC时钟频率和采样时间的方法就非常不方便。

        本例子使用定时器来控制ADC连续采样。

一、工程依赖的硬件及背景

        文章依赖的硬件及工程配置参考本文作者的其他文章:细说MCU的ADC模块单通道连续采样的实现方法-CSDN博客  https://blog.csdn.net/wenchm/article/details/140008718细说MCU用定时器控制ADC采样频率的实现方法-LMLPHPhttp://xn--https-rfa//blog.csdn.net/wenchm/article/details/140008718

二、设计目的

        信号源为TIM4的TIM_CHANNEL_1,管脚PA11,给ADC1_IN1输入信号;也可以用管脚PA5的LD2作为信号源给ADC1_IN1输入信号;

       ADC1_IN1采集到信号后,按缓冲大小的规定,循环给串口发送数据;

       ADC采集样品的频率由TIM3设置的规则控制;

三、 建立工程

1.选择时钟源和Debug模式

        使用片外时钟晶体作为HSE的时钟源。将Debug设置为Serial Wire。

2.配置系统时钟和ADC时钟

        将系统时钟(SYSCLK)频率配置为170 MHz,并设置ADC1的时钟为34 MHz。

3.配置串口

        配置USART2模式(Mode)为异步(Asychronous),其他参数设置均保持默认(波特率为115200),不开启中断。将USART2的两引脚PA2和PA3均设置为上拉(Pull-up)。

4.配置ADC

        配置ADC1的通道1(IN1),选择IN1 Single-ended;在下面的配置(Configuration)区,对几个参数进行调整:

  • ADC的时钟预分频参数(Clock Prescaler)选择Asynchronous clock mode divided by 1,也就是不分频(前面的例子是分频256倍,目的是想得到所需要的采样频率)。本例将用定时器实现对采样频率的控制,所以ADC的时钟可以不用进行分频处理。
  • 将ADC设置(ADC_Settings)参数栏中连续转换模式(Continuous Conversion Mode)设置为Disabled,即不使能,因为本例中ADC采样频率要通过定时器来控制。
  • 转换结束选择(End Of Conversion Selection)参数仍保持单次转换结束(End of single conversion);由于目前只使用了一个ADC通道,还可以选择序列转换结束(End of sequence conversion),对结果没有影响。
  • 在ADC规则转换模式(ADC_Regular_Conversion Mode)栏中,外部触发转换源(External Trigger Conversion Source)选择Timer 3 Trigger Out event,使用TIM3的触发输出作为ADC的触发源。
  • 位于Rank下的采样时间选择2.5个周期。前面提到过,这个参数决定着ADC的转换时间。如果选择2.5个周期,则在12位分辨率时ADC的转换时间为2.5+12+0.5=15个周期。
  • 使能ADC1的中断。

5.设置TIM3

        TIM3的模式(Mode)区,选择时钟源(Clock Source)为内部时钟(InterClock);计数器的预分频因子设置为169,则定时器的时钟频率为系统频率的1/170,如果系统频率为170 MHz,则定时器的时钟频率为1 MHz;计数器的周期设置为999,则计数器的溢出频率为1MHz/1000 =1 kHz。在Trigger Output参数栏中将发事件设置为更新事件(Update Event)。

6.设置TIM4 

        TIM4的模式(Mode)区,选择时钟源(Clock Source)为内部时钟(InterClock);通道1选择PWM Generation CH1;GPIO管脚默认PA11;计数器的预分频因子设置为999,计数器的周期设置为8499,auto reload=Enable;Pulse=2125;

7.配置中断

        将ADC1中断的优先级设为1。此外,由于将会用到HAL_Delay函数,所以要将tick timer中断的占式优先级设为0。

        TIM4的全局中断的优先级设置为2;

8.GPIO

        设置 PA5(LD2) 为GPIO OUTPUT,OUTput level默认LOW,PP,Pullup,High;别名LED;

四、代码修改

1.重新定义ADC回调函数

        在主程序中重写回调函数HAL_ADC_ConvCpltCallback()和串口发数据的putchar函数,并且将它们放到main.c的注释对中:

/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	ADC1ConvertedData[ADC1Data_index] = HAL_ADC_GetValue(&hadc1);
	if(ADCSampleFlag == 0)
		ADC1Data_index ++;
	if(ADC1Data_index == ADC_CONVERTED_DATA_BUFFER_SIZE)
	{
		ADCSampleFlag = 1;
		ADC1Data_index = 0;
	}
}

//信号源
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}

//串口打印
int __io_putchar(int ch)
{
	HAL_UART_Transmit(&huart2,(uint8_t *)&ch,1,0xFFFF);
	return ch;
}
/* USER CODE END 4 */

2.在主程序中编写数据发送代码

        将数据发送代码放置到main函数的while(1)循环中。

while(1)
/* USER CODE BEGIN 3 */
if(ADCSampleFlag == 1)
{
    for(uint16_t i=1;i<ADC_CONVERTED_DATA_BUFFER_SIZE;i++)
    {
        printf("ADC1ConvertedData[%d] = %d\r\n",i,ADC1Convertedata[i]);
    }
    ADCSampleFlag = 0;
}
HAL_Delay(1000);
/*USER CODE END 3 */

        上述函数中用到的变量需要定义。仍然是将它们定义为全局变量,放到主程序中的注释中:

/*USER CODE BEGIN PV*/
uint16_t ADC1ConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE];
uint16_t ADC1Data_index =0;
uint8_t ADCSampleFlag =0;
/*USER CODE END PV*/

        其中,数组长度ADC_CONVERTED_DATA_BUFFER_SIZE可以定义到main.h中:

/* USER CODE BEGIN Private defines */
#define ADC_CONVERTED_DATA_BUFFER_SIZE(uint16_t) 65
/* USER CODE END Private defines */

        同时,在main.c中,包含头文件stdio.h:

/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

3.使能ADC和开启定时器

        在主程序初始化代码中使能ADC中断,并开启定时器TIM3、TIM4。将HAL_ADC_Sta IT()、HAL_ADCEx_Calibration_Start()、HAL_TIM_Base_Start()、HAL_TIM_Base_Start_IT()HAL_TIM_PWM_Start()放到while(1)之前, MX_ADC1_Init()之后的注释对中: 

  /* USER CODE BEGIN 2 */
  HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);
  HAL_ADC_Start_IT(&hadc1);
  HAL_TIM_Base_Start(&htim3);
  HAL_TIM_Base_Start_IT(&htim4);
  HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);
  /* USER CODE END 2 */

4.查看结果

        把PA5(LD2)信号或者PA11(TIM4_CH1)信号施加信号到ADC1_IN1输入端PA0上,打开串口助手即可收到送上来的数据。

        为了实测ADC的采样频率,同样可以配置PC3作为输出引脚,在回调函数HAL_ADC _ ConvCpltCallback()中加入控制PC3输出状态的语句,并通过示波器测量PC3引脚的输出 形,此时测得的频率为采样频率。

        实测的PA5(LD2)信号:

细说MCU用定时器控制ADC采样频率的实现方法-LMLPHP

         实测的串口接收的数据:

细说MCU用定时器控制ADC采样频率的实现方法-LMLPHP 

07-12 19:07