原创 stm32学习——两轮平衡小车之定时器正交编码器功能应用

2016-4-9 12:38 3085 29 3 分类: MCU/ 嵌入式

废话不说,先上代码

#include "main.h"

/*

PA7——TIM3_CH2

PA6——TIM3_CH1

PB7——TIM4_CH2

PB6——TIM4_CH1

*/

 

int Timer3_Overflow;

int Timer4_Overflow;

 

void wheel_encoder_configuration(void)

{

         GPIO_InitTypeDef                                        ENCODER;

         TIM_TimeBaseInitTypeDef    TIMER3,  TIMER4;

         TIM_ICInitTypeDef                                      IC_ENCODER;

         NVIC_InitTypeDef                                        nvic;

 

         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB, ENABLE);

         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3|RCC_APB1Periph_TIM4, ENABLE);

        

         //PA6、PA7的复用功能一定要分开配置才行

         GPIO_PinAFConfig(GPIOA,GPIO_PinSource6, GPIO_AF_TIM3);

         GPIO_PinAFConfig(GPIOA,GPIO_PinSource7, GPIO_AF_TIM3);

         ENCODER.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

         ENCODER.GPIO_Mode = GPIO_Mode_AF;

         ENCODER.GPIO_Speed = GPIO_Speed_100MHz;

         ENCODER.GPIO_PuPd = GPIO_PuPd_DOWN;

         GPIO_Init(GPIOA, &ENCODER);

         GPIO_PinAFConfig(GPIOB,GPIO_PinSource6, GPIO_AF_TIM4);

         GPIO_PinAFConfig(GPIOB,GPIO_PinSource7, GPIO_AF_TIM4);

         ENCODER.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

         ENCODER.GPIO_Mode = GPIO_Mode_AF;

         ENCODER.GPIO_Speed = GPIO_Speed_100MHz;

         ENCODER.GPIO_PuPd = GPIO_PuPd_DOWN;

         GPIO_Init(GPIOB, &ENCODER);

 

         /***********configure the TIM3**********/

         TIMER3.TIM_Prescaler = 0;

         TIMER3.TIM_Period = 0xffff;

         TIMER3.TIM_ClockDivision = TIM_CKD_DIV1;

         TIMER3.TIM_CounterMode = TIM_CounterMode_Up;  

         TIM_TimeBaseInit(TIM3, &TIMER3);

         /***********configure the TIM4***********/

         TIMER4.TIM_Prescaler = 0;

         TIMER4.TIM_Period = 0xffff;

         TIMER4.TIM_ClockDivision = TIM_CKD_DIV1;

         TIMER4.TIM_CounterMode = TIM_CounterMode_Up;  

         TIM_TimeBaseInit(TIM4, &TIMER4);

        

         /**********Set TIM3 and TIM4 to the ecoder mode***************/

         TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);

         TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);

        

         /**********Set TIM3 and TIM4 to the input capture mode***************/

         IC_ENCODER.TIM_Channel    =       TIM_Channel_1;

         IC_ENCODER.TIM_ICSelection        =       TIM_ICSelection_DirectTI;

         TIM_ICInit(TIM3, &IC_ENCODER);

         IC_ENCODER.TIM_Channel    =       TIM_Channel_2;

         IC_ENCODER.TIM_ICSelection        =       TIM_ICSelection_DirectTI;

         TIM_ICInit(TIM3, &IC_ENCODER);

         IC_ENCODER.TIM_Channel    =       TIM_Channel_1;

         IC_ENCODER.TIM_ICSelection        =       TIM_ICSelection_DirectTI;

         TIM_ICInit(TIM4, &IC_ENCODER);

         IC_ENCODER.TIM_Channel    =       TIM_Channel_2;

         IC_ENCODER.TIM_ICSelection        =       TIM_ICSelection_DirectTI;

         TIM_ICInit(TIM4, &IC_ENCODER);

        

         /*************Configurate interrupts of TIM3 and TIM4*********/

         nvic.NVIC_IRQChannel = TIM3_IRQn;

         nvic.NVIC_IRQChannelPreemptionPriority = 2;

         nvic.NVIC_IRQChannelSubPriority = 2;

         nvic.NVIC_IRQChannelCmd = ENABLE;

         NVIC_Init(&nvic);

         nvic.NVIC_IRQChannel = TIM4_IRQn;

         nvic.NVIC_IRQChannelPreemptionPriority = 2;

         nvic.NVIC_IRQChannelSubPriority = 2;

         nvic.NVIC_IRQChannelCmd = ENABLE;

         NVIC_Init(&nvic);

        

         /*Clear the interruput flag and then enable the interrupt*/

         TIM_ClearFlag(TIM3, TIM_FLAG_Update);

         TIM_ClearFlag(TIM4, TIM_FLAG_Update);

         TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

         TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);

        

         /*Set TIM3 and TIM4 CNT to 0x7fff*/

         TIM_SetCounter(TIM3,0x7fff);

         TIM_SetCounter(TIM4,0x7fff);

         /*Enable TIM3 and TIM4 */

         TIM_Cmd(TIM3, ENABLE);

         TIM_Cmd(TIM4, ENABLE);

}

 

int encoderR_get_cnt(void)

{

         /*get the speed of right wheel */

         int cnt = 0;

         cnt = (TIM3 -> CNT) - 0x7fff;

         TIM3 -> CNT = 0x7fff;

         return cnt;

}

 

int encoderL_get_cnt(void)

{

         /*get the speed of left wheel*/

         int cnt = 0;

         cnt = (TIM4 -> CNT) - 0x7fff;

         TIM4 -> CNT = 0x7fff;

         return cnt;

}

 

void TIM3_IRQHandler(void)

{

         TIM_ClearFlag(TIM3, TIM_FLAG_Update);

         if(Timer3_Overflow != 0xffffffff)

         {

                   Timer3_Overflow++;

         }

}

 

void TIM4_IRQHandler(void)

{

         TIM_ClearFlag(TIM4, TIM_FLAG_Update);

         if(Timer4_Overflow != 0xffffffff)

         {

                   Timer4_Overflow++;

         }

}

刚开始在调试的时候遇到了问题,读出来的cnt值只有0,1,-1,而且根本没有什么规律,后来发现是gpio的配置有问题,相应的GPIO口应该配制成GPIO_Mode_AF,而不是GPIO_Mode_IN,而且配置复用功能的时候,GPIO_PinAFConfig()函数的参数一定要注意,GPIO_PinSource参数只能写一个,不要讲多个GPIO_PinSource与在一起。比如,要配置PA6和PA7,应写成这样:

GPIO_PinAFConfig(GPIOA,GPIO_PinSource6, GPIO_AF_TIM3);

         GPIO_PinAFConfig(GPIOA,GPIO_PinSource7, GPIO_AF_TIM3);

而不要写出这样:

GPIO_PinAFConfig(GPIOA,GPIO_PinSource6| GPIO_PinSource7,  GPIO_AF_TIM3);

         程序中CNT寄存器的初值设置为0X7fff,这样的话无论一开始轮子是正转还是反转,都基本不会溢出,但是为了防止溢出的情况,又在两个定时器的中断函数中对溢出次数进行计数,在后续的应用中就可以结合溢出次数和CNT计数器的值,得到实际的计数值。

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户1020667 2016-4-24 12:24

very Good !
相关推荐阅读
用户1834061 2016-04-09 16:17
利用Snubber电路消除开关电源和ClassD功放电路中的振铃
概述 开关电源和ClassD功放,因为电路工作在开关状态,大大降低了电路的功率损耗,在当今的电子产品中得到了广泛的应用。由于寄生电感和寄生电容的存在,电路的PWM开关波形在跳变时,常常伴随着振铃现象。...
用户1834061 2016-04-09 13:07
stm32学习——两轮平衡小车之MPU6050模块数据读取和解析(USART的DMA功能应用)
由于硬件上采用了mpu6050模块,这模块是自带姿态解算和卡尔曼滤波功能的,所以省了不少事儿。直接通过串口读模块发送的数据,然后按照模块固定的协议把数据解析出来,就能得到三轴角速度,三轴加速度,三...
用户1834061 2016-03-18 19:29
stm32学习——两轮平衡小车之硬件设计
学习一种单片机最快的方式莫过于用它实际制作一个作品了,前些天看到有人在玩平衡小车,感觉非常有趣,于是就决定自己动手制作一个基于stm32的两轮平衡小车。从电路板设计,到程序编写,一步一步的,希望自己在...
用户1834061 2015-10-11 23:41
stm32学习——JLINK与JTAG的区别
调试ARM,要遵循ARM的调试接口协议,JTAG就是其中的一种。当仿真时,IAR、KEIL、ADS等都有一个公共的调试接口,RDI就是其中的一种,那么我们如何完成RDI-->ARM调试协议(...
用户1834061 2015-10-11 12:10
stm32学习——MDK软件的安装教程
1.安装文件和注册机下载链接http://pan.baidu.com/s/1hqjOCio(本来想传附件,太大传不了) 2.双击打开MDK514.exe文件,开始安装。安装过程与普通软件无异,...
我要评论
1
29
关闭 站长推荐上一条 /3 下一条