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!