GPIO input drive experiment - key control

GPIO input drive experiment - key control

Write before:

Like beep experiment, just add functions to the existing engineering framework, Chong!!!
By the way, the gpio operation will be written into a function set for easy calling. Please pay attention.

1. Create new key and gpio folders under bsp

First, let's start with a GPIO operation set function, the same pair of CP: bsp_gpio.h,bsp_gpio.c

bsp_ The GPIO. H code is as follows:

#ifndef _BSP_GPIO_h
#define _BSP_GPIO_h
#define _BSP_KEY_h
#include "imx6ul.h"

/*Enumeration type and structure definition*/
typedef enum _gpio_pin_direction
{
    kGPIO_DigitalInput = 0U,//Input, plus a U to indicate that the constant is an unsigned integer
    kGPIO_DigitalOutput = 1U,//input

}gpio_pin_direction_t;

/*GPIO Configuration structure*/
typedef struct _gpio_pin_config
{
    gpio_pin_direction_t direction;//GPIO direction: input or output
    uint8_t outputLogic;//Default output level if output to
}gpio_pin_config_t;

/*Function declaration*/
void gpio_init(GPIO_Type *base,int pin,gpio_pin_config_t *config);
int gpio_pinread(GPIO_Type *base,int pin);
void gpio_pinwrite(GPIO_Type *base,int pin,int value);

#endif // !_BSP_GPIO_h

C basic knowledge enumeration and structure.

  • An enumeration type gpio_pin_direction_t and structure gpio_pin_config_t
  • Enumeration type gpio_pin_direction_t indicates GPIO direction, input or output
  • Structure gpio_pin_config_t is the configuration structure of GPIO, which contains two member variables: GPIO direction and default output level.

bsp_gpio.c code is as follows:

#include "bsp_gpio.h"
/*GPIO initialization*/
void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
{
    if(config->direction == kGPIO_DigitalInput)//input
    {
        base->GDIR &= ~(1 << pin);
    }
    else//output
    {
        base->GDIR |= (1 << pin);
        gpio_pinwrite(base, pin,config->outputLogic);//Default output level
    }
    
}
/*Reads the value of the specified GPIO*/
int gpio_pinread(GPIO_Type *base, int pin)
{
    return (((base->DR) >> pin) & 0x1);
}
/*Specifies whether the GPIO output is high or low*/
void gpio_pinwrite(GPIO_Type *base, int pin, int value)
{
    if (value == 0U)
    {
        base->DR &= ~(1U << pin);//Output low level
    }
    else
    {
        base->DR |= (1U << pin);//Output high point flat
    } 
}

GPIO initialize gpio_init, used to initialize the specified GPIO pin + configure the GDIR register

  • The parameter base refers to the group of GPIO;
  • The parameter pin refers to the label in the group;
  • Parameter config to specify GPIO input or output.

gpio_pinread reads the specified GPIO value, that is, the specified location of the DR register

  • The base and pin do not change, but point to the GPIO to be read
  • If there is one more return value, return the read GPIO value (0 / 1)

gpio_pinwrite is to control the specified GPIO pin input high level (1) or low level (0), that is, to set DR
Finger positioning of memory

  • base and bin are nothing special
  • Value is the value you want to set (0 / 1)

The above encapsulates the gpio configuration function.

2,bsp_key.c and bsp_key.h

Because we need to add a key function, of course, we can't do without the key CP.

bsp_key.h code is as follows:

#ifndef _BSP_KEY_H
#define _BSP_KEY_H
#include "imx6ul.h"

/*Define key values*/
enum keyvalue{
    KEY_NONE = 0,
    KEY0_VALUE,
};

/*Function declaration*/
void key_init(void);
int key_getvalue(void);

#endif // !_BSP_KEY_H

During the following cross compilation, I found the following problem: key0_ The initialization of value is actually key0 at this time_ Value has been initialized to 1. Don't ask me why, I don't know.

But I have a guess. First, this is an enumeration type. Who is it for? It's keyvalue. It's an enumeration of keyvalue. What do you enumerate: KEY_NONE and KEY0_VALUE: when you actively assign a value to it, it has a value. When you don't give it, it defaults to 1.

bsp_ The key. C code is as follows:

#include "bsp_key.h"
#include "bsp_gpio.h"
#include "bsp_delay.h"

/*Initialization key*/
void key_init(void)
{
    gpio_pin_config_t key_config;

    //IO multiplexing, GPIO1_IO18
    IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);

    //Configure IO properties
    IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);

    //GPIO1-18 set as input
    key_config.direction = kGPIO_DigitalInput;
    gpio_init(GPIO1,18, &key_config);

}

/*Get key value*/
int key_getvalue(void)
{
    int ret = 0;
    static unsigned char release = 1;//Key release

    if((release==1)&&(gpio_pinread(GPIO1,18) == 0))
    {
        delay(10);//Delay anti chattering
        release = 0;//Mark key press
        if (gpio_pinread(GPIO1,18) == 0)
            ret = KEY0_VALUE;
        
    }
    else if (gpio_pinread(GPIO1,18) == 1) //KEY0 not pressed
    {
        ret = 0;
        release = 1;//Mark key release
    }
    return ret;
}

You may see less, which is not suitable for the representation of structure + bit operator. You should stop and analyze it every time to understand it.

key_init and key_getvalue has two functions, where key_getvalue is to get the return value.

There is a key shake elimination operation. In fact, it is to add a delay and judge it. 51 and STM32 have talked about it.

3,main.c

Direct code:

#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"

int main(void)
{
	int i = 0;
	int keyvalue = 0;
	unsigned char led_state = OFF;
	unsigned char beep_state = OFF;

	clk_enable();		/* Enable all clocks 			*/
	led_init();			/* Initialize led 			*/
	beep_init();//Initialize beep
	key_init();	//Initialize key

	while(1)			/* Dead cycle 				*/
	{	
		keyvalue = key_getvalue();
		if (keyvalue)
		{
			switch (keyvalue)
			{
			case KEY0_VALUE:
				beep_state = !beep_state;
				beep_switch(beep_state);
				break;
			}
		}
		i++;
		if(i==50)
		{
			i = 0;
			led_state = !led_state;
			led_switch(LED0,led_state);
		}
		delay(10);
	}
	return 0;
}

The main function is very simple, which is to call various functions prepared before, but there is one thing to say:

led_state = !led_state
This procedure has been difficult for me for a long time, but now it seems to be very common. Maybe this is quantitative change to qualitative change.

4,makefile

CROSS_COMPILE ?= arm-linux-gnueabihf-#This line can be changed for different compilers
TARGET		  ?= key#The name of the target should also be changed for different processes

CC			  := $(CROSS_COMPILE)gcc
LD			  := $(CROSS_COMPILE)ld
OBJCOPY		  := $(CROSS_COMPILE)objcopy
OBJDUMP		  := $(CROSS_COMPILE)objdump
#The variable INCDIRS contains the. h header file directory of the whole project. All header file directories in the file should be added to the variable INCDIRS
INCDIRS		  := imx6ul \
				bsp/clk \
				bsp/led \
				bsp/delay\
				bsp/beep\
				bsp/gpio\
				bsp/key
#SRCDIRS contains all. c and. S file directories of the whole project
SRCDIRS 	  := project \
				bsp/clk \
				bsp/led \
				bsp/delay\
				bsp/beep\
				bsp/gpio\
				bsp/key
#The variable INCLUDE uses the function patsubst. Add a "- I" to the variable incdir through the function patsubst, because the Makefile syntax requires that "- I" be added when indicating the header file directory
INCLUDE		  := $(patsubst %, -I %, $(INCDIRS))

#The variable SFILES saves all. S assembly files (including absolute paths) in the project. The variable SRCDIRS has stored all. c and. S files in the project, so we only need to pick out all. S assembly files from it
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))

#The variable CFILES is the same as the variable SFILES, except that CFILES saves all. c files (including absolute paths) in the project
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))

#Use the function notdir to remove the paths in SFILES and CFILES
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))

#By default, all compiled. o files and source files are in the same directory
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))

#The variable OBJS is a collection of variables SOBJS and COBJS
OBJS := $(SOBJS) $(COBJS)

#VPATH specifies the search directory. The search element directory specified here is the directory saved by the variable SRCDIRS, so that the required. S and. c files will be found in the directory specified in SRCDIRS when compiling
VPATH := $(SRCDIRS)

.PHONY: clean

$(TARGET).bin : $(OBJS)
	$(LD) -Timx6ul.lds -o $(TARGET).elf $^
	$(OBJCOPY) -O binary -S $(TARGET).elf $@
	$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
	
$(SOBJS) : obj/%.o : %.S
	$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<


$(COBJS) : obj/%.o : %.c
	$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<

clean: 
	rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

Just change the name of the target file and the. h and. c paths of the driver.

OVER!!!

Good morning, good afternoon, good night!

Keywords: C Single-Chip Microcomputer stm32

Added by dta on Tue, 26 Oct 2021 14:46:00 +0300