目录
一、工程依赖的硬件及背景
二、设计目的
三、建立工程
1、配置GPIO
2、选择时钟源和Debug
3、配置ADC
4、配置系统时钟和ADC时钟
5、配置TIM3
6、配置串口
四、代码修改
1、重定义TIM3中断回调函数
2、启动ADC及重写其回调函数
3、定义用于存储转换结果的数组
4、重定义回调函数
5、在主程序中编写发送数据代码
6、在主程序初始化代码中使能ADC中断和TIM3中断
7、配置printf函数
五、运行并查看结果
在单次测量的例子中,当每次操作按键B1后,都要重复进行启动ADC、等待转换,然后读换结果这些步骤。实际应用中,很多时候是让ADC连续进行采样。此时,可以使能ADC的连续转换。在此转换模式下,ADC完成一次转换后会开始新的转换。
一、工程依赖的硬件及背景
文章依赖的硬件及工程配置参考本文作者的其他文章:细说MCU的ADC模块单通道单次采样的实现方法-CSDN博客文章浏览阅读1.1k次,点赞12次,收藏19次。由于希望在产生按键中断时,启动ADC采样,所以,需要重定义外部中断EXTI的回调函数。这个回调函数可以写在main.c文件后面的一个注释对中。https://wenchm.blog.csdn.net/article/details/139884221
二、设计目的
信号源:通过TIM3连续产生PWM波形,并通过LD2(PA5)显示并输出。
PA0为ADC1的信号输入,即把PA5的信号输出通过导线连接给PA0。
USART2为串口输出。ADC1_IN1采集信号源输入,达到ADCSampleFlag==1时,开始通过串口发送数据到显示设备,直到发送数据完毕时,ADCSampleFlag==0;
正常情况下:ADCSampleFlag==0时,ADC1开始采集数据到寄存器,直到达到SIZE的规模时,ADCSampleFlag==1;
注意:本例只是为了演示相关功能,事实,信号源是连续的时候,两次ADC1的采集间隔中是存在漏采的情况的。
三、建立工程
1、配置GPIO
配置PA5为输出(GPIO_Output),默认输出电平Low,推挽输出,上拉,速度High,标识为LED;PA5引脚输出高电平时LD2点亮,默认的低电平时熄灭;
2、选择时钟源和Debug
使用片外时钟晶体作为HSE的时钟源。在SYS中将Debug设置为Serial Wire。
3、配置ADC
选择Analog中的ADC1,在其模式(Mode)区,通道1(IN1)选择IN1 Single-ended(单端);其它参数设置可暂时均保持默认值。时钟预分频参数(Clock Prescaler)选择Asynchronous clock mode dividedby 1(其他选项亦可)。
4、配置系统时钟和ADC时钟
将系统时钟(SYSCLK)频率配置为170 MHz,设置ADC1的时钟频率为42.5 MHz。
设置ADC1的预分频参数为256,该参数将ADC1的时钟分频256倍,这个数值的选择与ADC1采样频率有关。
使能ADC1的连续转换模式;
在Rank下的采样时间选择为92.5个周期。这个参数决定着ADC的转换时间,则在12位分辨率时ADC1的转换时间为:92.5+12+0.5=105个ADC的时钟周期。
使能ADC1的中断;
ADC中断优先级设置为1;
5、配置TIM3
将Clock Source选择为内部时钟,
将预分频因子和计数器周期分别设置为999,16999;
TIM3中断优先级设置为1;
6、配置串口
选择 Connectivity中的 USART2,其模式( Mode)选择异步( Asynchronous),其他参数设置均保持默认(波特率为115200 bit/ s),不开启中断。将 USART2的两个引脚 PA2和 PA3均设置为上拉。
四、代码修改
打开main.c,修改代码。
1、重定义TIM3中断回调函数
重定义 HAL_TIM_PeriodElapsedCallback(),在其中使PA5(LD2)的输出状态翻转。产生5Hz的信号源,修改预分频因子和计数器周期数值,可以改变信号源的频率。
/* 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、启动ADC及重写其回调函数
关于ADC中断的使用,与外部中断、串口中断、定时器中断等的使用方法是类似的。关键点有两个:一是重写回调函数,二是在主程序初始化时开启中断。
ADC中断相关的回调函数可以用:
HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc);
启动ADC中断的库函数为:
HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc);
3、定义用于存储转换结果的数组
定义一个数组,用于存储A/D转换结果。每执行一次回调函数,就将此次A/D转结果存入数组,直到存满。随后,在主程序中,通过串口送出数组中存储的数据。为此,需要在主程序中定义几个变量(放到注释对中):
/* USER CODE BEGIN PV */
uint16_t ADC1ConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE]={0};
uint16_t ADC1Data_index =0;
uint8_t ADCSampleFlag =0;
/* USERCODE 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 */
4、重定义回调函数
在main.c中定义回调函数HAL_ADC_ConvCpltCallback():
/* 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;
}
}
/* USER CODE END 4 */
5、在主程序中编写发送数据代码
标志位变量ADCSampleFlag的作用:当数组存满后,该标志位置1,等待串口发送数组中的数据;一旦数据发送完毕,再将该变量赋值为0,继续更新数组中数将数据发送代码放到main函数中的while(1)循环中,实现代码如下:
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(ADCSampleFlag == 1)
{
for(uint16_ti=1;i<ADC_CONVERTED_DATA_BUFFER_SIZE;i++)
{
printf("ADC1ConvertedData[%d] = %d\r\n",i,ADC1ConvertedData[i]);
}
ADCSampleFlag =0;
}
HAL_Delay(1000);
}
/* USER CODE END 3 */
6、在主程序初始化代码中使能ADC中断和TIM3中断
将HAL_ADC_Start_IT()函数与HAL_ADCEx_Calibration_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_IT(&htim3);
/* USER CODE END 2 */
7、配置printf函数
在回调函数的最后,使用了 printf函数,将 A/ D转换的结果通过串口送出。
使用 printf函数从串口送出数据,需要在 main.c中将 stdio.h包含进来;此外,还要给出 putchar函数的定义。
/* USER CODE BEGIN 4 */
int __io_putchar(int ch)
{
HAL_UART_Transmit(&huart2,(uint8_t *)&ch,1,0xFFFF);
return ch;
}
/* USER CODE END 4 */
五、运行并查看结果
示波器采集到的信号源:
串口接收到的数据: