1、嵌入式基础与gpio

发布时间 2023-09-24 01:17:53作者: 深渊之巅

stm32芯片有若干端口(感觉就是接口),每组端口由很多寄存器控制,引脚就相当于寄存器中的位,可以自由编程。

 

反应在c语言代码中,引脚就是对应的第几位。

 

gpio 端口中的寄存器

 这些寄存器也就是库函数中gpio_typedef的成员。

 

注:输入输出方式MODE共有8种,四种输入(2位),四种输出(2位)。所以,每四位可以控制一个io口,其中有一个寄存器的两位决定输入输出。

 

 

 注:对于每个GPIO引脚,我们都有一对GPIO位(0和1),一个用于输入模式下的状态读取,另一个用于输出模式下的状态控制, 如在输入模式下,GPIO引脚可以读取其连接的设备的状态。

例如,如果一个设备被连接到一个GPIO引脚,并且该设备是开启的,那么读取该引脚的状态将返回1;如果该设备是关闭的,那么读取该引脚的状态将返回0。所以对于每个引脚,我们都有一对GPIO位(0和1)来表示其状态。

 

控制芯片的寄存器

直接地址法:
  顾名思义,直接操作stm32寄存器的地址,进行编程。
  读写一个地址的方法: *(地址) = ...;

偏移地址:

  用基地址+偏移量来进行寄存器和引脚的定位。

  实现方式:将各个寄存器的基地址记录在数组中,然后通过偏移量进行寻址。

  

 

gpio.c 源码

void gpio_init(uint16_t port_pin, uint8_t dir, uint8_t state) //port_pin高八位是port的偏移量,低八位是引脚位置,dir是输入输出模式,state是dir对应的状态
{
    GPIO_TypeDef *gpio_ptr;    //声明gpio_ptr为GPIO结构体类型指针
    uint8_t port,pin;    //声明端口port、引脚pin变量
    uint32_t temp;       //临时存放寄存器里的值
    //根据带入参数port_pin,解析出端口与引脚分别赋给port,pin
    gpio_get_port_pin(port_pin,&port,&pin);
    //根据port,给局部变量gpio_ptr赋值(GPIO基地址)
    if(7 == port) //GPIOH
        gpio_ptr = GPIO_ARR[port-2];
    else
        gpio_ptr = GPIO_ARR[port];
/* ***********到这里获取了端口位置************* */
//使能相应GPIO时钟 RCC->AHB2ENR |= (RCC_AHB2ENR_GPIOAEN<<(port * 1u)); //清GPIO模式寄存器对应引脚位 temp = gpio_ptr->MODER; //获取模式寄存器的值 temp &= ~(GPIO_MODER_MODE0 << (pin * 2u)); //清空模式, 这里 pin*2是因为输入输出由一对引脚控制。 if(dir == 1) //定义为输出引脚 { temp |= (GPIO_OUTPUT << (pin * 2u));  //第pin * 2位表示输入输出状态。 gpio_ptr->MODER = temp; //把暂存值写回 gpio_set(port_pin,state); //调用gpio_set函数,设定引脚初始状态 } else //定义为输入引脚 { temp |= (GPIO_INPUT << (pin * 2u)); gpio_ptr->MODER = temp; } }

 

void gpio_set(uint16_t port_pin, uint8_t state)
{
    //局部变量声明
    GPIO_TypeDef *gpio_ptr;    //声明port_ptr为GPIO结构体类型指针(首地址)
    uint8_t port,pin;        //声明端口port、引脚pin变量
    //根据带入参数port_pin,解析出端口与引脚分别赋给port,pin
    gpio_get_port_pin(port_pin,&port,&pin);
    //根据port,给局部变量gpio_ptr赋值(GPIO基地址)
    if(7 == port) //GPIOH
        gpio_ptr = GPIO_ARR[port-2];
    else
        gpio_ptr = GPIO_ARR[port];
/* ***** 到这里获取了端口 ***** */
//根据state,设置对应引脚状态 if(1 == state) //高电平(该引脚对应置位寄存器置1) gpio_ptr->BSRR = (uint32_t)(1u<<pin); //bsrr为设置寄存器,可以将 1 << pin 这一位设置为1 else //低电平(该引脚对应重置寄存器置1) gpio_ptr->BRR = (uint32_t)(1u<<pin);   //brr为重置寄存器,可以将 1 << pin 这一位重置为0 }

 

uint8_t gpio_get(uint16_t port_pin)
{
    //局部变量声明
    GPIO_TypeDef *gpio_ptr;    //声明port_ptr为GPIO结构体类型指针(首地址)
    uint8_t port,pin;        //声明端口port、引脚pin变量
    uint32_t temp;
    uint8_t value;
    //根据带入参数port_pin,解析出端口与引脚分别赋给port,pin
    gpio_get_port_pin(port_pin,&port,&pin);
    //根据port,给局部变量gpio_ptr赋值(GPIO基地址)
    if(7 == port) //GPIOH
        gpio_ptr = GPIO_ARR[port-2];
    else
        gpio_ptr = GPIO_ARR[port];

    //获得状态寄存器的值
    temp = gpio_ptr->MODER;

    if( (temp & (2u<<(pin*2)))>>(pin*2) == 1u )//GPIO输出 检查pin*2位置的那一位是否为1, 为1就是输出
    {
        //读取Output data寄存器对应引脚的值
        temp = gpio_ptr->ODR;    
        if((temp & (1u<<pin)) != 0x00u)   //查看输出寄存器中的数据是否为0,不为0返回1, 输入同理
            value = 1;
        else
            value = 0;
    }
    else                                       //GPIO输入
    {
        //读取Input data寄存器对应引脚的值
        temp = gpio_ptr->IDR;
        if((temp & (1u<<pin)) != 0x00u)
            value = 1;
        else
            value = 0;
    }

    return value;
}