第5章 IMX6ULL按键实验

一、编写cc.h文件:

#ifndef __CC_H
#define __CC_H

#define __I     volatile
#define __O     volatile
#define __IO    volatile

#define ON      1
#define OFF     0   

typedef signed char             int8_t;
typedef signed short int        int16_t;
typedef signed int              int32_t;
typedef unsigned char           uint8_t;
typedef unsigned short int      uint16_t;
typedef unsigned int            uint32_t;
typedef unsigned long long      uint64_t;

typedef signed char             s8;
typedef signed short int        s16;
typedef signed int              s32;
typedef signed long long int    s64;
typedef unsigned char           u8;
typedef unsigned short int      u16;
typedef unsigned int            u32;
typedef unsigned long long int  u64;

#endif

二、编写SDK文件:

1、fsl_common.h

2、fsl_iomuxc.h

3、MCIMX6Y2.h


三、编写imx6u.h文件:

        将所有的公共头文件,写在一个头文件中进行调用。

#ifndef __IMX6U_H
#define __IMX6U_H

#include "MCIMX6Y2.h"
#include "fsl_common.h"
#include "fsl_iomuxc.h"
#include "cc.h"


#endif

四、编写start.S文件:


.global _start

.global _bss_start
_bss_start:
    .word __bss_start

.global _bss_end
_bss_end:
    .word __bss_end

_start:

    /* 设置处理器进入SVC模式 */
    MRS R0, CPSR                @读取CPSR到R0
    BIC R0, R0, #0x1F           @清除CPSR中的Bit4-0
    ORR R0, R0, #0x13           @使用SVC模式
    MSR CPSR, R0                @将R0写入到CPSR

    /* 清除BSS段 */
    LDR R0, _bss_start
    LDR R1, _bss_end
    MOV R2, #0
bss_loop:
    STMIA R0!, {R2}
    CMP R0, R1                  @比较R0与R1中的值
    ble bss_loop                @如果R0地址小于R1地址,则继续清除BSS段

    /* 设置SP指针 */
    LDR SP, = 0x80200000        @设置SP指针起始地址
    B main                      @跳转到C语言main函数
    

五、编写bsp_led驱动文件:

1、编写bsp_led.c文件

#include "bsp_led.h"
#include "bsp_gpio.h"


/* 初始化LED */
void Led_Init(void)
{
    gpio_pin_config_t LED_Config;

    /* 复用GPIO1_IO03为GPIO */
    IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0x0);

    /* 设置GPIO1_IO03电气属性 */
    IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0x10B0);
    
    /* 设置GPIO1_IO03为输出 */
    LED_Config.Direction = GPIO_DigitalOutput;

    /* 设置GPIO1_IO03输出低电平,打开LED灯 */
    LED_Config.OutputLogic = 0;

    Gpio_Init(GPIO1, 3 ,&LED_Config);
}


/* LED开关控制函数 */
void Led_Switch(int led, int status)
{
    switch(led)
    {
        case LED1:
            if (status == ON)
            {
                Gpio_Pin_Write(GPIO1, 3, 0);                                /* Bit3清零,打开LED */
            }
            else if (status == OFF)
            {
                Gpio_Pin_Write(GPIO1, 3, 1);                                /* Bit3置位,关闭LED */
            }
            break;
    }
}

2、编写bsp_led.h文件

#ifndef __BSP_LED_H
#define __BSP_LED_H

#include "imx6u.h"


#define LED1    1
#define LED2    2
#define LED3    3
#define LED4    4
#define LED5    5
#define LED6    6
#define LED7    7
#define LED8    8
#define LED9    9
#define LED10   10
#define LED11   11
#define LED12   12
#define LED13   13
#define LED14   14
#define LED15   15
#define LED16   16


/* 函数声明 */
void Led_Init(void);
void Led_Switch(int led, int status);


#endif

六、编写bsp_beep文件:

1、编写bsp_beep.c文件

#include "bsp_beep.h"
#include "bsp_gpio.h"


/* 初始化BEEP */
void Beep_Init(void)
{
    gpio_pin_config_t BEEP_Config;

    /* 初始化IO复用,复用为GPIO5_IO01 */
    IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 0);

    /* 配置GPIO5_IO01的IO电气属性 */
    IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 0x10B0);

    /* 初始化GPIO5_IO01设置为输出 */
    BEEP_Config.Direction = GPIO_DigitalOutput;

    /* 设置GPIO5_IO01输出低电平,关闭蜂鸣器 */
    BEEP_Config.OutputLogic = 1;

    Gpio_Init(GPIO5, 1, &BEEP_Config);
    
}


/* 蜂鸣器开关控制函数 */
void Beep_Switch(int status)
{
    if (status == ON)
    {
        Gpio_Pin_Write(GPIO5, 1, 0);        /* 打开蜂鸣器 */
    } 
    else if (status == OFF)
    {
        Gpio_Pin_Write(GPIO5, 1, 1);        /* 关闭蜂鸣器 */
    }
}

2、编写bsp_beep.h文件

#ifndef __BSP_BEEP_H
#define __BSP_BEEP_H

#include "imx6u.h"


/* 函数声明 */
void Beep_Init(void);
void Beep_Switch(int status);


#endif

七、编写bsp_clk文件:

 1、编写bsp_clk.c文件

#include "bsp_clk.h"


/* 使能外设时钟 */
void Clk_Enable(void)
{
    CCM->CCGR0 = 0xFFFFFFFF;
    CCM->CCGR1 = 0xFFFFFFFF;
    CCM->CCGR2 = 0xFFFFFFFF;
    CCM->CCGR3 = 0xFFFFFFFF;
    CCM->CCGR4 = 0xFFFFFFFF;
    CCM->CCGR5 = 0xFFFFFFFF;
    CCM->CCGR6 = 0xFFFFFFFF;
}

2、编写bsp_clk.h文件

#ifndef __BSP_CLK_H
#define __BSP_CLK_H

#include "imx6u.h"


/* 函数声明 */
void Clk_Enable(void);

#endif

八、编写bsp_delay文件:

1、编写bsp_delay.c文件

#include "bsp_delay.h"

/* 短延时 */
void delay_short(volatile unsigned int n)
{
    while(n--) {}
}

/* 延时,在主频为396MHz时,一次循环大概1ms */
void delay_ms(volatile unsigned int time_ms)
{
    while(time_ms--) {
        delay_short(0x7FF);
    }
}

2、编写bsp_delay.h文件

#ifndef __BSP_DELAY_H
#define __BSP_DELAY_H

#include "imx6u.h"


/* 函数声明 */
void delay_short(volatile unsigned int n);
void delay_ms(volatile unsigned int time_ms);

#endif

九、编写bsp_gpio文件:

1、编写bsp_gpio.c文件

#include "bsp_gpio.h"


/*
 * @Description :GPIO初始化,设置输入、输出、默认输出电平
 * @Para-base   :GPIO组
 * @Para-pin    :GPIO引脚号
 * @Para-config :GPIO配置结构体
 * @return      :无
 */
void Gpio_Init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
{
    if (config->Direction == GPIO_DigitalInput)                 /* 输入 */
    {
        base->GDIR &= ~(1<<pin);
    }
    else                                                        /* 输出 */
    {
        base->GDIR |= (1<<pin);
        Gpio_Pin_Write(base, pin, config->OutputLogic);         /* 设置默认输出电平 */
    }
}


/*
 * @Description :读取GPIO的电平值
 * @Para-base   :GPIO组
 * @Para-pin    :GPIO引脚号
 * @return      :无
 */
int Gpio_Pin_Read(GPIO_Type *base, int pin)
{
    return (((base->DR)>>pin) & 0x1);
}


/*
 * @Description :控制GPIO输出高低电平
 * @Para-base   :GPIO组
 * @Para-pin    :GPIO引脚号
 * @Para-value  :GPIO输出电平
 * @return      :无
 */
void Gpio_Pin_Write(GPIO_Type *base, int pin, int value)
{
    if (value==0)                                           /* 写入0,输出低电平 */
    {
        base->DR &= ~(1<<pin);
    }
    else                                                    /* 写入1,输出高电平 */
    {
        base->DR |= (1<<pin);
    }
}

2、编写bsp_gpio.h

#ifndef __BSP_GPIO_H
#define __BSP_GPIO_H

#include "imx6u.h"


/* GPIO输入输出枚举类型定义 */
typedef enum _gpio_pin_direction
{
    GPIO_DigitalInput = 0U,             /* 输入 */
    GPIO_DigitalOutput = 1U,            /* 输出 */
} gpio_pin_direction_t;

/* GPIO配置结构体类型定义 */
typedef struct _gpio_pin_config
{
    gpio_pin_direction_t Direction;     /* GPIO方向:输入或输出 */
    uint8_t OutputLogic;                /* 如果为输出,设置默认输出电平 */
} gpio_pin_config_t;


/* 函数声明 */
void Gpio_Init(GPIO_Type *base, int pin, gpio_pin_config_t *config);
int Gpio_Pin_Read(GPIO_Type *base, int pin);
void Gpio_Pin_Write(GPIO_Type *base, int pin, int value);

#endif

十、编写bsp_key文件:

1、编写bsp_key.c文件

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


/* 按键初始化 */
void Key_Init(void)
{
    gpio_pin_config_t KEY_Config;

    /* 初始化IO复用,复用为GPIO1_IO18 */
    IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);

    /* 配置GPIO1_IO18的IO电气属性 */
    IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0xF0B0);

    /* 初始化GPIO1_IO18设置为输入 */
    KEY_Config.Direction = GPIO_DigitalInput;
   
    Gpio_Init(GPIO1, 18, &KEY_Config);
}


/* 获取按键值,并且进行消抖处理,即通过一定延时后对按键状态进行判断 */
int Key_GetValue(void)
{
    int ret = 0;
    static unsigned char release = 1;                       /* release = 1表示按键释放;release = 0表示按键按下 */
    
    if ((release==1) && (Gpio_Pin_Read(GPIO1, 18)==0))      /* 按键按下 */
    {
        delay_ms(10);                                       /* 延时大约10ms */
        release = 0;                                        /* release = 0,即按键按下 */
        if (Gpio_Pin_Read(GPIO1, 18)==0)                    /* 延时大约10ms后,KEY1仍是0,则表明按键有效 */
        {
            ret = KEY1_VALUE;                               /* 返回KEY1的键值 */
        }
    }
    else if (Gpio_Pin_Read(GPIO1, 18)==1)                   /* 按键未按下 */
    {
        ret = KEY_NONE;
        release = 1;                                        /* release = 1,即按键未按下 */
    }
    return ret;
}

2、编写bsp_key.h文件

#ifndef __BSP_KEY_H
#define __BSP_KEY_H

#include "imx6u.h"


/* 定义按键值 */
enum KeyValue
{
    KEY_NONE = 0,
    KEY1_VALUE = 1,
    KEY2_VALUE = 2,
    KEY3_VALUE = 3,
    KEY4_VALUE = 4,
    KEY5_VALUE = 5,
    KEY6_VALUE = 6,
    KEY7_VALUE = 7,
    KEY8_VALUE = 8,
};


/* 函数声明 */
void Key_Init(void);
int Key_GetValue(void);


#endif

十一、编写main.c文件:

#include "main.h"

#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 key_value = 0;
    unsigned char led_state = OFF;
    unsigned char beep_state = OFF;

    Clk_Enable();                                   /* 使能外设时钟 */
    Led_Init();                                     /* 初始化Led */
    Beep_Init();                                    /* 初始化Beep */
    Key_Init();                                     /* 初始化Key */

    while(1) 
    {
        /* 按键控制蜂鸣器 */
        key_value = Key_GetValue();
        if (key_value)
        {
            switch (key_value)
            {
                case KEY1_VALUE:
                    beep_state = !beep_state;
                    Beep_Switch(beep_state);
                    break;
            }
        }


        /* LED1每隔500ms闪烁一次,提示系统正常运行 */
        i++;
        if (i==50)
        {
            i = 0;
            led_state = !led_state;
            Led_Switch(LED1, led_state);
        }
        delay_ms(10);
    }
    return 0;
}


十二、编写imx6u.lds脚本链接文件:

        编写该文件时,尤其注意“__bss_start = . ;”前面必须添加四字节对齐程序,由于该单片机是32位,程序执行时以四字节为单位。

SECTIONS
{
    . = 0x87800000;
    .text :
    {
        obj/start.o
        *(.text)
    }
    .rodata ALIGN(4) : {*(.rodata*)}

    .data ALIGN(4) : {*(.data)}

    . = ALIGN(4);
    __bss_start = . ;
    
    .bss ALIGN(4) : {*(.bss) *(COMMON)}
    __bss_end = . ;
}

十三、编写Makefile文件:

TARGET			?= key
CROSS_COMPILE	?= arm-linux-gnueabihf-

LD				:= $(CROSS_COMPILE)ld
OBJCOPY			:= $(CROSS_COMPILE)objcopy
OBJDUMP			:= $(CROSS_COMPILE)objdump
GCC				:= $(CROSS_COMPILE)gcc

INCDIRS			:=	imx6u \
					bsp/clk \
					bsp/delay \
					bsp/led \
					bsp/beep \
					bsp/key \
					bsp/gpio

SRCDIRS			:=	project \
					bsp/clk \
					bsp/delay \
					bsp/led \
					bsp/beep \
					bsp/key \
					bsp/gpio

INCLUDE			:= $(patsubst %, -I %, $(INCDIRS))

SFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))

SFILENDIR		:= $(notdir $(SFILES))
CFILENDIR		:= $(notdir $(CFILES))

SOBJS			:= $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS			:= $(patsubst %, obj/%, $(CFILENDIR:.c=.o))

OBJS			:= $(SOBJS) $(COBJS)

VPATH			:= $(SRCDIRS)

.PHONY:clean

$(TARGET).bin : $(OBJS)
	$(LD) -Timx6u.lds -o $(TARGET).elf $^
	$(OBJCOPY) -O binary -S $(TARGET).elf $@
	$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis

$(SOBJS) : obj/%.o : %.S
	$(GCC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<

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

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

print:
	@echo INCLUDE = $(INCLUDE)
	@echo SFILES = $(SFILES)
	@echo CFILES = $(CFILES)
	@echo SFILENDIR = $(SFILENDIR)
	@echo CFILENDIR = $(CFILENDIR)
	@echo SOBJS = $(SOBJS)
	@echo COBJS = $(COBJS)
	@echo OBJS = $(OBJS)

十四、编写.vscode文件:

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "${workspaceFolder}/imx6u",
                "${workspaceFolder}/project",
                "${workspaceFolder}/bsp/clk",
                "${workspaceFolder}/bsp/delay",
                "${workspaceFolder}/bsp/led",
                "${workspaceFolder}/bsp/beep",
                "${workspaceFolder}/bsp/key",
                "${workspaceFolder}/bsp/gpio"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "gnu17",
            "cppStandard": "gnu++17",
            "intelliSenseMode": "linux-gcc-x64",
            "configurationProvider": "ms-vscode.makefile-tools"
        }
    ],
    "version": 4
}

十五、编译与烧写程序:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值