//江科大stm32教程
关于EXTI知识,查看我上一篇学习笔记
1.旋转编码器
1.旋转编码器简介
1.旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向
2.类型:机械触点式/霍尔传感器式/光栅式
2.硬件电路
这里使用A相接PB0 B相接PB1 (注意引脚号要不一样)
当A相是下降沿,B相是低电平为反转; 当B相是下降沿, A相是低电平是高电平;当然,这个你可以自己在Encoder文件配置,只要符合要求;判断编码器方向在网上已有很多文章
3.接线图
4.工程
1.在Hardware新建Encoder.c和Encoder.h文件
2.Encoder.c全部代码
常规操作:开启时钟,初始化GPIO,配置AFIO,配置EXTI,配置NVIC
获取旋转次数:封装函数,用一个变量Encoder_Count(stm32函数),清除Encoder_Count
#include "stm32f10x.h" // Device header
int16_t Encoder_Count;
void Encoder_Init(void)
{
//开启GPIO时钟和AFIO时钟 EXIT和NVIC的时钟是一直打开的
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//配置GPIO
GPIO_InitTypeDef GPIO_InitStruture;
GPIO_InitStruture.GPIO_Mode = GPIO_Mode_IPU; //可以在用户手册查看需要配置的模式
GPIO_InitStruture.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruture);
//配置AFIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_Pin_0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_Pin_1);
//配置EXTI
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1; //指定要配置的中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //指定选择中断线的新状态
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //指定外部中断线的响应方式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //指定触发信号的有效边沿
EXTI_Init(&EXTI_InitStructure);
//配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //指定中断通道来开启或关闭 中等密度MD
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC状态
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定所选通道的抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定所选通道的响应优先级
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //指定中断通道来开启或关闭 中等密度MD
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC状态
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定所选通道的抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //指定所选通道的响应优先级
NVIC_Init(&NVIC_InitStructure);
}
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp = Encoder_Count;
Encoder_Count = 0;
return Temp;
}
void EXTI1_IRQHandler(void)
{
//判断B相是否为下降沿
if (EXTI_GetITStatus(EXTI_Line1) == SET)
{
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
//判断A相是否为低电平, 如果是为正转
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
{
Encoder_Count++;
}
}
//调用清除中断标志位函数
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
void EXTI0_IRQHandler(void)
{
//判断A相是否为下降沿
if (EXTI_GetITStatus(EXTI_Line0) == SET)
{
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
{
//判断B相是否为低电平,如果是则为反转
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Encoder_Count--;
}
}
//调用清除中断标志位函数
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
3.Encoder.h全部代码
#ifndef _ENCODER_H
#define _ENCODER_H
int16_t Encoder_Get(void);
void EXTI0_IRQHandler(void);
void EXTI1_IRQHandler(void);
void Encoder_Init(void);
#endif
4. mian. c 全部代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#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);
}
}
不知道为什么无法识别到反转的次数,只能识别正转的,如果有人知道的话劳烦指正
我后面会出一个调试的教程
1. 对射式红外传感器
1.对射式红外传感器的内容我在 STM32学习笔记(十)- 库函数 光敏传感器控制蜂鸣器 已经讲过了
2.对射式红外传感器 的DO连接开发板的PB14, OLED SCL接PB8, SDA接PB9
3.复制 STM32学习笔记(十一)- 库函数 驱动OLED 的文件
链接:https://pan.baidu.com/s/1qpF13BmCOtzoATwQ6xNFeg?pwd=q2f8
提取码:q2f8
4.添加CountSensor.c 和 CountSensor.h文件
5.工程
1. EXTI配置流程
1.打开RCC, 外设才能正常工作
2.配置GPIO, 选择引脚为输入模式
3.配置AFIO, 选择所用GPIO通路,连接后面的EXIT
4.配置EXTI, 选择边沿触发方式, 选择触发响应方式(中断响应/事件响应)
5. 配置NVIC, 选择合适的中断优先级
2. 相关函数
1. 配置输出模式
2.相关gpio.h函数
//复位AFIO外设
void GPIO_AFIODeInit(void);
//锁定GPIO配置
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//配置AFIO的事件输出功能
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_EventOutputCmd(FunctionalState NewState);
//引脚重映射 重映射的方式和新的状态
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
//配置AFIO的数据选择器,来选择需要的中断引脚
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
3. exti.h函数
//把exti的配置全部清除,恢复为上电默认状态
void EXTI_DeInit(void);
//结构体参数配置EXIT外设
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
//把参数传递的结构体变量赋一个默认值
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
//软件触发中断
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
//在主程序 获取指定的标志位是否被置1
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
//在主程序 对置1的标志位清除
void EXTI_ClearFlag(uint32_t EXTI_Line);
//在中断函数 获取中断标志位是否被置1
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
//在中断函数 清除中断挂起标志位
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
4. NVIC的函数在mis. h文件
//用来中断分组,参数是中断分组的方式
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
//根据结构体里面的参数初始化NVIC
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
//设置中断向量表
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
//系统低功耗配置
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
3.代码部分
1.CountSensor.c
#include "stm32f10x.h" // Device header
//用一个数字来统计中断触发的次数
uint16_t CountSensor_Count;
//初始化
void CountSensor_Init(void)
{
//开启GPIO时钟和AFIO时钟 EXIT和NVIC的时钟是一直打开的
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//配置GPIO
GPIO_InitTypeDef GPIO_InitStruture;
GPIO_InitStruture.GPIO_Mode = GPIO_Mode_IPU; //可以在用户手册查看需要配置的模式
GPIO_InitStruture.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruture);
//配置AFIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14); //我用的是PB14
//配置EXTI
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line14; //指定要配置的中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //指定选择中断线的新状态
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //指定外部中断线的响应方式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //指定触发信号的有效边沿
EXTI_Init(&EXTI_InitStructure);
//配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //指定中断通道来开启或关闭 中等密度MD,14在EXTI15_10
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC状态
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定所选通道的抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定所选通道的响应优先级
NVIC_Init(&NVIC_InitStructure);
}
//返回中断次数
uint16_t CountSensor_Get(void)
{
return CountSensor_Count;
}
//中断函数,名字固定了,在启动文件找
void EXTI15_10_IRQHandler(void)
{
//中断标志位的判断, 判断14通道是否为1
if (EXTI_GetITStatus(EXTI_Line14) == SET)
{
CountSensor_Count++;
//调用清除中断标志位函数
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
2.CountSensor.h
#ifndef _COUNT_SENSOR_H
#define _COUNT_SENSOR_H
void CountSensor_Init(void);
uint16_t CountSensor_Get(void);
//void EXTI15_10_IRQHandler(void); 中断函数不需要调用,自动执行
#endif
3. main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"
int main(void)
{
OLED_Init();
CountSensor_Init();
OLED_ShowString(1,1,"COunt:");
while(1)
{
OLED_ShowNum(1, 7, CountSensor_Get(), 5);
}
}