C工程与寄存器封装

2023-05-16

目录

一、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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C工程与寄存器封装 的相关文章

  • vue报错:Component name “xxx“ should always be multi-word

    这个问题困扰我这个菜鸡很久了 xff0c 当我run serve的时候总是会报错Component name xxx should always be multi word 一直以为是命名的问题 xff0c 可是改了又改还是不行 xff0c
  • C语言学习---通过指针形参修改实参的值/交换两个数字的值---原理深究

    C语言学习 通过指针形参修改实参的值 交换两个数字的值 原理深究 要通过函数调用修改实参的值 xff0c 首先我们要明白函数调用过程中的传参方式与返回方式 xff1a 传参方式 xff1a 在c语言里面 xff0c 所有的参数传递都是单向的
  • [已解决]Git无法连接远程

    如果你是开了代理的情况下 xff0c Git失效了可以参考我的解决方法 今天Git忽然抽风了 xff0c 显示连接失败 正在获取 origin kex exchange identification Connection closed by
  • 服务端和客户端通信--UDP(含完整源代码)

    UDP通信实验 实验设备 xff1a 目标系统 xff1a Windows 软件工具 xff1a vs2022 vc6 dev 实验要求 xff1a 完成UDP服务端和客户端的程序编写 xff1b 分别实现UDP一对一通信和广播通信功能 实
  • Proteus 8 Professional发生关键仿真错误(疑似中文路径导致)

    Proteus 8 Professional发生关键仿真错误 xff08 疑似中文路径导致 xff09 在软件仿真时出现错误 显示好多红色代码 疑似之前把电脑名命名为中文了 所以缓存路径也是中文 导致Proteus 8 Profession
  • pm2实现linux重启后自启动node服务

    简介 利用pm2非常简单就可以实现 开机自启node服务的功能 目的是为解决服务器由于各种原因自动重启后 node服务没自动启动 导致无法工作的问题 操作步骤 使用pm2 start xff08 启动服务 执行pm2 save 保存当前已经
  • 【C++音视频开发】视频篇 | 图像基础概念

    前言 本专栏将不间断更新有关C 43 43 音视频开发的内容 xff0c 其中有初级章 中级章与高级章的内容 xff0c 包括但不限于音视频基础 FFmpeg实战 QT 流媒体客户端 流媒体服务器 WebRTC实战 Android NDK等
  • 【C++音视频开发】视频篇 | RGB与YUV

    前言 本专栏将不间断更新有关C 43 43 音视频开发的内容 xff0c 其中有初级章 中级章与高级章的内容 xff0c 包括但不限于音视频基础 FFmpeg实战 QT 流媒体客户端 流媒体服务器 WebRTC实战 Android NDK等
  • Docker-常用命令

    目录 一 docker基础命令1 启动与关闭docker2 查看docker信息3 docker帮助命令 二 docker镜像命令1 查询与搜索镜像2 拉取镜像3 删除镜像4 保存与加载镜像 三 docker容器命令1 查看容器运行及状态2
  • Ubuntu18.04安装VScode并配置ROS环境

    1 安装VScode 1 1通过命令安装 在终端命令行中依次输入以下命令 sudo add apt repository ppa ubuntu desktop ubuntu make sudo apt get update sudo apt
  • cropper.js使用

    这两天一直在写上传头像那一部分 xff0c 需要用到cropper裁剪 xff0c 算起来这是我第二次用了 xff0c 本来以为会比较顺手 xff0c 结果一直报这个错 本来以为是jq和cropper的引入顺序问题 xff0c 结果调好了还
  • linux编程基础——文件、进程

    stat 函数获取文件属性 运用 使用stat 函数获取文件属性 xff0c 输出文件大小 写入文件内容 include lt stdio h gt include lt unistd h gt include lt stdlib h gt
  • 【matlab】设置中文版帮助

    版本 xff1a MATLAB2016a 1 双击图标打开MATLAB 2 打开帮助文档页面 3 打开预设项界面 4 设置帮助文档位置 点击帮助 xff0c 文档位置选择在mathworks com上 xff08 需要Internet连接
  • plugin

    plugin是什么 xff1f 1 plugin是插件的意思 xff0c 通常是用于对某个现有的架构进行扩展 2 webpack中的插件 xff0c 就是对webpack现有功能的各种扩展 xff0c 比如打包优化 xff0c 文件压缩等等
  • 已知字符串STRING以‘$’为结束标志;统计其中小写字母的个数,结果送到COUNT单元,并把该字符串中的小写字母变成大写字母,其它字符保持不变。要求分别在屏幕上输出原字符串以及修改后的字符串。

    只为记录汇编作业 题目 xff1a 已知字符串STRING以 为结束标志 xff1b 统计其中小写字母的个数 xff0c 结果送到COUNT单元 xff0c 并把该字符串中的小写字母变成大写字母 xff0c 其它字符保持不变 要求分别在屏幕
  • thinkPHP项目部署后,访问接口提示404错误原因

    正常情况下 xff0c 服务器开启了pathinfo xff08 如何开启 xff1f xff09 之后 xff0c 再修改当前站点的conf文件 xff0c 加上URL重写隐藏index php入口 location api if e r
  • STM32CubeMX驱动4x4键盘模块

    文章目录 1 4x4键盘模块简介2 4x4键盘模块原理2 1 独立按键的原理2 2 矩阵键盘的原理 3 移植源码到工程4 实验 1 4x4键盘模块简介 4x4键盘模块是一种常用的电子组件 xff0c 它由16个按钮或开关以矩阵方式排列而成
  • xshell无法连接到ubuntu解决办法

    1 检查虚拟机 ssh是否启动 ps e grep ssh 2 没有看到ssh就说明未启动 xff0c 选择下面的一种方式手动启动就好了 如果手动明启动 xff0c 如果未安装则会报出以下错误 xff0c 需要手动安装 sudo apt i
  • 集成Planner与Px4的运行参考

    集成Planner与Px4的运行参考 下载代码 下载相关代码 由于部分需要科学上网环境下载且下载内容不全 xff0c 故首先借助百度网盘进行下载 xff0c 之后移植到Linux环境下进行下载 xff09 链接 xff1a link 提取码
  • stm32f407 FreeRTOS+LVGL移植

    参考资料 xff1a 正点原子 littleVGL 开发指南 正点原子 STM32F407 FreeRTOS 开发指南 硬件平台 xff1a stm32f407开发板 xff08 或最小系统 xff09 4 3寸TFTLCD 以正点原子的例

随机推荐