Pastebin
API
tools
faq
paste
Login
Sign up
Please fix the following errors:
New Paste
Syntax Highlighting
#define F_CPU 4800000UL #define PHASE 0b00000001 #define FAST 0b00000011 #define BLINK_ON_POWER #define VOLTAGE_MON #define MODES 0,4,10,120,255 #define MODE_PWM 0,PHASE,FAST,FAST,PHASE #define ADC_LOW 130 // When do we start ramping #define ADC_CRIT 120 // When do we shut the light off #define ADC_DELAY 188 // Delay in ticks between low-bat rampdowns (188 ~= 3s) #define MOM_EXIT_DUR 128 // .16ms each #define FULL_MODE -1 /* * ========================================================================= */ #include <avr/pgmspace.h> #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <avr/wdt.h> #include <avr/eeprom.h> #include <avr/sleep.h> //#include <avr/power.h> #define SWITCH_PIN PB3 // what pin the switch is connected to, which is Star 4 #define PWM_PIN PB1 #define VOLTAGE_PIN PB2 #define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 #define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 #define ADC_PRSCL 0x06 // clk/64 #define PWM_LVL1 OCR0B // OCR0B is the output compare register for PB1 #define DB_PRES_DUR 0b00000001 // time before we consider the switch pressed (after first realizing it was pressed) #define DB_REL_DUR 0b00001111 // time before we consider the switch released // each bit of 1 from the right equals 16ms, so 0x0f = 64ms #define LONG_PRESS_DUR 128 // How many WDT ticks until we consider a press a long press // 32 is roughly .5 s #define LOCK_PRESS_DUR 300 const uint8_t modes[] = { MODES }; const uint8_t mode_pwm[] = { MODE_PWM }; volatile int8_t mode_idx = 0; volatile uint8_t press_duration = 0; volatile uint8_t low_to_high = 1; volatile uint8_t locked = 0; volatile uint8_t in_momentary = 0; int8_t real_mode_idx = 0; int is_pressed() { // Keep track of last switch values polled static uint8_t buffer = 0x00; // Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released buffer = (buffer << 1) | ((PINB & (1 << SWITCH_PIN)) == 0); return (buffer & DB_REL_DUR); } inline void next_mode() { if (++mode_idx >= sizeof(modes)) { // Wrap around mode_idx = 1; } } inline void prev_mode() { if (mode_idx == 0 ) { // Wrap around mode_idx = sizeof(modes) - 1; } else { --mode_idx; } } inline void PCINT_on() { // Enable pin change interrupts GIMSK |= (1 << PCIE); } inline void PCINT_off() { // Disable pin change interrupts GIMSK &= ~(1 << PCIE); } // Need an interrupt for when pin change is enabled to ONLY wake us from sleep. // All logic of what to do when we wake up will be handled in the main loop. EMPTY_INTERRUPT(PCINT0_vect); inline void WDT_on() { // Setup watchdog timer to only interrupt, not reset, every 16ms. cli(); // Disable interrupts wdt_reset(); // Reset the WDT WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence WDTCR = (1<<WDTIE); // Enable interrupt every 16ms sei(); // Enable interrupts } inline void WDT_off() { cli(); // Disable interrupts wdt_reset(); // Reset the WDT MCUSR &= ~(1<<WDRF); // Clear Watchdog reset flag WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence WDTCR = 0x00; // Disable WDT sei(); // Enable interrupts } inline void ADC_on() { ADMUX = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2 DIDR0 |= (1 << ADC_DIDR); // disable digital input on ADC pin to reduce power consumption ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale } inline void ADC_off() { ADCSRA &= ~(1<<7); //ADC off } void sleep_until_switch_press() { // This routine takes up a lot of program memory Sad // Turn the WDT off so it doesn't wake us from sleep // Will also ensure interrupts are on or we will never wake up WDT_off(); // Need to reset press duration since a button release wasn't recorded press_duration = 0; // Enable a pin change interrupt to wake us up // However, we have to make sure the switch is released otherwise we will wake when the user releases the switch while (is_pressed()) { _delay_ms(16); } PCINT_on(); // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command. //set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Now go to sleep sleep_mode(); // Hey, someone must have pressed the switch!! // Disable pin change interrupt because it's only used to wake us up PCINT_off(); // Turn the WDT back on to check for switch presses WDT_on(); // Go back to main program } // The watchdog timer is called every 16ms ISR(WDT_vect) { static uint8_t adc_ticks = ADC_DELAY; static uint8_t lowbatt_cnt = 0; if (is_pressed()) { if (press_duration < 255) { press_duration++; } if (press_duration == LONG_PRESS_DUR) { // Long press if (mode_idx == 0 ) { // TODO: if we were off, enter strobe mode mode_idx = 4; } else { // if we were on, turn off mode_idx = 0; } } // Just always reset turbo timer whenever the button is pressed //turbo_ticks = 0; // Same with the ramp down delay adc_ticks = ADC_DELAY; } else { if (press_duration == LOCK_PRESS_DUR) { locked ^= 1; if (locked) { mode_idx = 0; } else { real_mode_idx = mode_idx; } } if (locked) { // don't do anything if the lock-out is active press_duration = 0; return; } // Not pressed if (press_duration > 0 && press_duration < LONG_PRESS_DUR) { // Short press if (mode_idx == 4) { // short-press from strobe goes to second-highest mode mode_idx = sizeof(modes)-4; } else { // regular short press if (low_to_high) { next_mode(); } } // Not pressed if (locked) { // don't do anything if the lock-out is active press_duration = 0; return; } // Only do voltage monitoring when the switch isn't pressed #ifdef VOLTAGE_MON if (adc_ticks > 0 ) { --adc_ticks; } if (adc_ticks == 0 ) { // See if conversion is done if (ADCSRA & (1 << ADIF)) { // See if voltage is lower than what we were looking for if (ADCH < ((mode_idx == 1) ? ADC_CRIT : ADC_LOW)) { ++lowbatt_cnt; } else { lowbatt_cnt = 0; } } // See if it's been low for a while if (lowbatt_cnt >= 4) { prev_mode(); lowbatt_cnt = 0; // If we reach 0 here, main loop will go into sleep mode // Restart the counter to when we step down again adc_ticks = ADC_DELAY; } // Make sure conversion is running for next time through ADCSRA |= (1 << ADSC); } #endif } press_duration = 0; } } int main(void) { // Set all ports to input, and turn pull-up resistors on for the inputs we are using DDRB = 0x00; PORTB = (1 << SWITCH_PIN); // Set the switch as an interrupt for when we turn pin change interrupts on PCMSK = (1 << SWITCH_PIN); // Set PWM pin to output DDRB = (1 << PWM_PIN); // Set timer to do PWM for correct output pin and set prescaler timing TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23 TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) // Turn features on or off as needed #ifdef VOLTAGE_MON ADC_on(); #else ADC_off(); #endif ACSR |= (1<<7); //AC off #ifdef BLINK_ON_POWER // blink once to let the user know we have power TCCR0A = PHASE | 0b00100000; // Only use the normal output PWM_LVL1 = 60; _delay_ms(3); PWM_LVL1 = 0; _delay_ms(1); #endif // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command. set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_until_switch_press(); uint8_t last_mode_idx = 0; int8_t real_mode_idx = 0; while(1) { // We will never leave this loop. The WDT will interrupt to check for switch presses and // will change the mode if needed. If this loop detects that the mode has changed, run the // logic for that mode while continuing to check for a mode change. if (mode_idx != last_mode_idx) { real_mode_idx = mode_idx; // The WDT changed the mode. if (mode_idx == FULL_MODE) { // strobe should use second-highest mode real_mode_idx = sizeof(modes) - 4; } else if (mode_idx > 0 ) { // No need to change the mode if we are just turning the light off // Check if the PWM mode is different if (mode_pwm[last_mode_idx] != mode_pwm[mode_idx]) { TCCR0A = mode_pwm[mode_idx] | 0b10100000; // Use both outputs } } PWM_LVL1 = modes[real_mode_idx]; last_mode_idx = mode_idx; // Handle strobe mode if (mode_idx == FULL_MODE) { PWM_LVL1=255; TCCR0A=PHASE | 0b00100000; } if (real_mode_idx == 0 ) { _delay_ms(1); // Need this here, maybe instructions for PWM output not getting executed before shutdown? // Go to sleep sleep_until_switch_press(); } } } return 0; // Standard Return Code }
Optional Paste Settings
Syntax Highlighting:
None
Bash
C
C#
C++
CSS
HTML
JSON
Java
JavaScript
Lua
Markdown (PRO members only)
Objective C
PHP
Perl
Python
Ruby
Swift
4CS
6502 ACME Cross Assembler
6502 Kick Assembler
6502 TASM/64TASS
ABAP
AIMMS
ALGOL 68
APT Sources
ARM
ASM (NASM)
ASP
ActionScript
ActionScript 3
Ada
Apache Log
AppleScript
Arduino
Asymptote
AutoIt
Autohotkey
Avisynth
Awk
BASCOM AVR
BNF
BOO
Bash
Basic4GL
Batch
BibTeX
Blitz Basic
Blitz3D
BlitzMax
BrainFuck
C
C (WinAPI)
C Intermediate Language
C for Macs
C#
C++
C++ (WinAPI)
C++ (with Qt extensions)
C: Loadrunner
CAD DCL
CAD Lisp
CFDG
CMake
COBOL
CSS
Ceylon
ChaiScript
Chapel
Clojure
Clone C
Clone C++
CoffeeScript
ColdFusion
Cuesheet
D
DCL
DCPU-16
DCS
DIV
DOT
Dart
Delphi
Delphi Prism (Oxygene)
Diff
E
ECMAScript
EPC
Easytrieve
Eiffel
Email
Erlang
Euphoria
F#
FO Language
Falcon
Filemaker
Formula One
Fortran
FreeBasic
FreeSWITCH
GAMBAS
GDB
GDScript
Game Maker
Genero
Genie
GetText
Go
Godot GLSL
Groovy
GwBasic
HQ9 Plus
HTML
HTML 5
Haskell
Haxe
HicEst
IDL
INI file
INTERCAL
IO
ISPF Panel Definition
Icon
Inno Script
J
JCL
JSON
Java
Java 5
JavaScript
Julia
KSP (Kontakt Script)
KiXtart
Kotlin
LDIF
LLVM
LOL Code
LScript
Latex
Liberty BASIC
Linden Scripting
Lisp
Loco Basic
Logtalk
Lotus Formulas
Lotus Script
Lua
M68000 Assembler
MIX Assembler
MK-61/52
MPASM
MXML
MagikSF
Make
MapBasic
Markdown (PRO members only)
MatLab
Mercury
MetaPost
Modula 2
Modula 3
Motorola 68000 HiSoft Dev
MySQL
Nagios
NetRexx
Nginx
Nim
NullSoft Installer
OCaml
OCaml Brief
Oberon 2
Objeck Programming Langua
Objective C
Octave
Open Object Rexx
OpenBSD PACKET FILTER
OpenGL Shading
Openoffice BASIC
Oracle 11
Oracle 8
Oz
PARI/GP
PCRE
PHP
PHP Brief
PL/I
PL/SQL
POV-Ray
ParaSail
Pascal
Pawn
Per
Perl
Perl 6
Phix
Pic 16
Pike
Pixel Bender
PostScript
PostgreSQL
PowerBuilder
PowerShell
ProFTPd
Progress
Prolog
Properties
ProvideX
Puppet
PureBasic
PyCon
Python
Python for S60
QBasic
QML
R
RBScript
REBOL
REG
RPM Spec
Racket
Rails
Rexx
Robots
Roff Manpage
Ruby
Ruby Gnuplot
Rust
SAS
SCL
SPARK
SPARQL
SQF
SQL
SSH Config
Scala
Scheme
Scilab
SdlBasic
Smalltalk
Smarty
StandardML
StoneScript
SuperCollider
Swift
SystemVerilog
T-SQL
TCL
TeXgraph
Tera Term
TypeScript
TypoScript
UPC
Unicon
UnrealScript
Urbi
VB.NET
VBScript
VHDL
VIM
Vala
Vedit
VeriLog
Visual Pro Log
VisualBasic
VisualFoxPro
WHOIS
WhiteSpace
Winbatch
XBasic
XML
XPP
Xojo
Xorg Config
YAML
YARA
Z80 Assembler
ZXBasic
autoconf
jQuery
mIRC
newLISP
q/kdb+
thinBasic
Paste Expiration:
Never
Burn after read
10 Minutes
1 Hour
1 Day
1 Week
2 Weeks
1 Month
6 Months
1 Year
Paste Exposure:
Public
Unlisted
Private
Folder:
(members only)
Password
NEW
Enabled
Disabled
Burn after read
NEW
Paste Name / Title:
Create New Paste
Hello
Guest
Sign Up
or
Login
Sign in with Facebook
Sign in with Twitter
Sign in with Google
You are currently not logged in, this means you can not edit or delete anything you paste.
Sign Up
or
Login
Public Pastes
jaeger-todo
Bash | 1 min ago
main.js
JavaScript | 16 min ago
energyCubeMonitor_...
Lua | 42 min ago
My Log File
HTML 5 | 51 min ago
My Log File
HTML 5 | 51 min ago
shorts.html
HTML | 1 hour ago
Sign.js
JavaScript | 1 hour ago
OwlHub
Lua | 2 hours ago
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the
Cookies Policy
.
OK, I Understand
Not a member of Pastebin yet?
Sign Up
, it unlocks many cool features!