十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux下使用AVRA汇编器开发ATtiny13:从环境搭建到功耗优化

Linux下使用AVRA汇编器开发ATtiny13:从环境搭建到功耗优化 1. 项目概述为什么要在Linux上用AVRA玩转ATtiny13如果你对嵌入式开发感兴趣尤其是迷恋那种在极其有限的资源下“螺蛳壳里做道场”的编程乐趣那么ATtiny13这颗芯片和AVRA汇编器的组合绝对是一个经典且迷人的起点。我最初接触它是因为一个朋友想做一个超低功耗的纽扣电池供电的LED闪烁小挂件市面上常见的Arduino方案对于这种微型项目来说无论是体积还是功耗都显得过于“奢侈”了。ATtiny13以其极小的封装、极低的价格和功耗成为了不二之选。而选择在Linux环境下用AVRA这样的原生汇编器进行开发则意味着你能够获得最直接、最底层的控制权从芯片的每一个时钟周期里榨出性能同时享受Linux命令行带来的高效与透明。这个项目标题“Program ATtiny13 with AVRA Assembler on Linux”清晰地勾勒出了一条技术路径目标芯片是ATtiny13开发语言是汇编工具链是AVRA操作系统平台是Linux。它解决的不仅仅是“如何点亮一个LED”的问题更是“如何在资源极度受限的8位MCU上进行精准、高效的裸机编程”这一核心挑战。对于嵌入式爱好者、电子专业学生或是希望深入理解微控制器底层工作原理的开发者来说这是一次绝佳的实践。你将摆脱高级语言和庞大库函数的“黑箱”亲手操控寄存器、精确计算指令周期最终让一段简洁的汇编代码在小小的芯片里焕发生命力。整个过程就像是用最原始的工具雕刻出一件精密的电子艺术品。2. 开发环境搭建与工具链解析在Linux上为ATtiny13搭建汇编开发环境其实是一个“组装”标准工具链的过程。这套工具链的核心是编译器汇编器、编程器和芯片支持。Linux的开源生态让这一切变得非常顺畅。2.1 核心工具安装与配置首先我们需要安装三个核心组件avra汇编器、avrdude编程器软件和gcc-avr可选但包含一些有用的工具如avr-objcopy。在基于Debian/Ubuntu的系统上一条命令即可搞定sudo apt update sudo apt install avra avrdude gcc-avr -y对于Arch Linux用户可以使用sudo pacman -S avra avrdude avr-gcc安装完成后可以通过avra --version和avrdude -v来验证安装。这里有个关键点不同发行版的软件仓库可能提供不同版本的AVRA。我建议至少使用1.4.2以上版本以获得更好的ATtiny13支持。如果你需要最新的特性从源码编译AVRA也是一个选择但通过包管理器安装对于入门来说是最稳妥的。注意avrdude的配置通常位于/etc/avrdude.conf。大多数情况下默认配置已经包含了我们常用的编程器如USBasp、Arduino as ISP等无需修改。但如果你使用非常冷门的编程器可能需要手动添加其定义。2.2 硬件连接与编程器选择ATtiny13没有内置USB因此我们需要一个独立的编程器Programmer作为电脑和芯片之间的桥梁。市面上常见且性价比高的选择有USBasp这是最经典、最廉价的AVR编程器之一在Linux上驱动支持良好。连接时你需要将USBasp的MOSI、MISO、SCK、RST、VCC、GND引脚与ATtiny13对应的引脚正确连接。Arduino as ISP如果你手头有一块Arduino开发板如Uno可以将其刷写成ISP编程器。这是一个灵活且零成本的方案假设你已有Arduino。你需要按照Arduino IDE中的示例“ArduinoISP”来烧录引导程序。USBtinyISP另一个流行的开源编程器与USBasp类似。以使用USBasp为例硬件连接如下表所示。请务必在接通电源前仔细核对接错线可能损坏芯片或编程器。USBasp引脚ATtiny13引脚功能说明MOSIPB0 (Pin 5)主设备输出从设备输入MISOPB1 (Pin 6)主设备输入从设备输出SCKPB2 (Pin 7)串行时钟RSTPB5 (Pin 1)复位低电平有效VCCVCC (Pin 8)电源5VGNDGND (Pin 4)地实操心得焊接一个包含6针ISP接口2x3排针的小型转接板会极大方便你反复烧录测试。对于ATtiny13这样的8引脚芯片直接焊接杜邦线容易短路或接触不良。另外确保你的USBasp是3.3V/5V兼容的并为ATtiny13提供稳定的5V电源通常VCC引脚接5V。如果使用3.3V系统需要确认你的USBasp支持3.3V输出并将ATtiny13的VCC连接到3.3V。2.3 创建项目结构与第一个汇编文件Linux命令行的高效在项目组织上也能体现。我习惯为每个小项目创建一个独立的目录。mkdir attiny13_blink cd attiny13_blink touch blink.asm这个blink.asm就是我们的汇编源码文件。接下来我们需要一个基本的汇编文件框架。这个框架主要包括两个部分设备定义和汇编指令。3. ATtiny13汇编编程核心概念与框架用汇编编程意味着你要直接面对硬件。对于ATtiny13我们首先需要了解它的内存架构和核心寄存器。3.1 芯片定义与常量声明AVRA汇编器需要知道我们为目标芯片定义了哪些寄存器和地址。这是通过包含一个“包含文件”Include File来实现的。对于ATtiny13这个文件通常是tn13def.inc。它定义了芯片的所有寄存器地址如PORTB、DDRB、位定义如PB0以及一些有用的常量。你的汇编文件通常这样开头; blink.asm - 让连接到PB4的LED闪烁 ; 设备定义 .NOLIST .INCLUDE tn13def.inc ; 包含ATtiny13的定义文件 .LIST ; 常量定义 .equ LED_PIN PB4 ; 假设LED连接在PB4物理引脚3.NOLIST和.LIST指令用于控制汇编器列表文件的输出不是必须的但可以让你的汇编过程更清晰。.INCLUDE指令是核心它告诉汇编器去哪里查找DDRB、PORTB这些符号的具体地址。为什么是tn13def.inc这个文件通常随AVRA一起安装位于/usr/share/avra或类似路径。AVRA知道去哪里找它。如果你遇到“文件未找到”错误可以指定完整路径如.INCLUDE /usr/share/avra/avra/tn13def.inc。3.2 复位向量与中断向量表ATtiny13的程序执行从复位向量Reset Vector开始。当芯片上电或复位后硬件会自动跳转到这个地址开始执行代码。我们需要在这里放置一条跳转指令跳到我们的主程序main起始处。; 中断向量表 .CSEG ; 代码段开始 .ORG 0x0000 ; 设置程序起始地址为0 rjmp RESET ; 复位向量跳转到RESET标签处 ; 其他中断向量ATtiny13中断很少这里省略 ; .ORG 0x0001 ; rjmp INT0_ISR ; 外部中断0向量如果使用 RESET: ; 这里是主程序开始的地方 ; 初始化栈指针对于ATtiny13这种小芯片简单的程序通常不用栈。 ; 直接开始设置端口方向。.CSEG定义代码段.ORG设置地址。rjmp是相对跳转指令。对于ATtiny13这样只有1K字1024条指令闪存的芯片中断向量表非常简单。3.3 端口控制让LED闪烁的原理控制一个LED闪烁本质就是控制一个GPIO通用输入输出引脚周期性地输出高电平和低电平。这涉及到两个核心寄存器DDRB (Data Direction Register B)方向寄存器。设置某一位为1对应的引脚PBx为输出设置为0则为输入。PORTB (Port B Data Register)数据寄存器。当引脚配置为输出时向某一位写1对应引脚输出高电平VCC写0则输出低电平GND。假设LED正极通过一个限流电阻如220Ω接到PB4负极接地GND。那么PORTB4输出高电平时LED两端有电压差点亮输出低电平时LED熄灭。初始化代码通常如下RESET: ; 设置PB4为输出模式 sbi DDRB, LED_PIN ; “Set Bit in I/O Register”将DDRB寄存器的LED_PIN位即PB4设为1 ; 初始状态熄灭LED输出低电平 cbi PORTB, LED_PIN ; “Clear Bit in I/O Register”将PORTB的LED_PIN位清0 MAIN_LOOP: ; 点亮LED sbi PORTB, LED_PIN ; 调用延时函数 rcall DELAY_500MS ; 熄灭LED cbi PORTB, LED_PIN ; 再次调用延时函数 rcall DELAY_500MS ; 循环 rjmp MAIN_LOOPsbi和cbi是汇编中操作I/O寄存器特定位的专用指令非常高效。rcall用于调用子程序这里是延时函数rjmp用于无限循环。4. 汇编程序实战编写精确延时与主循环上面的框架缺少一个关键的DELAY_500MS函数。在汇编中实现延时通常采用软件循环因为ATtiny13没有硬件延时外设。我们需要用循环来“消耗”时间。4.1 软件延时函数的计算与实现编写精确的软件延时需要知道两个关键参数芯片的系统时钟频率和执行一条指令所需的时钟周期数。ATtiny13默认使用内部9.6MHz RC振荡器但经过8分频后系统时钟CPU时钟为1.2MHz。这意味着一个时钟周期是 1 / 1.2MHz ≈ 0.833微秒。一条简单的nop空操作指令需要1个时钟周期。一个循环结构如decbrne需要更多周期。我们可以通过多层嵌套循环来实现较长的延时。下面是一个实现约500毫秒延时的子程序示例。这是一个经典的三重循环结构; 延时子程序约500ms 1.2MHz DELAY_500MS: ldi r18, 41 ; 外层循环计数器1 ldi r19, 150 ; 中层循环计数器2 ldi r20, 128 ; 内层循环计数器3 DELAY_LOOP: dec r20 ; 内层循环递减 (1 cycle) brne DELAY_LOOP ; 如果r20不为0跳回 (2 cycles if taken, 1 if not) dec r19 ; 中层循环递减 (1 cycle) brne DELAY_LOOP ; 跳回重新初始化内层循环 (2 cycles) dec r18 ; 外层循环递减 (1 cycle) brne DELAY_LOOP ; 跳回重新初始化中层循环 (2 cycles) ret ; 返回调用处 (4 cycles)延时计算原理 这个循环的总周期数大致是外层次数 * 中层次数 * 内层次数 * 每次内层循环的周期数。每次内层循环dec r20brne在循环时消耗3个周期12最后一次不跳转时消耗2个周期11。为了简化我们按平均估算。通过调整r18r19r20的初值可以逼近目标延时。上面的数值是针对1.2MHz时钟反复调试得到的近似值。重要提示软件延时极不精确且会被中断打断。它适用于对时间精度要求不高的场景如LED闪烁。如果需要精确计时必须使用定时器/计数器外设。对于ATtiny13有一个8位的定时器/计数器0TC0可以用来产生更精确的时间基准。4.2 主程序逻辑与状态机思维对于简单的闪烁一个主循环加延时足矣。但如果你想实现更复杂的行为比如不同的闪烁模式快闪、慢闪、SOS求救信号就需要引入状态机的概念。例如我们可以用寄存器中的一个字节比如r16作为状态寄存器用不同的值代表不同的闪烁阶段。.equ STATE_IDLE 0 .equ STATE_FAST 1 .equ STATE_SOS 2 MAIN_LOOP: ; 检查某个输入如按键这里假设按键在PB3内部上拉 sbic PINB, PB3 ; “Skip if Bit in I/O Register is Cleared”如果PB3为低电平按键按下则跳过下一条指令 rjmp CHECK_STATE ; 按键未按下去检查当前状态 ; 按键按下切换状态 inc r16 ; 状态值加1 cpi r16, 3 ; 比较状态值是否等于3 brlo STATE_OK ; 如果小于3跳转 clr r16 ; 否则清零回到状态0 STATE_OK: rcall DEBOUNCE_DELAY ; 调用按键去抖动延时 CHECK_STATE: cpi r16, STATE_IDLE breq DO_IDLE cpi r16, STATE_FAST breq DO_FAST cpi r16, STATE_SOS breq DO_SOS rjmp MAIN_LOOP ; 默认情况不应发生 DO_IDLE: cbi PORTB, LED_PIN ; 空闲状态LED灭 rjmp MAIN_LOOP DO_FAST: ; 快速闪烁逻辑 sbi PORTB, LED_PIN rcall DELAY_100MS cbi PORTB, LED_PIN rcall DELAY_100MS rjmp MAIN_LOOP DO_SOS: ; SOS信号三短三长三短逻辑需要更复杂的状态子循环 ; ... (此处省略具体实现) rjmp MAIN_LOOP这种基于状态机的编程模式能让你的汇编代码结构更清晰易于扩展和维护即使是在资源如此紧张的ATtiny13上。5. 编译、烧录与调试全流程代码写好了接下来就是将它转换成芯片能理解的机器码并烧录进去。5.1 使用AVRA编译汇编源码在项目目录下执行编译命令avra blink.asm如果一切顺利AVRA会输出类似以下信息AVRA: advanced AVR macro assembler Version 1.4.2 Copyright (C) 1998-2020. Check out README file for more info Pass 1... Pass 2... Done. Assembly complete with no errors. Segments: Code: 54 words (108 bytes) Data: 0 bytes EEPROM: 0 bytes这表示编译成功生成了几个文件其中最重要的是blink.hexIntel HEX格式和blink.cofCOFF格式可用于仿真。blink.hex就是我们最终要烧录到芯片闪存中的文件。如果编译出错AVRA会明确指出错误所在的行号和原因比如未定义的符号、语法错误等。这是排查代码问题的第一步。5.2 使用Avrdude进行芯片烧录烧录需要连接好硬件编程器。以使用USBasp编程器为例命令如下sudo avrdude -c usbasp -p t13 -U flash:w:blink.hex:i让我们拆解这个命令-c usbasp指定编程器类型为USBasp。-p t13指定目标芯片型号为ATtiny13。t13是avrdude内部对ATtiny13的简称。-U flash:w:blink.hex:i这是内存操作选项。flash操作目标为闪存Flash。w表示“写入”write。blink.hex要写入的文件名。i文件格式为Intel Hex。执行后avrdude会尝试连接芯片、擦除、编程、校验。成功的输出末尾会有“avrdude done. Thank you.”。常见问题1权限不足。操作USB设备通常需要root权限所以前面加了sudo。你也可以将你的用户加入dialout或plugdev组来避免每次使用sudo。常见问题2无法连接编程器/芯片。首先检查所有连线是否正确、牢固。然后尝试降低编程速度添加-B 32参数设置编程时钟周期为32微秒即降低频率。命令变为sudo avrdude -c usbasp -p t13 -B 32 -U flash:w:blink.hex:i。速度过快是导致连接失败的主要原因之一。5.3 熔丝位Fuse Bits配置详解熔丝位是AVR芯片的一组特殊配置位用于设定芯片的基础工作模式如时钟源、启动延时、看门狗、BOD掉电检测等。错误配置熔丝位可能导致芯片无法编程或无法运行需要高压编程器才能恢复因此操作需谨慎。对于ATtiny13常用的几个熔丝位是CKDIV8时钟分频使能。默认编程状态为1已编程表示系统时钟时钟源/8。如果我们使用内部9.6MHz RC振荡器则系统时钟为1.2MHz。如果你想全速运行9.6MHz需要将此熔丝位设为0未编程。SUT1 SUT0启动延时选择。控制上电后芯片等待时钟稳定的时间。对于内部RC振荡器通常使用最少的延时如SUT11 SUT00。CKSEL[3:0]时钟源选择。对于内部9.6MHz RC振荡器应设置为0010二进制。读取当前熔丝位sudo avrdude -c usbasp -p t13 -U lfuse:r:-:h -U hfuse:r:-:hr表示读取-表示输出到标准输出控制台h表示以十六进制显示。写入熔丝位示例禁用时钟分频使用9.6MHz内部RC振荡器 首先你需要计算熔丝位的值。可以使用在线熔丝位计算器如https://www.engbedded.com/fusecalc/辅助。假设我们想要低熔丝位lfuse0x7A二进制0111 1010其中CKDIV80 SUT[1:0]10 CKSEL[3:0]0010高熔丝位hfuse0xFF默认值看门狗禁用SPI编程使能写入命令sudo avrdude -c usbasp -p t13 -U lfuse:w:0x7A:m -U hfuse:w:0xFF:mw表示写入m表示数据是立即数十六进制格式。熔丝位操作黄金法则永远在写入前先读取并确认。最好将当前配置记录下来。除非你明确知道更改的后果否则不要轻易修改高熔丝位hfuse中与复位使能RSTDISBL和SPI使能SPIEN相关的位错误的设置会导致芯片无法再通过ISP编程。6. 进阶技巧与深度优化当基本功能实现后你可以追求更极致的代码效率和更低的功耗。6.1 利用定时器中断实现精准延时与多任务软件延时会占用CPU全部时间无法执行其他任务。使用定时器中断是解放CPU、实现多任务雏形的关键。ATtiny13的TC0定时器可以配置在CTC比较匹配清零模式下产生周期性中断。.INCLUDE tn13def.inc .DEF TEMP r16 .CSEG .ORG 0x0000 rjmp RESET .ORG OC0Aaddr ; Timer/Counter0 Compare Match A 中断向量地址 rjmp TIM0_COMPA_ISR RESET: ; 初始化栈指针如果中断中调用子程序或使用push/pop ldi TEMP, low(RAMEND) out SPL, TEMP ; 配置PB4为输出 sbi DDRB, PB4 ; 配置Timer0为CTC模式分频系数1024 ldi TEMP, (1WGM01) ; CTC模式 out TCCR0A, TEMP ldi TEMP, (1CS02) | (1CS00) ; 时钟分频1024 out TCCR0B, TEMP ; 设置比较匹配值OCR0A。目标1.2MHz/1024/100 ≈ 11.7Hz中断 (~85ms) ldi TEMP, 117 out OCR0A, TEMP ; 使能比较匹配A中断 ldi TEMP, (1OCIE0A) out TIMSK0, TEMP ; 全局中断使能 sei MAIN_LOOP: ; 主循环可以空转或者处理其他非实时任务 rjmp MAIN_LOOP ; 定时器中断服务程序 TIM0_COMPA_ISR: ; 保护现场如果中断中修改了SREG或主程序用到的寄存器 in TEMP, SREG push TEMP ; 中断处理逻辑翻转LED状态 sbis PORTB, PB4 ; 如果PB4为1LED亮 rjmp LED_ON ; 否则跳转到点亮分支 LED_OFF: cbi PORTB, PB4 ; 当前亮则熄灭 rjmp ISR_END LED_ON: sbi PORTB, PB4 ; 当前灭则点亮 ISR_END: ; 恢复现场 pop TEMP out SREG, TEMP reti这样LED会以固定的频率约85ms半周期自动闪烁而主循环MAIN_LOOP完全空闲可以用于处理按键扫描、状态判断等其他逻辑实现了最简单的“前后台”系统。6.2 功耗优化与睡眠模式对于电池供电设备功耗至关重要。ATtiny13支持多种睡眠模式。当CPU无事可做时可以将其置于睡眠模式以节省电能由定时器或外部中断唤醒。; 在进入主循环前使能睡眠 ; 设置睡眠模式为空闲模式Idle Mode定时器继续运行 ldi TEMP, (1SE) | (0SM1) | (0SM0) out MCUCR, TEMP MAIN_LOOP: ; 进入睡眠 sleep ; CPU在此处被唤醒继续执行下一条指令 ; 可以检查唤醒源执行相应处理 rjmp MAIN_LOOP在空闲模式下CPU和Flash停止工作但定时器、看门狗和中断系统继续运行。因此上面的定时器中断仍然可以正常工作并在每次中断发生时唤醒CPUCPU执行完中断服务程序后返回主循环立即又进入睡眠从而极大降低了平均功耗。6.3 代码大小与效率优化实战ATtiny13只有1K字的程序空间每一字节都弥足珍贵。优化技巧包括使用sbic/sbis和rjmp/rcall这些是单字指令2字节而cpibrne组合通常是双字4字节。在简单的状态判断中前者更节省空间。复用寄存器尽量减少全局变量的使用在子程序间通过寄存器传递参数。循环展开的权衡对于极短的固定次数循环如3-5次有时直接顺序执行几条指令比写一个循环更节省空间和时间。使用查表法对于复杂但固定的数据如七段数码管编码、正弦波表将其存放在程序存储器Flash中运行时读取比用计算生成更高效。例如实现一个根据索引值0-9返回七段数码管编码的子程序LED_TABLE: .DB 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F ; 0-9的共阴极编码 GET_LED_CODE: ; 输入: r16 (索引0-9), 输出: r17 (编码) ldi ZH, high(LED_TABLE*2) ; 表格地址高位 ldi ZL, low(LED_TABLE*2) ; 表格地址低位 add ZL, r16 ; 地址偏移 adc ZH, r0 ; 处理进位r0假设为0 lpm r17, Z ; 从程序存储器加载 ret.DB指令将数据直接编译到程序空间。LPM指令用于读取。7. 问题排查与调试经验实录即使按照步骤操作也难免会遇到问题。这里记录几个我踩过的坑和解决方法。7.1 常见问题速查表问题现象可能原因排查步骤与解决方案avrdude: error: could not find USB device1. USBasp未插入或接触不良。2. 系统未加载usbasp内核模块。3. 权限问题。1. 检查USB连接尝试更换USB口。2. 执行lsmod | grep usbasp若无输出尝试sudo modprobe usbasp。3. 使用sudo或检查用户组权限。avrdude: initialization failed, rc-11. 芯片型号选错 (-p参数)。2. 连线错误特别是MOSI/MISO、RST。3. 芯片电源问题电压不足、不稳。4. 编程时钟太快。1. 确认-p t13。2. 用万用表逐线检查连通性。3. 确保VCC和GND稳定在5V可在芯片电源引脚并联一个10uF电容。4. 添加-B 32或-B 64参数降低速度。程序烧录成功但LED不亮/常亮1. LED引脚配置错误输入/输出。2. 限流电阻过大或过小。3. 程序逻辑错误如延时过长/过短。4. 熔丝位配置错误如时钟源不对。1. 确认sbi DDRB, x指令已执行。2. 典型LED电流5-20mA使用220Ω-1kΩ电阻用万用表测量电压。3. 简化程序先测试“常亮” (sbi PORTB, x) 和“常灭” (cbi PORTB, x) 是否有效。4. 检查熔丝位确认系统时钟频率符合程序延时计算。代码编译通过但avrdude报错not in sync1. 芯片进入错误状态如看门狗复位循环。2. 编程器与芯片通信严重不同步。1. 尝试给芯片断电再上电然后立即执行烧录命令。2. 使用极慢的编程时钟-B 128或-B 256。3. 检查RST引脚是否被意外拉低或用作I/O。修改代码后重新烧录行为无变化1. 未重新编译生成新的.hex文件。2.avrdude命令指向了旧的.hex文件。3. 芯片未正确擦除。1. 每次修改后务必运行avra重新编译。2. 确认烧录命令中的文件名正确。3.avrdude的-U flash:w:...操作默认包含擦除。可尝试先单独擦除-U flash:e(eerase)。7.2 低成本调试技巧用LED和延时“打桩”在没有硬件调试器的情况下调试汇编程序是一大挑战。我最常用的方法是“LED状态指示法”和“延时探针法”。LED状态指示法除了主功能LED可以再用一个I/O口连接另一个LED或利用同一个LED的不同闪烁模式来指示程序运行到了哪个阶段。例如在程序初始化完成时让LED快速闪烁3下在进入某个错误分支时让LED常亮等。延时探针法当你怀疑某段代码是否被执行或者循环次数是否正确时可以在该处插入一个独特的、可识别的延时。例如在疑似代码块前后分别点亮和熄灭LED并观察LED的变化是否符合预期。虽然原始但在资源受限且无调试工具时非常有效。7.3 关于熔丝位锁死的补救最令人头疼的问题是熔丝位配置错误导致芯片无法再通过ISP编程例如误将RSTDISBL编程使复位引脚变成普通I/O或禁用SPIEN关闭了SPI编程接口。对于ATtiny13有以下几种补救尝试尝试低速编程首先用-B 256甚至-B 512尝试连接有时低速可以成功。使用高压并行编程器这是最终的硬件解决方案。你需要一个高压编程器如USBasp配合高压编程适配板通过12V电压和特定的并行编程模式来重置熔丝位。这需要额外的硬件和更复杂的接线。更换芯片如果项目不紧急且芯片廉价有时直接更换一颗新的芯片是最经济快捷的选择。这也提醒我们操作熔丝位前务必三思并备份。我个人在Linux上玩转ATtiny13和AVRA的体验是这是一个将控制权完全交还给开发者的过程。你不再被抽象层所隔离每一个字节的使用每一个时钟周期的流逝你都了然于胸。从最初点亮一个LED的兴奋到后来用状态机和中断实现复杂逻辑的成就感这种与硬件直接对话的乐趣是使用高级框架难以比拟的。它或许不是开发产品最快的方式但绝对是理解微控制器本质最深刻的途径之一。最后一个小建议养成写注释的好习惯尤其是在汇编中。因为几个月后回头看那些精妙的位操作和跳转逻辑没有注释的帮助你自己可能也会感到陌生。
返回列表