自己闲来无事,打算做一个小车玩,四个电机如果想知道速度的话,就需要对其编码器的信号进行采集。
之前采用的是编码器接口模式,但是这样的话,虽然使用很方便,但是比较占用单片机的资源,毕竟四个
电机就需要用四个编码器,暂时也不需要知道电机转动方向,所以就取编码器中的A相信号,利用定时器
输入捕获功能来计算电机转速。TIMER5 四个通道来采集四个电机,也可以利用中断的形势来计算,也能
实现,但是这样很占用中断,所以采用DMA来采集,然后通过TIMER定时中断,来每隔一段时间比如10ms
来计算一次转速,大致实验了一下,采集到的数据大致符合电机的转速。具体计算函数没写,可以自己来算
一个。也可能有更好的方式,以后如果发现的话,再来分享
u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度
u16 tim5_cnt[8]; //[0] [1] TIM5_CH1 [2] [3] TIM5_CH2
//[4] [5] TIM5_CH3 [6] [7] TIM5_CH4
//通用定时器5 通道1 2 3 4 用做输入捕获,通过DMA传送CNT
void TIM5_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//定时器时钟和GPIO配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能TIM5时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; //PA0 清除之前设置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0123 输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3); //PA0123 下拉
//初始化定时器5 TIM5
TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
//初始化TIM5输入捕获参数
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01 选择输入端 IC2映射到TI2上
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3; //CC1S=01 选择输入端 IC3映射到TI3上
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4; //CC1S=01 选择输入端 IC4映射到TI4上
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM_ICInitStructure);
//使能DMA请求
TIM_DMACmd(TIM5, TIM_DMA_CC1, ENABLE);
TIM_DMACmd(TIM5, TIM_DMA_CC2, ENABLE);
TIM_DMACmd(TIM5, TIM_DMA_CC3, ENABLE);
TIM_DMACmd(TIM5, TIM_DMA_CC4, ENABLE);
TIM_Cmd(TIM5,ENABLE );
}
void TIM5_DMA_CONFIG(void)
{
DMA2_Config(DMA2_Channel5,(u32)(&TIM5->CCR1),(u32)tim5_cnt,2);
DMA2_Config(DMA2_Channel4,(u32)(&TIM5->CCR2),(u32)&tim5_cnt[2],2);
DMA2_Config(DMA2_Channel2,(u32)(&TIM5->CCR3),(u32)&tim5_cnt[4],2);
DMA2_Config(DMA2_Channel1,(u32)(&TIM5->CCR4),(u32)&tim5_cnt[6],2);
}
//DMA2的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
void DMA2_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); //使能DMA传输
DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值
DMA1_MEM_LEN=cndtr;
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从外设到内存
DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为32位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为32位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
DMA_Cmd(DMA_CHx, ENABLE); //使能 所指示的通道
}
//开启一次DMA传输
void DMA_Channel_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
DMA_Cmd(DMA_CHx, DISABLE ); //关闭 所指示的通道
DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
DMA_Cmd(DMA_CHx, ENABLE); //使能所指示的通道
}
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
//在此可进行对数据的处理
DMA_Channel_Enable(DMA2_Channel5);
DMA_Channel_Enable(DMA2_Channel4);
DMA_Channel_Enable(DMA2_Channel2);
DMA_Channel_Enable(DMA2_Channel1);
}
}