集成智能小车(三...1)模块设计实现之GPIO

在后续的博客中,我找一些有谢不一样功能模块或者网上不太好找的现成传感器(如VL53L0X)代码,分享出来给各位智能小车爱好者,大家可以少走点弯路。如果你们有好的分享,请留言,谢谢。

为了配合博客,整了一些小车的视频,百度云上传下载太慢,我直接放在QQ2137418554空间里了(无需加好友,直接看就行)

今天我分享下在GPIO上我的用法。

我在智能小车上采用的一种全新的GPIO组织方式,往常很多项目多是把IO配置散列在功能模块中,用到了就初始化,这样做也没多大问题,就是找问题的时候,要把每个模块的引脚分配和初始化都得查一遍,看看是否有用错PORT,或者用错IO的,如下两个API是很常用的:

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, bsp_GetPinSource(GPIO_Pin_1));

前者配置IO属性(输入/输出,速率、是否上下拉等),

typedef struct
{
  uint16_t GPIO_Pin; 
  GPIOSpeed_TypeDef GPIO_Speed; 
  GPIOMode_TypeDef GPIO_Mode;   
}GPIO_InitTypeDef;

后者配置外部中断引脚映射。

这2个API里面的4个参数及其结构成员基本涵盖了GPIO的各项属性了,除了重映射之外。

为了避免满篇代码找GPIO映射的尴尬,更因为这份代码不用往别处移植,我就把所有用到的GPIO(其实已经用满了)都组织在一张结构数组的表里。

GPIO_CFG_STRU g_astrGpioDef[] = 
{
    /***********************************************************
    前部电机,WHEEL and MOTO,一个电机需要2路
    ***********************************************************/
    {GPIOC, GPIO_Pin_6,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,      0       },  // front left pwm1, TIM8-CH1
    {GPIOC, GPIO_Pin_7,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,      0       },  // front left pwm2, TIM8-CH2
    {GPIOC, GPIO_Pin_8,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,      0       },  // front right pwm1, TIM8-CH3
    {GPIOC, GPIO_Pin_9,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,      0       },  // front right pwm2, TIM8-CH4
    /***********************************************************
    前部电机,WHEEL and MOTO,一个电机需要2路
    ***********************************************************/
    {GPIOA, GPIO_Pin_8,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,      0       },  // back left pwm1, TIM1-CH1, CH1N脚PA7与红外周期发射共用
    {GPIOA, GPIO_Pin_9,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,      0       },  // back left pwm2, TIM1-CH2 , 与USART1_TX复用
    {GPIOA, GPIO_Pin_10,    GPIO_Speed_50MHz, GPIO_Mode_AF_PP,      0       },  // back right pwm1, TIM1-CH3, 与USART1_RX复用
    {GPIOA, GPIO_Pin_11,    GPIO_Speed_50MHz, GPIO_Mode_AF_PP,      0       },  // back right pwm2, TIM1-CH4
    /***********************************************************
    红外测距与避障,一个通道1个输入,进ADC,引脚mode不同
    ***********************************************************/
    {GPIOC, GPIO_Pin_2,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // left, ADC12
    {GPIOC, GPIO_Pin_0,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // middle, ADC10
    {GPIOC, GPIO_Pin_3,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // right, ADC13
    
    {GPIOA, GPIO_Pin_5,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // backleft, ADC5
    {GPIOA, GPIO_Pin_6,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // backmiddle, ADC6
    {GPIOA, GPIO_Pin_1,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // backright, ADC1
    /***********************************************************
    红外循迹,进通用IO,V12去掉后中位置sensor
    ***********************************************************/
    {GPIOB, GPIO_Pin_0,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // LEFT front,  ADC8
    {GPIOC, GPIO_Pin_4,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // MIDDLE front, ADC14 
    {GPIOC, GPIO_Pin_5,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // RIGHT front, ADC15 

    /***********************************************************
    MCU电池供电电压采样和电机电池供电电压供电
    ***********************************************************/
    {GPIOA, GPIO_Pin_4,    GPIO_Speed_50MHz, GPIO_Mode_AIN,         0       },  // MCU供电电压, ADC4
       
    

    /***********************************************************
    光感检测,一个通道1个输入,进ADC或做普通IO输入,引脚mode不同
    ***********************************************************/
    {GPIOA, GPIO_Pin_0,     GPIO_Speed_50MHz, GPIO_Mode_AIN,        0       },  // front light sensor, ADC0
    
    /***********************************************************
    超声波检测,一个通道1个输入,进中断或者进定时器捕获(本例进中断), 1个输出引脚
    ***********************************************************/
    {GPIOB, GPIO_Pin_1,      GPIO_Speed_50MHz, GPIO_Mode_IPD,       0       },  // ECHO 输入
    {GPIOB, GPIO_Pin_2,      GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // trig输出
    /***********************************************************
    舵机控制, 1个输出引脚
    ***********************************************************/
    {GPIOB, GPIO_Pin_9,      GPIO_Speed_50MHz, GPIO_Mode_AF_PP,     0       },  // PWM输出, TIM4_CH4
    /***********************************************************
    I2C2, LCD/MPU6050,ETC
    ***********************************************************/
    {GPIOB, GPIO_Pin_10,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // SCL
    {GPIOB, GPIO_Pin_11,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // SDA
    /***********************************************************
    SPI2, NRF24L01
    ***********************************************************/
    {GPIOB, GPIO_Pin_12,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // NSS0
    {GPIOC, GPIO_Pin_1,      GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // NSS1
    {GPIOB, GPIO_Pin_13,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,     0       },  // SCK
    {GPIOB, GPIO_Pin_14,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,     0       },  // MISO
    {GPIOB, GPIO_Pin_15,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,     0       },  // MOSI
    
    /***********************************************************
    SPI1,
    ***********************************************************/
    {GPIOA, GPIO_Pin_15,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0                   },  // NSS
    {GPIOB, GPIO_Pin_3,      GPIO_Speed_50MHz, GPIO_Mode_AF_PP,     GPIO_Remap_SPI1     },  // SCK
    {GPIOB, GPIO_Pin_4,      GPIO_Speed_50MHz, GPIO_Mode_AF_PP,     GPIO_Remap_SPI1     },  // MISO
    {GPIOB, GPIO_Pin_5,      GPIO_Speed_50MHz, GPIO_Mode_AF_PP,     GPIO_Remap_SPI1     },  // MOSI
    /***********************************************************
    WIFI CONTROL, V12 ENABLE不在与SPI1_MISO复用,直接上来
    ***********************************************************/
    //{GPIOB, GPIO_Pin_4,      GPIO_Speed_50MHz, GPIO_Mode_Out_PP,  0       },  // v12没有该引脚
    {GPIOA, GPIO_Pin_12,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // RESET
    /***********************************************************
    LED, 头部与尾部车灯
    ***********************************************************/
    {GPIOC, GPIO_Pin_10,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // 左前 led
    {GPIOC, GPIO_Pin_11,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // 右前 led
    {GPIOC, GPIO_Pin_12,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // 左后 led
    {GPIOD, GPIO_Pin_2,      GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // 右后 led
    /***********************************************************
    BODY FULL COLOR LED
    ***********************************************************/
    {GPIOC, GPIO_Pin_13,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // RED
    {GPIOC, GPIO_Pin_14,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // GREEN
    {GPIOC, GPIO_Pin_15,     GPIO_Speed_50MHz, GPIO_Mode_Out_PP,    0       },  // BLUE

    /***********************************************************
    红外周期发射发射控制,VCC接CPU_3V3+, GND接IO引脚
    ***********************************************************/
    {GPIOA, GPIO_Pin_7,    GPIO_Speed_50MHz, GPIO_Mode_AIN,       0       },  // PA7, TIM3_CH2
    /***********************************************************
    红外周期接收,分为左、中、右,用于跟随控制, V12没有单独跟随红外sensor
    ***********************************************************/
    /***********************************************************
    红外编码器接收,分为左、右,
    ***********************************************************/
    {GPIOB, GPIO_Pin_6,     GPIO_Speed_50MHz, GPIO_Mode_IPU,        0       },  // 左编码器, TIM4_CH1
    {GPIOB, GPIO_Pin_7,     GPIO_Speed_50MHz, GPIO_Mode_IPU,        0       },  // 右编码器, ITM4_CH2

    /***********************************************************
    红外接收头,与人体感应复用,与舵机复用,注意修改IO输出特性
    ***********************************************************/
    {GPIOB, GPIO_Pin_8,     GPIO_Speed_50MHz, GPIO_Mode_AF_PP,        0       },  // 红外接收头,TIM4_CH3(GPIO_Mode_IN_FLOATING)

    
};

结构体定义了GPIO的配置属性,以及是否要做某种功能的重映射AFIO

typedef struct
{

    GPIO_TypeDef* gpioX;
    GPIO_InitTypeDef strGpioType;
    uint32_t RemapGpioPin;     //是否需要重映射
}GPIO_CFG_STRU;

这样在初始化的时候,写一个函数就够了,如下:

void bsp_gpio_init(void)
{
    uint8_t i;
    GPIO_CFG_STRU * pstGpioTobeInit;
    GPIO_TypeDef * GPIOX;
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO,  ENABLE);

    pstGpioTobeInit = g_astrGpioDef;
    for(i = 0; i < enGpioMax; i++)
    {
    	GPIO_InitStructure.GPIO_Mode  = pstGpioTobeInit->strGpioType.GPIO_Mode;
    	GPIO_InitStructure.GPIO_Speed = pstGpioTobeInit->strGpioType.GPIO_Speed;
    	GPIO_InitStructure.GPIO_Pin = pstGpioTobeInit->strGpioType.GPIO_Pin;
        GPIOX = pstGpioTobeInit->gpioX;
    	GPIO_Init(GPIOX, &GPIO_InitStructure);

        //需要重映射的引脚在此处配置AFIO
        if(g_astrGpioDef->RemapGpioPin)
        {
            GPIO_PinRemapConfig(g_astrGpioDef->RemapGpioPin, ENABLE);
        }
        
        if((pstGpioTobeInit->strGpioType.GPIO_Mode == GPIO_Mode_Out_PP)
            || (pstGpioTobeInit->strGpioType.GPIO_Mode == GPIO_Mode_AF_PP))
            GPIOX->BRR = pstGpioTobeInit->strGpioType.GPIO_Pin;
            
        pstGpioTobeInit++;
    }
    
    HW_Set_Gpio_OutputValue(enGpioWifiReset, ENABLE);
    
    

}

有些人看到了里面有这么一句 

 HW_Set_Gpio_OutputValue(enGpioWifiReset, ENABLE);

这是把输入和输出读取和写入操作又封装了一层。

uint8_t HW_Get_Gpio_InputValue(GPIO_FUCNTIONALITY_ENUM enSeqNum)
{
    return(GPIO_ReadInputDataBit(g_astrGpioDef[enSeqNum].gpioX, g_astrGpioDef[enSeqNum].strGpioType.GPIO_Pin));
}
uint8_t HW_Get_Gpio_OutputValue(GPIO_FUCNTIONALITY_ENUM enSeqNum)
{
    return(GPIO_ReadOutputDataBit(g_astrGpioDef[enSeqNum].gpioX, g_astrGpioDef[enSeqNum].strGpioType.GPIO_Pin));
}
void HW_Set_Gpio_OutputValue(GPIO_FUCNTIONALITY_ENUM enSeqNum, uint8_t ucEnable)
{
    //输出高
    if(ucEnable == ENABLE)
    {
        g_astrGpioDef[enSeqNum].gpioX->BSRR = g_astrGpioDef[enSeqNum].strGpioType.GPIO_Pin;
    }
    //输出低
    else if(ucEnable == DISABLE)
    {
        g_astrGpioDef[enSeqNum].gpioX->BRR = g_astrGpioDef[enSeqNum].strGpioType.GPIO_Pin;
    }
}

有人说,这样做效率有点低,是的,我承认,但是代码里真正需要直接操作GPIO的地方是不多的,我忍了。在需要考虑性能的地方单独换成更高效的处理方式就行,比如I2C驱动,就是从某个开发板的down的吧(具体时间长了,我也记不到了)。

拉回来,说到最后了,上面设置和查询GPIO状态的枚举值,要跟之前定义的结构数组顺便必须保持一致:

typedef enum
{
    enGpioFrontMotoLeftIn1,
    enGpioFrontMotoLeftIn2,
    enGpioFrontMotoRightIn1,
    enGpioFrontMotoRightIn2,
    
    enGpioBackMotoLeftIn1,
    enGpioBackMotoLeftIn2,
    enGpioBackMotoRightIn1,
    enGpioBackMotoRightIn2,
    
    enGpioINFObsLeft,
    enGpioINFObsMiddle,
    enGpioINFObsRight,
        
    enGpioINFObsBackLeft,
    enGpioINFObsBackMiddle,
    enGpioINFObsBackRight,
    
    enGpioINFTraceLeftFront,
    enGpioINFTraceMiddleFront,
    enGpioINFTraceRightFront,
    //enGpioBuzzOut, 
    enGpioPwrMonitor,
    
    enGpioLightFront,

    enGpioUltraSonicEcho,
    enGpioUltraSonicTrig,

    enGpioServoPwmOut,//舵机

    enGpioI2C2Scl,
    enGpioI2C2Sda,

    enGpioSPI2Cs0,
    enGpioSPI2Cs1,
    enGpioSPI2Sck,
    enGpioSPI2Miso,
    enGpioSPI2Mosi,

    enGpioSPI1Cs0,
    enGpioSPI1Sck,
    enGpioSPI1Miso,
    enGpioSPI1Mosi,
    
    
    enGpioWifiReset,
    
    enGpioLeftFrontLed,
    enGpioRightFrontLed,
    enGpioLeftBackLed,
    enGpioRightBackLed,

    //RGB全彩灯
    enGpioBodyLedRed,
    enGpioBodyLedGreen,
    enGpioBodyLedBlue,

    
    enGpioInfPeriodTxOut,


    enGpioEncoderLeft,
    enGpioEncoderRight,
    
    enGpioInfReceiver, 


    enGpioMax

    
}GPIO_FUCNTIONALITY_ENUM;

讲到这里GPIO就结束了,代码比较简单,不需要那么多注释。

有用的大家借鉴下,认为没啥意义或者你已经这么做过了,鼓励我一下就行,砖头咱们就省了:)

谢谢

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值