1 项目功能

通过光电编码器进行转速测量

2 光电编码器工作原理

光电编码器,是一种通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。这是应用最多的传感器,光电编码器是由光源、光码盘和光敏元件组成。光栅盘是在一定直径的圆板上等分地开通若干个长方形孔。由于光电码盘与电动机同轴,电动机旋转时,光栅盘与电动机同速旋转,经发光二极管等电子元件组成的检测装置检测输出若干脉冲信号,通过计算每秒光电编码器输出脉冲的个数就能反映当前电动机的转速。此外,为判断旋转方向,码盘还可提供相位相差90º的两路脉冲信号。

下图为光电编码器的工作原理图:

合理安排光栏板和光电元件的位置,每转一圈会发出固定个数的脉冲,A相和B相脉冲相差90度,可以用来区分旋转方向,有些编码器每转一圈会发出一个Z相脉冲。

编码器有增量式和绝对式两种,我们采用增量式编码器进行转速测量。

3 AT32编码器接口

本例采用欧姆龙omron的E6B2-CWZ6C型光电编码器,分辨率为1000脉冲/秒。

AT32F407系列的通用定时器(TMR2 到TMR5)支持编码器输入。AT32F407编码器模式配置,需将SMSEL[2:0]配置为3’b001/3’b010/3’b011可开启编码模式,编码模式下需提供两个输入(C1IN/C2IN),根据一个输入的电平值,计数器将在另一个输入的边沿向上或向下计数。计数方向将由OWCDIR值指示。编码模式下计数器计数方向如下表所示:

如果采用在C1IN和C2IN上计数,计数值为脉冲数的4倍,AT32的编码器模式具备干扰脉冲自动滤除功能。需要注意的是,如果采用计数器溢出中断,AT32在某种特定条件下不会触发该中断。高级用户可能考官方给出的参考解决方案,见《FAQ0121_TMR在编码器模式下的Overflow事件_V2.0.0》,官方搜索即可。

4 掌上实验室与编码器连接电路图

图中右上脚为扩展接口,接法为:1脚-A相(黑);2脚-B相(白);12脚(GND)-0V(蓝);16脚(5V)-电源(褐)。

连接好编码器之后,试着转动编码器,可以看到LED2红色闪烁,是不是有意外收获?实际上《掌上实验室V8》PA1有复用,电路如下:

还有一点需要注意,编码器是NPN集电极开路输出(可以方便和不同电平的电路或单片机接口),接收电路需要增加上拉电阻。也可以用单片机内部的上拉电阻,需要程序配置。

5 程序设计

示例程序如下:

#include "at32f403a_407_conf.h"void delay_us(int us)
{SysTick->LOAD = system_core_clock/1000000 * us; SysTick->VAL = 0;SysTick->CTRL = 0x5; //Systick采用系统时钟为时钟源,并启动while((SysTick->CTRL & (1<<16)) == 0);SysTick->CTRL = 0;     //停止Systick
}void delay_ms(int ms)
{for(;ms>0;ms--)delay_us(1000);
}//端口初始化
void gpio_pins_init(void)
{//打开GPIO时钟crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);//配置PD2~PD5, PE0~PE7为输出gpio_init_type gpio_init_struct;gpio_init_struct.gpio_pins  = GPIO_PINS_0 | GPIO_PINS_1 | GPIO_PINS_2 | GPIO_PINS_3 | GPIO_PINS_4 | GPIO_PINS_5 | GPIO_PINS_6 | GPIO_PINS_7;gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;gpio_init(GPIOE, &gpio_init_struct);gpio_init_struct.gpio_pins  = GPIO_PINS_2 | GPIO_PINS_3 | GPIO_PINS_4 | GPIO_PINS_5;gpio_init(GPIOD, &gpio_init_struct);//蜂鸣器gpio_init_struct.gpio_pins  = GPIO_PINS_2;gpio_init(GPIOB, &gpio_init_struct);//按键上拉输入gpio_init_struct.gpio_pins  = GPIO_PINS_12 | GPIO_PINS_13 | GPIO_PINS_14 | GPIO_PINS_15;gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;gpio_init_struct.gpio_pull = GPIO_PULL_UP;gpio_init(GPIOD, &gpio_init_struct);//编码器输入gpio_init_struct.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1;gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_pull = GPIO_PULL_UP; //编码器为集电极开路输出,需上拉gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;gpio_init(GPIOA, &gpio_init_struct);
}//显示缓冲区定义
uint8_t disp_buf[4];//显示整数
void display_dec_int(int num)
{static uint8_t tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};disp_buf[0] = tab[num/1000%10];disp_buf[1] = tab[num/100%10];disp_buf[2] = tab[num/10%10];disp_buf[3] = tab[num%10];
}void display_minus()
{disp_buf[0] = 0xbf;disp_buf[1] = 0xbf & 0x7F;disp_buf[2] = 0xbf;disp_buf[3] = 0xbf;
}//扫描刷新
void display_scan()
{static int cur_digit = 0;//全关gpio_bits_set(GPIOD, GPIO_PINS_2 | GPIO_PINS_3 | GPIO_PINS_4 | GPIO_PINS_5); //输出字形码gpio_bits_reset(GPIOE, 0xff); //PE0~PE7 = 0gpio_bits_set(GPIOE, disp_buf[cur_digit]); //打开对应位开关gpio_bits_reset(GPIOD, GPIO_PINS_2 << cur_digit);//更新cur_digit, 准备下一次扫描cur_digit = (cur_digit + 1) % 4;
}
void tmr6_init(void)
{  /* enable tmr6 clock */  crm_periph_clock_enable(CRM_TMR6_PERIPH_CLOCK, TRUE);   /* 64000000/64/1000 = 1000Hz*//* tmr_base_init(TMR6, 1000 - 1, 64 - 1); */ tmr_base_init(TMR6, 1000 - 1, system_core_clock/1000000 - 1);  tmr_cnt_dir_set(TMR6, TMR_COUNT_UP);   /* overflow interrupt enable */  tmr_interrupt_enable(TMR6, TMR_OVF_INT, TRUE);   /* tmr1 overflow interrupt nvic init */  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);  nvic_irq_enable(TMR6_GLOBAL_IRQn, 0, 0);   /* enable tmr1 */  tmr_counter_enable(TMR6, TRUE);
}
void TMR6_GLOBAL_IRQHandler(void)
{    if(tmr_flag_get(TMR6, TMR_OVF_FLAG) != RESET)    {        tmr_flag_clear(TMR6, TMR_OVF_FLAG);//gSysTick++;        display_scan();            }
}
int getKey()
{if(gpio_input_data_bit_read(GPIOD,GPIO_PINS_12)==RESET){delay_ms(20);if(gpio_input_data_bit_read(GPIOD,GPIO_PINS_12)==RESET){while(gpio_input_data_bit_read(GPIOD,GPIO_PINS_12)==RESET);return 1;}    }return 0;
}void buzzer_ctrl(int on)
{if(on)gpio_bits_set(GPIOB, GPIO_PINS_2);elsegpio_bits_reset(GPIOB, GPIO_PINS_2);
}void tmr2_encoder_init(){/* enable tmr2/gpioa clock */crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);/* tmr2 encoder mode configurationtmr2 ti1pf1 ,ti2fp2 as encoder input pin, tmr2 counterchanged each signal edge. *//* enable tmr2 32bit function */tmr_32_bit_function_enable(TMR2, TRUE);tmr_base_init(TMR2, 0xFFFFFFFF, 0);tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);/* config encoder mode */tmr_encoder_mode_config(TMR2, TMR_ENCODER_MODE_C, TMR_INPUT_BOTH_EDGE, TMR_INPUT_BOTH_EDGE);/* enable tmr2 */tmr_counter_enable(TMR2, TRUE);
}int main(void)
{gpio_pins_init();tmr6_init();tmr2_encoder_init();uint32_t counter_1, counter_2;int32_t diff;float rpm;for(;;){counter_1 = tmr_counter_value_get(TMR2);delay_ms(1000);counter_2 = tmr_counter_value_get(TMR2);diff = counter_2 - counter_1;rpm = diff*60/4/1000.0;if(rpm<0)rpm = -rpm;display_dec_int(rpm);}
}

本例采用AB相脉冲上升沿和下降沿全部计数的方法,这样可以滤除干扰脉冲,所以实际的分辨率细分4倍,达到4000脉冲/转。程序每秒钟测获取一次编码器值,其差值就是1秒钟编码器产生的脉冲值,乘上60就换算成了转速,单位为转/分钟。

程序中counter_1, counter_2, diff分别定义为32位无符号和有符号整数,如不清楚C语言处理数据的相关机制,请自行了解和测试。

如果编码器带了转轮,还要考虑机械结构的转速转换系数。

可以进一步改进的地方,秒延时精度,增加方向和小数点的显示。

掌上实验室V8系列教程(九)光电编码器转速测量相关推荐

  1. 掌上实验室V8系列教程(八)ADC模数转换

    目录 1 项目功能 2 ADC工作原理 3 电路原理图 4 AT32 ADC应用 4.1 ADC基础操作流程 4.2 ADC触发 4.3 ADC采样和转换时间 4.4 读取ADC转换结果 5 示例程序 ...

  2. 掌上实验室V8系列教程(四)定时器PWM输出

    1 项目功能 三色RGB LED 通过PWM 调色 2 电路原理 我们可以通过3路PWM波分别调整RGB三个二极管的亮度,即调整RGB的比例,合成不同的颜色. PWM,英文名Pulse Width M ...

  3. 掌上实验室V8系列教程(二)跑马灯

    目录 1 项目功能 2 电路原理 3 软件流程 4 程序设计 5.参考资源 1 项目功能 循环点亮LED4, LED5, LED6, LED7 2 电路原理 根据硬件电路图,PC0输出"0& ...

  4. 掌上实验室V8系列教程(七)I2C应用 HP203B

    目录 1 项目功能 2 电路原理图 3 传感器HP203B 3.1 HP203B功能 3.2 HP203B技术指标 3.3 HP203B I2C总线接口命令 4 示例代码 1 项目功能 通过HB203 ...

  5. 掌上实验室V8系列教程(三)数码管动态显示

    目录 1 项目功能 2 电路原理 3 动态显示原理 4 示例代码 6 扩展功能 7 参考资源 1 项目功能 4位数码管动态显示 2 电路原理 3 动态显示原理 一位八段式数码管内部有8个LED,习惯上 ...

  6. 掌上实验室V8系列教程(五)定时器中断及应用

    1 项目目标 利用定时器产生周期为1ms的中断,作为系统时基.并在数码管上显示开机时间(分辨率为0.1秒):同时实现LED4.LED5.LED6和LED7分别以300ms.220ms.450ms和70 ...

  7. 基于雅特力AT32的 《掌上实验室》V8

    1 项目介绍 掌上实验室V8是由中国计量大学现代科技学院和雅特力共同研发的一款ARM学习板,内置AT-Link-Ez仿真器. 主MCU采用雅特力AT32F407VGT7. 板上资源: 1.通信接口 1 ...

  8. PVE系列教程(九)、openWRT设置主路由与旁路由模式

    PVE系列教程(九).openWRT设置主路由与旁路由模式 为了更好的浏览体验,欢迎光顾勤奋的凯尔森同学个人博客http://nas.hepcloud.top:7000 Hello,小伙伴们,这是凯尔 ...

  9. 毕业设计-基于微信小程序的“掌上实验室” 安全教育与管理系统

    目录 前言 课题背景与简介 实现设计思路 一."掌上实验室"安全教育与管理 平台功能架构 二."掌上实验室"的功能设计 三."掌上实验室"的 ...

最新文章

  1. 基于Mozilla Thunderbird的扩展开发(四)---修改Thunderbird源代码实现自动保存附件...
  2. php mysql 降_PHP,MySQL:mysql替代php in_array函数
  3. [原]《Web前端开发修炼之道》-读书笔记CSS部分
  4. LayUi 树形组件tree 实现懒加载模式,展开父节点时异步加载子节点数据
  5. js下载文件及命名(兼容多浏览器)
  6. Java+MyEclipse+Tomcat (二)配置Servlet及简单实现表单提交
  7. Python 读写文件和file对象(转)
  8. flink写入hive的时区问题
  9. python2中文输出代码_解决vscode python print 输出窗口中文乱码的问题
  10. 遗传相似系数怎么计算_如何计算遗传变异系数
  11. 《机器学习实战》学习总结(六)PCA算法原理
  12. HDU 5570:balls 期望。。。。。。。。。。。。。。。
  13. 数据分析与数据挖掘的区别
  14. 推荐阅读20100603
  15. vscode使用:tab键插入空格而不是tab
  16. 【openwrt】使用4G模块 移远EC20/25(1)内核配置
  17. PS动感映像插件ImageMotion 1.3中文汉化版
  18. 虚幻4引擎开发的手游_2019虚幻4手游大作排行-虚幻引擎开发的手机游戏
  19. 树莓派智能家居homeassistant之homekit篇
  20. python拟合二次函数_Python 最小二乘法 拟合 二次曲线

热门文章

  1. 北斗三号频点_全球首颗全面支持北斗三号基带芯片问世
  2. 投资人读一份BP只用3分44秒,你还敢不认真准备吗?
  3. Android Audio开发——AAudio基础(十五)
  4. 中国集装箱均价比去年8月降低了一半以上,至加拿大航线的单程租赁费近期降幅最大 | 美通社头条...
  5. element-UI el-select 简单修改下拉框样式
  6. matlab aviread函数,matlab 未定义函数或变量 aviread.
  7. 什么是前端、后端、数据库?
  8. 缺氧游戏 计算机研究,缺氧游戏攻略 资源内部修改方法以及代码大全
  9. Spring Cloud系列之Commons - 1. 背景与基础知识准备
  10. java flowlayout参数_java flowlayout 垂直