ATtiny85开发指南:用Arduino IDE驱动微型AVR芯片
1. 从Arduino到ATtiny85为什么我们需要这颗“小钢炮”如果你玩过Arduino Uno或者Nano肯定对它们那丰富的引脚和相对宽裕的Flash空间习以为常。但有没有遇到过这样的场景你只想做一个简单的LED呼吸灯、一个温度传感器数据记录器或者一个简单的红外遥控发射器用Arduino Uno来做感觉就像用牛刀杀鸡不仅体积大、成本高而且功耗也完全不在一个量级。这时候你就需要认识一下今天的主角——ATtiny85。ATtiny85是Microchip原Atmel公司生产的一款8位AVR微控制器。它有多“tiny”我们拿数据说话它只有8个引脚其中5个或6个可用作I/O8KB的Flash程序存储器512字节的SRAM512字节的EEPROM。跟Arduino Uno的32KB Flash和2KB SRAM比起来它确实是个“小不点”。但正是这种极致的精简让它成为了嵌入式项目中的“小钢炮”。它的核心优势非常明显超低功耗睡眠模式下电流可低至微安级、超小体积有DIP-8和SOIC-8两种封装后者只有指甲盖大小、极低成本单价通常只有Arduino主控芯片的几分之一。那么问题来了。我们习惯了用Arduino IDE那种“一键上传”的便捷开发方式而ATtiny85原生的开发环境是AVR-GCC和AVRdude需要配置熔丝位、编写Makefile门槛不低。有没有可能让我们用熟悉的Arduino代码那些digitalWrite、analogRead、Serial.print来驱动这颗小芯片呢答案是肯定的而且这个过程比你想象的要简单。本文将手把手带你完成两件事第一搭建一个用Arduino Uno作为编程器ISP来给ATtiny85烧录程序的硬件和软件环境第二深入理解在资源受限的ATtiny85上编写Arduino代码时需要注意的那些“坑”和优化技巧。无论你手头是方便插拔的DIP-8封装还是需要焊接到板子上的SOIC-8封装本文的流程都适用。2. 硬件准备与连接打造你的专属“微型编程工坊”要给ATtiny85烧录程序你需要一个“编程器”。最经济实惠的方案就是利用你手头已有的Arduino Uno或类似的AVR板卡如Nano来充当这个角色。这个模式在AVR领域被称为“ISP”In-System Programming即在线系统编程。Arduino Uno上的主控芯片ATmega328P本身就可以被配置成一个ISP编程器通过SPI接口向目标芯片我们的ATtiny85发送机器码。2.1 物料清单与核心原理你需要准备以下硬件一台Arduino Uno作为ISP编程器。一颗ATtiny85芯片DIP-8或SOIC-8封装均可。一块无焊面包板用于DIP封装测试或一个SOIC-8转DIP-8的适配座用于焊接好的SOIC芯片编程。若干杜邦线公对公。一个10μF的电解电容或钽电容可选但强烈推荐用于在编程时稳定Arduino Uno的复位信号。对于SOIC封装你还需要一个对应的编程夹具或已经将芯片焊接在带有ISP接口的自制PCB上。其核心连接原理基于SPI总线。在ISP编程中编程器Master通过三根信号线控制目标芯片SlaveMOSI (Master Out Slave In)编程器输出目标芯片输入。用于发送指令和数据。MISO (Master In Slave Out)目标芯片输出编程器输入。用于读取目标芯片的状态和数据。SCK (Serial Clock)时钟信号由编程器产生同步数据传输。除此之外还需要RESET线来控制目标芯片进入编程模式以及共地GND和电源VCC通常5V或3.3V。ATtiny85的引脚排列以DIP-8为例俯视半圆缺口朝上Pin 1: /RESET (PCINT5)Pin 2: (ADC3) PB3Pin 3: (ADC2) PB4Pin 4: GNDPin 5: (MOSI) PB0Pin 6: (MISO) PB1Pin 7: (SCK) PB2Pin 8: VCC2.2 两种封装的详细接线图对于DIP-8封装的ATtiny85使用面包板这是最简单的情况。将ATtiny85插入面包板注意方向缺口朝上。接线如下Arduino Uno 引脚连接到 ATtiny85 引脚信号线D10Pin 1 (RESET)RESETD11Pin 5 (PB0)MOSID12Pin 6 (PB1)MISOD13Pin 7 (PB2)SCK5VPin 8 (VCC)VCCGNDPin 4 (GND)GND重要提示在Arduino Uno的RESET引脚和GND之间接上一个10μF电容的正极正极接RESET负极接GND。这个电容的作用是防止Arduino Uno在编程过程中被自身串口信号意外复位导致编程失败。这是很多新手容易忽略但至关重要的一步。对于SOIC-8封装的ATtiny85SOIC芯片通常已经焊接在定制的小板子比如流行的“Digispark”开发板核心上。你需要找到板上引出的ISP接口通常是6个排针VCC、GND、RESET、SCK、MISO、MOSI。连接逻辑与DIP封装完全一致只是物理接口变成了排针。如果你是自己焊接的裸芯片那么强烈建议你制作或购买一个SOIC-8转DIP-8的编程座将芯片放入座中再按照DIP封装的接线方式连接这样最稳妥。连接好硬件后ATtiny85的VCC和GND就由Arduino Uno供电了。至此硬件“编程工坊”搭建完毕。3. 软件环境配置让Arduino IDE认识ATtiny85硬件就绪后我们需要在软件层面让Arduino IDE支持ATtiny85这颗“非官方”芯片。3.1 安装ATtiny核心支持包Arduino IDE默认的板卡列表里没有ATtiny85。我们需要通过“开发板管理器”添加第三方核心。打开Arduino IDE进入“文件” - “首选项”。在“附加开发板管理器网址”中输入以下URL如果你已有其他URL用逗号分隔https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json这是由David A. Mellis维护的ATtiny核心经典且稳定。点击“好”保存然后打开“工具” - “开发板” - “开发板管理器”。在搜索框中输入“attiny”你会找到“attiny by David A. Mellis”。点击并选择安装最新版本通常是1.0.2或更高。安装完成后关闭开发板管理器。现在在“工具” - “开发板”列表中你应该能看到“ATtiny”系列了。3.2 将Arduino Uno配置为ISP编程器接下来我们需要把连接着ATtiny85的这台Arduino Uno刷写成“Arduino as ISP”固件。用USB线将这台作为编程器的Arduino Uno连接到电脑。在Arduino IDE中选择开发板为“Arduino Uno”编程器本身。选择正确的端口。打开示例代码“文件” - “示例” - “11. ArduinoISP” - “ArduinoISP”。在代码中有一个重要的配置项。为了获得更稳定的编程体验建议找到#define USE_OLD_STYLE_WIRING这一行大约在第100行。取消它的注释即删除行首的//。这会让编程器使用更传统的接线方式兼容性更好。将此代码上传到你的Arduino Uno。上传成功后这块Uno就变成了一个专用于给其他AVR芯片烧录程序的ISP编程器。3.3 配置烧录参数与熔丝位现在我们来配置如何给目标芯片ATtiny85烧录程序。保持Arduino Uno通过USB连接电脑。在Arduino IDE中“工具”菜单下进行如下关键设置开发板选择“ATtiny25/45/85”。处理器选择“ATtiny85”。时钟这是至关重要的一步ATtiny85内部默认使用1MHz时钟。但为了与Arduino库函数特别是delay()和串口软件模拟的时序兼容我们通常将其设置为内部8MHz。请选择“Internal 8 MHz”。如果你使用外部晶振则选择对应的频率。编程器选择“Arduino as ISP”。端口选择你的Arduino Uno所在的COM端口。烧录引导程序Bootloader 在Arduino语境下对于ATtiny85“烧录引导程序”这个操作的实际作用是配置芯片的熔丝位Fuses而不是真的烧录一个BootloaderATtiny85通常没有空间放Bootloader。熔丝位决定了芯片的核心配置如时钟源、启动延时、BOD掉电检测电平等。 点击“工具” - “烧录引导程序”。IDE会通过我们刚才刷写的“Arduino as ISP”编程器向ATtiny85写入一组与“Internal 8 MHz”时钟匹配的熔丝位配置。 此时观察Arduino Uno上的指示灯通常Pin 13的LED会快速闪烁表示正在通信。如果一切顺利IDE底部状态栏会显示“烧录引导程序 完成”。如果报错如avrdude: stk500_getsync() attempt X of 10: not in sync请立即检查所有接线是否牢固尤其是RESET线。10μF电容是否接在Uno的RESET和GND之间。ATtiny85的VCC和GND是否接反。在“烧录引导程序”前是否正确选择了“编程器”为“Arduino as ISP”。软件环境至此全部配置完成。你的Arduino IDE已经准备好向ATtiny85编译和上传Arduino风格的代码了。4. 编写你的第一个ATtiny85“Arduino”程序环境搭好了我们来点个灯吧这是嵌入式世界的“Hello World”。我们将让ATtiny85的PB1引脚对应Arduino引脚号1也是物理Pin 6上的LED闪烁。4.1 引脚映射跨越封装的数字游戏这是从Arduino过渡到ATtiny85的第一个挑战。ATtiny85的物理引脚和Arduino IDE中使用的数字引脚号不是一一对应的我们需要一张映射表。基于我们选择的“ATtiny25/45/85”核心常用的映射关系如下以芯片内部端口PBx为准芯片端口物理引脚 (DIP-8)Arduino IDE 引脚编号模拟输入编号特殊功能PB050A0MOSI, DI, SDAPB161A1MISO, DOPB272A2SCK, SCL, ADC1PB323A3ADC3, /RESET (若禁用复位)PB434A2ADC2PB515A0/RESET (默认) 或作为I/O使用注意PB5物理Pin 1默认是复位引脚/RESET。如果你想把它当作普通IO引脚Pin 5使用必须在烧录引导程序前在“工具” - “处理器”下选择“ATtiny85 (internal 8 MHz clock, disable BOD, enable EEPROM,reset disabled)”。这会改变熔丝位永久禁用其复位功能使其变为普通IO。一旦禁用你将无法再通过此引脚用ISP方式编程必须使用高压并行编程器HVPP才能恢复新手请谨慎操作在我们的闪烁LED例子中我们将LED正极通过一个220Ω限流电阻接到PB1Arduino Pin 1负极接GND。4.2 代码编写与上传在Arduino IDE中新建一个草图输入以下代码void setup() { pinMode(1, OUTPUT); // 将ATtiny85的PB1Arduino Pin 1设置为输出 } void loop() { digitalWrite(1, HIGH); // LED亮 delay(1000); // 等待1000毫秒 digitalWrite(1, LOW); // LED灭 delay(1000); // 等待1000毫秒 }代码非常简单和标准的Arduino程序一模一样。这就是我们想要的效果——用熟悉的语法控制新硬件。点击左上角的“上传”按钮。注意这里不是普通的“上传”而是“通过编程器上传”。IDE会执行以下步骤编译代码将Arduino风格的C代码编译成ATtiny85可执行的机器码.hex文件。调用avrdude工具通过我们指定的“Arduino as ISP”编程器将编译好的.hex文件烧录到ATtiny85的Flash存储器中。烧录完成后avrdude会发送一个命令让ATtiny85复位并开始运行新程序。观察你的ATtiny85电路连接在Pin 6PB1上的LED应该开始以1秒的间隔稳定闪烁了恭喜你你已经成功用Arduino的方式驾驭了这颗微型芯片。5. 深入核心ATtiny85上Arduino库的局限性与优化实战让LED闪烁只是第一步。当你试图把更复杂的Arduino项目移植到ATtiny85上时会立刻撞上它的资源墙。8KB的Flash和512字节的RAM是极其宝贵的你必须成为一个“内存侦探”和“代码裁缝”。5.1 内存与Flash空间的精细化管理RAM512字节这是变量、数组、字符串常量和函数调用栈的生存空间。一个int变量占2字节一个float占4字节一个10个字符的String对象轻松占用几十字节。RAM耗尽会导致程序行为异常、崩溃且编译器不一定报错。实战技巧1使用F()宏存放字符串。Serial.print(Hello, ATtiny85!);这行代码会将字符串“Hello, ATtiny85!”放入RAM。在ATtiny85上这是奢侈的。正确的做法是Serial.print(F(Hello, ATtiny85!));F()宏将字符串常量存放在Flash程序存储器中仅在需要时调入RAM能节省大量空间。实战技巧2避免使用String类。Arduino的String类动态分配内存非常方便但开销大且容易产生内存碎片。在ATtiny85上应使用C语言风格的字符数组char array[]和相关的字符串处理函数如strcpy,strcat,atoi。实战技巧3使用局部变量慎用全局变量。全局变量在整个程序生命周期都存在而局部变量在函数退出后释放。在满足功能的前提下尽量使用局部变量。Flash8KB存放你的程序代码和用F()宏存储的常量。代码体积优化是关键。实战技巧4选择必要的库并了解其体积。SoftwareSerial库很有用但会占用约1.5KB的Flash。如果只是输出调试信息可以考虑更轻量的TinyDebugSerial或直接操作寄存器进行位操作。实战技巧5在IDE中查看编译结果。每次编译后IDE底部控制台会输出类似信息项目使用了 2342 字节28%的程序存储空间。最大为 8192 字节。 全局变量使用了 45 字节8%的动态内存剩下 467 字节用于局部变量。最大为 512 字节。时刻关注这两个百分比确保它们不会接近100%。5.2 模拟输入与PWM输出的特殊配置ATtiny85有一个10位精度的ADC模数转换器但引脚有限。模拟读取使用analogRead(Ax)其中x是模拟引脚编号见4.1的映射表。例如读取PB4物理Pin 3的模拟值int sensorValue analogRead(A2);。PWM输出ATtiny85支持PWM的引脚是PB0Pin 5和PB1Pin 6。使用analogWrite(pin, value)即可其中value是0-255之间的值。PB4Pin 3不支持硬件PWM如果需要更多PWM引脚需要使用软件模拟但这会消耗CPU周期和Flash空间。5.3 “串口”通信软件模拟的智慧ATtiny85没有硬件UART因此Serial对象在默认核心中是不可用的。我们需要使用SoftwareSerial库来模拟。#include SoftwareSerial.h // RX, TX。 注意在ATtiny85上只能使用支持PCINT的引脚作为RX。 SoftwareSerial mySerial(3, 4); // 使用PB3Pin 2作RX PB4Pin 3作TX void setup() { mySerial.begin(9600); } void loop() { mySerial.println(F(Hello from ATtiny85!)); delay(1000); }重要限制SoftwareSerial的RX引脚必须支持引脚变化中断PCINT。在ATtiny85上只有PB1、PB3、PB4支持作为RX。PB0和PB2不支持。同时软件串口会占用大量CPU时间在高波特率如115200下可能不稳定且会显著增加代码体积。对于仅输出的调试有时直接使用TinyDebugSerial它仅使用TX引脚是更节省资源的选择。6. 高级话题功耗优化与睡眠模式实战ATtiny85的真正威力在于其超低功耗特性非常适合电池供电的长期监测项目。实现低功耗的关键是让芯片在不工作时进入睡眠模式。6.1 配置时钟与关闭外设首先在代码层面进行优化降低时钟频率如果不是必须可以在“烧录引导程序”时选择更低的时钟如内部1MHz。功耗与频率大致成正比。禁用未用的外设ADC、模拟比较器、看门狗等在不需要时应该关闭。// 在setup()中关闭ADC以省电 ADCSRA ~(1 ADEN); // 关闭模拟比较器 ACSR | (1 ACD);6.2 实现深度睡眠我们需要使用avr/sleep.h和avr/power.h库。#include avr/sleep.h #include avr/power.h #include avr/wdt.h // 看门狗定时器可用于唤醒 void setup() { pinMode(1, OUTPUT); // 配置看门狗定时器中断唤醒可选 // 这里以外部中断唤醒为例 attachInterrupt(0, wakeUp, LOW); // 使用INT0PB2 Arduino Pin 2低电平唤醒 } void loop() { digitalWrite(1, HIGH); delay(100); digitalWrite(1, LOW); // 进入睡眠前的准备工作 sleep_enable(); // 使能睡眠功能 set_sleep_mode(SLEEP_MODE_PWR_DOWN); // 设置最省电的掉电模式 power_all_disable(); // 关闭所有外设电源 sleep_cpu(); // 进入睡眠程序在此暂停 // 被中断唤醒后程序从这里继续执行 sleep_disable(); // 禁用睡眠 power_all_enable(); // 重新开启需要的模块如ADC // ... 执行唤醒后的任务 delay(1000); // 模拟一些工作 } void wakeUp() { // 中断服务程序。这里可以什么都不做唤醒由硬件处理。 }在SLEEP_MODE_PWR_DOWN模式下ATtiny85的电流消耗可以降到1微安以下这意味着一颗纽扣电池可以支撑数年。唤醒方式可以是外部引脚中断、看门狗定时器中断等。6.3 实测功耗与电池寿命估算使用万用表电流档串联在电池和ATtiny85的VCC之间进行测量。确保测量时编程器的USB线已断开系统由电池独立供电。运行模式8MHz LED闪烁电流可能在5-10mA量级。空闲模式SLEEP_MODE_IDLE关闭CPU但保持外设电流在mA级别。掉电模式SLEEP_MODE_PWR_DOWN如上述代码电流1μA。假设我们使用一颗容量为240mAh的CR2032纽扣电池项目99%的时间在掉电睡眠0.001mA1%的时间在活跃工作5mA。 平均电流 ≈ (0.001mA * 0.99) (5mA * 0.01) ≈ 0.05099 mA 理论续航 ≈ 240 mAh / 0.05099 mA ≈ 4700小时 ≈196天。 这就是ATtiny85在低功耗项目中的巨大优势。7. 从原型到产品DIP与SOIC的最终抉择当你完成了面包板上的原型验证接下来就是考虑如何将项目产品化或固化这就涉及到封装的选择。DIP-8封装优点引脚粗壮可以直接插在面包板或IC座上非常适合原型开发、实验和学生教学。焊接和拆卸都非常容易甚至可以不焊接。缺点体积大不适用于对空间有严格要求的最终产品。引脚也更容易在反复插拔中损坏。SOIC-8封装优点体积非常小巧大约5mm x 6mm是最终产品、小型化设备的首选。采用表面贴装技术SMT可以自动化生产成本更低。缺点无法直接在面包板上使用必须焊接在PCB上。焊接需要一定的技巧可以使用热风枪或尖头烙铁配合助焊膏对于新手有挑战。调试时需要借助专用的测试座或焊出引线。我的实战建议开发阶段毫不犹豫地使用DIP封装的ATtiny85。配合一个8脚的IC座你可以随时拔插芯片烧录、测试、修改代码无比方便。多买几颗DIP芯片成本也不高。小批量生产或最终作品使用SOIC封装。你可以设计一块简单的PCB将ATtiny85、必要的电阻电容、传感器接口和电源接口都集成上去。在PCB上预留一个6Pin的ISP编程接口VCC, GND, RESET, SCK, MISO, MOSI这样即使焊接成SOIC仍然可以通过这个接口对芯片进行编程和调试。编程夹具如果经常需要烧录SOIC芯片投资一个SOIC-8测试夹或编程座是值得的。它能像夹子一样夹住芯片的引脚另一端引出杜邦线省去了焊接引线的麻烦。无论是选择可插拔的DIP进行快速迭代还是选择微型的SOIC打造精致作品ATtiny85都能让你用最熟悉的Arduino思维方式去探索嵌入式世界中那片高效、低功耗的广阔天地。它就像一把精巧的瑞士军刀虽然功能不像重型机械那样繁多但在其擅长的领域内它无比锋利、可靠且顺手。