GD32系列笔记五:用外部中断实现EC11差分编码器的方向识别和脉冲计数

目录

一、项目需求

二、EC11介绍

三、外部中断

 四、程序源码


一、项目需求

 通过GD32F150C8T6的IO口识别EC11的旋转方向和脉冲输出计数,将值产给PC,最终实现机械臂的角度输出和方向控制。由于EC11单圈20plu,分辨力低,所以程序上对其进行四倍频,提高分别率到单圈80plu,勉强满足要求。

二、EC11介绍

1.原理图

 2. 工作原理:S1、S2两相都输出方波,顺时针方向旋转编码器时,A相超前B相90度(如上图,A相先产生下降沿,B比A相滞后),逆时针方向旋转时,B相超前A相90度。

 3. 倍频:相对于刻度盘来说的,比如,刻度盘栅格数是100,那么转一圈就计数100次,为1倍频,如果通过某种方式可以实现转一圈计数400次,那就说实现了4倍频。

 4. 整理思路:

(1)如果不进行倍频,则GD32在EC11的脉宽内检测到第一个脉冲边沿时脉冲值计数一次,再通过判断A相超前还是滞后B相来判断方向,返回给PC;

(2)EC11的一个脉宽周期单向有4个边沿,而每个边沿均可被GD32的IO口识别,也就是说可以被检测4次,4次检测就相当于计数4次,在每次边沿检测时,可以判断该边沿极性和另外一向的电平高低来判断旋转方向,实现4倍频;

(3)对于GD32来说,每次和EC11输入信号(A、B相)都是一次信息交互,脉冲计数、方向判断都是在这次交互种中完成。而最佳的交互触发方式就是通过检测边沿跳变,只要有边沿跳变,那就进行通信。

(4)可以通过IO查询、外部中断、正交编码的方式实现该需求。用IO查询太慢了,因为程序执行周期较短,单圈80个脉冲,但在加速瞬间依然还是会丢脉冲值,不过对本次项目来说还勉强能接受。外部中断方式基本实现不丢包,但是消耗CPU资源。正交编码要求特定外设的IO口,由于搞硬件的一开始选错了IO,选了只有单通道捕获,双互补通道输出的IO口,所以不能用来做正交编码,所以这部分代码只配置,没测试。这里放出外部中断实现的代码。

三、外部中断

1.中断优先级:

(1)中断优先级分为主优先级(抢占优先级)和次优先级(响应优先级),抢占优先级的
级别高于响应优先级。

(2)而数值越小所代表的优先级就越高;

(3)如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;

(4)高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。

(5)抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。

2.中断和事件的区别:

       产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。

       简单点来说,就是中断最终会自动进入中断服务函数,而事件则不会有对应的服务函数。中断是软件级的,而事件是硬件级的。

3. GD32F150xx外部中断映射

 

 4.中断向量表(和F103不一样)

    如图红框,EXTI0和EXTI1公用一个中断向量EXTI0_1_IRQn;

                      EXTI2和EXTI3公用一个中断向量EXTI2_3_IRQn;

                      EXTI4---EXTI15公用一个中断向量EXTI4_15_IRQn;

 

四、程序源码

下面代码里的handler()函数是对计数的脉冲值和判断的方向值进行处理后发给PC,没上传。

 

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
你可以使用GD32系列微控制器中的定时器来实现脉冲计数功能。下面是一个简单的示例代码,演示如何使用GD32的定时器2来进行脉冲计数: ```c #include "gd32f10x.h" void timer2_init(void) { /* 使能定时器2的时钟 */ rcu_periph_clock_enable(RCU_TIMER2); /* 配置定时器2的工作模式为边沿计数模式 */ timer_ic_parameter_struct timer_icinitpara; timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING; // 上升沿触发 timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI; // 直接计数模式 timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1; // 输入捕获分频器预分频值 timer_icinitpara.icfilter = 0x0F; // 输入捕获滤波器 timer_input_capture_config(TIMER2, TIMER_CH_0, &timer_icinitpara); /* 配置定时器2的计数模式为上升沿计数 */ timer_counter_mode_config(TIMER2, TIMER_COUNTER_EDGE); /* 配置定时器2的触发源为TI0FP0 */ timer_external_trigger_source_config(TIMER2, TIMER_SMCFG_TRGSEL_CI0FE0); /* 配置定时器2的触发极性为上升沿触发 */ timer_external_trigger_polarity_config(TIMER2, TIMER_SMCFG_ETP); /* 配置定时器2的预分频值与计数值 */ timer_prescaler_config(TIMER2, 71, TIMER_PSC_RELOAD_UPDATE); timer_counter_value_config(TIMER2, 0); /* 使能定时器2的输入捕获功能 */ timer_channel_input_capture_config(TIMER2, TIMER_CH_0, TIMER_IC_SELECTION_DIRECTTI); timer_channel_enable(TIMER2, TIMER_CH_0); /* 使能定时器2 */ timer_enable(TIMER2); } uint32_t get_pulse_count(void) { /* 获取定时器2的当前计数值 */ return timer_channel_capture_value_register(TIMER2, TIMER_CH_0); } ``` 在使用之前,你需要确保已经正确初始化了GD32的系统时钟,并根据实际需求进行相应的配置。示例代码中的定时器2配置为边沿计数模式,上升沿触发,输入捕获滤波器为15个连续的采样结果,预分频值为71。可以根据实际情况进行调整。 使用`timer2_init()`函数初始化定时器2,然后使用`get_pulse_count()`函数可以获取当前的脉冲计数值。 请注意,示例代码中仅供参考,具体的配置和使用方法还需要根据你的实际需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值