当前位置: 首页 > news >正文

ARM不同层次开发

文章目录

  • 摘要
  • 一、纯寄存器操作( Bare-Metal / 裸机 )
  • 二、中间层:使用标准外设库/硬件抽象层(HAL)
  • 三、最上层:操作系统下的开发(如 Linux on ARM)
  • 四、总结


摘要

ARM开发的核心就是操作寄存器。越是底层,越是直接操作寄存器;越是上层,越是远离寄存器。


一、纯寄存器操作( Bare-Metal / 裸机 )

地址访问:每个寄存器在内存中都有一个特定的地址。通过读写这些地址来配置和控制硬件。
使用指针:在C语言中,通过定义指针变量指向这些特定地址,然后通过指针进行读写。

示例: 点亮一个LED(假设LED由GPIOA的第5引脚控制):

// 1. 定义寄存器地址(以STM32为例,地址来自芯片参考手册)
#define RCC_AHB1ENR   (*(volatile unsigned int*)0x40023830) // RCC 时钟使能寄存器地址
//**将整数地址 0x40023830 强制转换为 指向 32 位无符号整数的指针,然后对指针解引用。**
#define GPIOA_MODER   (*(volatile unsigned int*)0x40020000) // GPIOA 模式寄存器地址
#define GPIOA_ODR     (*(volatile unsigned int*)0x40020014) // GPIOA 输出数据寄存器地址// 2. 主函数
int main() {// a. 使能GPIOA的时钟(打开GPIOA的电源开关)RCC_AHB1ENR |= (1 << 0); // 将第0位设置为1// 等价于RCC_AHB1ENR = RCC_AHB1ENR | (1 << 0)// b. 配置GPIOA的第5引脚为输出模式// MODER5[1:0] = 0b01 (输出模式)GPIOA_MODER &= ~(0x3 << 10); // 先清空第10和11位GPIOA_MODER |=  (0x1 << 10); // 再将第10位设置为1while(1) {// c. 设置GPIOA第5引脚为高电平,点亮LEDGPIOA_ODR |= (1 << 5);delay(500000); // 简单延时// d. 设置GPIOA第5引脚为低电平,熄灭LEDGPIOA_ODR &= ~(1 << 5);delay(500000);}return 0;
}

二、中间层:使用标准外设库/硬件抽象层(HAL)

为了简化开发,芯片厂商(如ST、NXP)提供了封装好的函数库(如ST的Standard Peripheral Library、HAL库)。

优点: 开发效率高,代码可读性好,可移植性较强。
本质: 仍然是操作寄存器,只是由厂商的库函数代劳了。

库函数底层仍然是在操作寄存器,但开发者不再直接面对地址和比特位。
通过调用直观的函数和结构体来完成配置。

示例: 同样点亮一个LED(使用HAL库)

#include "stm32f4xx_hal.h"int main() {// 1. 初始化HAL库、系统时钟等(库函数帮你完成了寄存器配置)HAL_Init();SystemClock_Config();// 2. 定义一个GPIO初始化结构体并配置它GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin   = GPIO_PIN_5;        // 选择第5引脚GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP; // 推挽输出模式GPIO_InitStruct.Pull  = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;// 3. 调用库函数初始化GPIOA// 这个函数内部最终会写入GPIOA相关的MODER、OTYPER等寄存器HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);while (1) {// 4. 调用库函数控制引脚电平// 这些函数内部会读写ODR或BSRR寄存器HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);   // 亮HAL_Delay(500);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // 灭HAL_Delay(500);}
}

三、最上层:操作系统下的开发(如 Linux on ARM)

开发者几乎完全不直接操作寄存器。

驱动开发:由专门的驱动工程师编写内核驱动模块。驱动代码通过操作系统提供的接口(如ioremap、readl/writel)来间接地、安全地访问物理寄存器。

应用开发:绝大多数应用程序员只进行上层开发。他们通过操作系统提供的API(如打开设备文件/dev/xxx,然后使用read, write, ioctl等系统调用)来与硬件交互。

示例: 一个应用程序想控制LED

// 应用层代码,完全看不到寄存器
int main() {// 1. 打开Linux系统内核驱动暴露出来的设备文件int fd = open("/dev/led0", O_WRONLY);// 2. 通过写文件的方式控制硬件write(fd, "1", 1); // 亮sleep(1);write(fd, "0", 1); // 灭sleep(1);close(fd);return 0;
}

操作寄存器的工作,实际上是在/dev/led0对应的驱动程序中完成的。

四、总结

在这里插入图片描述

http://www.dtcms.com/a/391710.html

相关文章:

  • 【Python】高质量解析 PDF 文件框架和工具
  • RSS-2025 | 无地图具身导航新范式!CREStE:基于互联网规模先验与反事实引导的可扩展无地图导航
  • RNA-seq分析之共识聚类分析
  • Linux开发——ARM介绍
  • Force Dimension Sigma力反馈设备远程遥操作机械臂外科手术应用
  • 泛函驻点方程与边界条件的推导:含四阶导数与给定边界
  • C#开发USB报警灯服务,提供MES或者其它系统通过WebAPI调用控制报警灯
  • Docker基础篇08:Docker常规安装简介
  • 【软考-系统架构设计师】软件架构分析方法(SAAM)
  • 广西保安员考试题库及答案
  • 【Vue】Vue 项目中常见的埋点方案
  • 投稿之前去重还是投稿之后去重?
  • 【包教包会】CocosCreator3.x全局单例最优解
  • 为什么要使用dynamic_cast
  • 随机过程笔记
  • OpenHarmony:NDK开发
  • Dify 从入门到精通(第 87/100 篇):Dify 的多模态模型可观测性(高级篇)
  • 5种获取JavaScript时间戳函数的方法
  • Redis 三种集群模式
  • 初识kotlin协程
  • 多线程——内存可见性问题和指令重排序问题(volatile详解)
  • Linux第十八讲:应用层协议Http
  • 【C++】速识map与set
  • 多层感知机(MLP)
  • Linux系统诊断——拷贝日志系统
  • python中 ​实例方法​(普通方法)和 ​类方法​ 的核心差异
  • Sping AI接入deepseek-本地部署大模型-第二期
  • 数据分析-数据指标体系搭建及应用
  • 计算机专业课《大数据技术》课程导览:开启数据智能时代
  • dumpsys battery 简介