超级马里奥的蘑菇徽章

基于定制款 PCB 的闪光蘑菇

Cherry

喜欢

261
浏览
0
喜欢

> 更多图片

项目状态:已完成
开放度:公开
所属分类:电子
发布时间:2022-05-06
最近更新:2023-09-10

详细说明


今天给大家带来一期致敬经典的超级马里奥的徽章。可爱的蘑菇徽章,经典的红黄配色,立马把我们拉回到儿时的快乐的时光里(不小心暴露了年龄)。

这款可穿戴徽章由定制的 PCB 构成,采用 SOIC8 封装的 Attiny85 供电,添加了三个 WS2812B LED 灯可以使蘑菇徽章闪闪发光。你可以把它佩戴在身上也可以别在书包上。

制作过程很简单,喜欢的创客可以动手试试看!

链接表


文件库

WS2812B.pdf
[355361 Bytes at 2023-09-10, 0 次下载]



教程

组件清单
  • 定制PCB × 1
  • Attiny85 × 1
  • WS2812B LED 灯 × 3
  • 1uf 0805 电容 × 1
  • 胸针 × 1
  • SMD 纽扣电池座 × 1
  • CR2032 电池 × 1
  • SOIC8 烧写夹 × 1

项目介绍

该徽章基于 Microchip 8 位的低功耗微控制器,同时结合了 8 KB ISP 闪存、512B EEPROM、512B SRAM和六条通用 I/O 线,由 Attiny85 供电。

它是一个功能强大的小型 MCU,可以缩小整个设置实现很多基于 Arduino 的项目。更多的数据资料可点击查看,https://www.microchip.com/en-us/product/ATtiny85

我采用 CR2032 纽扣电池来供电,它可以为系统提供 3V 电压。其中,三个 WS2812B LED 灯,每个 LED 灯消耗 50mA,总共 150mA,CR2032 的容量为 210mAh,所以可以提供 1 小时以上的备份。

WS2812B LED 灯的数据资料可点击查看,https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf

PCB 板的创建过程

1、如图所示,我需要设计一个蘑菇形状的 PCB 板,将图形导入到 PCB Cad 软件。我选择黑白图像并将其作为 PCB 层导入。

2、如图所示,Attiny85 可以控制 Din Dout Config 并完成连接的三个 WS2812B LED 灯的所有工作。

第一个像素的 Dout 连接至第二个像素的 Din,第二个像素的 Dout 连接至第三个像素的 Din,然后再用第一个像素的 Din 提供一个信号来控制这三个像素。

每个LED 灯都有 1uf 的电容器,然后用一个开关连接到 Attiny85 的 D4。最后,将纽扣电池装入至电池仓供电。

3、设计 PCB 板

首先导入了蘑菇图像并将其用作 PCB 的轮廓,其中一些细节k可用于制作阻焊层。

所有组件都是 SMD,将它们放在背面,再将 LED 灯放置在圆形区域。在圆形区域我添加了一个阻焊层的开口,可以从顶部可以看到 LED 灯的余光。

这些 WS2812B LED 灯采取倒置的自定义封装,所以要将 LED 倒置焊接。

4、PCBWAY 打样

在最后一次检查完电路板后,我将 Gerber 数据发送到 PCBWAY 以获取样品。我选择的材料是带有白色丝印的红色阻焊层。
我在两侧的阻焊层上预留了开口,这样就可以从顶部可以看到底部的LED 灯。
PCBWAY:https://www.pcbway.com/

5、组装 PCB 板
组装 PCB 板主要有以下几个步骤:
a、锡膏点胶工艺
在每个元件焊盘上逐个添加焊膏。我使用的是带宽注射器的焊膏分配针,焊膏是由 63% 锡和 37% 铅组成的普通焊膏。
b、拾取和放置过程
使用镊子将每个组件放置在适当的位置,要小心地处理每一个元件。
c、热板回流
放置好元件后,将整个电路板放到我自制的热板回流焊板上进行焊接。完成后,请将其放置冷却。
d、安装 LED 灯
由于 PCB 板没有任何通孔组件,需要在焊盘上焊接电线,然后再将 LED 灯与它连接起来。焊接过程中尽量快一点,因为 LED 焊盘过热可能会引起外壳熔化。最后,完成三个 LED 灯的焊接。

安装 Attiny85

1、刷机过程中不能通过 USB 直接对 ATTINY85 进行编程,我采用 ISP 闪存的方法,通过 attiny85 的 SPI 引脚烧录引导加载程序,然后再烧录。
为了将 Attiny 与程序连接起来,我使用 SOIC8 烧写夹,直接将 Attiny 连接到该夹子上。

2、请在 Arduino IDE 中下载并安装 Attiny85 Core 文件,https://github.com/SpenceKonde/ATTinyCore

文件->首选项 PC 或者 Arduino->首选项 Mac,在 “Additional Boards Manager URLs” 中输入https://github.com/SpenceKonde/ATTinyCore
工具->主板->主板管理器,如果使用 1.6.6 版本,请关闭板子管理器并重新打开它。
选择"ATTinyCore by Spence Konde",然后单击安装。

3、设置 AVR 芯片。AVR 芯片通常是空白的,它需要设置与 Arduino IDE 兼容性,所以需要编程 AVR 程序,例如 USBASP。这里有一个非常简单的方法,你可以使用 Arduino Uno 或 Nano 板制作自己的 AVR 编程器。

将 Arduino 板与 com 端口连接并选择以下 sketch:
Example->在 ArduinoISP 中将 sketch 上传至主板。进入工具菜单并在程序部分选择 Arduino 作为 ISP 选项。点亮 Attiny85 后,在 Board 部分选择 Attiny85。

编程过程会使用到 VCC、GND 和四个数据引脚。三个引脚分别连接到 MISO、MOSI 和 SCK 来实现目标,第四个引脚起到复位的作用。

4、用线将 Attiny85 与 Arduino 连接起来。
注意在将 ISP Sketch 上传到 Arduino 之后,需要在 Arduino 的 Reset 和 GND 引脚之间添加一个 10uf 的电容。

我没有使用 Arduino 和面包板来完成这项工作,而是使用我自制的用 Attiny 或 Atmega MCU 制作的 DIY Attiny Programmer。
具体详情可点击查看,https://www.instructables.com/Multiple-ATtiny8513A-Programmer/

在以上接线配置中将主板连接到 Arduino 作为 ISP 设置。
选择正确的端口、正确的编程器(Arduino 作为 ISP),然后点击 Burn Bootloader。
等待几秒钟,你将完成烧录引导程序的消息。
打开要上传到这个 AttinyGo 的 Sketch,然后到 Sketch 菜单并选择上传程序。
最后 Sketch 会上传到 attiny85。

编码

编码是 Neopixel buttoncycler sketch,当按下连接到 attiny D4 的按钮时,就会改变 neopixels 的颜色和动画。


#include <Adafruit_NeoPixel.h>

#define BUTTON_PIN   4    // Digital IO pin connected to the button.  This will be
                          // driven with a pull-up resistor so the switch should
                          // pull the pin to ground momentarily.  On a high -> low
                          // transition the button press logic will execute.

#define PIXEL_PIN    0    // Digital IO pin connected to the NeoPixels.

#define PIXEL_COUNT 3

// Parameter 1 = number of pixels in strip,  neopixel stick has 8
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_RGB     Pixels are wired for RGB bitstream
//   NEO_GRB     Pixels are wired for GRB bitstream, correct for neopixel stick
//   NEO_KHZ400  400 KHz bitstream (e.g. FLORA pixels)
//   NEO_KHZ800  800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

bool oldState = HIGH;
int showType = 0;

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  // Get current button state.
  bool newState = digitalRead(BUTTON_PIN);

  // Check if state changed from high to low (button press).
  if (newState == LOW && oldState == HIGH) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
    if (newState == LOW) {
      showType++;
      if (showType > 9)
        showType=0;
      startShow(showType);
    }
  }

  // Set the last button state to the old state.
  oldState = newState;
}

void startShow(int i) {
  switch(i){
    case 0: colorWipe(strip.Color(0, 0, 0), 50);    // Black/off
            break;
    case 1: colorWipe(strip.Color(255, 0, 0), 50);  // Red
            break;
    case 2: colorWipe(strip.Color(0, 255, 0), 50);  // Green
            break;
    case 3: colorWipe(strip.Color(0, 0, 255), 50);  // Blue
            break;
    case 4: theaterChase(strip.Color(127, 127, 127), 50); // White
            break;
    case 5: theaterChase(strip.Color(127,   0,   0), 50); // Red
            break;
    case 6: theaterChase(strip.Color(  0,   0, 127), 50); // Blue
            break;
    case 7: rainbow(20);
            break;
    case 8: rainbowCycle(20);
            break;
    case 9: theaterChaseRainbow(50);
            break;
  }
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
  for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

最后,安装好 CR2032 纽扣电池,这枚可爱的蘑菇徽章就可以闪光了。