Programando microcontrolador ARM: 8 - Botones y estructura interna Input GPIO pull-down y pull-up (Eclipse) (stm32f103c8)

En esta entrada vamos a ver cómo podemos utilizar el botón con nuestro microcontrolador. Al igual que en otros microcontroladores interactuaremos con nuestro botón a través de los puertos del GPIO, de los cuales estudiaremos a fondo su estructura interna.

Vamos a configurar dos botones y darle diferente funcionalidad a cada uno de ellos, con el objetivo de reforzar los conocimientos.

Para visualizar la funcionalidad del vamos a incluir una variable de tipo entera que simplemente se verá afectada por los botones. En caso de pulsar uno de los botones la variable aumentará su valor en uno y de manera opuesta el otro botón restará uno al valor de la variable. Además se añaden unas condiciones que limitan a la variable a pertenecer entre el 1 y el 7.

Estructura interna input GPIO

Debemos entender primero con se configura físicamente nuestro pin GPIO. En el manual de referencia vamos a encontrar el diagrama eléctrico básico de los pines GPIO.


Como podemos ver estos pines incluyen el circuito necesario. Disponen tanto de una resistencia pull-up como pull-down. Para identificarlas se hace de manera intuitiva, la referencia es el punto medio que corresponde a la señal IO del pin, luego la resistencia que está arriba conectada a la fuente VDD es la resistencia pull-UP y la que está conectada abajo a tierra es pull-DOWN.

Estas resistencias internar se activan mediante software y solo se puede encontrar una de ella activada. Veremos cómo controlar estas resistencias mediante software en este mismo tutorial más adelante.

El fabricante nos indica que la tensión máxima a la que se debe conectar este pin IO es de máximo VDD + 0.3, en nuestro caso por lo tanto sería de 3.6V (3.3V +0.3), pero de manera típica se debe conectar a 3.3V.

Por otro lado, existen los pines GPIO FT que corresponde a pone denominados Five volts Tolerant, que pueden soportar una tensión de 5V.

La ventaja de tener esta resistencia interna, tanto pull-up como pull-down sobre todo la encontramos a la hora de diseñar hardware, estas resistencias internas nos evitan la colocación de resistencias externas, ahorrando tiempo de diseño, disminuyendo a la complejidad y ahorrando dinero, tanto en material como en proceso de ensamblado.

Configuración Pull-down

Pull-DOWN

Centrándonos en los GPIO base, los de 3.3V, la conexión mas simple es conectar el botón en serie directamente a una fuente de 3.3V, sin añadir ninguna resistencia extra ya que la resistencia interna hace todo el trabajo. De esta manera estaremos utilizando la resistencia pull-down interna. Y el microcontrolador estará leyendo en su estado estático o normal LOW, 0 binario o 0V. En el momento de pulsar el botón la corriente circulará por el pin y en ese momento leerá HIGH, 1 binario o 3.3V.

Pull-UP

Por otro lado, tenemos la opción de utilizar la resistencia interna pull-up que está conectada en serie con la alimentación interna del microcontrolador VDD. De esta manera la conexión mas normal sería conectar nuestro botón directamente a tierra. En este caso nuestro microcontrolador detecta en esa entrada normalmente HIGH, 1 en binario o 3.3V y en el momento de pulsar detectará LOW, 0 en binario o 0V.
Configuración pull-up

Floating Input

Por último, tenemos la opción de floating input, en esta opción ninguna de las resistencias internas del pin del microcontrolador estará activadas. Y debemos ser nosotros los que añadimos las resistencias pull-up o pull-down en cualquiera de los casos.

Es recomendable usar resistencia de resistencia de entre 1K a 10K con el fin de minimizar la corriente y por tanto el consumo del dispositivo.

CONEXIONES

El diagrama de conexiones es muy sencillo, simplemente necesitamos conectar uno de los lados de los botones a sus correspondientes pines, en este caso PB5 y PB6 y el otro lado a la fuente de 3.3V como se puede ver en el siguiente diagrama.
Diagrama de conexiones

PROGRAMACIÓN

De igual manera que hemos visto cómo configurar un pin como output podemos configurar un pin como tipo input. En este caso vamos a utilizar la estructura GPIO_InitTypeDef que nos permite configurar los pines de tipo GPIO.
GPIO_InitTypeDef GPIO_InitStruct_PB_B5;
GPIO_InitStruct_PB_B5.GPIO_Pin = GPIO_Pin_5;

A continuación, vamos a indicar el modo en el que queremos que actúen las resistencias internas, como hemos visto tenemos tres opciones:

- Pull-down
    GPIO_InitStruct_PB_B5.GPIO_Mode = GPIO_Mode_IPD; 

- Pull-up
    GPIO_InitStruct_PB_B5.GPIO_Mode = GPIO_Mode_IPU; 

- Floating
    GPIO_InitStruct_PB_B5.GPIO_Mode = GPIO_Mode_IN_FLOATING;

Por último, inicializamos el pin con la estructura de datos creados. 
GPIO_Init(GPIOB, &GPIO_InitStruct_PB_B5);

En este caso vamos a configurar nuestro pin GPIO como input pull-down. Para declarar ambos botones, por lo tanto:

    GPIO_InitTypeDef GPIO_InitStruct_PB_B5;
    GPIO_InitStruct_PB_B5.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStruct_PB_B5.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(GPIOB, &GPIO_InitStruct_PB_B5);

    GPIO_InitTypeDef GPIO_InitStruct_PB_B6;
    GPIO_InitStruct_PB_B6.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct_PB_B6.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(GPIOB, &GPIO_InitStruct_PB_B6);

Por último, para detectar estas pulsaciones vamos a utilizar una función que acede al registro de del estado del pin.

    GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5)

Esta función devuelve 0 y 1 dependiendo de estado del pin. De esta manera incluiremos esta función en una condición if y podremos saber el estado del pin.
    
    if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5)){
        //El botón está pulsado
    }else{
        //El botón no está pulsado
    }

Por lo tanto, el código completo

#include "stm32f10x.h"
#include <stdio.h>

void delay(long cycles);
void GPIOext_Init(void);
void led_blink(void);

int main(void)
{
       int gear = 1;
       GPIOext_Init();

       while(1){
             if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5)){
                    if(gear < 7){
                          gear++;
                    }else{
                          led_blink();
                    }
             }
             if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_6)){
                    if(gear > 2){
                          gear--;
                    }else{
                          led_blink();
                    }
             }
       }
}

/***************************************************
 * Initialize GPIOC and pin13 as PP y max speed V1
 ***************************************************/
void GPIOext_Init (void)
{
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    /*Configure GPIO pin : Input_Pin_C13 */
    GPIO_InitTypeDef GPIO_InitStructure_PC13;
    GPIO_InitStructure_PC13.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure_PC13.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure_PC13.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure_PC13);
    GPIOC -> BSRR |= GPIO_BSRR_BS13;

    //** PUSH BUTTONS
    /*Configure GPIO pin : PushButton_Pin_B5 */
    GPIO_InitTypeDef GPIO_InitStruct_PB_B5;
    GPIO_InitStruct_PB_B5.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStruct_PB_B5.GPIO_ModeGPIO_Mpde_IPD;
    GPIO_Init(GPIOB, &GPIO_InitStruct_PB_B5);
    /*Configure GPIO pin : PushButton_Pin_B6 */
    GPIO_InitTypeDef GPIO_InitStruct_PB_B6;
    GPIO_InitStruct_PB_B6.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct_PB_B6.GPIO_Mode = GPIO_Mpde_IPD;
    GPIO_Init(GPIOB, &GPIO_InitStruct_PB_B6);
}

/*******************************************
 * Blink led_blink macro
 *******************************************/
void led_blink(void){
       //clear pin set to 0
       GPIO_ResetBits(GPIOC, GPIO_Pin_13);
       //reset 0010 0000 0000 0000 |set 0000 0000 0000 0000
       delay(2000000);
    //set pin to 1
       GPIO_SetBits(GPIOC, GPIO_Pin_13);
       //reset 0000 0000 0000 0000 |set 0010 0000 0000 0000
       delay(2000000);
}

/*******************************************
 * Delay
 *******************************************/
void delay (long cycles){
       while (cycles > 0)
             cycles--;
}

0 comentarios:

Publicar un comentario