(沁恒WCH)CH32使用ADC+TIM+DMA进行数据采集
ch32v307,ADC+DMA+TIM,标准库
·
ADC+DMA+TIM
ADC转换数据,定时器触发采集,DMA搬运数据,这样可以在精准的时间,进行高效率的数据采集
如何配置

- 首先要知道的是,ADC中有两个寄存器,一个是规则通道数据寄存器,一个是注入通道数据寄存器,他们存放转化之后的数据的地址是不一样的,规则通道组是存放在
R32_ADCx_RDATAR(ADCx 规则数据寄存器,x=1,2),而注入通道组是存放在**ADCy 注入数据寄存器 x(ADCy_IDATARx)**中。(手册ADC寄存器部分) - 那是不是随便选择自己喜欢的通道呢,那肯定是不是的,此事在手册中亦有记载,如果使用注入组,就DMA就不会搬运数据,更别说进入DMA中断了

- 那定时器为什么要配置成PWM模式呢,此事在手册中亦有记载,只有检测到上升沿的时候,才可以启动转换

定时器配置
注意:定时器使能我是放在了初始化函数里面
/*******************************************************
* @function : TIM_Function_Init
* @param : uint16_t arr 自动重装载值
* @param : uint16_t psc 预分频系数
* @param : uint16_t ccp 比较值
* @retval : void
* @brief : 定时器初始化函数
********************************************************/
void TIM_Function_Init(uint16_t arr, uint16_t psc, uint16_t ccp)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
TIM_OCInitTypeDef TIM_OCInitStructure = {0};
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseInitStructure.TIM_Period = arr;
TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = ccp;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Disable);
TIM_ARRPreloadConfig(TIM1, ENABLE);
}
DMA配置
/**
* *@function : ADC_DMA_Function_Init
* @brief DMA 传输初始化函数
* @param DMA_CHx DMA 通道指针 (DMA_Channel_TypeDef*)
* @param memadr 存储器基地址 (uint32_t)
* @param bufsize 传输数据大小 (uint16_t),单位为数据单元个数
* @retval 无
* @note 调用此函数前,请确保 GPIO 及相关外设已初始化完毕;
* 本例使用 DMA1,如需使用 DMA2,请相应修改 RCC 时钟和通道参数。
*/
void ADC_DMA_Function_Init(DMA_Channel_TypeDef* DMA_CHx, uint32_t memadr, uint16_t bufsize)
{
DMA_InitTypeDef DMA_InitStructure = {0}; /**< DMA 配置结构体,先全部清零 */
NVIC_InitTypeDef NVIC_InitStructure = {0};
/* 1. 使能 DMA1 时钟 */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* 2. 复位指定的 DMA 通道,清除之前的状态 */
DMA_DeInit(DMA_CHx);
/* 3. 填充 DMA 参数结构体 */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->RDATAR; /**< 外设基地址(源地址) */
DMA_InitStructure.DMA_MemoryBaseAddr = memadr; /**< 存储器基地址(目的地址) */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; /**< 数据传输方向:外设 → 内存 */
DMA_InitStructure.DMA_BufferSize = bufsize; /**< 要传输的数据单元个数 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /**< 外设地址不递增 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /**< 存储器地址递增 */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /**< 外设数据宽度:半字(16 位) */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; /**< 存储器数据宽度:半字(16 位) */
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; /**< 循环模式*/
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; /**< 最高优先级 */
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /**< 关闭内存到内存模式 */
/* 4. 根据上述配置初始化 DMA 通道 */
DMA_Init(DMA_CHx, &DMA_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
/* 5. 使能 DMA 通道*/
DMA_Cmd(DMA_CHx, ENABLE);
}
ADC配置
/*******************************************************
* @function : ADC_Function_Init
* @param : void
* @retval : void
* @brief : ADC初始化函数
********************************************************/
void ADC_Function_Init(void)
{
// 定义 ADC 初始化结构体,并清零
ADC_InitTypeDef ADC_InitStructure = {0};
// 定义 GPIO 初始化结构体,并清零
GPIO_InitTypeDef GPIO_InitStructure = {0};
// //定义 NVIC 初始化结构体,并清零
// NVIC_InitTypeDef NVIC_InitStructure = {0};
// 使能 GPIOA 和 ADC1 的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// 配置 ADC 时钟分频
// ADC 的时钟通常来源于 APB2 时钟,这里设置为 PCLK2 的 8 分频
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置 ADC 输入引脚 GPIO
// 选择 GPIOA 的 Pin 7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
// 配置为模拟输入模式 (Analog Input)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
// 初始化 GPIOA 端口的相应引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 复位并去初始化 ADC1
// 确保 ADC 处于已知状态
ADC_DeInit(ADC1);
// 配置 ADC 工作模式为独立模式
// 表示 ADC1 独立工作,不与其他 ADC 配合使用
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// 关闭扫描模式
// 表示每次转换只转换一个通道,而不是按顺序转换多个通道
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
// 关闭连续转换模式
// 表示完成一次转换后,需要外部触发或软件触发下一次转换
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
// 配置规则通道的外部触发_
// 这里设置为定时器1的通道1触发 (T1_CC1)
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
// 配置 ADC 数据对齐方式
// 转换为12位数据,右对齐存储
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// 配置 ADC 转换通道数量
// 这里设置为转换 1个通道
ADC_InitStructure.ADC_NbrOfChannel = 1;
// 初始化 ADC1
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_55Cycles5);
ADC_DMACmd(ADC1, ENABLE); // 使能ADC的DMA请求功能
ADC_Cmd(ADC1, ENABLE);
// 关闭 ADC 内部缓冲(如果存在)
// 有些芯片有内部缓冲,这里显式关闭
ADC_BufferCmd(ADC1, DISABLE); //disable buffer
// ADC 校准过程
// 复位校准寄存器
ADC_ResetCalibration(ADC1);
// 等待校准复位完成
while(ADC_GetResetCalibrationStatus(ADC1));
// 启动 ADC 校准
ADC_StartCalibration(ADC1);
// 等待校准完成
while(ADC_GetCalibrationStatus(ADC1));
// 获取校准值
// 将校准后的值保存到变量 Calibrattion_Val 中 (Calibrattion_Val 应该在函数外部定义)
Calibrattion_Val = Get_CalibrationValue(ADC1);
// 使能ADC1的外部触发转换
ADC_ExternalTrigConvCmd(ADC1, ENABLE);
}
DMA中断处理函数
void DMA1_Channel1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void DMA1_Channel1_IRQHandler(void)
{
printf("DMA1 Channel1 IRQHandler");
// 检查是否是传输完成中断
if(DMA_GetITStatus(DMA1_IT_TC1)) // 假设是DMA1 Channel1的传输完成中断标志
{
// DMA已经将bufsize个数据搬运到了您的缓冲区
// 在这里处理缓冲区中的数据,例如打印或进行计算
// 注意:在循环模式下,DMA会自动继续下一轮传输
printf("DMA Transfer Complete!\r\n");
// 遍历并打印采集到的数据(示例)
for(int i = 0; i < 3; i++)
{
printf("Sample %d: %04d\r\n", i, Get_ConversionVal(ADC_DMA_Buffer[i])); // 假设 adc_buffer 是您的采集缓冲区
}
DMA_ClearITPendingBit(DMA1_IT_TC1); // 清除DMA传输完成中断标志
}
// 检查是否是半传输中断 (如果使能了)
// if(DMA_GetITStatus(DMA1_IT_HT1))
// {
// // 在这里处理缓冲区的前半部分数据
// DMA_ClearITPendingBit(DMA1_IT_HT1);
// }
// 检查是否有传输错误
// if(DMA_GetITStatus(DMA1_IT_TE1))
// {
// // 处理错误
// DMA_ClearITPendingBit(DMA1_IT_TE1);
// }
}
总体代码
/*
* app_adc.c
*
* Created on: 2025年5月4日
* Author: 86180
*/
#include "app_adc.h"
#define ADC_BUFFER_SIZE 30 //ADC缓冲区的大小
#define CURRENT_ADC_SETTING 2 // 假设当前的 ADC 设置是模式 1
// 定义 ADC_MODE 宏,它检查当前的设置是否与传入的参数匹配
#define ADC_MODE(mode) (CURRENT_ADC_SETTING == (mode))
uint16_t Calibrattion_Val = 0; //校准电压
uint16_t ADC_DMA_Buffer[ADC_BUFFER_SIZE]; //ADC数据缓冲区
float Voltage; //转换的电压值
/*******************************************************
* @function : Get_ConversionVal
* @param : uin16_t val 原始采样值
* @retval : uin16_t 校准后的采样值
* @brief : 对采样值进行校准值补偿并裁剪到[0,4095]范围
********************************************************/
uint16_t Get_ConversionVal(uint16_t val)
{
if ((val + Calibrattion_Val) < 0) return 0;
if ((val + Calibrattion_Val) > 4095 || val == 4095) return 4095;
return (val + Calibrattion_Val);
}
#if ADC_MODE(1)
/*******************************************************
* @function : Adc_Init_Porc
* @param : void
* @retval : 0 - 初始化完成
* @brief : ADC 初始化
* 配置 PA1 为模拟输入;
* 设置 ADC1 独立模式、连续转换、软件触发、右对齐;
* 使能 DMA 请求并执行 ADC 校准
********************************************************/
uint8_t Adc_Init_Porc(void)
{
ADC_InitTypeDef ADC_InitStructure={0};
GPIO_InitTypeDef GPIO_InitStructure={0};
/* 使能 GPIOA 和 ADC1 时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE );
/* ADC 时钟分频为 PCLK2/8
* 96MHz / 8 = 12MHz
* */
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
/* 配置 PA1 为模拟输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* ADC 基本配置 */
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 非扫描模式(单通道)
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 软件触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; // 通道数:1
ADC_Init(ADC1, &ADC_InitStructure);
/* 使能 ADC DMA */
ADC_DMACmd(ADC1, ENABLE);
/* 使能 ADC */
ADC_Cmd(ADC1, ENABLE);
/* 关闭内部缓冲,执行校准 */
ADC_BufferCmd(ADC1, DISABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
/* 获取校准值 */
Calibrattion_Val = Get_CalibrationValue(ADC1);
return 0;
}
/*******************************************************
* @function : ADC_Get_Channel_Val
* @param : uint8_t ch 对应ADC的通道
* ADC_Channel_0 - ADC Channel0 selected.
* ADC_Channel_1 - ADC Channel1 selected.
* ADC_Channel_2 - ADC Channel2 selected.
* ADC_Channel_3 - ADC Channel3 selected.
* ADC_Channel_4 - ADC Channel4 selected.
* ADC_Channel_5 - ADC Channel5 selected.
* ADC_Channel_6 - ADC Channel6 selected.
* ADC_Channel_7 - ADC Channel7 selected.
* ADC_Channel_8 - ADC Channel8 selected.
* ADC_Channel_9 - ADC Channel9 selected.
* ADC_Channel_10 - ADC Channel10 selected.
* ADC_Channel_11 - ADC Channel11 selected.
* ADC_Channel_12 - ADC Channel12 selected.
* ADC_Channel_13 - ADC Channel13 selected.
* ADC_Channel_14 - ADC Channel14 selected.
* ADC_Channel_15 - ADC Channel15 selected.
* ADC_Channel_16 - ADC Channel16 selected.
* ADC_Channel_17 - ADC Channel17 selected.
*
*
* @retval : uint16_t val 返回转化结果
* @brief : 获取指定通道的 ADC 转换值
* ch -- 要读取的 ADC 通道编号
********************************************************/
uint16_t ADC_Get_Channel_Val(uint8_t ch)
{
uint16_t val;
/* 配置规则通道和采样时间 */
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
/* 软件触发开始转换 */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
/* 等待转换结束 */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));
/* 读取转换结果 */
val = ADC_GetConversionValue(ADC1);
return val;
}
/**
* *@function : ADC_DMA_Init_Proc
* @brief DMA 传输初始化函数
* @param DMA_CHx DMA 通道指针 (DMA_Channel_TypeDef*)
* @param ppadr 外设基地址 (uint32_t)
* @param memadr 存储器基地址 (uint32_t)
* @param bufsize 传输数据大小 (uint16_t),单位为数据单元个数
* @retval 无
* @note 调用此函数前,请确保 GPIO 及相关外设已初始化完毕;
* 本例使用 DMA1,如需使用 DMA2,请相应修改 RCC 时钟和通道参数。
*/
void ADC_DMA_Init_Proc(DMA_Channel_TypeDef* DMA_CHx, uint32_t ppadr, uint32_t memadr, uint16_t bufsize)
{
DMA_InitTypeDef DMA_InitStructure = {0}; /**< DMA 配置结构体,先全部清零 */
/* 1. 使能 DMA1 时钟 */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* 2. 复位指定的 DMA 通道,清除之前的状态 */
DMA_DeInit(DMA_CHx);
/* 3. 填充 DMA 参数结构体 */
DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr; /**< 外设基地址(源地址) */
DMA_InitStructure.DMA_MemoryBaseAddr = memadr; /**< 存储器基地址(目的地址) */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; /**< 数据传输方向:外设 → 内存 */
DMA_InitStructure.DMA_BufferSize = bufsize; /**< 要传输的数据单元个数 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /**< 外设地址不递增 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /**< 存储器地址递增 */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /**< 外设数据宽度:半字(16 位) */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; /**< 存储器数据宽度:半字(16 位) */
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; /**< 循环模式*/
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; /**< 最高优先级 */
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /**< 关闭内存到内存模式 */
/* 4. 根据上述配置初始化 DMA 通道 */
DMA_Init(DMA_CHx, &DMA_InitStructure);
}
/*******************************************************
* @function : Adc_Data_Proc
* @param : MultiTimer* timer 指向触发回调的定时器实例的指针
* @param : void* user_data 用户自定义数据指针
* @retval : void
* @brief : ADC数据处理函数
* PB10 - USART3_TX
* PB11 - USART3_RX
********************************************************/
void Adc_Data_Proc(MultiTimer* timer,void* user_data)
{
uint32_t sum = 0;
uint8_t i = 0;
for (i = 0; i < ADC_BUFFER_SIZE; i++) {
sum += ADC_DMA_Buffer[i];
}
Voltage = (float)sum / 30.0f / 4096.0f * 3.3f;
multiTimerStart(&adc_proc_time,10,Adc_Data_Proc,NULL);
}
#elif ADC_MODE(2) // ADC+DMA+TIM
void ADC1_2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*******************************************************
* @function : ADC_Function_Init
* @param : void
* @retval : void
* @brief : ADC初始化函数
********************************************************/
void ADC_Function_Init(void)
{
// 定义 ADC 初始化结构体,并清零
ADC_InitTypeDef ADC_InitStructure = {0};
// 定义 GPIO 初始化结构体,并清零
GPIO_InitTypeDef GPIO_InitStructure = {0};
// //定义 NVIC 初始化结构体,并清零
// NVIC_InitTypeDef NVIC_InitStructure = {0};
// 使能 GPIOA 和 ADC1 的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// 配置 ADC 时钟分频
// ADC 的时钟通常来源于 APB2 时钟,这里设置为 PCLK2 的 8 分频
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置 ADC 输入引脚 GPIO
// 选择 GPIOA 的 Pin 7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
// 配置为模拟输入模式 (Analog Input)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
// 初始化 GPIOA 端口的相应引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 复位并去初始化 ADC1
// 确保 ADC 处于已知状态
ADC_DeInit(ADC1);
// 配置 ADC 工作模式为独立模式
// 表示 ADC1 独立工作,不与其他 ADC 配合使用
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// 关闭扫描模式
// 表示每次转换只转换一个通道,而不是按顺序转换多个通道
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
// 关闭连续转换模式
// 表示完成一次转换后,需要外部触发或软件触发下一次转换
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
// 配置规则通道的外部触发_
// 这里设置为定时器1的通道1触发 (T1_CC1)
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
// 配置 ADC 数据对齐方式
// 转换为12位数据,右对齐存储
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// 配置 ADC 转换通道数量
// 这里设置为转换 1个通道
ADC_InitStructure.ADC_NbrOfChannel = 1;
// 初始化 ADC1
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_55Cycles5);
ADC_DMACmd(ADC1, ENABLE); // 使能ADC的DMA请求功能
ADC_Cmd(ADC1, ENABLE);
// 关闭 ADC 内部缓冲(如果存在)
// 有些芯片有内部缓冲,这里显式关闭
ADC_BufferCmd(ADC1, DISABLE); //disable buffer
// ADC 校准过程
// 复位校准寄存器
ADC_ResetCalibration(ADC1);
// 等待校准复位完成
while(ADC_GetResetCalibrationStatus(ADC1));
// 启动 ADC 校准
ADC_StartCalibration(ADC1);
// 等待校准完成
while(ADC_GetCalibrationStatus(ADC1));
// 获取校准值
// 将校准后的值保存到变量 Calibrattion_Val 中 (Calibrattion_Val 应该在函数外部定义)
Calibrattion_Val = Get_CalibrationValue(ADC1);
// 使能ADC1的外部触发转换
ADC_ExternalTrigConvCmd(ADC1, ENABLE);
}
/*******************************************************
* @function : TIM_Function_Init
* @param : uint16_t arr 自动重装载值
* @param : uint16_t psc 预分频系数
* @param : uint16_t ccp 比较值
* @retval : void
* @brief : 定时器初始化函数
********************************************************/
void TIM_Function_Init(uint16_t arr, uint16_t psc, uint16_t ccp)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
TIM_OCInitTypeDef TIM_OCInitStructure = {0};
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseInitStructure.TIM_Period = arr;
TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);
//ADC1通道7对应的定时器触发通道是TIM1通道1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = ccp;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Disable);
TIM_ARRPreloadConfig(TIM1, ENABLE);
// TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);
}
/**
* *@function : ADC_DMA_Function_Init
* @brief DMA 传输初始化函数
* @param DMA_CHx DMA 通道指针 (DMA_Channel_TypeDef*)
* @param memadr 存储器基地址 (uint32_t)
* @param bufsize 传输数据大小 (uint16_t),单位为数据单元个数
* @retval 无
* @note 调用此函数前,请确保 GPIO 及相关外设已初始化完毕;
* 本例使用 DMA1,如需使用 DMA2,请相应修改 RCC 时钟和通道参数。
*/
void ADC_DMA_Function_Init(DMA_Channel_TypeDef* DMA_CHx, uint32_t memadr, uint16_t bufsize)
{
DMA_InitTypeDef DMA_InitStructure = {0}; /**< DMA 配置结构体,先全部清零 */
NVIC_InitTypeDef NVIC_InitStructure = {0};
/* 1. 使能 DMA1 时钟 */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* 2. 复位指定的 DMA 通道,清除之前的状态 */
DMA_DeInit(DMA_CHx);
/* 3. 填充 DMA 参数结构体 */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->RDATAR; /**< 外设基地址(源地址) */
DMA_InitStructure.DMA_MemoryBaseAddr = memadr; /**< 存储器基地址(目的地址) */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; /**< 数据传输方向:外设 → 内存 */
DMA_InitStructure.DMA_BufferSize = bufsize; /**< 要传输的数据单元个数 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /**< 外设地址不递增 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /**< 存储器地址递增 */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /**< 外设数据宽度:半字(16 位) */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; /**< 存储器数据宽度:半字(16 位) */
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; /**< 循环模式*/
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; /**< 最高优先级 */
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /**< 关闭内存到内存模式 */
/* 4. 根据上述配置初始化 DMA 通道 */
DMA_Init(DMA_CHx, &DMA_InitStructure);
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 5. 使能 DMA 通道*/
DMA_Cmd(DMA_CHx, ENABLE);
printf("ADC DMA OK!!!\r\n");
}
///*******************************************************
//* @function : ADC1_2_IRQHandler
//* @param : void
//* @retval : void
//* @brief : ADC1中断函数
//********************************************************/
//
void ADC1_2_IRQHandler(void)
{
uint16_t ADC_val;
if(ADC_GetITStatus(ADC1, ADC_IT_EOC))
{
printf("ADC Extline trigger conversion...\r\n");
ADC_val = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
printf("JADC %04d\r\n", Get_ConversionVal(ADC_val));
}
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
}
void DMA1_Channel1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void DMA1_Channel1_IRQHandler(void)
{
printf("DMA1 Channel1 IRQHandler");
// 检查是否是传输完成中断
if(DMA_GetITStatus(DMA1_IT_TC1)) // 假设是DMA1 Channel1的传输完成中断标志
{
// DMA已经将bufsize个数据搬运到了您的缓冲区
// 在这里处理缓冲区中的数据,例如打印或进行计算
// 注意:在循环模式下,DMA会自动继续下一轮传输
printf("DMA Transfer Complete!\r\n");
// 遍历并打印采集到的数据(示例)
for(int i = 0; i < 3; i++)
{
printf("Sample %d: %04d\r\n", i, Get_ConversionVal(ADC_DMA_Buffer[i])); // 假设 adc_buffer 是您的采集缓冲区
}
DMA_ClearITPendingBit(DMA1_IT_TC1); // 清除DMA传输完成中断标志
}
// 检查是否是半传输中断 (如果使能了)
// if(DMA_GetITStatus(DMA1_IT_HT1))
// {
// // 在这里处理缓冲区的前半部分数据
// DMA_ClearITPendingBit(DMA1_IT_HT1);
// }
// 检查是否有传输错误
// if(DMA_GetITStatus(DMA1_IT_TE1))
// {
// // 处理错误
// DMA_ClearITPendingBit(DMA1_IT_TE1);
// }
}
#endif
/*******************************************************
* @function : ADC_Init_Func
* @param : void
* @retval : void
* @brief : ADC初始化函数
********************************************************/
void ADC_Init_Func(void)
{
#if ADC_MODE(1)
uint8_t i = 0;
Adc_Init_Porc();//ADC配置初始化
printf("CalibrattionValue:%d\n", Calibrattion_Val);//打印校准值
ADC_DMA_Init_Proc(DMA1_Channel1,(uint32_t)&ADC1->RDATAR,(uint32_t)ADC_DMA_Buffer,ADC_BUFFER_SIZE); //初始化DMA
DMA_Cmd(DMA1_Channel1, ENABLE);
/* 配置ADC通道并启动连续转换 */
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
Delay_Ms(50);
// ADC_SoftwareStartConvCmd(ADC1, DISABLE);
/* 打印前30次采样值 */
printf("%04d\r\n", Get_ConversionVal(ADC_DMA_Buffer[i]));
#elif ADC_MODE(2)
ADC_DMA_Function_Init(DMA1_Channel1,(uint32_t)ADC_DMA_Buffer,ADC_BUFFER_SIZE);
ADC_Function_Init();
TIM_Function_Init(1000 - 1,96 - 1,500 - 1);
TIM_Cmd(TIM1, ENABLE);
#endif
}
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)