Another project that illustrates how to build a lighting system for Electronic Scooters and Bikes. However, this project also can be applied in car lightning accessories such as under chassis lightning or grill light effects using addressable LED Stripe & Microcontroller. See below the required components.
The 8Bit ATTINY AVRT Microcontroller
ATtiny25/45/85 is a low-power CMOS 8-bit microcontroller based on the AVR enhanced RISC architecture. By executing excellent instructions in a single clock cycle, the ATtiny25/45/85 achieves throughputs resembling 1 MIPS per MHz allowing you to optimize power consumption versus processing speed.
Requirements and Alternatives
- Arduino IDE | PlatformIO | Visual Studio Code
- ATTINY85 Chip or Modules
- SONY SPRESENSE Development Board
- Please refer to this link
- ESPRESSIF Microcontrollers
- 3S 20Amp Battery Management System / Battery Protection Board)
- N-Channel MOSFET
- 12v Addressable LED Strip WS2812
- 4x or 6x Li-Ion 18650 Battery 3.7v-2500mAH
- Tactile Switch
- Push Button
- Resistors (See below-required values)
- Capacitor(See below-required values)
- Others (see below diagram for other requirements)
Wiring Diagram
Wiring Diagram Schematics for 3S 12v 20A BMS / BPB
The 3S 20A 12.6v Lithium BMS (Battery Management System / Battery Protection Board) comes with an auto-recovery function, with a nominal voltage of 3.6v, 3.7v Li-ion battery continuously discharges at 20A. keep in mind that the higher the load the board will become much hotter, in this case, need to mind the current load is in use. please refer to this link how to calculate load to the battery
Wiring Digram for 3S 3P & 4S 4P 12v and 16v on BMS (Battery Management System)
Bootloading ATTINY85
As you can see in the diagram below it is segregated into 2 different ways to flash an ATTINY MCU. The first guide is using an Arduino MCU board as a chip programmer, and the 2nd guide is using a USBASP USBISP AVR Programmer. Keep in mind that when you program the chip you need to disconnect it from the 5v L7805 regulator.
Steps how to bootload the ATTINY using USBASP AVR
Copy & Phase this the board manager > http://drazzy.com/package_drazzy.com_index.json
Any of these parts will be programmed by the use of any ISP (USB-UART) programmer. If using a version of Arduino before 1.8.13, be sure to choose a programmer with ATTinyCore after its name and connect the pins as normal for that ISP programmer.
Steps how to Bootload ATTINY85 using Arduino Board
Copy this link & phase > https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json > for wiring diagram how to hookup the ATTINY85 manually to Arduino board please refer to this link.
To program our ATtiny Microcontroller with Arduino Bootloader we need to first set Arduino Uno as an ISP. Attach the Arduino Uno to the PC. Open the Arduino IDE and open the ArduinoISP example file (File -> Examples -> ArduinoISP) and upload it. If there are no error messages your Arduino should be good to go. A wiring diagram can be found here, how to hook the ATTINY MCU to the Arduino board. | Copy this link & phase > https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json
Finally, we have now an 8MHz Arduino board with input/output pins. The ATtiny85 can run on 2.7-5.5V without a regulator – so a 3.7V LiPo can power the board and make a cheap, effective, slim Arduino board. The best way to verify that the ATtiny Arduino is working properly is to upload a simple code sketch. You can use the code below to run a LED light effects. If you can upload the sketch to the ATtiny85 then you have a fully working Arduino 8MHz ATtiny85 Microcontroller, the possibilities are nearly identical to the ATmega328p, except for fewer ports and some limitations. However, the ATtiny Arduino is fully capable of managing analog read and writing, digital reading and writing, UART communication, power-down modes, SPI-interface, interrupt capabilities. However, you can now load the code below directly to ATTINY85 with your IDE.
Source Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
#include <avr/sleep.h> #include #include #include // ATTINY85 RGB WS2812 / WS2812B | WS2815 5050 >> TEST CODE // #define adc_disable() (ADCSRA &= ~(1<<ADEN)) // disable ADC (before power-off) #define adc_enable() (ADCSRA |= (1<<ADEN)) // re-enable ADC #define RC_PIN 3 #define LED_NUMBER 8 #define LED_MULTIPLIER 5 #define LED_PIN 2 #define SLEEP_TIME 30 #define BUTTON_PIN 0 #define COLORS 7 #define LONG_PUSH_THRESHOLD 20 #define MAX_CYCLE 256 #define MODES 9 #define EEPROM_MODE_ADDRESS 0 #define EEPROM_COLOR_ADDRESS 1 #define LPF_FACTOR 0.8 const byte colors[COLORS][3] = { {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 0, 255}, {255, 255, 0}, {0, 255, 255}, {255, 255, 255} }; WS2812 LED(LED_NUMBER * LED_MULTIPLIER); byte mode = 0; byte pushStartCycle; byte i; byte colorIndex = 0; byte cycle = 0; cRGB currentColor; cRGB off; cRGB background; cRGB output[LED_NUMBER] = {}; volatile unsigned long risingStart = 0; volatile unsigned int channelLength = 0; int smooth(int data, float filterVal, float smoothedVal){ if (filterVal > 1){ // check to make sure params are within range filterVal = .99; } else if (filterVal <= 0){ filterVal = 0; } smoothedVal = (data * (1 - filterVal)) + (smoothedVal * filterVal); return (int)smoothedVal; } void setColor() { currentColor.r = colors[colorIndex][0]; currentColor.g = colors[colorIndex][1]; currentColor.b = colors[colorIndex][2]; background.r = colors[colorIndex][0] / 5; background.g = colors[colorIndex][1] / 5; background.b = colors[colorIndex][2] / 5; } void setup() { adc_disable(); LED.setOutput(LED_PIN); pinMode(BUTTON_PIN, INPUT_PULLUP); off.r = 0; off.g = 0; off.b = 0; mode = EEPROM.read(EEPROM_MODE_ADDRESS); if (mode >= MODES) { mode = 0; } colorIndex = EEPROM.read(EEPROM_COLOR_ADDRESS); if (colorIndex >= COLORS) { colorIndex = 0; } setColor(); attachPinChangeInterrupt(RC_PIN, onChange, CHANGE); } void onChange(void) { uint8_t trigger = getPinChangeInterruptTrigger(RC_PIN); if(trigger == RISING) { risingStart = micros(); } else if(trigger == FALLING) { unsigned int val = micros() - risingStart; channelLength = smooth(val, LPF_FACTOR, channelLength); } } void modeOff(byte currentCycle) { for (i = 0; i < LED_NUMBER; i++) { output[i] = off; } } void modeOn(byte currentCycle) { for (i = 0; i < LED_NUMBER; i++) { output[i] = currentColor; } } byte getDivider(byte denom, byte cycle) { return cycle / denom; } void modeSingleWander(byte currentCycle) { currentCycle = getDivider(2, currentCycle); for (i = 0; i < LED_NUMBER; i++) { output[i] = background; } output[currentCycle % LED_NUMBER] = currentColor; } void setOutput(byte led, cRGB color) { // if (led <= LED_NUMBER) { output[led] = color; // } } void modeRapid(byte currentCycle) { for (i = 0; i < LED_NUMBER; i++) { output[i] = background; } if (currentCycle == LED_NUMBER << 2) { cycle = 0; currentCycle = 0; } if (currentCycle < LED_NUMBER) { setOutput(currentCycle % LED_NUMBER, currentColor); if (currentCycle + 1 < LED_NUMBER) { setOutput((currentCycle + 1) % LED_NUMBER, currentColor); } if (currentCycle + 2 < LED_NUMBER) { setOutput((currentCycle + 2) % LED_NUMBER, currentColor); } } } void modeBoldWander(byte currentCycle) { currentCycle = getDivider(2, currentCycle); for (i = 0; i < LED_NUMBER; i++) { output[i] = background; } output[currentCycle % LED_NUMBER] = currentColor; output[(currentCycle + 1) % LED_NUMBER] = currentColor; } void modeBolderWander(byte currentCycle) { currentCycle = getDivider(2, currentCycle); for (i = 0; i < LED_NUMBER; i++) { output[i] = off; } output[currentCycle % LED_NUMBER] = currentColor; output[(currentCycle + 1) % LED_NUMBER] = currentColor; output[(currentCycle + 2) % LED_NUMBER] = currentColor; output[(currentCycle + 3) % LED_NUMBER] = currentColor; } void modeDoubleWander(byte currentCycle) { currentCycle = getDivider(2, currentCycle); for (i = 0; i < LED_NUMBER; i++) { output[i] = off; } output[currentCycle % LED_NUMBER] = currentColor; output[(MAX_CYCLE - currentCycle) % LED_NUMBER] = currentColor; } void modeChase(byte currentCycle) { currentCycle = getDivider(2, currentCycle); for (i = 0; i < LED_NUMBER; i++) { output[i] = off; } output[currentCycle % LED_NUMBER] = currentColor; output[(currentCycle + (LED_NUMBER / 2)) % LED_NUMBER] = currentColor; } void modeFlash(byte currentCycle) { currentCycle = getDivider(2, currentCycle); cRGB state = off; if (currentCycle % 16 == 12 or currentCycle % 16 == 15) { state = currentColor; } for (i = 0; i < LED_NUMBER; i++) { output[i] = state; } } byte previousPin = LOW; byte controllState = LOW; byte previousState = LOW; void loop() { byte pin = digitalRead(BUTTON_PIN); controllState = LOW; if (channelLength > 1750 && channelLength < 2200 || digitalRead(BUTTON_PIN) == LOW) { controllState = HIGH; } if (controllState == HIGH and previousState == LOW) { pushStartCycle = cycle; } if (controllState == LOW and previousState == HIGH) { if (abs(cycle - pushStartCycle) > LONG_PUSH_THRESHOLD) { /* * Cycle color procedure */ colorIndex++; if (colorIndex == COLORS) { colorIndex = 0; } EEPROM.write(EEPROM_COLOR_ADDRESS, colorIndex); setColor(); cycle = 0; pushStartCycle = 0; } else if (abs(cycle - pushStartCycle) > 1) { mode++; if (mode == MODES) { mode = 0; } cycle = 0; pushStartCycle = 0; EEPROM.write(EEPROM_MODE_ADDRESS, mode); } } previousState = controllState; switch (mode) { case 0: modeOff(cycle); break; case 1: modeOn(cycle); break; case 2: modeSingleWander(cycle); break; case 3: modeBoldWander(cycle); break; case 4: modeDoubleWander(cycle); break; case 5: modeChase(cycle); break; case 6: modeFlash(cycle); break; case 7: modeBolderWander(cycle); break; case 8: modeRapid(cycle); break; } for (byte strip = 0; strip < LED_MULTIPLIER; strip++) { for (byte i = 0; i < LED_NUMBER; i++) { LED.set_crgb_at(i + (strip * LED_NUMBER), output[i]); } } LED.sync(); cycle++; if (cycle == MAX_CYCLE) { cycle = 0; } delay(SLEEP_TIME); } |
Downloads
- ATTIY Core Bootload Source
- Project Source Code with Library Zip
- LED Effects Library | WS2812 Library Zip
- Download FastLed Library Including Examples Zip
- Download ATTINY85 Datasheets PDF
- Download L7805 Datasheet PDF