8.ARM-Key按键实验

ARM-Key按键实验

  • 一、查看原理图

    • (1)查看外设板原理图(搜索K2

      • Key原理图
      • 控制逻辑
        • K2 按下 ---- GPX1_1 低电平
          K2 抬起 ---- GPX1_1 高电平
    • (2)查看外设板原理图(搜索UART_RING

      • Key外设板
      • 通过搜索发现UART_RING连接到外设板CON4的58号引脚
    • (3)查看核心板原理图(搜索UART_RING

      • 通过开发板丝印发现核心板CON3连接到外设板CON4上
      • CON3+CON4
      • Key核心板
      • 通过搜索发现UART_RING连接到核心板GPX1_1,这个引脚为GPX1的第1个引脚
  • 二、查看芯片手册

    • 芯片手册搜索GPX1

      • GPX1CON1
      • GPX1CON2
  • 三、操作GPIO

    • (1)GPX1CON寄存器

      • GPX1CON地址为0x1100C20;
      • K2如果要做为输入设备,只需要将GPX1CON[7:4]设置为0x0
    • (2)GPX1DAT寄存器

      • GPX1DAT
      • 只需要读取引脚状态即可判定K2状态
  • 四、编写代码

    • exynos_4412.h中有这款芯片所有的寄存器地址,可以通过查找得到对应结构体

      • typedef struct {
        	unsigned int CON;
        	unsigned int DAT;
        	unsigned int PUD;
        	unsigned int DRV;
        }gpx1;
        #define GPX1 (*(volatile gpx1 *)0x11000C20)
        
      • 寄存器结构体
      • #define GPX1 (*(volatile gpx1 *)0x11000C20)
        • 常量0x11000C20 强转成struct gpx1类型指针
        • 查找指针对应的内存驱动,即对应整个结构体变量,结构体变量地址为0x11000C20
        • GPX1等价于地址为0x11000C20的结构体变量
        • 要想操作GPX1的寄存器,就可以像结构体变量一样操作即可。
      • //key.c
        #include "exynos_4412.h"
        #include "exynos_setup.h"
        
        extern void led_init(int num);
        extern void led_on(int num);
        extern void led_off(int num);
        
        //GPX1_1:GPX1的第1个引脚(每个引脚4位)K2
        
        //按键K2初始化
        void key2_init(void)
        {
        #if 0
            GPX1.CON = GPX1.CON & ~(0xf << 4); //将GPX1CON寄存器[7,4]位清0
            GPX1.CON = GPX1.CON | (0x0 << 4); //将GPX1CON寄存器[7,4]赋值0x0设置输入模式
        #endif
            SET_GPIO_MODE(GPX1.CON, 1, 0x0); //等价于if和endif之间的语句
            return ;
        }
        
        //读取按键K2状态
        int read_key2(void)
        {
            return GPX1.DAT & (0x1 << 1); //将GPX1DAT寄存器[7,0]第1位的值返回(1:抬起高电平或0:按下低电平)
        }
        
        //延迟函数(单位:ms)
        void delay_ms(int ms)
        {
            int i = 0, j = 0;
            while(ms--)
            {
                for(i = 0; i < 5; i++)
                {
                    for(j = 0; j < 514; j++)
                    {
                        ;
                    }
                }
            }
            return ;
        }
        
        //key测试
        void key_test(void)
        {
            /*按下按键灯点亮、松开按键灯熄灭
            key2_init();
            led_init(3); //初始化LED5
            while (1)
            {
                if (read_key2() == 0) //按下按键LED5点亮
                {
                    led_on(3);
                }
                else //松开按键LED5熄灭
                {
                    led_off(3);
                }
            }
            */
        
            //按下按键灯点亮,再次按下按键灯熄灭
            key2_init();
            led_init(0); //初始化LED2
            int flag = 0; //设置用户按下次数的标志位,奇数次亮,偶数次灭
            while (1)
            {
                //用户按下了K2按键
                if(read_key2() == 0)
                {
                    delay_ms(5); //等待5ms
                    //用户按下还没有松开
                    if(read_key2() == 0)
                    {
                        if(flag == 0) //第基数次按下
                        {
                            led_on(0);
                            flag = 1; //更新标志位
                        }
                        else //第偶数次按下
                        {
                            led_off(0);
                            flag = 0; //更新标志位
                        }
                        while(read_key2() == 0) //用户一直按下没有松开
                        {
                            ;
                        }
                        delay_ms(5); //等待5ms
                    }
                }
            }
            return ;
        }
        
      • //led.c
        #define DAT_OFFSET  4
        
        struct led_des{
        	int pin; //引脚
        	int addr; //寄存器起始地址
        };
        
        struct led_des  leds[] = {
        	{7,0x11000c40}, //0  LED2
        	{0,0x11000c20}, //1  LED3
        	{4,0x114001E0}, //2  LED4
        	{5,0x114001E0}, //3  LED5
        };
        
        
        void led_init(int num)
        {
            //设置为输出工作模式
            int *p;
            
            //传入参数的合法性
        	if(num < 0 || num > 3){
        		return;
        	}
        	
        	p = (int *)leds[num].addr;
            *p = *p & ~(0xf << (4 * leds[num].pin));
            *p = *p |  (0x1 << (4 * leds[num].pin));
            
            return;
        }
        
        void led_on(int num)
        {
            //输出高电平
            int *p;
            
        	if(num < 0 || num > 3){
        		return;
        	}
        	
        	p = (int *)(leds[num].addr + DAT_OFFSET);
        	*p = *p | (1 << leds[num].pin);
        	
        	return;
        }
        
        void led_off(int num)
        { 
             //输出低电平
            int *p;
            
        	if(num < 0 || num > 3){
        		return;
        	}
        	
        	p = (int *)(leds[num].addr + DAT_OFFSET);
        	*p = *p & ~(1 << leds[num].pin);
        	
        	return;
        }
        
        void delay_time(int time)
        {
        	int i,j;
        	
        	for(i = 0;i < 100 * time;i ++){
        		
        		for(j = 0;j < 5000;j ++){
        			
        		}
        	}
        }
        
        void water_flower_led(int n)
        {
        	int i;
        	
        	for(i = 0;i < n;i ++){
        		led_init(i);
        	}
        	
        	while(1){
        		
        		for(i = 0;i < n;i ++){
        			led_on(i);
        			delay_time(1);
        			led_off(i);
        			delay_time(1);
        		}
        	}
        }
        
      • //start.s
        .global _start
        
        _start:
          b reset
        	ldr pc,_undefined_instruction 	@ B undefined_instruction
        	ldr pc,_software_interrupt  	@ B software_interrupt
        	ldr pc,_prefetch_abort 			@ B prefetch_abort
        	ldr pc,_data_abort 				@ B data_abort
        	ldr pc,_not_used 				@ B not_used
        	ldr pc,_irq 					@ B irq
        	ldr pc,_fiq 					@ B fiq
        
        @ 异常向量表
        _undefined_instruction:.word _undefined_instruction @ 未定义异常
        _software_interrupt:.word software_interrupt 		@ 软件中断异常
        _prefetch_abort:.word _prefetch_abort 				@ 取指令中止异常
        _data_abort:.word _data_abort 						@ 取数据中止异常
        _not_used:.word _not_used 							@ 未使用异常
        _irq:.word irq 										@ 一般中断异常
        _fiq:.word _fiq 									@ 快速中断异常
        
        reset:
        	@告诉ARM核异常向量表所在的基地址
        	adr r0,_start @获得异常向量表所在的地址
        	mcr p15,0,r0,c12, c0, 0 @将异常向量表的基地址写入cp15协处理器的寄存器c12
        
        	ldr sp,=0x40008000
        	bl main
        
        stop:
        	b stop
        
        software_interrupt:
        	ldr sp,=0x40009000
        	stmfd sp!,{r0-r12,lr}
        
        	ldr r0,[lr,#-4]
        	mov r1,#0xff
        	bic r0,r0,r1,lsl #24
        
        	ldmfd sp!,{r0-r12,pc}^
        
        irq:
        	ldr sp,=0x40010000
        	sub lr,lr,#4
        	stmfd sp!,{r0-r12,lr}
        	ldmfd sp!,{r0-r12,pc}^
        
      • //Config.mk
        COBJECTS += driver/led.o
        COBJECTS += driver/key.o
        
      • //main.c
        extern void key_test(void);
        
        int main(void)
        {
        	key_test();
        	return 0;
        }
        
      • //Makefile
        CROSS_COMPILE = arm-none-eabi-
        GCC  = $(CROSS_COMPILE)gcc
        LOAD  = $(CROSS_COMPILE)ld
        OBJECTCOPY = $(CROSS_COMPILE)objcopy
        ELF = key.elf
        BIN = key.bin
        CINCLUDES = -I ./Include
        
        LOADFLAGS += -static -L ./Lib -lc -lm -lnosys
        LOADFLAGS += -static -L ./Lib -lgcc
        
        include Config.mk
        
        # arm-none-eabi-ld -Ttext=0x40000000 start.o main.o led.o -o led.elf
        # arm-none-eabi-objcopy -O binary led.elf led.bin
        $(ELF):Start/start.o main.o  $(COBJECTS)
        	$(LOAD) -Ttext=0x40000000 $^ -o $@ $(LDFLAGS) 	
        	$(OBJECTCOPY) -O binary $(ELF) $(BIN) 			
        	
        
        # arm-none-eabi-gcc -c start.s -o start.o
        # arm-none-eabi-gcc -c led.c -o led.o
        # arm-none-eabi-gcc -c main.c -o main.o
        %.o:%.s
        	$(GCC) -c $< -o $@
        
        %.o:%.c
        	$(GCC) -c $< -o $@  $(CINCLUDES)
        
  • 五、编译代码

    • 利用Makefile编译文件,提升效率

      • Makefile
      • Key按键工程文件结构
      • Driver
      • Include
      • Lib
      • Start
  • 六、下载代码到开发板上

    • 和LED灯的下载代码步骤一致(==超级终端)

    • 按键Key控制LED的亮灭

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
首先,这个错误提示是在编译过程中出现的,具体的错误是 C compiler cannot create executables,意思是 C 编译器无法生成可执行文件。那么解决这个问题,一般可以按照以下步骤来进行: 1. 检查编译器是否正确安装 这个问题的根源是编译器无法生成可执行文件,所以我们需要检查编译器是否正确安装。使用以下命令可以查看已经安装的编译器: ``` dpkg --get-selections | grep gcc ``` 如果没有安装或者安装的版本不正确,可以使用以下命令来安装: ``` sudo apt-get install build-essential ``` 2. 检查编译环境是否正确设置 使用以下命令可以检查编译环境是否正确设置: ``` echo $PATH ``` 如果没有包含编译器的路径,可以使用以下命令添加路径: ``` export PATH=$PATH:/usr/local/bin ``` 3. 检查是否有必要的依赖库 有些编译器需要依赖库才能正常工作,如果没有安装这些依赖库,也会出现 C 编译器无法生成可执行文件的问题。使用以下命令可以检查是否安装了 libtool: ``` sudo apt-get install libtool ``` 4. 检查系统架构 最后,还需要检查系统架构是否正确。根据提示信息,可以看到目标系统是 arm-ostl-linux-gnueabi,而本机的系统是 x86_64-pc-linux-gnu,因此需要在编译过程中指定目标系统的架构,比如: ``` ./configure --host=arm-ostl-linux-gnueabi ``` 通过以上步骤,一般就可以解决 C 编译器无法生成可执行文件的问题。如果仍然无法解决,可以查看 config.log 文件,里面会有详细的错误信息,根据错误信息再进行调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值