第五章第二节 对射式红外传感器计次旋转编码器计次
一、对射式红外传感器计次
① 外部中断(EXTI) 初始化
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line14;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
(1) 功能:配置外部中断线14的参数
(2) 逐行解释:
- EXTI_InitTypeDef EXTI_InitStructure:定义 EXTI 配置结构体
- EXTI_Line = EXTI_Line14:选择中断线14
- EXTI_Mode = EXTI_Mode_Interrupt:设置为中断模式
- EXTI_Trigger = EXTI_Trigger_Falling:关键设置-下降沿触发
- EXTI_Linecmd = ENABLE:使能此中断线
- EXTI_Init(&EXTI_InitStructure):应用配置
② NVIC 配置分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
(1) 中断优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
- 将4位优先级分成:2位用于抢占优先级(可设置0-3),2位用于子优先级(可设置0-3)
- 抢占优先级高的中断可以打断正在执行的抢占优先级低的中断(抢占式)
- 相同抢占优先级时,子优先级决定执行顺序(非抢占)
(2) 中断通道选择
NVIC_IRQChannel = EXTI15_10_IRQn;
- 外部中断线 10-15 共享同一个中断通道
③ main.c 模块
int main(void)
{// 初始化OLED显示屏和计数器传感器OLED_Init();CountSensor_Init();// 在OLED屏幕第一行第一列显示"Count:"文本OLED_ShowString(1, 1, "Count:");// 进入无限循环,持续更新显示while (1){// 在屏幕第一行第七列显示计数器的数值// 参数说明:// 1 - 显示在第一行// 7 - 从第7列开始显示// CountSensor_Get() - 获取传感器计数值// 5 - 显示5位数字OLED_ShowNum(1, 7, CountSensor_Get(), 5);}
}
(1) OLED_ShowNum(1, 7, CountSensor_Get(), 5):包含多层功能:
- CountSensor_Get():调用获取当前计数值的函数
- 将获取的数值显示在屏幕第一行第七列
- 5:显示总位数为5位(如数值23显示为“00023”)
二、旋转编码器计次
1. 中断服务函数(核心逻辑)
(1) 全局变量声明
int16_t Encoder_Count; // 全局计数器,记录编码器转动步数
① 为什么选择 int16_t,而不是 uint16_t?
- 旋转编码器需要表示两个旋转方向:正数为顺时针转动(增加数值),负数(减少数值)
(2) 编码器数值获取函数
int16_t Encoder_Get(void)
{int16_t Temp; // 声明临时变量Temp = Encoder_Count; // 读取当前计数值Encoder_Count = 0; // 立即清零计数器(用于下次测量)return Temp; // 返回读取的计数值(此方向转动步数)
}
① 核心功能:
- 读取当前计数值 → Temp = Encoder_Count
- 立即清零计数器 → Encoder_Count = 0
- 返回读取值 → return Temp
② 工作流程示例:
时间点 | 动作 | Encoder_Count |
初始状态 | 编码器开始旋转 | 0 |
旋转5步后 | 5 | |
调用函数 | Temp = 5; Encoder_Count = 0 | 0 → 返回5 |
再旋转3步 | 3 | |
调用函数 | Temp = 3; Encoder_Count = 0 | 0 → 返回3 |
(3) 检测编码器旋转方向并计数
void EXTI0_IRQHandler(void)
{// 确认是否发生Line0中断if (EXTI_GetITStatus(EXTI_Line0) == SET) {// 读取B相电平(关键:方向判断)if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) {Encoder_Count--; // B相为低电平时逆时针转动}EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志}
}