你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

定时器输入捕获加DMA不成功

[复制链接]
澍澍澍澍1 提问时间:2016-6-14 20:29 /
求教:本人想用输入捕获来读取遥控的数据,然后通过DMA来传输数据。本人主要的程序配置如下所示,但是一直没有读数(为0)。如果用中断的方式来读的话,数据倒是正常的。暂时想不出什么解决的方法,希望群里的大神们能够给予指点,或者有已经成功了的程序,能够
发来共享,供本人研究学习下。PS:本人不是伸手党啊!仅仅是学习参考用的。

//定时器的配置
void Capture_Init(u16 arr,u16 psc)
{
//此部分需手动修改 IO口设置  
RCC->APB2ENR|=1<<0;    // 开启辅助功能IO时钟
RCC->APB1ENR|=1<<0;    //TIM2 时钟使能
RCC->APB2ENR|=1<<2;    //使能PORTA时钟

TIM2->ARR=arr;  //设定计数器自动重装值//刚好1ms   
TIM2->PSC=psc;  //预分频器,
GPIOA->CRL&=0XFFFFFFF0;//PA0 输出  
GPIOA->CRL|=0X00000004;//复用功能输出      
GPIOA->ODR|=1<<0;//PA0 上拉

TIM2->SMCR|=0x00D4;//从模式控制器
//TIM2->SMCR|= 1<<5; //MSM=1 主/从模式
//TIM2->SMCR|= 5<<4; //TS=101 触发选择
//TIM2->SMCR|= 4<<0; //SMS=100 复位模式
TIM2->CCMR1|=1<<0;//CC1S=01 选择输入端  
TIM2->CCMR1|=3<<4; //IC1F=0011配置输入滤波器
TIM2->CCER|=0<<1; //CC1P=0 选择有交转换边沿
TIM2->CCMR1|=0<<2; //IC1PS=00 配置输入分频
TIM2->CCER|=1<<0; //CC1E=1 允许捕获计数器的值到捕获寄存器中
//TIM2->DIER|=1<<1;   //允许更新捕获中断   
TIM2->DIER|=1<<9;   //允许DMA捕获请求
//TIM2_EGR|=1<<1;
TIM2->CR2|=0<<3;   //当发生CC1事件时,送出CC1的DMA请求
TIM2->CR1|=0x01;    //使能计数器2
MY_NVIC_Init(1,3,TIM2_IRQn,2);//抢占1,子优先级3,组2         
}

//DMA配置
void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
u32 DR_Base;  //做缓冲用,不知道为什么.非要不可
RCC->AHBENR|=1<<0;//开启DMA1时钟
DR_Base=cpar;
DMA_CHx->CPAR=DR_Base;   //DMA1 外设地址
DMA_CHx->CMAR=(u32)cmar; //DMA1,存储器地址
DMA1_MEM_LEN=cndtr;      //保存DMA传输数据量
DMA_CHx->CNDTR=cndtr;    //DMA1,传输数据量
DMA_CHx->CCR=0X00000000;//复位
DMA_CHx->CCR|=0<<4;  //从外设读
DMA_CHx->CCR|=1<<5;  //循环模式
DMA_CHx->CCR|=0<<6;  //外设地址非增量模式
DMA_CHx->CCR|=1<<7;  //存储器增量模式
DMA_CHx->CCR|=2<<8;  //外设数据宽度为32位
DMA_CHx->CCR|=2<<10; //存储器数据宽度32位
DMA_CHx->CCR|=2<<12; //高等优先级
DMA_CHx->CCR|=0<<14; //非存储器到存储器模式     
}

//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
DMA_CHx->CCR&=~(1<<0);       //关闭DMA传输
//  Get_Adc(0);
DMA_CHx->CNDTR=DMA1_MEM_LEN; //DMA1,传输数据量
DMA_CHx->CCR|=1<<0;          //开启DMA传输
}  

//主函数处理
#define BUF_SIZE 2
u32 IC2Value[BUF_SIZE]={0};//地址
float pro=0;//进度

int main(void)
{        
  Stm32_Clock_Init(9); //系统时钟设置
  delay_init(72);//延时函数初始化
  uart_init(72,115200);
  LED_Init()  ;
  Capture_Init(5000,72-1); //65535
  MYDMA_Config(DMA1_Channel5,(u32)(&TIM2->CCR1),(u32)IC2Value,2);//sizeof(IC2Value)
//   MYDMA_Enable(DMA1_Channel5);
        while(1)
        {
//         TIM2->CR2|=0<<3;   //当发生CC1事件时,送出CC1的DMA请求
        TIM2->DIER|=1<<9;   //允许DMA捕获请求
        MYDMA_Enable(DMA1_Channel5); //开始一次DMA传输
                while(1)
                {
                        if(DMA1->ISR&(1<<1))//等待通道1传输完成
                        {
                                 LED1=0; //亮灯检验
                                DMA1->IFCR|=1<<1;//清除通道1传输完成标志
                                break;
                        }
                pro=DMA1_Channel5->CNDTR;//得到当前还剩余多少个数据
    }
   delay_ms(500);
         LED1=1;        //关灯
//   printf("IC2Value = %d\r\n",IC2Value[0]);
//         printf("TIM2->CCR1 = %d\r\n",TIM2->CCR1);
        }
}

收藏 评论1 发布时间:2016-6-14 20:29

举报

1个回答
澍澍澍澍1 回答时间:2016-6-16 11:33:56
下面是本人根据原子哥之前的例程以及查数据手册等初略调试写出的一个程序,可以实现定时器输入捕获PWM信号同时通过DMA传输的实验程序。经过本人实验,是稳定可靠能用的,对遥控器的通道的读取能保证在0到100
之间的数据范围同时通道间不互相影响。因为只是实验的版本,所以写得有点乱,请勿喷,希望在这方面有所研究的朋友能共同交流,能够写出更好的程序出来。芯片用到的是STM32F051,主要程序配置如下:

/**************************************
* 函数名   : timer1_init
* 描述     : 定时器1的输入捕获加DMA初始化配置
* 输入参数 : 无
* 返回值   : 无
**************************************/
#define BUF_SIZE_TIM1  2 //定义数据的长度
uint32_t IC2Value_TIM1[BUF_SIZE_TIM1]={0,0}; //数据存放的数组
void timer1_init(uint16_t arr,uint16_t psc)
{
  RCC->APB2ENR|=1<<11;           //TIM1 时钟使能
  RCC->AHBENR|=1<<17;            //使能PORTA时钟

  // PA引脚设置
  GPIOA->MODER|=0x00820000;              // PA.8、PA.11设置为AF模式;
  GPIOA->OTYPER&=~0x0900;                // 设置推挽输出;
  GPIOA->OSPEEDR|=0x00c30000;            // 设置IO口高速翻转;
  GPIOA->PUPDR|=0x00820000;              // 内部下拉;
  GPIOA->AFR[1]|=0X02002;                                   // AF2;       
       
  /*输入捕获需要用到中断的时候再打开*/       
//         // 配置NVIC,中断向量号TIM1_CC_IRQn= 14
//         NVIC_SetPriority(TIM1_CC_IRQn, 0);
//         NVIC->ISER[0] = (uint32_t)0x01 <<14; // 使能NVIC;

        TIM1->ARR=arr; //设定计数器自动重装载值
        TIM1->PSC=psc; //预分频器
       
        TIM1->CCMR1|=1<<0;                //CC1S=01         选择输入端 IC1映射到TI1上
        TIM1->CCMR1|=0<<4;                 //IC1F=0000 配置输入滤波器 不滤波
        TIM1->CCMR1|=0<<2;           //IC1PS=00         配置输入分频,不分频

       
        TIM1->CCMR2|=1<<8;                //CC4S=01         选择输入端 IC4映射到TI4上       
        TIM1->CCMR2|=0<<12;         //IC4F=0000 配置输入滤波器 不滤波
        TIM1->CCMR2|=0<<10;         //IC4PS=00         配置输入分频,不分频
       
        TIM1->CCER|=0<<1;                 //CC1P=0        上升沿捕获
        TIM1->CCER|=1<<0;                 //CC1E=1         允许捕获计数器的值到捕获寄存器中
        TIM1->CCER|=0<<13;                 //CC4P=0        上升沿捕获
        TIM1->CCER|=1<<12;                 //CC4E=1         允许捕获计数器的值到捕获寄存器中
        /*DMA配置*/       
        MYDMA_Config(DMA1_Channel2,(uint32_t)(&TIM1->CCR1),(uint32_t)(&IC2Value_TIM1[0]),1);
     //   MYDMA_Config(DMA1_Channel4,(uint32_t)(&TIM1->CCR4),(uint32_t)(&IC2Value_TIM1[1]),1);
        /*定时器打开DMA传输的配置*/
        TIM1->CR2|=0<<3;   //当发生CCx事件时,送出CCx的DMA请求
        TIM1->DIER|=1<<9;   //允许CCR1 DMA捕获请求       
        //TIM1->DIER|=1<<12;   //允许CCR4 DMA捕获请求
       
        /*定时器打开中断传输的配置*/
//         TIM1->DIER|=1<<1;           //允许捕获1中断       
//         TIM1->DIER|=1<<4;           //允许捕获4中断       
//         TIM1->DIER|=1<<0;           //允许更新中断       
        TIM1->CR1|=0x01;            //使能定时器1               
}

///////////////DMA配置/////////////////
uint16_t DMA1_MEM_LEN;//保存DMA每次数据传送的长度        
void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,uint32_t cpar,uint32_t cmar,uint32_t cndtr)
{
uint32_t DR_Base;  //做缓冲用,不知道为什么.非要不可
RCC->AHBENR|=1<<0;//开启DMA1时钟
DR_Base=cpar;
DMA_CHx->CPAR=DR_Base;   //DMA1 外设地址
DMA_CHx->CMAR=(uint32_t)cmar; //DMA1,存储器地址
DMA1_MEM_LEN=cndtr;      //保存DMA传输数据量
DMA_CHx->CNDTR=cndtr;    //DMA1,传输数据量
DMA_CHx->CCR=0X00000000;//复位
DMA_CHx->CCR|=0<<4;  //从外设读
DMA_CHx->CCR|=1<<5;  //循环模式
DMA_CHx->CCR|=0<<6;  //外设地址非增量模式
DMA_CHx->CCR|=1<<7;  //存储器增量模式
DMA_CHx->CCR|=2<<8;  //外设数据宽度为32位
DMA_CHx->CCR|=2<<10; //存储器数据宽度32位
DMA_CHx->CCR|=2<<12; //高等优先级
DMA_CHx->CCR|=0<<14; //非存储器到存储器模式   

//  /* 开启DMA1_Channel2、DMA1_Channel3通道中断控制,0级先占优先级,0级次占优先级*/
//         // 配置NVIC,中断向量号DMA1_Ch2_3= 10
//   NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0);
//   NVIC->ISER[0] = (uint32_t)0x01 <<10;                                // 使能NVIC;  
}
//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
DMA_CHx->CCR&=~(1<<0);       //关闭DMA传输  
DMA_CHx->CNDTR=DMA1_MEM_LEN; //DMA1,传输数据量
DMA_CHx->CCR|=1<<0;          //开启DMA传输
}  

/*TIM1数据采集回来后的处理程序*/
uint8_t  TIM1_CAPTURECH_STA1=0;        //输入捕获状态
uint8_t  TIM1_CAPTURECH_STA4=0;        //输入捕获状态
uint8_t duty_b_CH5=0; //遥控最终的读数
uint8_t duty_b_CH6=0; //遥控最终的读数
uint16_t TIM1_CH1ReadValue= 0; //TIM1->CCR1采集的数值
uint16_t TIM1_CH4ReadValue= 0; //TIM1->CCR4采集的数值
uint32_t temp_CH5=0;
uint32_t temp_CH6=0;

void TIM1CH1_CaptureHandle_Program(void)
{
                        if(TIM1_CAPTURECH_STA1&0X40)                //捕获到一个下降沿                
                        {                                 
                                TIM1_CAPTURECH_STA1|=0X80;                //标记成功捕获到一次高电平脉宽
                          TIM1_CH1ReadValue=IC2Value_TIM1[0];        //获取当前的捕获值.
                                temp_CH5=TIM1_CAPTURECH_STA1&0X3F;
                                temp_CH5+=TIM1_CH1ReadValue;                //得到总的高电平时间
                                duty_b_CH5=(uint8_t)((temp_CH5-2000)*0.1);
                                if((0<duty_b_CH5)&&(duty_b_CH5<5)) //开关信号
                                {        duty_b_CH5=0xAA;}
                                if((44<duty_b_CH5)&&(duty_b_CH5<55)) //关闭信号
                                {        duty_b_CH5=0xBB;}
                               
                                        TIM1_CAPTURECH_STA1=0;                        //开启下一次捕获                               
                                        TIM1->CCER&=~(1<<1);                        //CC1P=0 设置为上升沿捕获
                                }else                                                                  //还未开始,第一次捕获上升沿
                                {
                                        TIM1_CAPTURECH_STA1=0;                        //清空
                                        TIM1_CH1ReadValue=0;    //
                                        TIM1_CAPTURECH_STA1|=0X40;                //标记捕获到了上升沿
                                        TIM1->CNT=0;                                        //计数器清空
                                        TIM1->CCER|=1<<1;                                 //CC1P=1 设置为下降沿捕获
                                }                    
}

/**************************************
* 函数名   : main
* 描述     : 主函数
* 输入参数 : 无
* 返回值   : 无
**************************************/
int main(void)
{
        UserSystemClock48MInit(Internal_Clock_Source);
        LED_Init();
        SysTick_Init(); //开启延时
        USART_Configuration(); /* USART1 config 115200 8-N-1 */
        //LED灯控制程序
        UserTIMER1617PWMInit(1000); //1000hz频率
        //遥控通道
       timer1_init(65535,48-1);// 定时器初始化配置  48/48=1M的计数频率,自动重装载值为65536
while (1)
  {
   MYDMA_Enable(DMA1_Channel2); //开始一次DMA传输
   if(DMA1->ISR&(1<<5))//等待通道2传输完成
    {
      LED_ON_D4;
      TIM1CH1_CaptureHandle_Program();
      DMA1->IFCR|=1<<5;//清除通道2传输完成标志
    }
  }
}

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版