先发一张效果图,使用逻辑分析仪和GPIO查看是否触发成功
直接上代码和注释
#define DMA_BUFFER_SIZE 2
unsigned char sample_finish = 0;
short adc_dma_tab[DMA_BUFFER_SIZE] = { 0 };
unsigned char sample_index = 0;
//采样点数据
short sample_1[6] = { 0 };
short sample_2[6] = { 0 };
void adc_gpio_init(void)
{
GPIO_InitTypeDef gpio_init_structure;
//使能GPIO时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_StructInit(&gpio_init_structure);
//GPIOA //PA-0 6用作ADC
gpio_init_structure.GPIO_Pin = (GPIO_Pin_1 | GPIO_Pin_6);
gpio_init_structure.GPIO_Mode = GPIO_Mode_AN; //使用附加(模拟)功能
gpio_init_structure.GPIO_OType = GPIO_OType_PP; //推挽输出
gpio_init_structure.GPIO_Speed = GPIO_Speed_50MHz; //Fast speed
gpio_init_structure.GPIO_PuPd= GPIO_PuPd_NOPULL; //上拉
GPIO_Init(GPIOA, &gpio_init_structure);
//这部分代码可以屏蔽掉,只是为了方便逻辑分析仪显示效果
gpio_init_structure.GPIO_Pin = (GPIO_Pin_11);
gpio_init_structure.GPIO_Mode = GPIO_Mode_AF; //使用附加(模拟)功能
gpio_init_structure.GPIO_OType = GPIO_OType_PP; //推挽输出
gpio_init_structure.GPIO_Speed = GPIO_Speed_50MHz; //Fast speed
gpio_init_structure.GPIO_PuPd= GPIO_PuPd_UP ; //上拉
GPIO_Init(GPIOA, &gpio_init_structure);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_2);
//这部分代码可以屏蔽掉,只是为了方便逻辑分析仪显示效果
gpio_init_structure.GPIO_Pin = ( GPIO_Pin_3);
gpio_init_structure.GPIO_Mode = GPIO_Mode_OUT; //使用附加(模拟)功能
gpio_init_structure.GPIO_OType = GPIO_OType_PP; //推挽输出
gpio_init_structure.GPIO_Speed = GPIO_Speed_50MHz; //Fast speed
gpio_init_structure.GPIO_PuPd= GPIO_PuPd_NOPULL; //上拉
GPIO_Init(GPIOB, &gpio_init_structure);
}
void adc_config(void)
{
ADC_InitTypeDef adc_init_structure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC时钟
ADC_DeInit(ADC1); //复位ADC
ADC_StructInit(&adc_init_structure); //初始化ADC结构体
adc_init_structure.ADC_ContinuousConvMode = DISABLE; //禁用连续转换模式
adc_init_structure.ADC_DataAlign = ADC_DataAlign_Right; //采样数据右对齐
adc_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC4; //外部触发设置为TIM2
adc_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;//上升沿触发
adc_init_structure.ADC_Resolution = ADC_Resolution_12b; //12位分辨率
adc_init_structure.ADC_ScanDirection = ADC_ScanDirection_Upward;//向上扫描0-18通道
ADC_Init(ADC1, &adc_init_structure);
ADC_OverrunModeCmd(ADC1, ENABLE); //使能数据覆盖模式 .OVRMOD: 过冲管理模式 1: 当检测到过冲事件时,ADC_DR 寄存器用最后一次的转换数据覆盖
ADC_ChannelConfig(ADC1, ADC_Channel_1 | ADC_Channel_6,
ADC_SampleTime_13_5Cycles); //配置采样通道,采样时间125nS
ADC_GetCalibrationFactor(ADC1); //使能前校准ADC
ADC_Cmd(ADC1, ENABLE); //使能ADC1
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN) == RESET); //等待ADC1使能完成
ADC_DMACmd(ADC1, ENABLE); //使能ADC_DMA
ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);//ADC_DMAMode_Circular);//ADC_DMAMode_OneShot); //配置DMA请求模式为循环模式
ADC_StartOfConversion(ADC1); //开启一次转换(必须)
}
void adc_dma_init(void)
{
DMA_InitTypeDef dma_init_structure;
NVIC_InitTypeDef nvic_init_structure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA时钟
nvic_init_structure.NVIC_IRQChannel = DMA1_Channel1_IRQn; //选择DMA1通道中断
nvic_init_structure.NVIC_IRQChannelCmd = ENABLE; //中断使能
nvic_init_structure.NVIC_IRQChannelPriority = 0; //优先级设为0
NVIC_Init(&nvic_init_structure);
DMA_DeInit(DMA1_Channel1); //复位DMA1_channel1
DMA_StructInit(&dma_init_structure); //初始化DMA结构体
dma_init_structure.DMA_BufferSize = DMA_BUFFER_SIZE; //DMA缓存数组大小设置
dma_init_structure.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA方向:外设作为数据源
dma_init_structure.DMA_M2M = DISABLE; //内存到内存禁用
dma_init_structure.DMA_MemoryBaseAddr = (unsigned int)&adc_dma_tab[0];//缓存数据数组起始地址
dma_init_structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据大小设置为Halfword
dma_init_structure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址递增
dma_init_structure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal; DMA_Mode_Circular //DMA循环模式,即完成后重新开始覆盖
dma_init_structure.DMA_PeripheralBaseAddr = (unsigned int) &(ADC1->DR);//取值的外设地址
dma_init_structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设取值大小设置为Halfword
dma_init_structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址递增禁用
dma_init_structure.DMA_Priority = DMA_Priority_High; //DMA优先级设置为高
DMA_Init(DMA1_Channel1, &dma_init_structure);
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //使能DMA中断
DMA_ClearITPendingBit(DMA_IT_TC); //清除一次DMA中断标志
DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA1
}
void adc_timer_init(void)
{
TIM_TimeBaseInitTypeDef timer_init_structure;
NVIC_InitTypeDef nvic_init_structure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //使能TIM1时钟
TIM_DeInit(TIM1); //复位TIM1
TIM_TimeBaseStructInit(&timer_init_structure); //初始化TIMBASE结构体
timer_init_structure.TIM_ClockDivision = TIM_CKD_DIV1; //系统时钟,不分频,48M
timer_init_structure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
timer_init_structure.TIM_Period = 99; //uS触发一次中断,开启ADC
timer_init_structure.TIM_Prescaler = 48-1; //计数时钟预分频,f=1M,systick=1 uS
timer_init_structure.TIM_RepetitionCounter = 0x00; //发生0+1次update事件产生中断
TIM_TimeBaseInit(TIM1, &timer_init_structure);
/* 频道4的PWM 模式设置 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_Pulse = 40;//使能频道4配置
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
/* TIM1 主输出使能 */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_Cmd(TIM1, ENABLE); //使能TIM2
}
void DMA1_Channel1_IRQHandler(void)
{
if(DMA_GetITStatus(DMA_IT_TC)) //判断DMA传输完成中断
{
GPIO_SetBits(GPIOB,GPIO_Pin_3);
if(sample_finish == 0)
{
sample_1[sample_index] = adc_dma_tab[0];
sample_2[sample_index] = adc_dma_tab[1];
sample_index++;
}
if(sample_index >= 6) //注意防止数组越界导致未知错误
{
sample_index = 0;
//TIM_Cmd(TIM2, DISABLE); //完成周波采样,停止定时器
//DMA_Cmd(DMA1_Channel1, DISABLE); //完成周波采样,停止DMA
//sample_finish = 1; //置采样完成标志位
}
GPIO_ResetBits(GPIOB,GPIO_Pin_3);
}
DMA_ClearITPendingBit(DMA_IT_TC); //清除DMA中断标志位
}
在main函数里调用
adc_gpio_init();
adc_config(); // 注意此处的初始化顺序,否则采样传输的数据容易出现数据错位的结果
adc_dma_init(); //
adc_timer_init();
几个注意点,否则无法触发