-
2021-05-18 03:17:24
给你我自己的一段定时器中断的程序,学习时候自己编的,功能:每一秒钟a+1;
#include "time.h"
#include "stm32f10x.h"
//#include "key.h"
//#include "SysTickDelay.h"
u8 a;
u16 i=0;
void TIME_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //时钟配置
TIM_DeInit(TIM2); //复位定时器
TIM_TimeBaseStructure.TIM_Prescaler = 1; //预分频(时钟分频)72M/(1+1)=36M
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseStructure.TIM_Period = 35999; //装载值36M/36000=1000hz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //初始化定时器的值
TIM_ClearFlag(TIM2,TIM_FLAG_Update); //清除定时器中断标志
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能中断
TIM_Cmd(TIM2,ENABLE); //开启时钟
}
void NVIC_Configuration(void)//嵌套中断配置
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn; //选择TIM2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; //
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能
NVIC_Init(&NVIC_InitStructure);
}
void TIM2_IRQHandler(void)//定时器中断函数
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET) //判断是否定时中断
{
i++;
if(i==1000) {i=0;a++;}
}
TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);//必须清除中断标志位否则一直中断
}
更多相关内容 -
STM32定时器触发ADC采集,数据发送至上位机
2020-12-26 13:18:15STM32用的F103,定时器用的TIM2,CH2,程序里用的是0.5ms采集一次,在定时器初始化里也可以自己设置 -
基于STM32的定时器触发ADC采集数据
2014-08-11 16:15:20有时因为数据处理需求,DMA速度传送太快,易丢失数据,采用TIM定时器触发AD进行转换,能有效精确地采集所要的数据段。 -
hal库定时器触发adc dma采集
2018-06-26 11:16:38基于stm32f103c8t6通过定时触发单通道adc dma采集数据 -
Cube配置 定时器 触发 ADC1,2同步规则采样并用DMA传输
2020-05-10 14:42:33Cube配置 用定时器触发ADC1,2同步规则采样并用DMA传输,单片机选择的是STM32L476RGT6,用定时器2对ADC进行触发,更改定时器2定时周期便更改ADC的采样速率,程序里面设置的是1MHz的采样速率,ADC1和ADC2同时进行采集,... -
FM33LC0xx-定时器触发ADC.pdf
2020-12-26 17:13:03复旦微FM33LC0xxx系列MCU定时器触发ADC例程说明 -
STM32 定时器触发 ADC 多通道采集,DMA搬运至内存
2020-08-24 15:03:28使用定时器中断,每隔一段时间进行 ADC 转换,但是这样每次都必须读 ADC 的数据寄存器,非常浪费时间。 把 ADC 设置成连续转换模式,同时对应的 DMA 通道开启循环模式,这样 ADC 就一直在进行数据采集然后通过 DMA ...引言
ADC 的功能是将模拟信号采样得到数字信号,而有些时候,我们需要使用到定时采样,比如在计算一个采集的波形的频率的时候,我们需要精确的知道采样频率,也就是 1 s 内采集的点数,这个时候,就需要使用到定时采集。 定时采样有如下三种方法:
- 使用定时器中断,每隔一段时间进行 ADC 转换,但是这样每次都必须读 ADC 的数据寄存器,非常浪费时间。
- 把 ADC 设置成连续转换模式,同时对应的 DMA 通道开启循环模式,这样 ADC 就一直在进行数据采集然后通过 DMA 把数据搬运至内存。这样进行处理的话,需要加一个定时中断,用来读取内存中的数据。
- 使用 ADC 的定时器触发 ADC 转换的功能,然后使用 DMA 进行数据的搬运。这样就只要设置好定时器的触发间隔,就能实现 ADC 定时采样转换的功能,然后使能 DMA 转换完成中断,这样每次转换完就会产生中断。
本文,笔者将采用第三种方法进行 AD 采集,使用 TIM 定时器触发 AD 采集,然后 DMA 搬运至内存。
ADC 简介
首先来看一下 ADC 的框图:
在本文中,我们使用的是规则通道进行转换,这里要指出的一点是规则通道和注入通道两者的区别,以下是关于两种通道的说明:- 规则通道:我们平时使用的就是这个通道,就是规规矩矩的按照我们设定的转换顺序就行转换的通道。
- 注入通道:注入通道可以理解为是插入,也就是插队的意思,它是一种不安分的通道。它是一种在规则通道转换的时候强行插入要进行转换的一种,它的存在就像是程序中的中断一样,换个角度说,也就是注入通道只有在规则通道存在的情况下才会存在。
说了规则通道和注入通道的区别之后,我们来看我们在本文中所用到的规则通道的触发方式。我们最为常用的一种就是软件触发,即配置到 ADC 之后,就会自动地进行转换,然后去读 ADC 的数据寄存器就可以得到 ad 转换得到的数值。还有一种方法就是外部触发,而外部触发又包括定时器触发和外部 IO 触发,在本文中,我们使用的是定时器触发,通过上述的 ADC 功能框图,我们可以知道 ADC 的定时器触发又有如下几种类型:
- TIM1_CH1 :定时器 1 的通道 1 的 PWM 触发
- TIM1_CH2 : 定时器 2 的通道 2 的 PWM 触发
- TIM1_CH3: 定时器 1 的通道 3 的 PWM 触发
- TIM2_CH2 : 定时器 2 的通道 2 的 PWM 触发
- TIM3_TRGO: 定时器 3 触发,TRGO属于内部触发,不需要配置对应的输出IO脚.相当于是TIM3的定时器内部计数一样,只是到了一定时间就触发ADC转换,而这个触发的实现,不依赖IO口的配置.
- TIM4_CH4 : 定时器 4 的通道 4 的 PWM 触发
定时器配置
在进行了上述简单的介绍之后,我们来具体到代码的细节来看,本文采用的是 TIM4_CH4 进行外部触发 ADC 采样。首先来看 TIM 的配置,代码如下:
void ADC1_External_T4_CC4_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); /* Time Base configuration */ TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = 72 - 1; TIM_TimeBaseStructure.TIM_Prescaler = sample_psc; TIM_TimeBaseStructure.TIM_ClockDivision = 0x00; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); /* TIM1 channel1 configuration in PWM mode */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 60; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OC4Init(TIM4, &TIM_OCInitStructure); TIM_CtrlPWMOutputs(TIM4, ENABLE); TIM_Cmd(TIM4, DISABLE); }
在这里需要注意的是 和
sample_psc
是个变量,而这个变量可以通过调用库函数TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC)
重新配置 TIM 所产生的 pwm 的频率,详细的原理不在这里进行赘述了,既然都能够改变 TIM 产生的 PWM 的原理,那么也就能够动态地改变 ADC 的采样频率,也就是决定 ADC 在 1 s 中能够采样多少个点,具体的原理在后续指出。还有一个需要注意的地方是TIM_Cmd(TIM4,DISABLE)
,这里配置的是禁止 TIM 定时器使能,因为还有 ADC 和 DMA 还没有进行配置,因此,我们需要在 ADC 和 DMA 都配置好之后,再将 TIM4 进行使能。DMA 配置
因为笔者所涉及到的 ADC 的具体应用是这样的,也就是通过定时器触发 ADC 采集,然后采集一定数量的点数之后,在这里笔者每个 ADC 的通道是采集了 256 个点,然后对这 256 个点进行处理,处理完毕之后,再以一定时间间隔再采集 256 个点,周而复始地进行采集和处理。并且,这里需要的是同时采集 2 个通道的数据,每个通道采集 256 个点,也就是说,我们一次性处理的是
256 * 2 = 512
个点的数据,采集完成之后,再通过 DMA 将数据其搬运至内存,因此,也就有了如下所示的 DMA 配置:static void ADC1_DMA1_Init(void) { DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* DMA1 Channel1 Configuration ----------------------------------------------*/ DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = ADC_BUFF_LEN*2; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); /* Enable DMA1 channel1 */ DMA_Cmd(DMA1_Channel1, ENABLE); }
代码比较直观,都是一些相关的配置,这里所要指出的一点是在第五行配置了中断服务函数
DMA1_Channel1_IRQn
,具体的思路就是当采集的点数满足设定的点数时,就进入中断服务函数进行处理,在这里需要注意的是我们是从 ADC 外设将数据搬运至内存,所以DMA外设的地址是 ADC1 数据寄存器的地址,可以使用宏定义的方式定义如下:#define ADC1_DR_Address ((uint32_t)0x4001244C)
也可以直接取地址的方式设置,设置方式如下所示:
DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( & ( ADC_x->DR ) );
设置好外设的地址之后,我们就需要设置内存的地址,在这里,因为我们要采集两个通道的数据,并且每个通道要采集 256 个点的数据,所以在这里定义了一个如下所示的二维数组:
uint16_t ADC_ConvertedValue[ADC_BUFF_LEN][2] = {0};
上述中的
ADC_BUFF_LEN
就是一个通道要采集的点数,也就是 256 个,2所代表的就是有两个通道。在这里需要稍微思考的一下是二维数组的定义方式,为什么定义成的是 256 行 2 列 的二维数组,而不是 2 行 256 列的二维数组,我们来看一下 256 行 2 列的数组的布局如下:
根据二维数组的大小也解释了 DMA 的 Buffer_size 是 ADC_BUFF_LEN * 2 ,同时,由于在下面设置了 内存地址是递增的,而又有两个通道,那么他的转换顺序是这样的,也就是先转换通道 1 的值存入数组,然后再转换通道 2 的数据存入数组,然后,以一定时间间隔地转换 512 次,然后发生 DMA 中断,这样也就能够说明数组为什么是定义成 256 行 2 列了。ADC 配置
在配置了定时器和 DMA 之后,我们接下来来进行 ADC 的配置,上文中,我们配置的是使用 TIM4 的 4 通道产生 PWM 来触发 ADC 进行采集,然后设置了 DMA 来进行数据的搬运,因此, ADC 模块的配置如下所示:
void ADC_init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); /* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 2; ADC_Init(ADC1, &ADC_InitStructure); RCC_ADCCLKConfig(RCC_PCLK2_Div6); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_239Cycles5); ADC_Cmd(ADC1, ENABLE); //外部触发 ADC_ExternalTrigConvCmd(ADC1, ENABLE); //使用DMA ADC_DMACmd(ADC1, ENABLE); //校准ADC ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); }
配置过程比较简单,没有什么逻辑性可言,不在这里进行赘述,这里需要指出的一点是因为我们设置的是 2 个通道的采集,所以,在这里应该使能 ADC 的扫描模式,另一方面,我们采用的是 TIM 产生 pwm 触发 adc 进行采集,所以要禁止 ADC 的连续转换模式,这就是两个需要注意的地方。
DMA 中断服务函数
在前文我们说了,我们通过 pwm 触发 ADC 采集,当采集了规定的点数之后,就会产生 DMA 中断,然后在 DMA 中断里面去处理数据,但是由于中断服务函数的要求是执行时间尽可能短,所以,我们可以在中断服务函数里置位数据采集完成标志位的方式来使得主程序进行数据处理,程序代码如下所示:
void ADC1_DMA1_IT_Hander(void) { if (DMA_GetFlagStatus(DMA1_FLAG_TC1)) { DMA_ClearITPendingBit(DMA1_FLAG_TC1); //rt_sem_release(adc_complete_sem); adc_complete_flag = 1; } }
上述代码中,被注释掉的部分是释放信号量,这个是使用 RTOS 是用来同步线程的一个操作,其功能与裸机的标志位是相同的。
总结
上述便是本次分享的内容,其实现的一个功能便是使用 PWM 触发 ADC 多通道采集,并使用 DMA 进行搬运,通过这样子就可以精确地控制 ADC 的采样频率,也就是控制 1 s 钟可以采集多少个点。最后,而这个采样频率就是 pwm 的频率,但是为了更加精确的计算其真实的采样频率还应该加上 ADC 通道的扎转换一个数据的转换时间,这样才是最为精确的采样频率。在下一篇文章中,笔者将继续介绍基于这篇文章的应用,也就是根据采样得到的点,计算波形的频谱,计算波形的频率。
-
STM32F407 定时器触发ADC-DMA采集
2017-07-30 13:44:51基于STM32F407的程序,实现了通过DMA方式进行ADC采样,并通过定时器定是触发。程序中使用了ADC3-channel0,1,2;通过定时器2触发。程序已在STM32F407开发板上验证。 -
Cube生成定时器2触发双ADC同步采集并用DMA传输
2021-01-06 03:13:28用cube生成一个用定时器触发ADC1,ADC2同步采集的程序,单片机选择的是STM32L476RGT6,用定时器2进行ADC采集触发,更改定时器2的定时周期便可以更改ADC的采样周期,ADC1和ADC2使用同步规则模式,并用DMA进行数据的... -
基于stm32f4定时器触发双ADC多通道规则同步采样
2016-04-12 14:51:53基于stm32f4定时器3的TRGO溢出中断触发双ADC多通道规则同步采样,ADC采样数据经DMA的TCIF中断接收处理,本代码已经经过项目测试。 -
stm32 HAL库使用定时器触发adc采样
2020-12-05 21:05:44我的目的是使用定时器触发adc采样,采样频率是500khz,在DMA传输完500个数据之后,求这500个数据的平均值,通过串口发送出去,相当于串口接收端的采样频率是1khz。 cube设置: 时钟 adc timer设置 keil代码部分:...我的目的是使用定时器触发adc采样,采样频率是500khz,在DMA传输完500个数据之后,求这500个数据的平均值,通过串口发送出去,相当于串口接收端的采样频率是1khz。
cube设置:
时钟
adc
timer设置
keil代码部分:
生成代码后调用以下函数开启DMA传输和相关中断
HAL_TIM_Base_Start_IT(&htim2); HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2); HAL_ADC_Start_DMA(&hadc1, (uint32_t *);
在中断服务函数中求平均值
HAL的DMA传输完成中断服务函数跟其他中断服务函数(比如串口、定时器)不一样,不是weak的,好像用户不能重定义,只能使用自动生成的中断服务函数,这个中断服务是在库函数HAL_ADC_Start_DMA中被关联的,
所以找到ADC_DMAConvCplt之后,将自己的代码加入到里面就可以啦!
-
STM32F030 定时器触发多通道adc采集
2017-11-10 17:52:31定时器触发多通道ADC采集,使用DMA传输数据。。验证可用 -
stm32定时器触发ADC1多通道规则转换
2021-02-07 17:30:17stm32定时器触发ADC多通道规则转换 之前也查了不少资料,参考了其他人写的,综合了一下,通过定时器触发ADC多通道转换,并通过DMA传输数据,希望能给大家带来一些启发。 使用定时器2的CC2触发ADC1转换,AD转换包含...stm32定时器触发ADC多通道规则转换
之前也查了不少资料,参考了其他人写的,综合了一下,通过定时器触发ADC多通道转换,并通过DMA传输数据,希望能给大家带来一些启发。
使用定时器2的CC2触发ADC1转换,AD转换包含ADC_Channel_8和ADC_Channel_9,转换结果通过DMA1_Channel1放入缓冲区ADC为一个整体,其外部不单只外部引脚,除ADC外的其他所有均为外部
以下代码运行中stm32F103上,主时钟为72MHzuint16_t AD_Data[200]; //AD转换结果存放 void ADC_Init(void) { ADC_InitTypeDef ADC_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC1, ENABLE ); //开启时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADC时钟6分频,12MHZ,ADC时钟最高不超过14MHz //ADC端口配置 PB0为ch8,PB1为ch9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入状态 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化端口 /************ADC1初始化*************/ ADC_DeInit(ADC1); //复位ADC1相关寄存器 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立转换模式,单独使用ADC1 ADC_InitStructure.ADC_ScanConvMode = ENABLE; //开启扫描模式,采集端口数量超过1个时,需开启扫描模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //关闭连续转换模式,连续转换开启后不需要其他触发就会一直转换,本例程为外部触发,需要关闭 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //外部触发源为TIM2的CC2 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //转换结果数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 2; //需要转换的通道数为2个 ADC_Init(ADC1, &ADC_InitStructure); //初始化ADC1 /*设定两个通道的转换顺序和AD转换周期,通道8第一个转换,通道9第二个转换,注意转换顺序要连续,从1开始*/ ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_239Cycles5);// ADC_RegularChannelConfig(ADC1,ADC_Channel_9,2,ADC_SampleTime_239Cycles5); /**********DMA传输配置*****************/ DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(ADC1->DR); //外设地址为ADC1的数据寄存器 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Data[0]; //缓冲区地址为数据起始地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据由外设传输到缓冲区 DMA_InitStructure.DMA_BufferSize = 200; //DMA缓冲区大小,不能超过数组大小 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存储为循环模式,存储满之后会开始覆盖以往数据 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //关闭内存到内存模式 DMA_Init(DMA1_Channel1,&DMA_InitStructure); //初始化,ADC转换对应DMA通道1,不能修改 /******开启DMA中断,优先级需要根据优先级分组选择,例程中采用的优先级分组2******/ NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; //DMA1通道中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //开启 NVIC_Init(&NVIC_InitStructure); //初始化 DMA_ITConfig(DMA1_Channel1,DMA1_IT_TC1,ENABLE); //开启DMA1通道1的传输完成中断 ADC_DMACmd(ADC1,ENABLE); //开启ADC与DMA的关联 ADC_Cmd(ADC1, ENABLE); //开启ADC1 ADC_ResetCalibration(ADC1); //重置ADC校准 while(ADC_GetResetCalibrationStatus(ADC1)); //等待重置完成 ADC_StartCalibration(ADC1); //开始校准 while(ADC_GetCalibrationStatus(ADC1)); //等待校准完成 DMA_Cmd(DMA1_Channel1,ENABLE); //开启DMA, ADC_ExternalTrigConvCmd(ADC1,ENABLE); //开启外部触发 } /*DMA中断函数*/ void DMA1_Channel1_IRQHandler(void) { if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET) //传输完成中断检测 { DMA_ClearITPendingBit(DMA1_IT_TC1); //内容自行编写 } }
以上为ADC与DMA的初始化过程。
定时器2触发需使用PWM模式,定时器比较匹配输出信号,该信号用于触发AD转换。
触发信号未与外部引脚相连,所以引脚上不会产生PWM波形,与常规PWM波形发生只差引脚关联。/* Period为PWM周期,Prescaler为定时器预分频洗漱 定时器2采用内部时钟,为72MHz */ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; void TIM2_Init(u16 Period,u16 Prescaler) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); TIM_TimeBaseStructure.TIM_Prescaler = Prescaler-1; //预分频系数 TIM_TimeBaseStructure.TIM_Period = Period-1; //周期 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式, TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //定时器时钟不分频,为72MHz TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //初始化 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM1模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能 TIM_OCInitStructure.TIM_Pulse = Period/2; //比较寄存器值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //比较匹配完成后输出极性 TIM_OC2Init(TIM2, & TIM_OCInitStructure); //初始化 TIM_Cmd(TIM2,ENABLE); //定时器使能 TIM_InternalClockConfig(TIM2); //定时内部时钟使能 TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //重装载使能 TIM_UpdateDisableConfig(TIM2, DISABLE); }
使用外部触发AD转换并采用DMA传输数据,比较适合需要高频率AD转换的环境,不用频繁手动开启AD转换,只需转换完成之后到DMA缓冲区读取即可。
-
stm32 定时器触发ADC多通道采样+DMA提取数据
2021-02-25 18:50:37stm32g0 定时器触发ADC多通道采样+DMA提取数据 stm32g0 定时器触发ADC多通道采样+DMA提取数据 stm32g0 单片机对三相电流采样,用定时器3作为触发源 触发频率为1kHz #定时器3的配置如下: #ADC配置如下: #ADC的... -
定时器+dma采集+FFT的操作系统例程
2021-08-10 11:11:03使用ucosIII新建了任务,然后使用定时器adc+DMA采集数据,之后采用fft串口发送到电脑上。 初学者,希望多多交流 -
STM32F103定时器触发ADC+DMA传输
2020-06-07 22:54:25STM32F103定时器触发ADC+DMA传输 ADC除了软件触发方式之外还有外部触发模式,我用TIM2定时器触发ADC,并用DMA传输ADC的数据。配有例程。 定时器部分 我选择TIM2定时器发出PWM波的方式触发ADC; PWM模式可以产生一个... -
STM32F103 定时器触发ADC+DMA中断+双缓冲
2018-01-23 21:39:57STM32F103 使用定时器触发ADC,并使用DMA中断+双缓冲实现数据采集。 -
STM32定时器触发ADC +DMA
2018-06-08 18:26:323、使用ADC的定时器触发ADC转换的功能,然后使用DMA进行数据的搬运!这样只要设置好定时器的触发间隔,就能实现ADC定时采样转换的功能,然后可以在程序的死循环中一直检测DMA转换完成标志,然后进行数据的读取,或者... -
定时器下ADC采集向内存双缓冲DMA传输
2021-08-18 20:39:10定时器下ADC采集向内存双缓冲DMA传输前言配置 前言 本文主要接上篇ADC多通道采集DAM传输配置,配置大致一样,这篇主要讲的是单通道采集双缓冲传输。 先说一下为什么使用双缓冲,一般来说我们不会同时对一个内存... -
GD32E230Fx DMA方式读内部ADC+定时器触发
2021-04-08 14:56:41由于需要使用GD32的片上ADC采集输入电压,所以了解了关于内部ADC的配置,这里为了不占用过多内核资源,我选择用DMA的方式定时采集ADC数据。因为CH1和CH2用来做串口数据收发,所以只能选择CH0: 至于ADC的外部触发... -
STM8单片机ADC采样功能通过定时器触发
2021-12-13 14:51:40一般使用的方式就是通过定时器定时,然后在定时中断函数中再去读取ADC采样的数据。但是这种方式采样的时间是不固定的,比如进入定时器中断后,ADC采样刚结束,就可以直接使用当前采样到的数据。但是如果运气不好的话... -
stm32H7 HAL库 定时器触发多通道adc采样 DMA
2022-05-13 00:37:21stm32H7 HAL库 定时器触发多通道adc采样 DMA -
stm32定时器触发ADC参考
2015-03-30 19:51:45stm32单片机在开发行业被广泛使用,其外设众多,也是它的优势之一。但在运用过程中我门也会常常遇到很多麻烦,该文档中的代码,实现的功能是使用定时器中断触发ADC采集。 -
linux 定时采样 adc,定时器触发 ADC采集
2021-05-18 03:18:50给你我自己的一段定时器中断的程序,学习时候自己编的,功能:每一秒钟a+1;#include "time.h"#include "stm32f10x.h"//#include "key.h"//#include "SysTickDelay.h"u8 a;u16 i=0;void TIME_Configuration(void){... -
STM32CUBEMX定时器触发多通道ADC+DMA搬运
2021-05-19 10:44:17一.STM32CUBEMX设置 1.RCC设置 2.SYS设置---一定要Debug设定为Serial Wire 4.ADC设置 ...a.通道设置---选择通道ADC1的11和15 ...b.adc内容设定 ...4.定时器设定 5.DMA设定 正在上传…重新上传取消 -
笔记10:STM32F407ADC简介+定时器触发ADC1
2020-07-10 18:08:37ADC,即Anolog to Digital Converter,模拟信号到数字信号的转换。... 采集信号范围:0-3.3V ADC 输入范围为: VREF- ≤ VIN ≤ VREF+。由 VREF-、 VREF+ 、 VDDA 、 VSSA、这四个外部引脚决定.在设计时,已经将VREF-与 -
stm32 TIM2定时器触发ADC、DMA采样
2018-08-31 14:38:55使用ADC的定时器触发ADC转换的功能,然后使用DMA进行数据的搬运!采用TIM2定时器的触发间隔,实现ADC定时采样转换的功能,然后可以在程序的死循环中一直检测DMA转换完成标志,然后进行数据的读取,或者使能DMA转换... -
【STM32】定时器TIM触发ADC采样,DMA搬运到内存(超详细讲解)
2019-05-07 16:45:17本文提供的解决方案是:使用ADC的定时器触发ADC单次转换的功能,然后使用DMA进行数据的搬运! 这样只要设置好定时器的触发间隔,就能实现ADC定时采样转换的功能(即采样速率),然后可以在程序的死循环中一直检测DMA...