江协STM32笔记(二)

这边建议看我这篇笔记的话不如去看江协的课程:

OLED

OLED(Organic Light Emitting Diode):有机发光二极管

供电:3~5.5V,通信协议:I2C/SPI,分辨率:128*64

然后这边是江协给的库函数文件,我也没改也没看,直接拿过来用:

image.png image.png

中断

概念

中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行

中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源

在stm32里面中断优先级会有很多的分类,然后根据这个分类来配置具体的中断优先级。

中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回 image.png

stm32中断

包含68个可屏蔽中断通道(即中断源,这个68个是F1系列的上限,具体的还要看型号是多少个),包含EXTI(外部中断,即外设控制的中断)、TIM、ADC、USART、SPI、I2C、RTC等多个外设

image.png image.png image.png

使用NVIC(嵌套中断向量控制器)统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级

其中抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队

NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级

image.png
image.png

EXTI、AFIO

EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序

如果CPU是医生,NVIC就是叫号机,然后EXTI就是护士站里面负责观察情况叫号排号的。

支持的触发方式:上升沿/下降沿/双边沿/软件触发

支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断,具体的原因实际上是因为AFIO是个数据选择器,在相同的Pin下只能从GPIOA

而具体的AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择

通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒

触发响应方式:中断响应/事件响应

中断响应就是正常的触发CPU进行处理,而事件响应就是触发别的外设对来的这个事件进行响应。

后面四个是因为EXTI有能够从低功耗模式下唤醒的功能,然后顺便加上的功能

下面这个图是做外部中断时候的重中之重,记住他就记住了总体怎么配置怎么写:

image.png

硬件模块

旋转编码器

旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向

类型:机械触点式/霍尔传感器式/光栅式

然后我们使用的旋转编码器的具体阴间电路如下

image.png

库函数介绍

stm32f10x_exti

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void EXTI_DeInit(void);
//重置exti为上电之后的默认状态,即缺省值
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
//初始化exti
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
//给该结构体默认值,即按照缺省值填入参数
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
//产生一个软件中断,参数的意味是使能或者失能这个线路中断
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
//检查标志位设置与否
void EXTI_ClearFlag(uint32_t EXTI_Line);
//挂起标志位
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
//检查这个线路是否发生了中断触发
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//清除挂起位

misc.h

1
2
3
4
5
6
7
8
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);
//系统低功耗配置
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);

程序编写

初始化

具体就是从这个GPIO到NVIC一条线路配置调通就好。

首先是RCC配置外部时钟,这个配置AFIO和GPIO的就够了,其中NVIC和EXTI的时钟不用我们配置,具体原因EXTI不知道,NVIC是因为他是内核的外设,RCC管不到。

1
2
3
4
5
6
7
8
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);

然后是配置AFIO的端口,具体为:

1
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);

然后初始化EXTI给连接上,这个函数来自于 stm32f10x_exti.c

1
2
3
4
5
6
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line14;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStruct);

配置优先级分组

1
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

初始化NVIC

1
2
3
4
5
6
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruct);

中断函数

具体而言就是从 startup_stm32f10x_md.c找这个中断向量表,这个中断函数都名称都是定好的

其中中断向量表是位于内存固定位置的一个数组。其每个表项(称为中断向量)存储着特定中断号对应的中断服务程序(ISR)的入口地址。当 CPU 接收到中断请求并获取中断号后,硬件自动以该中断号为索引访问此表,获取对应的 ISR 入口地址并跳转执行,从而实现快速、准确的中断处理。

这里的用的是下面的这个,注意还要判别一下这个标志位:

1
2
3
4
5
6
7
8
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line14) == SET)
{
CountSonser_Count++;
EXTI_ClearITPendingBit(EXTI_Line14);
}
}

江协STM32笔记(二)
http://example.com/2025/08/12/嵌入式/江协STM32入门/江协STM32笔记(二)/
作者
ZHW
发布于
2025年8月12日
许可协议