打印
[其他ST产品]

STM32入门基础

[复制链接]
333|47
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
GPIO
<1>说明
· 引脚电平:0~3.3V,部分可达到5V(参考引脚定义,带FT的就可以)

同时 GPIO有两个模式

输出模式:进行端口高低电平的输出,用于驱动LED,蜂鸣器等

输入模式:读取端口高低电平的电压/电平,用于按键输入,ADC电压采集等

<2>基本结构


APB2外设时钟总线,所有的GPIO都是挂载再APB2上的,其中GPIO的名称是按照GPIO A/B/C来命名的,每个外设都有15个引脚,编号为0~15

使用特权

评论回复
沙发
为你转身|  楼主 | 2023-7-30 15:50 | 只看该作者
<3>GPIO模式

使用特权

评论回复
板凳
为你转身|  楼主 | 2023-7-30 15:50 | 只看该作者
GPIO库函数编码
(1)使用RCC开启GPIO的时钟

(2)使用GPIO_Init()初始化GPIO

(3)使用输出/输入函数控制GPIO口

使用特权

评论回复
地板
为你转身|  楼主 | 2023-7-30 15:50 | 只看该作者
一个涉及到RCC和GPIO两个外设

1.常用的RCC外设时钟控制函数 AHB/APB2/APB1(最主要就这三个,其他几乎不用)
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

使用特权

评论回复
5
为你转身|  楼主 | 2023-7-30 15:50 | 只看该作者
2.GPIO库函数
// 参数写入GPIOX,所指定的GPIO外设就会被复位
void GPIO_DeInit(GPIO_TypeDef* GPIOx);

//可以复位AFIO外设
void GPIO_AFIODeInit(void);

//GPIO初始化函数,我们需要先定义一个结构体变量,然后赋值,最后调用这个函数
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

//可以把结构体变量变成一个默认值
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);

/***********下面四个为GPIO的读取函数********/
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

/*************读写GPIO口的函数**************/
//设置指定的端口为高电平
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//设定指定的端口为低电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//前面的参数为选择端口,最后为指定写入数据值(Bit_SET  / Bit_RESET)
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);


//剩下的这些我们现在还不会用到
//锁定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);

//EXTI GPIO开启
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);

使用特权

评论回复
6
为你转身|  楼主 | 2023-7-30 15:50 | 只看该作者
3,开启流程(GPIO初始化)
//1.开启RCC外设
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  /*uint32_t RCC_APB2Periph*/, ENABLE);

//2.开启GPIO
GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //选择模式
/*AIN模式输入,IN_FLOATING浮空输入,IPD下拉输入,IPU上拉输入
OUT_OD开漏输出(低电平有驱动力,高电平没有),PUT_PP推挽输出,AF则为复用 */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;        //选择引脚

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//选择频率

GPIO_Init(GPIOA, &GPIO_InitStructure);           //初始化

使用特权

评论回复
7
为你转身|  楼主 | 2023-7-30 15:51 | 只看该作者
EXTI中断函数
<1>中断
中断 : 在主程序运行过程中,出现特定的中断触发条件,使得CPU暂停当前正在运行的程序,而去处理中断程序,完成后,又返回原来被暂停的位置继续工作

中断优先 : 当有多个中断开始时,CPU会根据事情的轻重响应更加紧急的中断

中断嵌套 : 一个中断正常进行,又来一个更高级的中断,会先去做刚来的高级的中断,然后依次返回

使用特权

评论回复
8
为你转身|  楼主 | 2023-7-30 15:52 | 只看该作者
<2>NVIC
68个可屏蔽中断通道,包含EXTI,TIM,ADC,USART,SPI,IIC,RTC等多个外设

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

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

使用特权

评论回复
9
为你转身|  楼主 | 2023-7-30 15:52 | 只看该作者
<3>EXTI:(Extern Interrupt)外部中断
EXTI可以检测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序

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

支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断

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

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

使用特权

评论回复
10
为你转身|  楼主 | 2023-7-30 15:52 | 只看该作者

AFIO选择中断引脚,外部中断的9-5,15-10会触发同一个中断函数,再根据标志位来区分到底是哪个中断进来的

配置数据选择器,只有一个Pin接到EXTI  

使用特权

评论回复
11
为你转身|  楼主 | 2023-7-30 15:53 | 只看该作者
<4>配置步骤:
第一步,配置RCC,把设计到的外设时钟都打开

第二步,配置GPIO,选择端口为输入模式

第三步,配置AFIO,选择使用的一路GPIO,连接到后面的EXTI

第四步,配置EXTI,选择边沿触发方式,选择触发响应方式

第五步,配置NVIC,给中断选择一个合适的优先级

使用特权

评论回复
12
为你转身|  楼主 | 2023-7-30 15:53 | 只看该作者
<5>库函数说明

首先,EXTI本身是不需要打开什么时钟的,所以前面正常打开GPIO就可以了

AFIO也使用RCC使能

使用特权

评论回复
13
为你转身|  楼主 | 2023-7-30 15:54 | 只看该作者
void GPIO_EXTILineConfig(GPIO_PortSourceGPIOB /*引脚所在的源*/,GPIO_PinSource14 /*第14个中断线路);

使用特权

评论回复
14
为你转身|  楼主 | 2023-7-30 15:54 | 只看该作者
这个函数,可以让14号引脚的电平顺利通过AFIO,进入到后级EXTI电路中

EXTI库函数:
//调用他,可以清除EXTI的配置,恢复为默认的上电状态
void EXTI_DeInit(void);

//初始化EXTI,方法与GPIO相同
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

//参数传递的结构体变量赋一个默认值
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);

使用特权

评论回复
15
为你转身|  楼主 | 2023-7-30 15:54 | 只看该作者
EXTI_Init参数
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//选择中断线路
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);///选择自己的引脚相同线路就好
       
        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);//写入参数

使用特权

评论回复
16
为你转身|  楼主 | 2023-7-30 15:55 | 只看该作者
NVIC内核外设库函数
//中断分组,参数是中断分组的方式
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);

使用特权

评论回复
17
为你转身|  楼主 | 2023-7-30 15:55 | 只看该作者
分组在整个流程中只要进行一次就可以了,如果模块化要注意选择是同一个,可以选择放在主函数里

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组

使用特权

评论回复
18
为你转身|  楼主 | 2023-7-30 15:55 | 只看该作者
NVIC结构体初始化内容
        //我们选择了两个分组,那么我们就配置两个
    NVIC_InitTypeDef NVIC_InitStructure;//定义NVIC结构体
        NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//设置中断通道
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//通道使能
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级
        NVIC_Init(&NVIC_InitStructure);//写入参数



        NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//设置中断通道
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//通道使能
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//响应优先级
        NVIC_Init(&NVIC_InitStructure);//写入参数

使用特权

评论回复
19
为你转身|  楼主 | 2023-7-30 15:55 | 只看该作者
中断服务函数

在STM32中,每个通道的中断服务函数名字都是固定的
void EXTI0_IRQHandler(void)//线路0中断函数
void EXTI1_IRQHandler(void)//线路1中断函数

使用特权

评论回复
20
为你转身|  楼主 | 2023-7-30 15:55 | 只看该作者
获取标志位

if (EXTI_GetITStatus(EXTI_Line0) == SET)//判断中断挂起位

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

625

帖子

0

粉丝