C工程与寄存器封装

news2024/11/15 9:28:40

目录

一、C语言工程简介

二、启动代码分析

三、C语言实现LED

四、寄存器的封装方式

五、寄存器操作的标准化

六、流水灯


一、C语言工程简介

 先将工程模板解压

 

 include里是.h文件  src里是.c文件   start里面是.s启动文件  

 

 #=============================================================================#
  NAME = interface
  CROSS_COMPILE = arm-none-linux-gnueabi-
  #=============================================================================#
   CC = $(CROSS_COMPILE)gcc
   LD = $(CROSS_COMPILE)ld
   OBJDUMP = $(CROSS_COMPILE)objdump
   OBJCOPY = $(CROSS_COMPILE)objcopy
   CFLAGS  += -g -O0 -mabi=apcs-gnu -mfpu=neon -mfloat-abi=softfp -fno-builtin \
                     -nostdinc -I ./common/include
  #============================================================================#
  OBJSss  := $(wildcard start/*.S) $(wildcard common/src/*.S) $(wildcard *.S) \
                     $(wildcard start/*.c) $(wildcard common/src/*.c)                         \
                    $(wildcard usr/*.c) $(wildcard *.c)
  OBJSs   := $(patsubst %.S,%.o,$(OBJSss))
  OBJS    := $(patsubst %.c,%.o,$(OBJSs))
  #============================================================================#
  %.o: %.S
         $(CC) $(CFLAGS) -c -o $@ $<
 %.o: %.c
          $(CC) $(CFLAGS) -c -o $@ $<
  all:clean $(OBJS)
          $(LD) $(OBJS) -T map.lds -o $(NAME).elf
          $(OBJCOPY) -O binary  $(NAME).elf $(NAME).bin 
         $(OBJDUMP) -D $(NAME).elf > $(NAME).dis 
 #============================================================================#
  clean:
          rm -rf $(OBJS) *.elf *.bin *.dis *.o
 #============================================================================#
 

OBJDUMP是用来反汇编的,将二进制文件生成汇编代码。

map.lds是链接用的脚本文件告诉编译器C程序代码都放到哪儿段,代码段、数据段、BSS段在内存中的分部,程序的起始地址、对齐问题等。

二、启动代码分析

 1 .text
  2 .global _start
  3 _start:
  4         /*
  5          * Vector table
  6          */
  7         b reset
  8         b .
  9         b .
 10         b .
 11         b .
 12         b .
 13         b .
 14         b .
 15 
 16 reset:
 17         /*
 18          * Set vector address in CP15 VBAR register
 19          */
 20         ldr     r0, =_start
 21         mcr     p15, 0, r0, c12, c0, 0  @Set VBAR
 22 
 23         /*
 24          * Set the cpu to SVC32 mode, Disable FIQ/IRQ
 25          */
 26         mrs r0, cpsr
 27         bic r0, r0, #0x1f
 28         orr     r0, r0, #0xd3
 29         msr     cpsr ,r0
 30 
 31         /*
 32          * Defines access permissions for each coprocessor
 33          */
 34     mov r0, #0xfffffff
 35     mcr p15, 0, r0, c1, c0, 2
 36 
 37         /*
 38          * Invalidate L1 I/D                                                                                                                       
 39          */
 40         mov     r0, #0                                  @Set up for MCR
 41         mcr     p15, 0, r0, c8, c7, 0   @Invalidate TLBs
 42         mcr     p15, 0, r0, c7, c5, 0   @Invalidate icache
 43 
 44         /*
 45          * Set the FPEXC EN bit to enable the FPU
 46          */
 47         mov r3, #0x40000000
 48         fmxr FPEXC, r3
 49 
 50         /*
 51          * Disable MMU stuff and caches
 52          */
 53         mrc     p15, 0, r0, c1, c0, 0
 54         bic     r0, r0, #0x00002000             @Clear bits 13 (--V-)
 55         bic     r0, r0, #0x00000007             @Clear bits 2:0 (-CAM)
 56         orr     r0, r0, #0x00001000             @Set bit 12 (---I) Icache
 57         orr     r0, r0, #0x00000002             @Set bit 1 (--A-) Align
 58         orr     r0, r0, #0x00000800             @Set bit 11 (Z---) BTB
 59         mcr     p15, 0, r0, c1, c0, 0
 60 
 61         /*
 62          * Initialize stacks                                                                                                                      
 63          */
 64 init_stack:
 65         /*svc mode stack*/
 66         msr cpsr, #0xd3
 67         ldr sp, _stack_svc_end
 68 
 69         /*undef mode stack*/
 70         msr cpsr, #0xdb
 71         ldr sp, _stack_und_end
 72 
 73         /*abort mode stack*/
 74         msr cpsr,#0xd7
 75         ldr sp,_stack_abt_end
 76 
 77         /*irq mode stack*/
 78         msr cpsr,#0xd2
 79         ldr sp, _stack_irq_end
 80 
 81         /*fiq mode stack*/
 82         msr cpsr,#0xd1
 83         ldr sp, _stack_fiq_end
 84 
 85         /*user mode stack, enable FIQ/IRQ*/
 86         msr cpsr,#0x10
 87         ldr sp, _stack_usr_end
 88 
 89         /*Call main*/
 90         b main
 91 
 92 _stack_svc_end:
 93         .word stack_svc + 512
 94 _stack_und_end:
 95         .word stack_und + 512
 96 _stack_abt_end:
 97         .word stack_abt + 512
 98 _stack_irq_end:
 99     .word stack_irq + 512
100 _stack_fiq_end:
101     .word stack_fiq + 512
102 _stack_usr_end:
103     .word stack_usr + 512
104 
105 .data
106 stack_svc:
107         .space 512
108 stack_und:
109         .space 512
110 stack_abt:
111         .space 512
112 stack_irq:
113         .space 512
114 stack_fiq:
115         .space 512
116 stack_usr:
117         .space 512

6~14是异常向量表的位置b.就是跳转到自身相当于死循环

ldr     r0, =_start
mcr     p15, 0, r0, c12, c0, 0  @Set VBAR

将异常向量表存入 R0,然后将R0存入cp15的C12,总体作用就是转存异常向量表。

TLB和MMU都是和虚拟内存相关的东西,由于现在没有操作系统所以直接运行在物理内存条就行。

.space伪操作把512个字节占了,占的这些就是栈的位置。6个有栈指针的模式都有自己的栈空间。

 92 _stack_svc_end:
 93         .word stack_svc + 512

用来计算栈指针的起始位置,因为是满减栈,要从高往低压

三、C语言实现LED

void delay(unsigned int time)
{
	while(time --);
}
int main()
{
	/*设置GPX2CON将GPX2_7设置成输出*/
	*(unsigned int *)0x11000c40 = 0x10000000;
	while(1)
	{
		*(unsigned int *)0x11000c44 = 0x00000080;
		delay(1000000);
		*(unsigned int *)0x11000c44 = 0x00000000;
		delay(1000000);
	}

	return 0;
}

四、寄存器的封装方式

为了增强可读性、也为了安全,所以将寄存器封装一下以寄存器名字命名:

void delay(unsigned int time)
{
	while(time --);
}
#if 0
int main()
{
	/*设置GPX2CON将GPX2_7设置成输出*/
	*(unsigned int *)0x11000c40 = 0x10000000;
	while(1)
	{
		*(unsigned int *)0x11000c44 = 0x00000080;
		delay(1000000);
		*(unsigned int *)0x11000c44 = 0x00000000;
		delay(1000000);
	}

	return 0;
}
#endif

#define GPX2CON (*(unsigned int *)0x11000c40)
#define GPX2DAT (*(unsigned int *)0x11000c44)

int main()
{
	GPX2CON = 0x10000000;
	while(1)
	{
		GPX2DAT = 0x00000080;
		delay(1000000);
		GPX2DAT = 0x00000000;
		delay(1000000);
	}

	return 0;
}

通过观察手册我们可以发现描述一个引脚的四个寄存器他的空间是连续的,而同样连续空间的还有数组和结构体,诶一下就能想到我们在学习32时使用的库函数,32中的GPIO初始化结构体,我们是不是可以自己写一个呢。

void delay(unsigned int time)
{
	while(time --);
}
#if 0
int main()
{
	/*设置GPX2CON将GPX2_7设置成输出*/
	*(unsigned int *)0x11000c40 = 0x10000000;
	while(1)
	{
		*(unsigned int *)0x11000c44 = 0x00000080;
		delay(1000000);
		*(unsigned int *)0x11000c44 = 0x00000000;
		delay(1000000);
	}

	return 0;
}
#endif
#if 0
#define GPX2CON (*(unsigned int *)0x11000c40)
#define GPX2DAT (*(unsigned int *)0x11000c44)

int main()
{
	GPX2CON = 0x10000000;
	while(1)
	{
		GPX2DAT = 0x00000080;
		delay(1000000);
		GPX2DAT = 0x00000000;
		delay(1000000);
	}

	return 0;
}
#endif
typedef struct 
{
	unsigned int CON;
	unsigned int DAT;	
	unsigned int PUD;	
	unsigned int DRV;	
}gpx2;

#define GPX2 (*(gpx2 *)0x11000c40)

int main()
{
	GPX2.CON = 0x10000000;
	while(1)
	{
		GPX2.DAT = 0x00000080;
		delay(1000000);
		GPX2.DAT = 0x00000000;
		delay(1000000);
	}
	
	return 0;
}

既然一个可以写,那是不是我们可以将全部的寄存器都写好放到一个.h文件中呢。果然有将近3000行的库文件我们可以直接调用。

void delay(unsigned int time)
{
	while(time --);
}
#if 0
int main()
{
	/*设置GPX2CON将GPX2_7设置成输出*/
	*(unsigned int *)0x11000c40 = 0x10000000;
	while(1)
	{
		*(unsigned int *)0x11000c44 = 0x00000080;
		delay(1000000);
		*(unsigned int *)0x11000c44 = 0x00000000;
		delay(1000000);
	}

	return 0;
}
#endif
#if 0
#define GPX2CON (*(unsigned int *)0x11000c40)
#define GPX2DAT (*(unsigned int *)0x11000c44)

int main()
{
	GPX2CON = 0x10000000;
	while(1)
	{
		GPX2DAT = 0x00000080;
		delay(1000000);
		GPX2DAT = 0x00000000;
		delay(1000000);
	}

	return 0;
}
#endif
#if 0
typedef struct 
{
	unsigned int CON;
	unsigned int DAT;	
	unsigned int PUD;	
	unsigned int DRV;	
}gpx2;

#define GPX2 (*(gpx2 *)0x11000c40)

int main()
{
	GPX2.CON = 0x10000000;
	while(1)
	{
		GPX2.DAT = 0x00000080;
		delay(1000000);
		GPX2.DAT = 0x00000000;
		delay(1000000);
	}
	
	return 0;
}
#endif

#include "exynos_4412.h"

int main()
{
	GPX2.CON = 0x10000000;
	while(1)
	{
		GPX2.DAT = 0x00000080;
		delay(1000000);
		GPX2.DAT = 0x00000000;
		delay(1000000);
	}
	
	return 0;
}

五、寄存器操作的标准化

其实程序还有问题,因为我们操作的不够具体,每次操作不光操作LED2还操作了其它的位。

在修改代码前先做两个小题:

1.unsigned int a;        将a的第三位置1,其它位保持不变

a = a | (1 << 3)

2.unsigned int a;     将a的第三位置0, 其它位保持不变

a = a & (~(1 << 3))

3.unsigned int a;     将a的【7:4】位置为0101,其它位不变

a = a & (~(0xF << 4));

a = a | (0x5 << 4);

a = a &(~(0xF << 4)) | (0x5 << 4)

 

void delay(unsigned int time)
{
	while(time --);
}
#include "exynos_4412.h"

int main()
{
	GPX2.CON = GPX2.CON & (~(0xF << 28)) | (0x1 << 28);
	while(1)
	{
		GPX2.DAT = GPX2.DAT | (1 << 7);
		delay(1000000);
		GPX2.DAT = GPX2.DAT & (~(1 << 7));
		delay(1000000);
	}
	
	return 0;
}

六、流水灯

基本操作都学的差不多了,还等什么流水灯呀

 LED2和LED3在上篇博客发了

GPIO实验_宇努力学习的博客-CSDN博客

现在补全LED4和LED5的电路图和相关寄存器

 正好这俩挨着

 

void delay(unsigned int time)
{
	while(time --);
}
#include "exynos_4412.h"

int main()
{
	GPX2.CON = GPX2.CON & (~(0xF << 28)) | (0x1 << 28);
	GPX1.CON = GPX1.CON & (~(0xF)) | (0x1);
	GPF3.CON = GPF3.CON & (~(0xFF << 16)) | (0x11 << 16);
	while(1)
	{
		GPX2.DAT = GPX2.DAT | (1 << 7);
		delay(1000000);
		GPX2.DAT = GPX2.DAT & (~(1 << 7));
		delay(1000000);
		GPX1.DAT = GPX1.DAT | 1;
		delay(1000000);
		GPX1.DAT = GPX1.DAT & (~1);
		delay(1000000);	
		GPF3.DAT = GPF3.DAT | (1 << 4);
		delay(1000000);
		GPF3.DAT = GPF3.DAT & (~(1 << 4));
		delay(1000000);
		GPF3.DAT = GPF3.DAT | (1 << 5);
		delay(1000000);
		GPF3.DAT = GPF3.DAT & (~(1 << 5));
		delay(1000000);	
			
	}
	
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/130992.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Fusion360 外壳开孔零件居中对齐的方法

DIY时需要根据从市场上采购的成品盒子进行开孔&#xff0c;通过3维软件进行开孔设计是比较方便的。Solidworks由于版权问题不易采用&#xff0c;Fusion360的个人版由于软件差异不像Solidworks方便约束定位。我通过尝试找到了适用方法。 先看成果。在一块板上居中位置开孔以便安…

电子学会2020年9月青少年软件编程(图形化)等级考试试卷(三级)答案解析

目录 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 二、判断题&#xff08;共10题&#xff0c;每题2分&#xff0c;共20分&#xff09; 三、编程题【该题由测评师线下评分】&#xff08;共3题&#xff0c;共30分&#xff09; 青少年软件…

阶段性回顾(4)与四道题目

TIPS 1. 当创建数组的时候&#xff0c;如果没有指定数组的元素个数也没关系&#xff0c;编译器会根据你初始化的内容来自行确定。 2. 在逻辑表达式当中&#xff0c;如果为真&#xff0c;就以1作为结果&#xff0c;如果为假&#xff0c;就以0作为结果。 3. 输入字符串的时候&…

VUE实例的组件的生命周期和数据共享和ref的使用方法(建议直接看ref)

目录VUE实例的组件的生命周期和数据共享组件间的数据共享ref的使用方法使用ref操作dom使用ref引用组件this.$nextTick(cb)方法的使用VUE实例的组件的生命周期和数据共享 生命周期和生命周期函数 这个是我学校vue书籍阿里云盘地址,有需要可以点击看看 生命周期&#xff08;Life…

对Java中异常的认识

文章目录一、异常的概念与体系结构1.异常的概念2.异常的体系结构3.异常的分类二、异常的处理1.防御式编程2. 异常的抛出3.异常的捕获4.异常处理流程总结三、自定义异常类一、异常的概念与体系结构 1.异常的概念 在生活中&#xff0c;当我们发现朋友表现出不舒服的情况&#x…

LabVIEW ​​单​进程​共享​变量​与​​全局​变量

LabVIEW ​​单​进程​共享​变量​与​​全局​变量 单​进程​共享​变量​与​LabVIEW​全局​变量​相似。​事实​上&#xff0c;​单​进程​共享​变量​的​实现​是在​LabVIEW​全局​变量​的​基础​上​增加​了​时间​标识​功能。 ​为了​比较​单​进程​…

《终身成长》读书笔记

文章目录书籍信息思维模式思维模式解析关于能力和成就的真相体育&#xff1a;冠军的思维模式商业&#xff1a;思维模式和领导力人际关系&#xff1a;关于相处的思维模式父母、老师与教练&#xff1a;思维模式的传播改变思维模式书籍信息 书名&#xff1a;《终身成长》 作者&am…

Java算法_LeetCode26:删除排序数组中的重复项

LeetCode26&#xff1a;删除排序数组中的重复项 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。 由于在某些语言中不能改变数组的长度&a…

设计模式-责任链模式之**动态配置责任链**

正在参加2022年度博客之星评选&#xff0c;大家帮我点个五星好评。有投必会 责任链的优势劣势我就不说&#xff0c;百度上很多。 1、怎么&#xff1a;动态配置责任链 通过配置文件yml来指定你的责任链的执行顺序。 地址 配置文件如何配置&#xff0c;怎么读取 为什么&#x…

HTTP协议详解 - 通过C++实现HTTP服务剖析HTTP协议

前言 C/C程序员一般很少会接触到HTTP服务端的东西&#xff0c;所以对HTTP的理解一般停留在理论。 本文章实现通过C实现了一个http服务&#xff0c;可以通过代码对HTTP协议有更深的理解&#xff0c;并且通过抓包工具对HTTP协议进行更为详细的分析。 HTTP协议简介 HTTP(hypert…

Linux--多线程

目录1. 什么是线程2. 创建线程3. 线程等待3.1 pthread_join函数3.2 线程分离3.2 线程终止的方案4. 线程ID1. 什么是线程 Linux中没有专门为线程设计TCB&#xff0c;而是用进程的PCB来模拟进程。 这也是为什么有种观点会说Linux下没有真正意义上的线程。 对于线程来说&#xf…

Elasticsearch搜索引擎(二)——SpringData Elasticsearch

SpringData Elasticsearch SpringData介绍 Spring Data是一个用于简化数据库访问&#xff0c;并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷&#xff0c;并支持map-reduce框架和云计算数据服务。 Spring Data可以极大的简化JPA的写法&#xff0c;可以在…

CSND近期推出的猿如意到底怎么样?

CSND近期推出的猿如意到底怎么样&#xff1f; 投稿测评正文 猿如意传送门 猿如意下载地址&#xff1a;猿如意-程序员的如意兵器,工具代码,一搜就有 猿如意使用了几次了&#xff0c;今天来想分享一下我对于猿如意的使用感受吧&#xff01;&#xff01; 先说结论&#xff1a…

吴恩达《机器学习》——Logistics回归代码实现

Logisitc回归1. Sigmoid与二分类Sigmoid函数为什么Sigmoid函数可以表示二分类概率&#xff1f;2. Logistics回归交叉熵损失函数梯度过拟合与欠拟合正则化3. Python代码实现4. 单维与多维Logistic分类单维数据分类多维数据分类数据集、源文件可以在Github项目中获得 链接: https…

04 kafka 中一些常用的配置的使用

前言 呵呵 也是最近有一些 搭建 kafka 的环境的需求 然后 从新看了一下 一部分的配置情况, 这里 大致理一下 一些我这里比较关心的配置 那些配置关联了 kafka 服务器绑定服务 绑定 tcp 服务的配置来自于这里, 读取的是 config.dataPlaneListeners config.dataPlaneListen…

Java母婴商城母婴店孕妇商城婴幼儿商城网站系统源码

简介 java使用ssm开发的母婴商城系统&#xff0c;用户可以注册浏览商品&#xff0c;加入购物车或者直接下单购买&#xff0c;在个人中心管理收货地址和订单&#xff0c;管理员也就是商家登录后台可以发布商品&#xff0c;上下架商品&#xff0c;处理待发货订单等。 演示视频&…

Allegro如何在PCB上查看pin number的三种方法操作指导

Allegro如何在PCB上查看pin number的三种方法操作指导 Allegro支持快捷的在PCB上查看pin number,如下图 具体操作如下 方法一:show element 选择Show Element命令Find选择Pins

2022年学习机器人和人工智能的一些期待

2022年学习机器人和人工智能的一些体会 2023年即将到来&#xff0c;满满的期待。 做好规划是非常非常重要的&#xff0c;有时候甚至比认真做事本身更为重要。 《礼记中庸》&#xff1a;“凡事豫则立&#xff0c;不豫则废。言前定则不跲&#xff0c;事前定则不困&#xff0c;行…

视频解码学习备忘

媒体文件知识 日常都是播放器直接播&#xff0c;其实这里面还有不少内容的。 首先是视频容器&#xff0c;就是所谓的.mp4 .mkv 这类文件,其目的主要就是用来存放音频视频字幕等内容&#xff0c;所以叫做容器。这些都有一定规范&#xff0c;比如mp4&#xff0c;叫ISO 14496-12…

流程图+BPMN+脑图 JointJS++ 3.6.3 Crack

一个库&#xff0c;‍ 无限的UI选择&#xff0c;直接在您的应用程序中享受交互式流程图、BPMN 和其他图表工作室。利用我们的模板化应用程序&#xff0c;将开发时间缩短至几天。 经过十多年和数百万行代码的编写&#xff0c;我们推出了一组随时可用的功能&#xff0c;以帮助您创…