入门STM32--GPIO(跑马灯)(保姆级别)

目录

前言

一、GPIO是什么?

二、GPIO干什么

三、GPIO怎么干

三、如何用GPIO点亮一个LED灯

        1.  GPIO_InitTypeDef 

2.GPIO_Init   

3.RCC_APB2PeriphClockCmd

四、初始化

五、合成

延时

头文件

初始化

六、两个灯


前言

这也是比较简单的一部分,我们就从这里正式开始咱们的32之路。

typedef 

结构体 

枚举 

上面这些是基础,如果想看懂程序,了解即可。 

一、GPIO是什么?

所有的嵌入式处理器内部均集成了通用输入输出(General Purpose Input Output,GPIO)接口,通俗地讲呢,其实就是你的开发版上面的插针,那个东西就是和你的单片机上面的IO口(GPIO)连起来了(连起来好用,方便开发)。 STM32的IO口被分成了若干组,PA、PB、PC等,每一组有16个管脚,PA0、PA1、PA2、PA3等等。

二、GPIO干什么

从 Output Input 这两个单词也可以看出来,他是做输入输出作用的。

我们的单片机一般就是做主控,来控制其他电路或者是电机,既然是控制肯定就要输出控制信号,所以说就需要IO口,来做输出。同样,单片机肯定也需要外部的信息,所以说也需要输入功能。

 最基本的输出功能是由STM32控制引脚输出高、低电平,实现开关控制,如把GPIO引脚接入到LED灯,那就可以控制LED灯的亮灭,引脚接入到继电器或三极管,那就可以通过继电器或三极管控制外部大功率电路的通断。

三、GPIO怎么干

简单地说一下,这个图呢可以被分为两部分, 上面是输入,下面是输出。

从右往左看,先是引脚然后是保护二极管(作用是保护你的管脚不会被一个比3V3该有可能是5V高一点,或者比0V低一点的电压伤害,但要记住是一点),让后就分别进入到两个部分。

输入部分是,进入后经过上拉或者下拉电阻,然后是TTL肖特基触发器(TTL肖特基触发器其实可以理解为用肖特基管构成的施密特触发器,作用简单说就是将相对缓慢变化的模拟信号变成矩形信号,便于后面读取。)然后就可以被读取。

输出部分,是经过MOS管的导通与断开来控制输出电平的高低。可以看到,输出最高电平时VDD(单片机工作电压,2.0~3.6V,一般是3.3V),最低电平是Vss(单片机电源地,0V)。

三、如何用GPIO点亮一个LED灯

 毫无疑问,我们肯定需要写代码嘛,通过我们写的代码,告诉单片机我们想干的事。

如果我们选择的功能是输入,那么我们需要的就是读取相关寄存器(可以理解为一个存储器,我们可以往里面写数,就可以控制单片机。同样,单片机的一些数据也存放在这里。)的值,就可以的得到相关IO口的电平,如果我们选择的是输出,我们需要做的就是控制MOS管的导通和关闭。

首先我们要做的确定我们要使用的IO口,我们应该查找原理图,然后找到LED灯对应的管脚。

 

我们可以看到,LED0对应的是PB5这个管脚,下面要做的就是写程序了。 

1.  GPIO_InitTypeDef 

 首先,我们要定义一个结构体,上面有提到,我们是通过往寄存器里面写数字来控制单片机,寄存器转化到程序里面被分成了许多结构体,我们要往里面写数字,也要通过结构体的方式。

 GPIO_InitTypeDef  GPIO_InitStructure;

 这个 GPIO_InitTypeDef是通过typedef得到的一个宏定义,方便用它来定义结构体中的变量和GPIO寄存器类型结构相符合结构体。后面的那个GPIO_InitStructure就是我们定义的结构体(名字随意,我学习的时候就叫这个)。

typedef struct
{
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

下面让我们来分析这个结构体里面的成员,

1. GPIO_Pin的意思是哪个管脚,例如GPIO_Pin_5,代表的是PX5这个管脚,其中X=A、B、C、D等。

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

2.GPIOSpeed_TypeDef GPIO_Speed,这里是一个的枚举定义,前面是枚举的类型,后面是枚举的名字。

GPIO 引脚速度: GPIO_Speed_2MHz     (10MHz, 50MHz) ;

又称输出驱动电路的响应速度:(芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路,通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。)

简单的理解就是,IO口的响应速度。

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

typedef enum
{ 
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

 3.GPIOMode_TypeDef GPIO_Mode显而易见,这里又是一个枚举的定义,前面是类型,后面是名称。

typedef enum
{ GPIO_Mode_AIN = 0x0,
  GPIO_Mode_IN_FLOATING = 0x04,
  GPIO_Mode_IPD = 0x28,
  GPIO_Mode_IPU = 0x48,
  GPIO_Mode_Out_OD = 0x14,
  GPIO_Mode_Out_PP = 0x10,
  GPIO_Mode_AF_OD = 0x1C,
  GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;

这里有不同的模式,如果我们选择输出的话,GPIO_Mode_Out_PP就是我们想要的,叫推挽输出,还有很多种方式,我就不细讲了,可以参考其他文章。

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

2.GPIO_Init   

当我们配置好上面的结构体成员后,我们就完成了大部分,但是还没有结束,你会发现,我们只是把我们的定义的结构体里面的值确定了,并没有放到单片机的寄存器里面,这时候肯定不行啊。

怎么放进去呢,别人在就想到了这一点,直接调用函数就可以了。

GPIO_Init(GPIOB, &GPIO_InitStructure); 

 可以看到,这个函数需要输入两个参数,一个就是A、B、C、D等,确定我们要控制哪一组管脚。

另一个参数是我们定义的结构体的地址。

举一个例子,我们定义的结构体就更好比是一个包裹,这个函数就是快递员,我们要告诉的我们寄哪个快递,寄到哪。

到这你可能感觉差不多了,其实还没有。我们是不是要告诉收快递的那个人,你有快递了,怎么告诉呢,来一句函数就OK了。

3.RCC_APB2PeriphClockCmd

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   

 可以看到,这个函数也有两个参数,第一个参数是使能哪一组管脚的时钟,第二个管脚是使能(ENABLE)。
使能外设时钟的原因https://blog.csdn.net/weixin_43217963/article/details/97792677注意:一定要先使能PB端口的时钟然后在配置GPIO

void GPIO_Init(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PB端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				 //PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
 GPIO_SetBits(GPIOB,GPIO_Pin_5);						 //PB.5 输出高
}

四、初始化

初始化是一个比较重要的问题,很多新手在经历过千难万险把函数写好之后,把程序下进去,发现灯不亮。BBQ了,大部分原因都是初始化的原因。

 可能很多新手创建了一个新的文件LED,里面有 led.c 和 led.h 这两个文件,把自己写的函数放到led.c里面了,这样也是可以的,不过大可不必,我还是建议直接写到 main.c 这个文件里面,毕竟我们只是点个灯。

就想这样

 

 虽然没有写到 led.c里面简洁,但是初始化会方便很多(避免很多坑)。

如果你非要建立一个文件的话,千万记得在 led.h 里面声明 ,main.c文件要包括相关的头文件。

五、合成

把我们之前写的合到一起,像下面这样

 但是你会发现,灯是一直在亮,这是因为单片机的执行速度的是很快的,一瞬间就完成了高低电平的设置,人的肉眼反应不过来。

所以需要延时函数,就是让灯等一会亮,也等一会灭。

延时

延时的方法有两种,第一种是我们可以直接调用延时函数(别人写好的函数),也可以自己写一个循环进行延时。

我们就是用第一种吧,需要做的就是包括对应的头文件,和初始化延时函数。

头文件

直接在主函数里面包括就行

 初始化

加上一句 delay_init(); 即可

delay_ms(200); 就是延时200毫秒

delay_ms(500); 就是延时500毫秒

注意:单次延时时间不能超过1864ms

把延时函数加上后

灯就闪了起来 ~~~

六、两个灯

就像这样

 

 简单讲解一下,首先就是端口时钟多了一个PE的,直接使用一个函数就可以,但是注意有一个 或 的步骤。

第二个地方就是,在配置PE5时,仍然使用了上一次的结构体。因为第二个灯也是五号管脚,不需要做其他修改。

第三个地方就是主函数,这里也很简单,就是多了两句话。

  • 60
    点赞
  • 161
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苦瓜人生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值