STM32入门开发操作记录(七)——旋转编码器计次

一、项目准备

1. 工程模板

  本篇项目所用模板包含以下模块,声明函数见头文件,模块添加和函数功能详见往期记录。
请添加图片描述

2. 器件接线

  主装置:ST-Link仿真器,STM32系统板,MB102面包板,OLED显示屏(接线详见往期记录)

  除了A15B3B4JLINK的调试端口,其他端口可随意使用。各类器件默认接线方式如下。

器件端口/电源
3.3/VCC+
GND-
Encoder-AB0
Encoder-BB1
OLED-SCLB8
OLED-SDAB9

  增加模块:旋转编码器A相 – B0端口,B相 – B1端口)
  注:可能需要对旋转编码器的引脚稍作调整才能插入面包板。
在这里插入图片描述
  旋转编码器往不同方向旋转时输出的电平变化如上所示:顺时针旋转时,B相的下降沿处,A相输出低电平逆时针旋转时,A相的下降沿处,B相输出低电平
  

二、旋转编码器模块

  与上篇同理,利用上述波形特点作为中断源,触发中断实现计数。

Encoder.c

  其中:若有多个中断,可以把优先级分组配置放在main函数内,while循环之前。取增量值的设计可以提高代码的可移植性,以便于后续的功能迁移,如测量转速等。

#include "stm32f10x.h"

int16_t Encoder_Count;		// 增量

void Encoder_Init(void)
{
	// 开启外设时钟:外设EXTI、NVIC除外,内核外设不受RCC控制
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	// 外设GPIOB
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	// 外设AFIO
	
	// 配置结构体参数
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;			// 上拉输入模式:默认高电平
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 最大速度50MHz
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;	// 中断引脚:PB0和PB1
	// 初始化B0和B1端口
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	
	// 配置中断线路:0号,1号
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
	
 	// 配置结构体参数
	EXTI_InitTypeDef EXTI_InitStructure;
 	EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;		// 0号和1号中断线路
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;					// 中断线状态:使能
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			// 中断模式	
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		// 下降沿触发
	// 初始化外部中断事件控制器
 	EXTI_Init(&EXTI_InitStructure);
	
	// 配置中断优先级:分组2
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				// 抢占/响应优先级范围:0~3
	
	// 定义结构体
	NVIC_InitTypeDef NVIC_InitStructure;
	
	// 配置结构体参数
 	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			// 中断请求通道:0号
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				// 中断请求通道状态:使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	// 抢占优先级:1	
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			// 响应优先级:1
	// 初始化嵌套中断向量控制器:0号中断请求通道
 	NVIC_Init(&NVIC_InitStructure);
	
	// 配置结构体参数
 	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;			// 中断请求通道:1号
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				// 中断请求通道状态:使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	// 抢占优先级:1	
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;			// 响应优先级:2
	// 初始化嵌套中断向量控制器:1号中断请求通道
 	NVIC_Init(&NVIC_InitStructure);
}

// 0号中断函数
void EXTI0_IRQHandler(void)
{
	// 检查0号中断线请求状态寄存器的标志位
	if(EXTI_GetITStatus(EXTI_Line0) == SET)					// 0号中断线:中断源触发
	{
		if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)	// B1端口输入低电平
		{
			Encoder_Count --;								// 反转减数
		}
		EXTI_ClearITPendingBit(EXTI_Line0);					// 重置标志位
	}
}

// 1号中断函数
void EXTI1_IRQHandler(void)
{
	// 检查中断线请求状态寄存器的标志位
	if(EXTI_GetITStatus(EXTI_Line1) == SET)					// 1号中断线:中断源触发
	{
		if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)	// B0端口输入低电平
		{
			Encoder_Count ++;								// 正转加数
		}
		EXTI_ClearITPendingBit(EXTI_Line1);					// 重置标志位
	}
}


// 获取增量值
int16_t Encoder_Get(void)
{
	int16_t Temp;			// 初始化中继变量
	Temp = Encoder_Count;	// 传递增量
	Encoder_Count = 0;		// 重置计数
	return Temp;
}

  

Encoder.h

#ifndef __ENCODER_H
#define __ENCODER_H

void Encoder_Init(void);
int16_t Encoder_Get(void);

#endif

  

三、增量计数

  建议:尽量不要在主函数和中断函数里调用同一硬件或变量,减少代码耦合性。

#include "stm32f10x.h"		// 器件模块
#include "OLED.h"			// OLED模块
#include "Encoder.h"		// 旋转编码器模块

int16_t Num;	// 增量

int main(void)
{	
	// 初始化
	OLED_Init();
	Encoder_Init();
	
	// 显示计数
	OLED_ShowString(1, 1, "Num:");
	
	while(1)
	{
		Num += Encoder_Get();
		OLED_ShowSignedNum(1, 5, Num, 5);
	}
}

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值