[其他ST产品] STM32入门基础

[复制链接]
1195|47
 楼主| 为你转身 发表于 2023-7-30 15:49 | 显示全部楼层 |阅读模式
GPIO
<1>说明
· 引脚电平:0~3.3V,部分可达到5V(参考引脚定义,带FT的就可以)

同时 GPIO有两个模式

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

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

<2>基本结构
2261464c6161005eb8.png

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

 楼主| 为你转身 发表于 2023-7-30 15:50 | 显示全部楼层
<3>GPIO模式

2732664c616285dae9.png
 楼主| 为你转身 发表于 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(最主要就这三个,其他几乎不用)
  1. void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
  2. void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
  3. void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
 楼主| 为你转身 发表于 2023-7-30 15:50 | 显示全部楼层
2.GPIO库函数
  1. // 参数写入GPIOX,所指定的GPIO外设就会被复位
  2. void GPIO_DeInit(GPIO_TypeDef* GPIOx);

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

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

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

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

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


  22. //剩下的这些我们现在还不会用到
  23. //锁定GPIO配置
  24. void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

  25. //配置AFIO的事件输出功能函数
  26. void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
  27. void GPIO_EventOutputCmd(FunctionalState NewState);

  28. //配置引脚重映射函数
  29. void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

  30. //EXTI GPIO开启
  31. void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
  32. void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);
 楼主| 为你转身 发表于 2023-7-30 15:50 | 显示全部楼层
3,开启流程(GPIO初始化)
  1. //1.开启RCC外设
  2. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  /*uint32_t RCC_APB2Periph*/, ENABLE);

  3. //2.开启GPIO
  4. GPIO_InitTypeDef GPIO_InitStructure;

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

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

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

  10. GPIO_Init(GPIOA, &GPIO_InitStructure);           //初始化
 楼主| 为你转身 发表于 2023-7-30 15:51 | 显示全部楼层
EXTI中断函数
<1>中断
中断 : 在主程序运行过程中,出现特定的中断触发条件,使得CPU暂停当前正在运行的程序,而去处理中断程序,完成后,又返回原来被暂停的位置继续工作

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

中断嵌套 : 一个中断正常进行,又来一个更高级的中断,会先去做刚来的高级的中断,然后依次返回
4092964c616751ed1b.png
 楼主| 为你转身 发表于 2023-7-30 15:52 | 显示全部楼层
<2>NVIC
68个可屏蔽中断通道,包含EXTI,TIM,ADC,USART,SPI,IIC,RTC等多个外设

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

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

8203864c616c1e18a5.png
 楼主| 为你转身 发表于 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唤醒、以太网唤醒

触发响应方式:中断响应/事件响应
 楼主| 为你转身 发表于 2023-7-30 15:52 | 显示全部楼层
4816864c616d26bf2a.png
AFIO选择中断引脚,外部中断的9-5,15-10会触发同一个中断函数,再根据标志位来区分到底是哪个中断进来的

配置数据选择器,只有一个Pin接到EXTI  
 楼主| 为你转身 发表于 2023-7-30 15:53 | 显示全部楼层
<4>配置步骤:
第一步,配置RCC,把设计到的外设时钟都打开

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

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

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

第五步,配置NVIC,给中断选择一个合适的优先级
 楼主| 为你转身 发表于 2023-7-30 15:53 | 显示全部楼层
<5>库函数说明

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

AFIO也使用RCC使能
6206264c616ef4f449.png
 楼主| 为你转身 发表于 2023-7-30 15:54 | 显示全部楼层
  1. void GPIO_EXTILineConfig(GPIO_PortSourceGPIOB /*引脚所在的源*/,GPIO_PinSource14 /*第14个中断线路);
 楼主| 为你转身 发表于 2023-7-30 15:54 | 显示全部楼层
这个函数,可以让14号引脚的电平顺利通过AFIO,进入到后级EXTI电路中

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

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

  5. //参数传递的结构体变量赋一个默认值
  6. void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);

  7. //软件触发外部中断
  8. void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);


  9. //下面为模板函数
  10. //读写中断标志位
  11. FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
  12. //清楚中断标志
  13. void EXTI_ClearFlag(uint32_t EXTI_Line);
  14. //只能读写中断标志位
  15. ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
  16. void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
 楼主| 为你转身 发表于 2023-7-30 15:54 | 显示全部楼层
EXTI_Init参数
  1.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//选择中断线路
  2.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);///选择自己的引脚相同线路就好
  3.        
  4.         EXTI_InitTypeDef EXTI_InitStructure;//定义外部中断结构体
  5.         EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;//设置中断线
  6.         EXTI_InitStructure.EXTI_LineCmd = ENABLE;//开启中断线路
  7.         EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
  8.         EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
  9.         EXTI_Init(&EXTI_InitStructure);//写入参数
 楼主| 为你转身 发表于 2023-7-30 15:55 | 显示全部楼层
NVIC内核外设库函数
  1. //中断分组,参数是中断分组的方式
  2. void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

  3. // NVIC初始化函数,根据结构体参数初始化
  4. void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);


  5. void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
  6. //系统低功耗配置
  7. void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);

  8. void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
 楼主| 为你转身 发表于 2023-7-30 15:55 | 显示全部楼层
分组在整个流程中只要进行一次就可以了,如果模块化要注意选择是同一个,可以选择放在主函数里

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
 楼主| 为你转身 发表于 2023-7-30 15:55 | 显示全部楼层
NVIC结构体初始化内容
  1.         //我们选择了两个分组,那么我们就配置两个
  2.     NVIC_InitTypeDef NVIC_InitStructure;//定义NVIC结构体
  3.         NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//设置中断通道
  4.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//通道使能
  5.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
  6.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级
  7.         NVIC_Init(&NVIC_InitStructure);//写入参数



  8.         NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//设置中断通道
  9.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//通道使能
  10.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
  11.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//响应优先级
  12.         NVIC_Init(&NVIC_InitStructure);//写入参数
 楼主| 为你转身 发表于 2023-7-30 15:55 | 显示全部楼层
中断服务函数

在STM32中,每个通道的中断服务函数名字都是固定的
  1. void EXTI0_IRQHandler(void)//线路0中断函数
  2. void EXTI1_IRQHandler(void)//线路1中断函数
 楼主| 为你转身 发表于 2023-7-30 15:55 | 显示全部楼层
获取标志位

if (EXTI_GetITStatus(EXTI_Line0) == SET)//判断中断挂起位
您需要登录后才可以回帖 登录 | 注册

本版积分规则

82

主题

741

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部