
求教:本人想用输入捕获来读取遥控的数据,然后通过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); } } |
之间的数据范围同时通道间不互相影响。因为只是实验的版本,所以写得有点乱,请勿喷,希望在这方面有所研究的朋友能共同交流,能够写出更好的程序出来。芯片用到的是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传输完成标志
}
}
}