叠甲
大家理性讨论 我要是作为一个初学者分享自己的学习思路 如果有说错的地方欢迎大家和我说
这个学习心得是基于b站一up的视频学习过程中一些问题得来的 我会将视频链接放在下面 大家可以去看完视频 如果有不懂的朋友再回来看我这个文章或许会解答你学习中的疑惑
大卫-史密斯的个人空间-大卫-史密斯个人主页-哔哩哔哩视频 (bilibili.com)
第二天 我们开始配置gpio 以及中断
配置gpio输出高低电平
首先我们配置gpio 先要了解他的大概结构 可能大家和我一样是初学者看手册非常的困难 所以我给大家说一下如何快速理解那么配置参数
GPIO_Pin:这个就是你要用哪个引脚
GPIO_Mode:这个就是你要用哪种模式 一共有4种模式:输入 ,输出, 复用(就是将使用权给其他硬件)模拟输入,
GPIO_OType:这个直接配置为 GPIO_OType_PP 基本上百分之99.99都使用这个模式 因为推挽输出的驱动能力非常强 不要管就配置这个模式
GPIO_PuPd:这个配置要不要上拉或者下拉 或者不拉 怎么配置呢 当你引脚外接设备时候电压是稳定的就可以不拉 但如果你外接设备时候电压不稳定 那么就可以上拉或者下拉 他们两的区别就是你引脚没工作时候上拉默认为高电平 下拉默认为低电平
GPIO_Speed:配置引脚响应速度 这个看你需求
这样我们的引脚就配置好了
但是最重要的一点是配置设备时候的思想是
第一步打开设备对应的硬件时钟
第二步配置设备的结构体 然后初始化
第三步使能设备(有些需要有些不需要)
在32的配置过程中基本上全是套用这个模式 所以这个思想比gpio的具体配置要重要 这个思想一直在smt32的学习中延续
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;
GPIO_Init(GPIOB,&GPIO_InitStruct);
这里我将 3 4 5引脚配置为复用模式 推挽输出 无上下拉 高速模式
配置一个外部中断
我要配置一个当某个引脚电平发生变化时候产生中断 应该如何配置
你要配置外部中断 那么你就要接收信号 那么就要将引脚配置为输入模式来接收外面来的信 号 我exit可以和和pa1 pb1 pc1 连接 那么我这个一号引脚要和谁连接呢 你要告诉我 所以就要将exit与gpio连接起来 然后你exit是产生下降沿还是上升沿触发这些就要在exit结构体里面配置了 然后就要配置nvic nvic配置他是否同意你这个中断 有可能你给一个中断申请 nvic不同意呢 当所有的配置好了就可以产生中断 但产生中断函数你要在启动文件里面去找对应中断名的函数 现在来梳理一下思路
1使能gpio时钟
2配置gpio为输入模式
3初始化gpio
4使能exit时钟
5配置exit结构体
6初始化exit
7连接exit
8配置nvic结构体
9初始化nvic
10配置中断函数
可以看见 每一步都非常的公式话 stm32后续的配置也大差不差
#include "stm32f4xx.h" // Device header
#include "sys.h"
int flag=0;
void led_init(void);
void exit_init(void);
void delay(void);
int main (void)
{
led_init();
exit_init();
while(1)
{
}
}
void EXTI0_IRQHandler(void) //外部中断0服务函数
{
//判断是否有中断请求
if(EXTI_GetITStatus(EXTI_Line0) == SET)
{
delay();
while(PAin(0) == 0);
flag++;
if(flag == 2)
{
PFout(9) = 1;
flag = 0;
}
if(flag == 1)
{
PFout(9) = 0;
}
EXTI_ClearITPendingBit(EXTI_Line0);
delay();
}
}
void EXTI2_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line2) == SET)
{
delay();
while(PEin(2) == 0);
flag++;
if(flag == 2)
{
PFout(10) = 1;
flag = 0;
}
if(flag == 1)
{
PFout(10) = 0;
}
EXTI_ClearITPendingBit(EXTI_Line2);
delay();
}
}
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3) == SET)
{
delay();
while(PEin(3) == 0);
flag++;
if(flag == 2)
{
PEout(13) = 1;
flag = 0;
}
if(flag == 1)
{
PEout(13) = 0;
}
EXTI_ClearITPendingBit(EXTI_Line3);
delay();
}
}
void EXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4) == SET)
{
delay();
while(PEin(4) == 0);
flag++;
if(flag == 2)
{
PEout(14) = 1;
flag = 0;
}
if(flag == 1)
{
PEout(14) = 0;
}
EXTI_ClearITPendingBit(EXTI_Line4);
delay();
}
}
void delay(void)
{
int i;
int j;
for( i=1000 ; i>0 ; i--)
for( j=10000 ; j>0 ; j--);
}
void led_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //创建引脚配置结构体
//使能端口 给他通电
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF , ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE , ENABLE);
//配置gpio引脚模式
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10; //引脚号为10和9
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT; //配置为输出模式
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP; //配置为推挽输出
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL; //配置无上拉无下拉
GPIO_InitStruct.GPIO_Speed=GPIO_Medium_Speed; //配置引脚速度
GPIO_Init(GPIOF,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_14; //引脚号为10和9
GPIO_Init(GPIOE,&GPIO_InitStruct);
}
void exit_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //创建引脚配置结构体
EXTI_InitTypeDef EXTI_InitStruct; //创建外部中断结构体
NVIC_InitTypeDef NVIC_InitStruct; //创建nvic结构体 用于配置优先级中断优先级一些参数
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE);//使能A端口时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE , ENABLE);//使能端口时钟
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组
//配置gpio引脚模式
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0; //选择pa0号引脚
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN; //配置为输入模式
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP; //配置无上拉无下拉
GPIO_InitStruct.GPIO_Speed=GPIO_Medium_Speed; //配置引脚速度
GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化gpioa的0号引脚
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4; //选择pe2 3 4号引脚
GPIO_Init(GPIOE,&GPIO_InitStruct); //初始化gpioE的2 3 4号引脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG , ENABLE);//使能系统配置控制器的时钟
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA , EXTI_PinSource0); //将PA0与exit0连接起来
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE , EXTI_PinSource2); //将PE2与exit2连接起来
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE , EXTI_PinSource3); //将PE3与exit3连接起来
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE , EXTI_PinSource4); //将PE4与exit4连接起来
EXTI_InitStruct.EXTI_Line=EXTI_Line0 |EXTI_Line2 |EXTI_Line3 | EXTI_Line4; //配置外部中断为exti_0
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //配值exit_0的模式为外部中断
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //触发方法为下降沿触发 (EXTI_Trigger_Rising:上升沿触发 EXTI_Trigger_Falling:下降沿触发 EXTI_Trigger_Rising_Falling:双边沿触发)
EXTI_InitStruct.EXTI_LineCmd=ENABLE; //使能exit_0 2 3 4;
EXTI_Init(&EXTI_InitStruct); //初始化exit_0 2 3 4
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0x03; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority=0x03; //响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能
NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn ; //打开外部中断0的请求通道
NVIC_Init(&NVIC_InitStruct); //初始化外部中断通道
NVIC_InitStruct.NVIC_IRQChannel=EXTI2_IRQn ; //打开外部中断2的请求通道
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel=EXTI3_IRQn; //打开外部中断3的请求通道
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel=EXTI4_IRQn; //打开外部中断4的请求通道
NVIC_Init(&NVIC_InitStruct);
}
定时器延时函数
这里直接使用就可以了 哪里需要就复制到哪里
void colock_ms(uint32_t x)
{
while(x--)
{
SysTick->CTRL = 0; // 关闭系统定时器 这一步用来配置接下来的系统定时器的值
SysTick->LOAD = 168000; // 配置计数值
SysTick->VAL = 0; // 清空计数标志位 防止使用之前没有清空从而导致计数错误
SysTick->CTRL = 5; // 5:0 1 0 1
// 这个一表示使用的时钟源是系统时钟源 如果这个值是0表示使用的是系统时钟源/8分频的时钟源
// 这个一表示使能系统时钟源
while ((SysTick->CTRL & 0x00010000)==0); // 判断这个标志位是否为1 如果到1了代表时间到了 没有就一直循环
}
SysTick->CTRL = 0; // Disable SysTick //关闭系统定时器
}
void colock_us(uint32_t x)
{
SysTick->CTRL = 0; // 关闭系统定时器 这一步用来配置接下来的系统定时器的值
SysTick->LOAD = (168)*x; // 配置计数值
SysTick->VAL = 0; // 清空计数标志位 防止使用之前没有清空从而导致计数错误
SysTick->CTRL = 5; // 5:0 1 0 1
// 这个一表示使用的时钟源是系统时钟源 如果这个值是0表示使用的是系统时钟源/8分频的时钟源
// 这个一表示使能系统时钟源
while ((SysTick->CTRL & 0x00010000)==0); // 判断这个标志位是否为1 如果到1了代表时间到了 没有就一直循环
SysTick->CTRL = 0; // Disable SysTick //关闭系统定时器
}