一、编写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
}