先讲讲AFIO,其实这个不难,主要功能就是复用重映射引脚和链接外部中断引脚。
1、先讲讲复用引脚重映射,我们的板子上有许多引脚,也有许多外设,也有对应的外设引脚,未免会有一些引脚拥有多种功能,比如说定时器的引脚和uart的引脚共用,如果我们需要同时用到,可以使用AFIO将某一个引脚映射到其他引脚使用,举个例子:
我们此时可以通过AFIO去将PA9,PA10映射到PB6,PB7,这就是AFIO的其中一个作用。寄存器的话,我建议自己去翻数据手册。记得先使能AFIO时钟。
优先级这一块要了解
NVIC:管理中断,选择中断源,设置优先级组,中断仲裁(多个中断就绪的时候,按照优先级来选择)
一个demo,NVIC的寄存器配置比较抽象一些,要先配置SCB->AIRCR设置优先级组
这边是一个极简写法,详细在NVIC_Init函数实现里面,其他寄存器对着手册配就好。
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" void gpio_init(){ //开启GPIOA的时钟 RCC->APB2ENR |= (1ul << 2); //PA0浮空输入0100 GPIOA->CRL &= ~(0x0F << (4 * 0)); GPIOA->CRL |= (0x04 << (4 * 0)); //PA5推挽输出0011 GPIOA->CRL &= ~(0x0F << (4 * 5)); GPIOA->CRL |= (0x03 << (4 * 5)); } void afio_exti_init(){ //开启AFIO时钟 RCC->APB2ENR |= (1ul << 0); //AFIO_EXTICR1,操作低四位EXTI0[3:0],然后选择PA0 AFIO->EXTICR[0] &= ~(0x0F << (4 * 0)); //开放来自线0上的中断请求 EXTI->IMR |= (1ul << 0); //允许输入线0上的下降沿触发 EXTI->FTSR |= (1ul << 0); } void nvic_init(){ //优先级组,2位抢占优先级,2位子优先级 SCB->AIRCR |= (0x5FA << 16) | (1ul << 10) | (1ul << 8); SCB->AIRCR &= ~(1ul << 9); //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /*设置优先级,抢占优先级2,子优先级1,这里是我本人知道优先级组2,2的情况,如果是其他优先级组的话,参考官方写法。 如果是3,1的话:NVIC->IP[6] = ((2 << 1) | 1) << 4;抢占只左移一位,4个位置占三个,就有0~7可选,子优先级只有1位,只有0~1可选 */ NVIC->IP[6] = ((1 << 2) | 1) << 4; //开启EXTI0_IRQn中断,注意查看中断号,数组下标为中断号/32,后面为中断号对32取余,以此类推 NVIC->ISER[0] |= (1ul << 6); // NVIC_InitTypeDef NVIC_InitStruct; // NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; //中断响应函数 // NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级 // NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //子优先级 // NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //使能中断 // // NVIC_Init(&NVIC_InitStruct); } void led_toggle(){ if(GPIOA->ODR & (1ul << 5)){ GPIOA->BSRR = (1ul << 21); } else{ GPIOA->BSRR = (1ul << 5); } } void EXTI0_IRQHandler(){ if(EXTI->PR & (1ul << 0)){ led_toggle(); //清除中断标志位 EXTI->PR |= (1ul << 0); } } int main(void) { gpio_init(); afio_exti_init(); nvic_init(); while (1) { } }