裸机开发VS单片机:架构与实战对比

裸机开发和单片机的区别:

|--------------|-------------------------------------------------------------------------|----------------------------------------------------------|
| 对比维度 | ARM 裸机开发(以 IMX6ULL 等 Cortex-A 系列为例) | 单片机开发(以 51/STM32 等 Cortex-M 系列为例) |
| 核心架构 | 基于 Cortex-A 系列,带MMU(内存管理单元)、Cache 缓存,支持虚拟内存,复杂多核 / 多总线架构 | 基于 Cortex-M/8051 等,无 MMU、无 Cache,单总线极简架构,纯实时控制 |
| 启动流程 | 必须手动编写启动文件(start.S),完成关看门狗、时钟树配置、栈初始化、重定位数据段、清 BSS 段后,才能跳转到 main 函数 | 上电直接执行,无需手动写启动文件,复位后直接进入 main 函数,流程极简 |
| 时钟配置 | 必须手动配置PLL、总线分频、时钟树,所有外设时钟需单独使能,否则外设无法工作 | 多数外设默认时钟已配置,仅需简单分频 / 使能,时钟树结构简单 |
| 开发方式 | 几乎无官方标准库,全程寄存器操作,所有驱动(UART/GPIO/ 定时器等)需从零编写 | 官方提供完善 HAL/LL 库 / 标准库,直接调用库函数开发,无需手动操作寄存器 |
| 工具链与编译 | 必须使用交叉编译工具链(如 arm-linux-gnueabihf-gcc),生成 bin 文件,通过 SD 卡 / USB 下载 | 直接使用 IDE(Keil/STM32CubeIDE)本地编译,通过 ST-Link/J-Link 一键下载调试 |
| 资源与寻址 | 4GB 完整寻址空间,片上资源丰富(大 Flash/RAM、多外设),外设地址分散,需复杂地址映射 | 小地址空间,Flash/RAM 容量小,外设直接挂内核,地址映射简单 |
| 应用场景 | 底层原理学习、Linux 驱动开发前置、高端嵌入式产品裸机开发 | 工业控制、物联网终端、小家电等实时控制类小项目 |
| 学习门槛 | 门槛高,需掌握 ARM 架构、汇编、时钟原理、链接脚本等底层知识 | 门槛低,上手快,专注应用层控制,无需深入架构原理 |
| 调试方式 | 多为离线调试,依赖串口打印、JTAG/SWD 调试成本高 | 支持在线实时调试,断点、变量查看等功能完善,调试便捷 |
| 可扩展性 | 可直接移植 Linux 系统,为上层系统开发打基础 | 仅支持裸机 / RTOS,无法移植完整 Linux 系统 |

DAY1

1 .RISC和CISC 是什么?

RISC(精简指令集)

指令少,简单,长度固定·

执行快,功耗低

常见代表:ARM,RISC-V

比如imx6ull /ARM9/Cortex-A都是RISC

CISC(复杂指令集)

指令多,复杂,长度不固定

功能强,但慢,费电

代表:x86(Intel / AMD )

总结ARM = RISC CPU = CISC

  1. pc lr sp cpsr spsr 寄存器的作用

pc 存下一条指令的地址。

lr 函数调用的时候,存返回地址----函数跑完,回通过他回到原来的位置

sp 栈顶指针,指向栈的顶部-----存临时变量,函数现场

cpsr 当前程序状态寄存器 -------存标志位(正负,进错位),工作模式,中断开关

spcr 进入异常时,备份程序的当前运行状态

3 .什么是MMU?

作用 :

管理虚拟内存到物理内存的映射

裸机必须关闭

linux驱动必须打开

4 . 什么是cache icache dcache ?

cache: CPU内部高速缓存

解决:CPU很快,内存很慢-----用cache 缓冲

icache :存指令

dcahe:存数据

cache 就是CPU的临时小书桌,比内存快几十倍

5 .单总线 VS多总线

单总线:

所有设备用一根总线

简单,便宜,慢,会堵塞

多总线;

高速设备一条,低速设备一条

快,不堵,结构复杂

总结:一个不堵,一个堵

6,AHB总线 VS APB总线

AHB:高速总线

给CPU RAM LCD 网卡

APB:低速总线

给 串口,定时器,GPIO, SPI, 12C

7 .编译程序需要哪几个步骤?

预处理:头文件,宏的展开

编译:生成汇编代码.s

汇编;生成机器码.o

链接:生成可执行程序

8 . imx6ull 内核与指令集

内核:cortex-A7

指令集:ARMv7-A

  1. ARM有几种工作模式?

User:用户工作模式

FIQ:紧急中断

IRQ:外部中断

SVC; 复位或软中断

abort:存储异常

undef 执行未被定义的指令

system 系统模式----用户模式的特权模式

Linux 内核跑在 SVC

应用程序跑在 User

  1. ARM的异常处理流程

备份cpsr到spsr

lr保存返回地址

关闭中断(视为异常类型)

跳去异常向量表

执行异常处理

恢复spcr到cpsr---跳回lr继续执行

11 . ARM9 和 Cortex-A 各有多少寄存器?

ARM9: 37个

Cortex-A : 40个

DAY2

  1. 立即数如何判断?

数值范围在0-0xFF之间的8位基础数,并且最右边含有偶数个0.

  1. b / bl / bx 指令的区别?

b 无条件跳转,不保存lr.正负32MB,用于死循环,长跳转(不返回)

bl 带链接跳转,保存下一条指令地址存入正负32MB,用于函数调用(需要返回)

bx 带状态切换跳转(blx:可保存lr),任意32位地址,用于切换ARM状态,跳转绝对地址。

  1. 栈的分类及特性?

满递减栈:由高到低存储,sp指向最后一个有效数据 ARM默认 *--psr,先减再写数据。

空递减栈:由高到低存储,sp指向下一个空闲的位置 少见

满递增栈:由低到高存储 sp指向最后一个有效数据 x86常用

空递增栈:由低到高存储 sp指向下一个空闲位置 少见 先写数据,再挪动指针

  1. ARM汇编调用C函数,C函数调用汇编函数有什么规则?

ARM汇编调用C函数时:

import main

bl main

规则1:传参

前4个参数:用r0-r3(超过的话使用栈来传递)

返回值:用r0返回

规则2:栈操作规范

调用前:压栈保护现场:stmfd sp!,{r1-r12,lr}

掉用后:出栈恢复现场: ldmfd sp!,{r1-r2,lr}

C函数调用汇编里面的函数的时候

在main.c中的声明:

extern int asm_max(int a,int b);

_as,max(10,20)

在汇编程序中:

export asm_max

规则1:寄存器使用规范

参数接收:r0-r3接收C传递的前4个参数

返回值:用 r0 返回

返回指令:用bx lr返回,恢复C程序的执行

SOC:

核心定位:核心板的【大脑+主控】,相当于电脑的CPU

·本质:是把CPU,GPU,总线控制器,外设接口(UART,SPI,GPIO,I2C)等全部集结在一颗芯片里面的【超级芯片】

·我们所写的汇编启动代码,C语言程序,Linux系统,全部都在SOC中运行,他是整个系统的绝对核心。

·我们所写的代码里:中断向量表,复位函数,栈初始化,时钟配置,都是给soc写的,用来初始化这颗主控芯片。

RAM / DDR3 512MB (运行内存)

·核心定位:核心板的(运行内存),相当于内存条------读写速度快,掉电数据丢失

·SOC可以直接从内存上面读取数据

·用来存放程序的临时变量,栈空间,堆空间(代码里面的 ldr sp, =0x84000000),栈就放在DDR3里面

·Linux在运行的时候 ,所有进程,内存数据都存在这里。

EMMC / NAND FLASH 8GB(存储芯片 )

核心定位:核心板的【硬盘】,相当于电脑的SSD/机械硬盘

·本质:掉电数据不丢失,永久存储数据,文件,系统。

核心作用:

·用来存放我的裸机程序,uboot,linux内核,设备树,根文件系统

·相当于系统的仓库,芯片上电后,从EMMC里把程序加载到DDR3中运行

·8GB 容量用来存系统,文件,数据。

关键特性:

·属于NAND FLASH中的一种(EMMC是封装好的NAND Flash ,带主控)

·读/ 写速度比DDR3慢,掉电数据不丢失

核心板接口(邮票孔/ 插针接口)

本质:·把SOC的所有外设引脚(GPIO , UART , SPI , I2C , LCD , 网口)引出来,用来接底板或外设。

开始进行代码操作:

·配制异常向量表

·所有时钟初始化R0-R6-----打开所有的外设,相当于提前开

初始化led的模式

置电平,来控制led

复位入口:

SOC 通过读取控制灯的寄存器来点灯

DAY3

|------------------------------------------|-------------------------------|-----------------------------------------------|
| 工具 | 定义 | 核心作用 |
| gcc(arm-linux-gnueabihf-gcc) | GNU 交叉编译器,用于将 C / 汇编源码编译为目标文件 | 对.c/.S源码执行语法检查、代码生成,输出.o目标文件,仅编译不链接 |
| ld(arm-linux-gnueabihf-ld) | GNU 链接器,用于整合多个目标文件 | 按照链接脚本规则,将多个.o文件链接为 ELF 格式可执行文件,分配内存地址、解决函数引用 |
| objcopy(arm-linux-gnueabihf-objcopy) | GNU 格式转换器,用于 ELF 与二进制互转 | 将带符号 / 调试信息的 ELF 文件,转为裸机可烧录的纯二进制.bin文件,去除冗余信息 |
| objdump(arm-linux-gnueabihf-objdump) | GNU 反汇编器,用于代码分析调试 | 将 ELF 文件反汇编为汇编代码,用于查看代码逻辑、验证链接地址、排查错误 |

  1. 链接脚本 imx6ull.lds的核心配置

·程序入口:ENTRY_(_start),指定芯片上电第一行执行的代码(汇编启动文件的_start标签)

·代码段地址:-Ttext 0x87800000,指定代码在 IMX6ULL DDR 中的运行地址。

·段分配:定义 . text(代码段)分为:

rodata(只读数据段)

data(数据段),

bss(未初始化的数据)

·链接顺序:指定 start.o 优先链接,保证复位入口在代码最前端。

·栈地址:配置C语言运行所需的栈的空间地址,为C语言执行提供基础

  1. beep和led 实验

·led实验:配置GPIO_IO03的MUX(复用功能),PAD(电气属性),再通过GPIOS输出高低电平来控制。

·beep实验:配置对应的GPIO的MUX,PAD,再通过GPIO输出低电平,导通PNP三极管,驱动蜂鸣器发声。

完整的流程:编译(gcc)----->链接(ld)------->格式转换(objcopy)------>烧录到SD卡上,上电后程序运行,灯亮,器响。

DAY4:

上电复位

进入 start.S 的 _start 中断向量表入口

跳转到 _reset_handler 复位初始化

【1. 配置 CP15 协处理器】

关闭 ICache、配置内存相关

→ 目的:保证中断向量表不被缓存干扰

【2. 设置 IRQ 模式栈】

cps #0x12

ldr sp, =0x86000000

【3. 设置 System 模式栈(C语言用)】

cps #0x1F

ldr sp, =0x84000000

【4. 开启 CPU 总中断】

cpsie i

【5. 清空 bss 段(全局变量清0)】

bl _bss_clear

【6. 进入 C 语言 main 函数】

b main

=====================================

进入 main

【1. 中断系统初始化】

system_interrupt_init

├─ 设置中断向量表基地址 VBAR = 0x87800000

└─ 初始化 GIC 中断控制器

【2. 打开所有外设时钟】

enable_clocks

【3. 初始化 LED、蜂鸣器】

led_init、beep_init

【4. 按键中断初始化(核心配置)】

key_init

├─ 配置 GPIO1_IO18 复用为 GPIO

├─ 配置引脚电气属性

├─ 设置为输入模式 GDIR

├─ 设置中断触发方式 ICR2

├─ 打开 GPIO 中断屏蔽 IMR

├─ 设置 GIC 中断优先级

└─ 使能 GIC 对应中断号

【5. 主循环等待中断】

while(1) { delay(); }

=====================================

【外部事件:按键按下】

GPIO1_IO18 产生中断信号

中断发送到 GIC 中断控制器

GIC 仲裁优先级 → 发给 CPU

CPU 检测到 IRQ 中断请求

硬件自动跳转到 start.S 的 _irq_handler

=====================================

【中断响应流程】

  1. 修正返回地址

sub lr, lr, #4

  1. 保护现场(压栈 R0~R12, LR)

stmfd sp!, {r0-r12, lr}

  1. 从 GIC 读取当前中断号

  1. 进入 System 模式,方便调用 C 函数

  1. 保存 LR,调用 C 语言中断处理函数

bl system_interrupt_handler

=====================================

【C 语言中断服务流程】

  1. 判断中断号是否为 GPIO1 组中断

  1. 判断是否是 GPIO1_IO18 触发的中断

  1. 执行中断动作:led_on()

  1. 清除中断标志位 ISR

(必须,否则会重复进中断)

中断函数执行完毕,返回汇编

=====================================

【中断返回流程】

  1. 通知 GIC 中断处理完成

  1. 恢复现场(出栈 R0~R12, PC)

ldmfd sp!, {r0-r12, pc}

  1. CPU 自动恢复 CPSR、返回主程序断点

回到 main 的 while(1) 继续等待下一次中断

DAY5:

  1. 什么时PPL, Prescaler, FPD,他们各自的用途是什么?

·PPL:锁相环电路-----倍频

·Prescaler: 预分频器------分频

·PFD:相位频率检测器----也可以分频也可以倍频

  1. IMX6ULL中有几个锁相环,几个相位分数分配器?

·7个独立的PPL:PPL1--PPL7

·PLL2和PLL3各含有4个相位频率检测器(PFD)

  1. 简述ARM PLL的配置
  1. IMX6ULL 中的EPIT和GPT的工作原理是什么?

|-------------|------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------|
| 对比项 | EPIT 定时器 | GPT 定时器 |
| 全称 | Event Periodic Interrupt Timer事件周期性中断定时器 | General Purpose Timer通用定时器 |
| 计数方式 | 固定向下计数从装载值开始,减到 0 触发事件 | 可向上 / 向下计数更灵活,支持自由运行模式 |
| 核心工作原理 | 1. 选择时钟源(通常为 IPG_CLK) 2. 经过预分频得到计数时钟 3. 从 LR 寄存器加载初值并向下计数 4. 计到 0 时自动触发中断5. 自动重载 LR 值,循环定时 | 1. 可选多种时钟源 2. 经预分频后开始计数 3. 可配置为自由运行或比较匹配 4. 支持输入捕获、输出比较 5. 溢出或匹配时触发中断 |
| 主要功能 | 专注做周期性定时中断简单、稳定、适合系统节拍 | 功能更全:定时、输入捕获、PWM、脉冲测量 |
| 自动重载 | 支持,计到 0 自动重装 | 可自由配置是否重载 |
| 低功耗特性 | 支持停止模式下运行 | 一般不支持低功耗独立运行 |
| 典型用途 | 周期性任务、系统滴答、延时 | 测频率、测脉宽、输出方波 / PWM |
| 与你代码关系 | 依赖配置好的 IPG_CLK_ROOT | 同样使用 AHB/IPG 时钟,依赖时钟初始化 |

|--------------|----------------------------------------------------|----------------------------|
| 对比项目 | 同步通信 | 异步通信 |
| 是否有时钟线 | 有独立时钟线(SCLK、SCK、SCL) | 无时钟线,只有数据线 ± 地线 |
| 时钟来源 | 主机统一提供时钟,收发共用同一时钟 | 收发双方各自使用内部时钟,相互独立 |
| 时钟使用方式 | 以时钟边沿为基准,时钟一跳传一位 | 按约定波特率,用内部定时器定时采样 |
| 同步机制 | 时钟线同步:时钟决定何时采样、何时发送 | 帧格式同步:靠起始位对齐,之后按时间间隔采样 |
| 时钟线的作用 | 1. 统一收发时序,保证步调一致2. 明确告诉对方 "此刻数据有效"3. 从根本上避免数据错位、误码 | 无时钟线,依靠事先约定的波特率代替时钟功能 |
| 对时钟精度要求 | 极高,必须严格同源或高度同步 | 较低,只要频率接近、误差在容忍范围即可 |
| 数据传输特点 | 连续传输,效率高,适合高速通信 | 按帧传输,每帧带起始位 / 停止位,有额外开销 |
| 优点 | 速度快、协议简单、抗干扰强、不易出错 | 线路少、实现简单、适合远距离、布线方便 |
| 缺点 | 多一根线,布线复杂,远距离时钟易畸变 | 速度相对较低,帧结构占用额外带宽 |
| 典型硬件接口 | SPI、I2C、同步 UART、CAN (量化同步)、各类总线 | 标准 UART(串口)、蓝牙、USB (含特殊同步) |

1,单工:固定了通信的发送方和接收方。

半双工:通信双方都可以发送和接收数据,但不能同一时刻进行发送和接收。

全双工:通信双方可以同时进行数据的接手和发送。本质是收发分离。

2.串口通信:用一条线进行数据的传输,单次接收一长串的bit。

并行通信:用多条线进行数据的传输,多条线同时发送一个bit。

3,异步通信:通信双方按照起始位和约定好的波特率,利用各自时钟进行通信,不需要时钟线。

同步通信:通信双按照一条时钟线的频率,来进行特定周期通信。

4,串口通信属于异步串行全双工通信。

5,串口通信的电器表达:

电平标准:

TTL电平

RS-232电平

接口形式:

UART:仅需TX,RX,GND 三根线。

波特率的范围常见:115200,9600 频率越高抗干扰能力越差。

I2C时序传输:

问题 1:描述 IIC 通信的时序

IIC 是双线同步通信,核心时序有四个:起始是 SCL 高时 SDA 高变低,停止是 SCL 高时 SDA 低变高;数据在 SCL 低时变化、高时采样,高位在前;每字节后紧跟应答位,ACK 为低表示继续,NACK 为高表示停止。通信分为写操作(发地址 + 数据)和读操作(先写地址定位,再发重复起始读数据),通过 ACK 保证传输可靠。

问题 2:AT24C02 实验代码调试要点

首先完成硬件调试,检查上拉电阻、接线和电源,用逻辑分析仪验证 100kHz 时钟和时序正常;然后调试代码,实现 I2C 基础时序函数和 AT24C02 的字节写、页写、随机读、连续读驱动,添加 ACK 校验和写周期延时;最后验证读写功能,确保数据掉电不丢失,页写不溢出,连续读逻辑正确。

流程细节:

总线空闲时:

时钟线SCL和数据线SDA都为高电平,谁先在数据线上产生一个低电平0,谁就赢得了总线的控制权(总线抢占),即认为发送了一个start信号,通信开始,作为主机(发送方);

主机发送数据时:

遵循MSB优先原则

在SCL为低电平时,只能发送方改变SDA,接收方不能采样SDA

SCL为高电平时,只能接收方采样SDA,发送方需保证SDA稳定

每一次通信都是先发送从机地址(7位)+数据流向位(0:主发从接;1:从发主接)

发送完8位数据时,在第9个时钟周期必须发送应答类型(ACK/NACK)

数据传输:(都先要主机发送从机地址+数据流向位(0:主发从接)+要写、读的寄存器地址)

写时序(主机发送,从机应答):主机发送一字节数据,从机回复一个应答类型,从机接收到ACK就继续向从机发送数据,直到收到NACK应答类型

读时序(从机发送,主机应答):重新发送start信号;再次发送从机地址,主机切换数据流向位(1:从发主接),开始连续读取数据(先应答,再读取数据,发ACK告诉从机我开始读了,你发送数据),直到主机读到倒数第二个数据时,发给从机NACK,告诉从机,下一个数据是最后一个了,你不用再发送数据了),读取结束发送stop

stop停止:SCL保持高电平时,SDA从低到高,并保持稳定,视为通信停止

  1. 什么是ADC?

把模拟信号转换成数字信号的转换器。

  1. 什么是ADC的基准电压?

是ADC进行模数转换时的参考电压,他决定了ADC输入电压的量程范围。

  1. ADC的工作原理是什么?

·采样:在特定的时间点对于模拟信号进行采取,获取该时刻的电压值。

·保持:把采集到的电压保持一段时间,便于后续处理。

·量化:根据参考电压的值和保持的电压进行比较,并且把他转换成离散的数字等级。

·编码:把量化后的等级转换为对应的二进制数字输出。

逐次逼近法:

核心是把连续变化的电压或电流,转换成离散的二进制代码。

  1. 什么是ADC的分辨率?常见的分辨率有哪些?

ADC的分辨率指的是ADC能够分辨的最小模电压变化量,分辨率越高对于,量化的误差越小,转换结果越接近真实的模拟电压值。

常见的分辨率有:8位,10位,12位,14位,16位,24位等。

·8位:可以区分 2^8 = 256 个不同的电压等级。

  1. 假设采用12位分辨率,基准电压为3.3v,量化结果为n时的实际电压应该如何计算?

n * 3.3 / 2^12 = n/4096 *3.3

相关推荐
神一样的老师3 小时前
【兆易创新GD32VW553开发板试用】红外遥控接入天气时钟实战
驱动开发·单片机·嵌入式硬件
多看多敲多思考6 小时前
华润微CS32ME10 MCU使用教程(2)---CS32ME10之UART串口模块使用
stm32·单片机·嵌入式硬件·mcu
神一样的老师6 小时前
【兆易创新GD32VW553开发板试用】天气时钟设计与调试实战
单片机·嵌入式硬件·物联网
国科安芯6 小时前
核电站仪控与监测系统中抗辐射 MCU 芯片应用研究
单片机·嵌入式硬件·macos·无人机·cocos2d·核电站
黑白园6 小时前
STM32系统时钟由72M修改为36M验证示例
stm32·单片机·嵌入式硬件
LCG元7 小时前
基于ARM7的LCD设计与实现:S3C4510B通用IO口控制液晶模块
stm32·单片机·嵌入式硬件
The_superstar68 小时前
衡山派学习之串口
单片机·嵌入式硬件·串口·衡山派
Ww.xh8 小时前
STM32按键去抖动软件实现详解
stm32·单片机·嵌入式硬件
ghie90908 小时前
基于STM32的CAN通信完整例程(HAL库实现)
stm32·单片机·嵌入式硬件