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

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

项目中需要进行红外学习,如果采用输入捕获的方式,因为定时器只能捕获上升沿或者下降沿,

所以只能获得周期,而不能得到具体的红外波的高低电平的时间.

所以采用PWM输入的方式进行捕获. 采用的是PA8脚,对应TIM1的通道1.

/*********************************************************************
 *             函数
 **********************************************************************/

/*********************************************************************
 *             接口函数:初始化红外学习模块
 **********************************************************************/

void inf_infrared_study_init( void )
{
  //初始化io口
  inf_init_io( );
  //初始化中断
  //inf_init_irq();
  //初始化定时器
  inf_init_timer( );

  //打开DMA
  inf_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_8;
  //设置为输入
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  //初始化
  GPIO_Init( GPIOA, &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通道配置
  DMA_DeInit( DMA1_Channel2 );
  //外设地址
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) ( &TIM1->CCR1 );
  //内存地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) Rx_Buf_Tim_Dma1;
  //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_Channel2, &DMA_InitStructure );

  //启动DMA时钟
  RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );
  //DMA1通道配置
  DMA_DeInit( DMA1_Channel3 );
  //外设地址
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) ( &TIM1->CCR2 );
  //内存地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) Rx_Buf_Tim_Dma2;
  //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_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );
  //重新将Timer设置为缺省值
  TIM_DeInit( TIM1 );
  //采用内部时钟提供时钟源
  TIM_InternalClockConfig( TIM1 );
  //预分频
  timInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
  //计数频率为500ns跳转1次
  timInitStruct.TIM_Prescaler = SystemCoreClock / 1000000 - 1;
  //向上计数
  timInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
  timInitStruct.TIM_RepetitionCounter = 0;
  //这个值实际上就是TIMX->ARR,延时开始时重新设定即可
  timInitStruct.TIM_Period = 0xffff;
  //初始化定时器
  TIM_TimeBaseInit( TIM1, &timInitStruct );

  //输入捕获配置
  //选择通道
  tim_icinit.TIM_Channel = TIM_Channel_1;
  //硬件滤波
  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(TIM1,&tim_icinit);
  TIM_PWMIConfig( TIM1, &tim_icinit );
  //禁止ARR预装载缓冲器
  //TIM_ARRPreloadConfig(TIM1, DISABLE);  

  //输入跳变选择
  TIM_SelectInputTrigger( TIM1, TIM_TS_TI1FP1 );
  //从机模式:复位模式
  TIM_SelectSlaveMode( TIM1, TIM_SlaveMode_Reset );
  //主从模式选择
  TIM_SelectMasterSlaveMode( TIM1, TIM_MasterSlaveMode_Enable );

  //配置定时器的DMA
  TIM_DMAConfig( TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_2Bytes );
  //产生DMA请求信号
  TIM_DMACmd( TIM1, TIM_DMA_CC1, ENABLE );

  //配置定时器的DMA
  TIM_DMAConfig( TIM1, TIM_DMABase_CCR2, TIM_DMABurstLength_2Bytes );
  //产生DMA请求信号
  TIM_DMACmd( TIM1, TIM_DMA_CC2, ENABLE );

  //打开定时器
  TIM_Cmd( TIM1, ENABLE );
}

/*********************************************************************
 *             接口函数:打开定时器
 *参数:state:状态:0:关闭,1:打开
 **********************************************************************/

void inf_infrared_study_open_timer( uint8_t state )
{
  if ( state )
  {
    TIM_Cmd( TIM1, ENABLE );
  }
  else
  {
    TIM_Cmd( TIM1, 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);
    //打开DMA
    DMA_Cmd( DMA1_Channel2, ENABLE );
    DMA_Cmd( DMA1_Channel3, ENABLE );
  }
  else
  {
    DMA_Cmd( DMA1_Channel2, DISABLE );
    DMA_Cmd( DMA1_Channel3, ENABLE );
  }
}

/*********************************************************************
 *             接口函数:得到DMA接收帧长
 *返回:帧长
 **********************************************************************/

uint16_t inf_infrared_study_dma_rx_len( void )
{
  //获得接收帧帧长
  return ( RX_LEN_TIM_DMA - DMA_GetCurrDataCounter( DMA1_Channel2 ) );
}
时间: 2024-10-25 18:49:57

STM32的PWM输入模式设置并用DMA接收数据的相关文章

STM32的USART使用DMA接收带校验位的数据

工作中用到了一个数据包里面的数据采用不同的校验方式,一部分为奇校验,一部分为偶校验.这时我的方案为: 1.USART设置9bit数据长度,1个停止位,无校验位,这时确保能接收到带校验位的数据 2.设置DMA接收和发送数据,设置外设地址和内存地址都为halfword(16bit)可以接收到带校验位的数据包. 3.然后通过软件来校验接收到的数据 4.由于设置了无校验位,那么此时用发送的数据必须加上软件计算出的校验位发送

STM32之PWM君

PWM..英语好的人估计又知道这三个大写字母代表哪三个英语单词了.小弟不才,就说中文意思好了:脉冲宽度调制,玩过飞思卡尔的人估计对PWM非常的不陌生吧.电机驱动需要PWM,控制舵机的转向需要PWM,总之.可以说,PWM,you are so good. 好了..言归正传,广大的互联网的网友们,咱们又见面了,大家早上晚上中午好好好.额..好像也没见过面,STM32的PWM,可谓是小强中的小强,STM32的PWM,就是由定时器产生的,但是奇怪的是除了定时器TIM6和TIM7不能产生PWM外,其他的定

stm32寄存器版学习笔记08 DMA

DMA(Direct Memory Access),直接存储器访问.DMA传输方式无需CPU直接控制传输,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,使CPU效率大大提高.stm32f103有2个DMA控制器,DMA1有7个通道,DMA2有5个通道,专门用来管理来自外设对存储器的访问请求,还有一个仲裁器来协调各个DMA请求的优先权. 1.DMA各通道请求 从外设产生的DMA请求通过逻辑"或"输入到DMA控制器,这就意味着同时只能有一个请求有效. 例如,串口1发送的DMA,就

详解STM32的PWM输出及频率和脉宽(占空比)的计算——寄存器配置六步曲!(转)

一.stm32的pwm输出引脚是使用的IO口的复用功能. 二.T2~T5这4个通用定时器均可输出4路PWM--CH1~CH4. 三.我们以tim3的CH1路pwm输出为例来进行图文讲解(其它类似),并在最后给出tim3的ch1和ch2两路pwm输出的c代码(已在STM32F103RBT6上测试成功,大家放心使用!). 四.给出了PWM频率和占空比的计算公式. 步骤如下: 1.使能TIM3时钟 RCC->APB1ENR |= 1 << 1; 2.配置对应引脚(PA6)的复用输出功能 GPI

stm32之PWM

PWM是pulse width modulation的缩写,即脉冲宽度调制.其通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形: 1.PWM是一种对模拟信号电平进行数字编码的方法.通过高分辨率计数器的使用,方波的占空比被调制,用来对一个具体模拟信号的电平进行编码.等效的实现是基于采样定理中的一个重要结论:冲量相等而形状不同的窄脉冲加在具有惯性的环节上时,其效果基本相同.冲量即指窄脉冲的面接.这里所说的效果基本相同,是指该环节的输出响应波形基本相同. 2.如把各输出波形用傅立叶分析,则它们的

PWM输入模式

一.概念理解 PWM输入捕获模式是输入捕获模式的特例, 输入捕获就是当连接到定时器的引脚上产生电平变化时对应的捕获装置会立即将当前计数值复制到另一个寄存器中.你可以开启捕获中断然后在中断处理函数中读出保存的计数值. 与输入捕获不同的是PWM输入模式会将同一个输入信号(TI1或TI2)连接到两个捕获装置(IC1和IC2).这两个捕获装置一个捕获上升沿一个捕获下降沿.TI1FP1.TI2FP2它们中的一个被选择为触发输入且从模式控制器被配置为复位模式. 自己理解如下 1. 每个定时器有四个输入捕获通

stm32之PWM学习

下图是一个STM32普通PWM形成的图形原理说明 自动重装载寄存器(ARR)用于定波形的频率(即周期).捕获比较寄存器(CCRx)(用于确定占空比的) 如图为向上计数: 定时器重装载值为ARR,比较值CCRx t时刻对计数器值和比较值进行比较 如果计数器值小于CCRx值,输出低电平 如果计数器值大于CCRx值,输出高电平 PWM的一个周期 定时器从0开始向上计数 当0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平 t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输

STM32 GPIO fast data transfer with DMA

AN2548 -- 使用 STM32F101xx 和 STM32F103xx 的 DMA 控制器 DMA控制器 DMA是AMBA的先进高性能总线(AHB)上的设备,它有2个AHB端口: 一个是从端口,用于配置DMA,另一个是主端口,使得DMA可以在不同的从设备之间传输数据. DMA的作用是在没有Cortex-M3核心的干预下,在后台完成数据传输. 在传输数据的过程中,主处理器可以执行其它任务,只有在整个数据块传输结束后, 需要处理这些数据时才会中断主处理器的操作. 它可以在对系统性能产生较小影响

STM32通用定时器库函数设置

通用定时器 STM32的通用定时器为:TIM2.TIM3.TIM4和TIM5 在使用通用定时器时利用库函数直接设置定时器如下: 1.使能定时器TIM_X的时钟:(X=2.3.4.5) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIMX,ENABLE); 2.计算要定时的时间,根据定时时间来设定分频数和最大计数值(以向上计数为例子),其中计算关系如下: 系统时钟(一般为72MHZ) = 定时器分频数 * 计数值 假如分频数为7200,则定时器时钟为:72MHZ/7