新闻中心

EEPW首页>嵌入式系统>设计应用> STM32输入捕获模式设置并用DMA接收数据

STM32输入捕获模式设置并用DMA接收数据

作者: 时间:2016-11-19 来源:网络 收藏

参考:STM32的PWM输入模式设置并用DMA接收数据

Input capture mode

The input stage samples the corresponding TIx input to generate a filtered signal TIxF.

本文引用地址://m.amcfsurvey.com/article/201611/318505.htm

Then, an edge detector with polarity selection generates a signal (TIxFPx)

which can beused as trigger input by the slave mode controller or as the capture command.

It isprescaledbefore the capture register (ICxPS).

In Input capture mode, the Capture/Compare Registers (TIMx_CCRx) are used to latch thevalue of the counter

after a transition detected by the corresponding ICx signal.

When acapture occurs, the corresponding CCXIF flag (TIMx_SR register) is set and aninterrupt

ora DMA request can be sent if they are enabled.

If a capture occurs while the CCxIF flag wasalready high, then the over-capture flag CCxOF (TIMx_SR register) is set.

CCxIF can becleared by software by writing it to ‘0’ or by reading the captured data stored in theTIMx_CCRx register.

CCxOF is cleared when you write it to ‘0’.

The following example shows how to capture the counter value in TIMx_CCR1 when TI1input rises.

To do this, use the following procedure:

 Select the active input:
TIMx_CCR1 must be linked to the TI1 input, so write the CC1Sbits to 01 in the TIMx_CCMR1 register.
As soon as CC1S becomes different from 00,the channel is configured in input and the TIMx_CCR1 register becomes read-only.

 Program the input filter duration you need with respect to the signal you connect to thetimer
(by programming ICxF bits in the TIMx_CCMRx register if the input is a TIx input).
Let’s imagine that, when toggling, the input signal is not stable during at must 5 internalclock cycles.
We must program a filter duration longer than these 5 clock cycles.
Wecan validate a transition on TI1 when 8 consecutive samples with the new level havebeen detected (sampledat fDTS frequency).
Then write IC1F bits to 0011 in theTIMx_CCMR1 register.

 Select the edge of the active transition on the TI1 channel by writing CC1P and CC1NPbits to 0
in the TIMx_CCER register (rising edge in this case).

 Program the input prescaler. In our example, we wish the capture to be performed ateach valid transition,
so the prescaler is disabled (write IC1PS bits to ‘00’ in theTIMx_CCMR1 register).


 Enable capture from the counter into the capture register by setting the CC1E bit in theTIMx_CCER register.
 If needed, enable the related interrupt request by setting the CC1IE bit in theTIMx_DIER register,
and/or the DMA request by setting the CC1DE bit in theTIMx_DIER register.


When an input capture occurs:
 The TIMx_CCR1 register gets the value of the counter on the active transition.
 CC1IF flag is set (interrupt flag). CC1OF is also set if at least two consecutive capturesoccurred whereas the flag was not cleared.
 An interrupt is generated depending on the CC1IE bit.
 A DMA request is generated depending on the CC1DE bit.
In order to handle the overcapture, it is recommended to read the data before theovercapture flag.
This is to avoid missing an overcapture which could happen after readingthe flag and before reading the data.

Note:

IC interrupt and/or DMA requests can be generated by software by setting thecorresponding CCxG bit in the TIMx_EGR register.

STM32输入捕获模式设置并用DMA接收数据

本文博客链接:http://blog.csdn.net/jdh99,作者:jdh

环境:

主机:WIN7

开发环境:MDK4.72

MCU:STM32F103

说明:

项目中需要进行红外学习,于是采用输入捕获取得电平变化时间.并将数据放在DMA中.这样可以避免频繁中断消耗CPU资源.

采用的是PB1脚,对应TIM3的通道4.

/********************************************************************** 接口函数:初始化红外学习模块**********************************************************************/void inf_infrared_study_init(void){//初始化io口inf_init_io();//初始化中断//inf_init_irq();//初始化定时器inf_init_timer();//打开DMAinf_infrared_study_open_dma(1);//打开定时器inf_infrared_study_open_timer(1);}/********************************************************************** 初始化io口**********************************************************************/static void inf_init_io(void){//定义IO初始化结构体GPIO_InitTypeDef GPIO_InitStructure;//初始化时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//管脚初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//设置为输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //初始化 GPIO_Init(GPIOB, &GPIO_InitStructure); }/********************************************************************** 初始化中断**********************************************************************/static void inf_init_irq(void){//定义外部中断结构体EXTI_InitTypeDef EXTI_InitStructure;//初始化中断脚复用时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//配置中断源GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);// 配置下降沿触发EXTI_ClearITPendingBit(EXTI_Line1);EXTI_InitStructure.EXTI_Line = EXTI_Line1;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);}/********************************************************************** 初始化定时器**********************************************************************/static void inf_init_timer(void){//定义定时器结构体TIM_TimeBaseInitTypeDef timInitStruct;//输入捕获结构体TIM_ICInitTypeDef tim_icinit;//定义DMA结构体DMA_InitTypeDef DMA_InitStructure;//启动DMA时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1通道3配置DMA_DeInit(DMA1_Channel3);//外设地址DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&TIM3->CCR4);//内存地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Rx_Buf_Tim_Dma;//dma传输方向单向DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//设置DMA在传输时缓冲区的长度DMA_InitStructure.DMA_BufferSize = RX_LEN_TIM_DMA;//设置DMA的外设递增模式,一个外设DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA的内存递增模式DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//外设数据字长DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//内存数据字长DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//设置DMA的传输模式//DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//设置DMA的优先级别DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA的2个memory中的变量互相访问DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel3,&DMA_InitStructure); //开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//重新将Timer设置为缺省值TIM_DeInit(TIM3);//采用内部时钟给TIM3提供时钟源TIM_InternalClockConfig(TIM3);//预分频timInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //计数频率为500ns跳转1次 timInitStruct.TIM_Prescaler = SystemCoreClock / 2 - 1; //向上计数 timInitStruct.TIM_CounterMode = TIM_CounterMode_Up; timInitStruct.TIM_RepetitionCounter = 0;//这个值实际上就是TIMX->ARR,延时开始时重新设定即可 timInitStruct.TIM_Period = 0xffff; //初始化定时器3TIM_TimeBaseInit(TIM3, &timInitStruct);//输入捕获配置//选择通道tim_icinit.TIM_Channel = TIM_Channel_4;//硬件滤波tim_icinit.TIM_ICFilter = 0x0;//触发捕获的电平tim_icinit.TIM_ICPolarity = TIM_ICPolarity_Falling;//每次检测到触发电平都捕获tim_icinit.TIM_ICPrescaler= TIM_ICPSC_DIV1;//通道方向选择tim_icinit.TIM_ICSelection = TIM_ICSelection_DirectTI;//初始化TIM_ICInit(TIM3,&tim_icinit);//禁止ARR预装载缓冲器 TIM_ARRPreloadConfig(TIM3, DISABLE); //输入跳变选择TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);//从机模式:复位模式TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//主从模式选择TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);//配置定时器的DMATIM_DMAConfig(TIM3,TIM_DMABase_CCR4,TIM_DMABurstLength_2Bytes);//产生DMA请求信号TIM_DMACmd(TIM3, TIM_DMA_CC4, ENABLE);//打开定时器TIM_Cmd(TIM3, ENABLE);}/********************************************************************** 接口函数:打开定时器*参数:state:状态:0:关闭,1:打开**********************************************************************/void inf_infrared_study_open_timer(uint8_t state){if (state){TIM_Cmd(TIM3, ENABLE);}else{TIM_Cmd(TIM3, DISABLE);}}/********************************************************************** 接口函数:打开中断*参数:state:状态:0:关闭,1:打开**********************************************************************/void inf_infrared_study_open_irq(uint8_t state){//定义中断结构体NVIC_InitTypeDef NVIC_InitStructure ;if (state){//打开中断NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //通道设置为外部中断线NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //中断抢占先等级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中断响应优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打开中断NVIC_Init(&NVIC_InitStructure); //初始化}else{//关闭中断NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //通道设置为外部中断线NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //中断抢占先等级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中断响应优先级NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; //打开中断NVIC_Init(&NVIC_InitStructure); //初始化}}/********************************************************************** 接口函数:打开DMA*参数:state:状态:0:关闭,1:打开**********************************************************************/void inf_infrared_study_open_dma(uint8_t state){if (state){//设置传输数据长度//DMA_SetCurrDataCounter(DMA1_Channel3,RX_LEN_TIM_DMA);//打开DMADMA_Cmd(DMA1_Channel3,ENABLE);}else{DMA_Cmd(DMA1_Channel3,DISABLE);}}/********************************************************************** 接口函数:得到DMA接收帧长*返回:帧长**********************************************************************/uint16_t inf_infrared_study_dma_rx_len(void){//获得接收帧帧长return (RX_LEN_TIM_DMA - DMA_GetCurrDataCounter(DMA1_Channel3));}

注意:

除TIM6和TIM7之外的定时器都只能采用上升沿或者下降沿捕捉而不能采用双边沿捕捉.

#define TIM_ICPolarity_Rising ((uint16_t)0x0)#define TIM_ICPolarity_Falling ((uint16_t)0x2)#define TIM_ICPolarity_BothEdge ((uint16_t)0xA)#define IS_TIM_IC_POLARITY(POLARITY) (((POLARITY) == TIM_ICPolarity_Rising) ((POLARITY) == TIM_ICPolarity_Falling))#define IS_TIM_IC_POLARITY_LITE(POLARITY) (((POLARITY) == TIM_ICPolarity_Rising) ((POLARITY) == TIM_ICPolarity_Falling) ((POLARITY) == TIM_ICPolarity_BothEdge))



评论


技术专区

关闭