STM32学习笔记—外设GPIO输出(基于标准库)

        单片机的学习最简单的外设当I/O口莫属,今天就让我们简单了解一下STM32F103C8T6的I/O口相关知识吧! 

1.STM32 I/O口相关介绍

        本章要实现的是,通过控制IO口输出高低电平去点亮面包板上的两个LED,这个实验的关键在于了解怎么样可控制IO口的输出,这是学习STM32的第一步。

        STM32 的 IO 口相比 51 而言要复杂得多,所以使用起来也困难很多。 首先 STM32 的 IO 口可以由软件配置成如下 8 种模式:

1、 输入浮空

2、 输入上拉

3、 输入下拉

4、 模拟输入

5、 开漏输出

6、 推挽输出

7、 推挽式复用功能

8、 开漏复用功能

        32的每个IO口都可以独立编程,但是IO口的寄存器必须要按32位字被访问。每个IO口都由七个寄存器来控制:配置模式的 2 个 32 位的端口配置寄存器 CRL 和 CRH; 2 个 32 位的数据寄存器 IDR 和 ODR; 1 个 32 位的置位/复位寄存器BSRR;一个 16 位的复位寄存器 BRR; 1 个 32 位的锁存寄存器 LCKR。这里我们抽CRL和CRH讲解一下:

CRL 和 CRH 控制着每个 IO 口的模式及输出速率

STM32 的 IO 口位配置表如表 6.1.4 所示:

 STM32 的 IO 口位配置表如表 6.1.4 所示:

接下来让我们看看CRL的描述:

         由上图可知,该寄存器的复位值就是0x4444 4444(CNF:01 MODE:00)也就是浮空输入模式。从图中我们还可以知道的是:CRL控制的是IO口的PIN0~PIN7,MODE决定的是IO口是输入/输出以及传输速率CNF决定的是IO口输入/输出模式,也就是说每个IO口占用寄存器的四位。CRH 的作用和 CRL 完全一样,只是 CRL 控制的是低 8 位输出口,而 CRH 控制的是高 8位输出口(PIN8~PIN15)。这里我们对 CRH 就不做详细介绍了。下面我们讲解一下怎样通过固件库设置 GPIO的相关参数和输出。

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

        此函数,通过配置CRL和CRH寄存器来实现对IO口模式和传输速率的控制以及GPIOx_Pinx的打开,转到GPIO_InitStruct可以看到结构体成员:

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;

        这是上面讲的GPIO的八种模式,看到这里想必大家也会有疑惑,为什么和上面的不太一样,这个我在学习的时候也有点疑惑,上网查了下也没什么太好的解答。后来我自己研究了一下,如果说我现在需要配置某个Pin口为浮空输入模式,那么我的CNFx:01 MODEx:00,也就是0x40。

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_Init()函数里面,他通过按位操作符很巧妙的得到了IO口的模式和传输速率,虽然看不太懂,但是感觉这样理解也是没有问题的;

currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);//保留第四位数据
  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)//高四位的第一位判断IO口输入还是输出
  { 
    /* Check the parameters */
    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
    /* Output mode */
    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;//得到输出模式+传输速率      
  }

        接下来,让我们了解下另外一个重要的寄存器吧——IDR(Input Data Register)和ODR(Output Data Register)
        

         该寄存器高十六位为保留数据0,低十六位可读对应IO口的状态,其中对应固件库的函数:

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)

            其实这两个函数没什么太大的区别,用第一个函数也可以实现第二个函数的功能:

int main(void)
{
    int State = 0;
    State = GPIO_ReadInputDataBit(GPIOA,0xffff);
    return 0;
}

 该寄存器高十六位为保留数据0,低十六位可读可写IO口的状态,但是只能以字(16位)的形式操作,其中对应固件库的函数:

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)
{
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  
  GPIOx->ODR = PortVal;
}

         BSRR 寄存器是端口位设置/清除寄存器。 该寄存器和 ODR 寄存器具有类似的作用,都可以用来设置 GPIO 端口的输出位是 1 还是 0。BRR 寄存器是端口位清除寄存器。该寄存器的作用跟 BSRR 的高 16 位雷同,这里就不做详细讲解。在 STM32 固件库中, 通过 BSRR 低十六位和 BRR 高16位设置 GPIO 端口输出

 

 其中对应固件库的函数:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  
  GPIOx->BSRR = GPIO_Pin;
}

/**
  * @brief  Clears the selected data port bits.
  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param  GPIO_Pin: specifies the port bits to be written.
  *   This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
  * @retval None
  */
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  
  GPIOx->BRR = GPIO_Pin;
}

        GPIO 相关的函数我们先讲解到这里。 虽然 IO 操作步骤很简单,这里我们还是做个概括性的总结,操作步骤为:

1) 使能 IO 口时钟。调用函数为 RCC_APB2PeriphClockCmd()。

2) 初始化 IO 参数。调用函数 GPIO_Init();

3) 操作 IO。操作 IO 的方法就是上面我们讲解的方法。

2.软件设计

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
    /*==========开启APB2时钟==============*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	/*==========GPIO初始化==============*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	while (1)
	{
		GPIO_Write(GPIOA, ~0x0001);	//0000 0000 0000 0001
		Delay_ms(100);
		GPIO_Write(GPIOA, ~0x0002);	//0000 0000 0000 0010
		Delay_ms(100);
		GPIO_Write(GPIOA, ~0x0004);	//0000 0000 0000 0100
		Delay_ms(100);
		GPIO_Write(GPIOA, ~0x0008);	//0000 0000 0000 1000
		Delay_ms(100);
		GPIO_Write(GPIOA, ~0x0010);	//0000 0000 0001 0000
		Delay_ms(100);
		GPIO_Write(GPIOA, ~0x0020);	//0000 0000 0010 0000
		Delay_ms(100);
		GPIO_Write(GPIOA, ~0x0040);	//0000 0000 0100 0000
		Delay_ms(100);
		GPIO_Write(GPIOA, ~0x0080);	//0000 0000 1000 0000
		Delay_ms(100);
	}
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值