历史上的今天
返回首页

历史上的今天

今天是:2025年03月07日(星期五)

正在发生

2019年03月07日 | STM32之通用定时器编码器模式

2019-03-07 来源:eefocus

1、编码器原理

如果两个信号相位差为90度,则这两个信号称为正交。由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向、根据每个信号脉冲数量的多少及整个编码轮的周长就可以算出当前行走的距离、如果再加上定时器的话还可以计算出速度。


2、为什么要用编码器



从上图可以看出,由于TI,T2一前一后有个90度的相位差,所以当出现这个相位差时就表示轮子旋转了一个角度。但有人会问了:既然都是脉冲,为什么不用普通IO中断?实际上如果是轮子一直正常旋转当然没有问题。仔细观察上图,如果出现了毛刺呢?这就是需要我们在软件中编写算法进行改正。于是,我们就会想到如果有个硬件能够处理这种情况那不是挺好吗?


3、stm32编码器




还是刚才那张图,但这时候我们看到STM32的硬件编码器还是很智能的,当T1,T2脉冲是连续产生的时候计数器加一或减一一次,而当某个接口产生了毛刺或抖动,则计数器计数不变,也就是说该接口能够容许抖动。在STM32中,编码器使用的是定时器接口,通过数据手册可知,定时器1,2,3,4,5和8有编码器的功能,而其他没有。编码器输入信号TI1,TI2经过输入滤波,边沿检测产生TI1FP1,TI2FP2接到编码器模块,通过配置编码器的工作模式,即可以对编码器进行正向/反向计数。如果用的是定时器3,则对应的引脚是在PC6和PC7上。根据stmn32手册上编码器模式的说明,有6中组合计数方式,见下表。 


 


由此可知,通过选择可以确定使用定时器的哪种方式来得到我们所要的结果。STM32编码器的使用也非常简单,其基本步骤和开发STM32其他部件的操作一致,都是打开时钟,配置接口,配置模式,如果要用中断则打开中断。具体可以参考以下代码(这里使用的是TIM8,引脚采用GPIOC 6和GPIOC7)


正转向上计数,反转向下计数,方向在CR1的DIR位里


1.编码器有个转速上限,超过这个上限是不能正常工作的,这个是硬件的限制,原则上线数越多转速就越低,这点在选型时要注意,编码器的输出一般是开漏的,所以单片机的io一定要上拉输入状态. 


2.定时器初始化好以后,任何时候CNT寄存器的值就是编码器的位置信息,正转他会加反转他会减这部分是不需要软件干预的,初始化时给的TIM_Period 值应该是码盘整圈的刻度值,在减溢出会自动修正为这个数.加超过此数值就回0. 


3.如果要扩展成多圈计数需要溢出中断像楼主说的,程序上圈计数加减方向位就行了. 


4.每个定时器的输入脚可以通过软件设定滤波 


5.应用中如果没有绝对位置信号或者初始化完成后还没有收到绝对位置信号前的计数只能是相对计数.收到绝对位置信号后重新修改一次CNT的值就行了.码盘一般都有零位置信号,结合到定时器捕获输入就行.上电以后要往返运动一下找到这个位置. 


6.即便有滤波计数值偶尔也会有出错误的情况,一圈多计一个或少计一个数都是很正常的特别是转速比较高的时候尤其明显,有个绝对位置信号做修正是很有必要的.绝对位置信号不需要一定在零位置点,收到这个信号就将CNT修正为一个固定的数值即可. 


7.开启定时器的输入中断可以达到每个步计数都作处理的效果,但是高速运转的时候你可能处理不过来.


#include "stm32f10x.h"

 

/* RCC时钟配置 */

void RCC_config()

    ErrorStatus HSEStartUpStatus;

 

    /* RCC寄存器设置为默认配置 */

    RCC_DeInit();

    /* 打开外部高速时钟 */

    RCC_HSEConfig(RCC_HSE_ON);

    /* 等待外部高速时钟稳定 */

    HSEStartUpStatus = RCC_WaitForHSEStartUp();

    if(HSEStartUpStatus == SUCCESS) 

    { 

        /* 设置HCLK = SYSCLK */

        RCC_HCLKConfig(RCC_SYSCLK_Div1);

        /* 设置PCLK2 = HCLK */

        RCC_PCLK2Config(RCC_HCLK_Div1);

        /* 设置PCLK1 = HCLK / 2 */

        RCC_PCLK1Config(RCC_HCLK_Div2);

//        /* 设置FLASH代码延时 */

//        FLASH_SetLatency(FLASH_Latency_2);

//        /* 使能预取址缓存 */

//        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

        /* 设置PLL时钟源为HSE倍频9 72MHz */

        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

        /* 使能PLL */

        RCC_PLLCmd(ENABLE);

        /* 等待PLL稳定 */

        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

        /* 设置PLL为系统时钟源 */

        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

        /* 等待系统时钟源切换到PLL */

        while(RCC_GetSYSCLKSource() != 0x08);

    }

}

 

/* GPIO配置 */

void GPIO_config()

{

    GPIO_InitTypeDef GPIO_InitStructure;

    

    /* 使能GPIOA时钟 */

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

    

    /* 将GPIOA时钟设置为默认参数 */

    GPIO_DeInit(GPIOA);    

    

    /* 浮空输入 */

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    /* 第3引脚 */

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

    /* 初始化GPIOA */

    GPIO_Init(GPIOA, &GPIO_InitStructure);

}

 

/* 定时器配置 */

void TIMER_config()

{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    TIM_ICInitTypeDef TIM_ICInitStructure;

    

    /* 允许TIM2的时钟 */

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

 

    /* 将定时器2寄存器设为初始值 */

    TIM_DeInit(TIM2);

 

    /* 填入缺省值 */

    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

    /* 预分频值 */

    TIM_TimeBaseStructure.TIM_Prescaler = 0;

    /* 自动重载值 */

    TIM_TimeBaseStructure.TIM_Period = 65536 - 1;

    /* 时钟分割 */

    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

    /* 向上计数 */

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    /* 初始化定时器2 */

    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

 

    /* 设置编码器模式 */

    TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling ,TIM_ICPolarity_Falling);

    

    /* 填入缺省值 */

    TIM_ICStructInit(&TIM_ICInitStructure);

    /* 输入比较滤波器 */

    TIM_ICInitStructure.TIM_ICFilter = 6;

    /* 初始化定时器2 */

    TIM_ICInit(TIM2, &TIM_ICInitStructure);

 

    /* 计数器初始化 */

    TIM_SetCounter(TIM2, 32768);

 

    /* 开启定时器2 */

    TIM_Cmd(TIM2, ENABLE);

}

 

/* 毫秒延时 */

void delay_ms(uint16_t time)

{    

    uint16_t i = 0;

 

    while(time--)

    {

        i = 12000;

        while(i--);

    }

}

 

int main()

{

    int16_t speed;

    

    /* 时钟配置 */

    RCC_config();

 

    /* GPIO配置 */

    GPIO_config();

 

    /* 定时器2配置 */

    TIMER_config();

 

    while(1)

    {

        speed = TIM2->CNT - 32768;

        TIM_SetCounter(TIM2, 32768);

        delay_ms(1000);

    }

}

 

推荐阅读

史海拾趣

EOS POWER INDIA Pvt公司的发展小趣事

随着市场的不断发展和客户需求的变化,EOS意识到只有不断创新才能保持竞争力。因此,公司加大了对研发的投入,引进了一批高素质的研发人才。经过数年的努力,EOS成功研发出了一系列高性能、高可靠性的电源产品,如交钥匙电源解决方案、定制电源等。这些产品不仅满足了客户的多样化需求,还帮助EOS在市场上获得了更多的份额。

GHz Technology ( Microsemi )公司的发展小趣事

EOS一直将质量管理作为公司发展的核心。公司建立了完善的质量管理体系,从原材料采购到生产、检测、包装等各个环节都进行严格的质量控制。EOS还引入了先进的质量检测设备和方法,确保每一件产品都符合高标准的质量要求。此外,公司还定期对员工进行质量培训,提高员工的质量意识和操作技能。这些措施使得EOS的产品在市场上赢得了良好的口碑和信誉。

DDK公司的发展小趣事

在电子行业中,产品质量是企业生存和发展的关键。DDK公司深知这一点,因此始终将产品质量放在首位。公司建立了严格的质量管理体系,从原材料采购到产品生产、检测的每一个环节都严格把控,确保每一件产品都符合高标准、严要求。这种对品质的执着追求,让DDK公司的产品在市场上赢得了良好的声誉,赢得了消费者的信任和忠诚。

屹晶微(EG)公司的发展小趣事

屹晶微的创始人黄米龙,原本在发电厂从事电气运营工作长达八年。这段经历让他对电子领域有了深入的了解和浓厚的兴趣。然而,他并没有满足于现状,而是看到了中国芯片产业的巨大潜力和发展空间。于是,在2007年,他毅然决定从发电厂辞职,利用自己的积蓄和借来的资金,在台州创立了屹晶微电子有限公司。

在创立初期,屹晶微面临着资金短缺、技术落后和市场竞争激烈的困境。但黄米龙凭借对电子行业的深刻理解和坚定的信念,带领团队克服了种种困难。他们不断引进先进技术和设备,加强研发力量,提升产品质量。经过几年的努力,屹晶微逐渐在芯片设计领域崭露头角,并成功推出了多款具有自主知识产权的芯片产品。

Dicon Fiberoptics Inc公司的发展小趣事

进入21世纪后,随着互联网的普及和信息技术的飞速发展,光纤通信技术迎来了新的发展机遇。DiCon凭借其在微机电系统(MEMS)、微光学设计等领域的技术积累,成功推出了一系列具有创新性的光纤通信产品。这些产品不仅提高了数据传输的速度和稳定性,还降低了成本,进一步扩大了公司在市场上的份额。

Elite Enterprises (H K) Co Ltd公司的发展小趣事

为了进一步提升公司的竞争力和市场份额,Elite Enterprises积极寻求与行业内外的合作伙伴建立战略合作关系。公司与多家知名企业签订了长期合作协议,共同开发新产品、拓展新市场。此外,公司还与一些高校和研究机构建立了产学研合作关系,共同推动LED技术的创新和应用。

问答坊 | AI 解惑

2010 ARM嵌入式开发技术巡回研讨会北京站见闻后记

周末阿牛哥整理2010ARM 嵌入式开发技术研讨会搜集的资料。当时听过TI 的FAE 讲座,整理资料TI 的Stelaris Product lines ,还有 TI的Stelari COTEX-M3 在LED 应用, 还有TI M3 在网络收音机上的应用。想到会场武汉理工大学李宁博士做的的基于云计 ...…

查看全部问答>

关于arm

arm指令用什么编译器编译 我初学这个,不知道这样问对不对? 请大家指教…

查看全部问答>

s3c2410支持4G的sd卡吗

各位牛人,有没有做过s3c2410中,wince4.2下4G的SDHC卡驱动吗? 能不能行,准备尝试一下,恳请指点少走弯路。 看过wince5.0的大容量sd卡驱动实现,4.2下如何做? …

查看全部问答>

弱弱的问一句:配置虚拟内存地址有什么用

写第一个基于ARM9的wince驱动的时候,参照人家的例子,加入这个函数,但是本质上的作用是什么我不清楚?看不明白~求教 volatile IOPreg         *s2440IOP = (IOPreg *)IOP_BASE; volatile INTreg         ...…

查看全部问答>

DZ60流水灯延时问题

刚学习freecalce单片机,DZ60的一个开发板,外部晶振是8M的,写了一个最简单的流水灯代码。可以实现功能,但有一些问题搞不明白。 先把代码放在下面 #include <hidef.h> /* for EnableInterrupts macro */#include \"derivative.h\" /* inclu ...…

查看全部问答>

TI 2013电源管理指南(最新)

TI 2013电源管理指南(最新) 看看2013TI最新的电源管理有哪些变化和新东西,, TI 2013电源管理指南(最新) …

查看全部问答>

初学单片机的40个实验

初学单片机的40个实验,word格式,一共205页,很实用的资料,欢迎下载。 1. 闪烁灯1.  实验任务如图4.1.1所示:在P1.0端口上接一个发光二极管L1,使L1在不停地一亮一灭,一亮一灭的时间间隔为0.2秒。2.  电路原理图 3.  系统板上硬 ...…

查看全部问答>

请大侠推荐集线器HUB芯片 要工业级!要稳定!

请大侠推荐集线器HUB芯片,最好是8口的 要工业级要稳定…

查看全部问答>