FmC_8055

Nanjg105c_1Mode_Test5

Dec 6th, 2014
225
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. * NANJG 105C Diagram
  3. * ---
  4. * -| |- VCC
  5. * Star 4 -| |- Voltage ADC
  6. * Star 3 -| |- PWM
  7. * GND -| |- Star 2
  8. * ---
  9.  
  10. * CPU speed is 4.8Mhz without the 8x divider when low fuse is 0x75
  11. *
  12. * define F_CPU 4800000 CPU: 4.8MHz PWM: 9.4kHz ####### use low fuse: 0x75 #######
  13. * /8 PWM: 1.176kHz ####### use low fuse: 0x65 #######
  14. * define F_CPU 9600000 CPU: 9.6MHz PWM: 19kHz ####### use low fuse: 0x7a #######
  15. * /8 PWM: 2.4kHz ####### use low fuse: 0x6a #######
  16. *
  17. * Above PWM speeds are for phase-correct PWM. This program uses Fast-PWM, which when the CPU is 4.8MHz will be 18.75 kHz
  18. *
  19. * FUSES
  20. * I use these fuse settings
  21. * Low: 0x75
  22. * High: 0xff
  23. *
  24. * STARS
  25. * Star 2 = Moon if connected
  26. * Star 3 = H-L if connected, L-H if not
  27. * Star 4 = Memory if not connected
  28. *
  29. * VOLTAGE
  30. * Resistor values for voltage divider (reference BLF-VLD README for more info)
  31. * Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
  32. *
  33. * VCC
  34. * |
  35. * Vd (~.25 v drop from protection diode)
  36. * |
  37. * 1912 (R1 19,100 ohms)
  38. * |
  39. * |---- PB2 from MCU
  40. * |
  41. * 4701 (R2 4,700 ohms)
  42. * |
  43. * GND
  44. *
  45. * ADC = ((V_bat - V_diode) * R2 * 255) / ((R1 + R2 ) * V_ref)
  46. * 125 = ((3.0 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
  47. * 121 = ((2.9 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
  48. *
  49. * Well 125 and 121 were too close, so it shut off right after lowering to low mode, so I went with
  50. * 130 and 120
  51. *
  52. * To find out what value to use, plug in the target voltage (V) to this equation
  53. * value = (V * 4700 * 255) / (23800 * 1.1)
  54. *
  55. */
  56. #define F_CPU 4800000UL
  57.  
  58. /*
  59. * =========================================================================
  60. * Settings to modify per driver
  61. */
  62.  
  63. #define VOLTAGE_MON // Comment out to disable
  64. #define STEPDOWN_MINIMUM 60 // Hidden mode level for low voltage step down
  65. // #define MODE_MOON 6 // Can comment out to remove mode, but should be set through soldering stars
  66. // #define MODE_LOW 12 // Can comment out to remove mode
  67. // #define MODE_MED 39 // Can comment out to remove mode
  68. // #define MODE_HIGH_W_TURBO 110 // MODE_HIGH value when turbo is enabled
  69. #define MODE_HIGH 255 // Can comment out to remove mode
  70. // #define MODE_TURBO 255 // Can comment out to remove mode
  71. // #define TURBO_TIMEOUT 240 // How many WTD ticks before before dropping down (.5 sec each)
  72.  
  73. #define WDT_TIMEOUT 2 // Number of WTD ticks before mode is saved (.5 sec each)
  74.  
  75. #define ADC_LOW 130 // When do we start ramping
  76. #define ADC_CRIT 120 // When do we shut the light off
  77.  
  78. /*
  79. * =========================================================================
  80. */
  81.  
  82. #ifdef MODE_TURBO
  83. #undef MODE_HIGH
  84. #define MODE_HIGH MODE_HIGH_W_TURBO
  85. #endif
  86.  
  87. //#include <avr/pgmspace.h>
  88. #include <avr/io.h>
  89. #include <util/delay.h>
  90. #include <avr/interrupt.h>
  91. #include <avr/wdt.h>
  92. #include <avr/eeprom.h>
  93. #include <avr/sleep.h>
  94. //#include <avr/power.h>
  95.  
  96. #define STAR2_PIN PB0
  97. #define STAR3_PIN PB4
  98. #define STAR4_PIN PB3
  99. #define PWM_PIN PB1
  100. #define VOLTAGE_PIN PB2
  101. #define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2
  102. #define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2
  103. #define ADC_PRSCL 0x06 // clk/64
  104.  
  105. #define PWM_LVL OCR0B // OCR0B is the output compare register for PB1
  106.  
  107. /*
  108. * global variables
  109. */
  110.  
  111. // Mode storage
  112. uint8_t eepos = 0;
  113. uint8_t eep[32];
  114. uint8_t memory = 0;
  115.  
  116. // Modes (gets set when the light starts up based on stars)
  117. static uint8_t modes[10]; // Don't need 10, but keeping it high enough to handle all
  118. volatile uint8_t mode_idx = 0;
  119. int mode_dir = 0; // 1 or -1. Determined when checking stars. Do we increase or decrease the idx when moving up to a higher mode.
  120. uint8_t mode_cnt = 0;
  121.  
  122. uint8_t lowbatt_cnt = 0;
  123.  
  124. void store_mode_idx(uint8_t lvl) { //central method for writing (with wear leveling)
  125. uint8_t oldpos=eepos;
  126. eepos=(eepos+1)&31; //wear leveling, use next cell
  127. // Write the current mode
  128. EEARL=eepos; EEDR=lvl; EECR=32+4; EECR=32+4+2; //WRITE //32:write only (no erase) 4:enable 2:go
  129. while(EECR & 2); //wait for completion
  130. // Erase the last mode
  131. EEARL=oldpos; EECR=16+4; EECR=16+4+2; //ERASE //16:erase only (no write) 4:enable 2:go
  132. }
  133. inline void read_mode_idx() {
  134. eeprom_read_block(&eep, 0, 32);
  135. while((eep[eepos] == 0xff) && (eepos < 32)) eepos++;
  136. if (eepos < 32) mode_idx = eep[eepos];//&0x10; What the?
  137. else eepos=0;
  138. }
  139.  
  140. inline void next_mode() {
  141. if (mode_idx == 0 && mode_dir == -1) {
  142. // Wrap around
  143. mode_idx = mode_cnt - 1;
  144. } else {
  145. mode_idx += mode_dir;
  146. if (mode_idx > (mode_cnt - 1)) {
  147. // Wrap around
  148. mode_idx = 0;
  149. }
  150. }
  151. }
  152.  
  153. inline void WDT_on() {
  154. // Setup watchdog timer to only interrupt, not reset, every 500ms.
  155. cli(); // Disable interrupts
  156. wdt_reset(); // Reset the WDT
  157. WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
  158. WDTCR = (1<<WDTIE) | (1<<WDP2) | (1<<WDP0); // Enable interrupt every 500ms
  159. sei(); // Enable interrupts
  160. }
  161.  
  162. inline void WDT_off()
  163. {
  164. cli(); // Disable interrupts
  165. wdt_reset(); // Reset the WDT
  166. MCUSR &= ~(1<<WDRF); // Clear Watchdog reset flag
  167. WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
  168. WDTCR = 0x00; // Disable WDT
  169. sei(); // Enable interrupts
  170. }
  171.  
  172. inline void ADC_on() {
  173. ADMUX = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
  174. DIDR0 |= (1 << ADC_DIDR); // disable digital input on ADC pin to reduce power consumption
  175. ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale
  176. }
  177.  
  178. inline void ADC_off() {
  179. ADCSRA &= ~(1<<7); //ADC off
  180. }
  181.  
  182. #ifdef VOLTAGE_MON
  183. uint8_t low_voltage(uint8_t voltage_val) {
  184. // Start conversion
  185. ADCSRA |= (1 << ADSC);
  186. // Wait for completion
  187. while (ADCSRA & (1 << ADSC));
  188. // See if voltage is lower than what we were looking for
  189. if (ADCH < voltage_val) {
  190. // See if it's been low for a while
  191. if (++lowbatt_cnt > 8) {
  192. lowbatt_cnt = 0;
  193. return 1;
  194. }
  195. } else {
  196. lowbatt_cnt = 0;
  197. }
  198. return 0;
  199. }
  200. #endif
  201.  
  202. ISR(WDT_vect) {
  203. static uint8_t ticks = 0;
  204. if (ticks < 255) ticks++;
  205.  
  206. if (ticks == WDT_TIMEOUT) {
  207. if (memory) {
  208. store_mode_idx(mode_idx);
  209. } else {
  210. // Reset the mode to the start for next time
  211. store_mode_idx((mode_dir == 1) ? 0 : (mode_cnt - 1));
  212. }
  213. #ifdef MODE_TURBO
  214. //} else if (ticks == TURBO_TIMEOUT && modes[mode_idx] == MODE_TURBO) { // Doesn't make any sense why this doesn't work
  215. } else if (ticks == TURBO_TIMEOUT && mode_idx == (mode_cnt - 1)) {
  216. // Turbo mode is always at end
  217. PWM_LVL = modes[--mode_idx];
  218. #endif
  219. }
  220.  
  221. }
  222.  
  223. int main(void)
  224. {
  225. // All ports default to input, but turn pull-up resistors on for the stars (not the ADC input! Made that mistake already)
  226. PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN) | (1 << STAR4_PIN);
  227.  
  228. // Set PWM pin to output
  229. DDRB = (1 << PWM_PIN);
  230.  
  231. // Set timer to do PWM for correct output pin and set prescaler timing
  232. TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
  233. TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
  234.  
  235. // Turn features on or off as needed
  236. #ifdef VOLTAGE_MON
  237. ADC_on();
  238. #else
  239. ADC_off();
  240. #endif
  241. ACSR |= (1<<7); //AC off
  242.  
  243. // Load up the modes based on stars
  244. // Always load up the modes array in order of lowest to highest mode
  245. // 0 being low for soldered, 1 for pulled-up for not soldered
  246. // Moon
  247. #ifdef MODE_MOON
  248. if ((PINB & (1 << STAR2_PIN)) == 0) {
  249. modes[mode_cnt++] = MODE_MOON;
  250. }
  251. #endif
  252. #ifdef MODE_LOW
  253. modes[mode_cnt++] = MODE_LOW;
  254. #endif
  255. #ifdef MODE_MED
  256. modes[mode_cnt++] = MODE_MED;
  257. #endif
  258. #ifdef MODE_HIGH
  259. modes[mode_cnt++] = MODE_HIGH;
  260. #endif
  261. #ifdef MODE_TURBO
  262. modes[mode_cnt++] = MODE_TURBO;
  263. #endif
  264. if ((PINB & (1 << STAR3_PIN)) == 0) {
  265. // High to Low
  266. mode_dir = -1;
  267. } else {
  268. mode_dir = 1;
  269. }
  270. // Not soldered (1) should enable memory
  271. memory = ((PINB & (1 << STAR4_PIN)) > 0) ? 1 : 0;
  272.  
  273. // Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
  274. // Will allow us to go idle between WDT interrupts
  275. set_sleep_mode(SLEEP_MODE_IDLE);
  276.  
  277. // Determine what mode we should fire up
  278. // Read the last mode that was saved
  279. read_mode_idx();
  280. if (mode_idx&0x10) {
  281. // Indicates we did a short press last time, go to the next mode
  282. // Remove short press indicator first
  283. mode_idx &= 0x0f;
  284. next_mode(); // Will handle wrap arounds
  285. } else {
  286. // Didn't have a short press, keep the same mode
  287. }
  288. // Store mode with short press indicator
  289. store_mode_idx(mode_idx|0x10);
  290.  
  291. WDT_on();
  292.  
  293. // Now just fire up the mode
  294. PWM_LVL = modes[mode_idx];
  295.  
  296. uint8_t i = 0;
  297. uint8_t hold_pwm;
  298. while(1) {
  299. #ifdef VOLTAGE_MON
  300. if (low_voltage(ADC_LOW)) {
  301. // We need to go to a lower level
  302. if (mode_idx == 0 && PWM_LVL <= STEPDOWN_MINIMUM) {
  303. // Can't go any lower than the lowest mode
  304. // Wait until we hit the critical level before flashing 10 times and turning off
  305. while (!low_voltage(ADC_CRIT));
  306. i = 0;
  307. while (i++<10) {
  308. PWM_LVL = 0;
  309. _delay_ms(250);
  310. PWM_LVL = modes[0];
  311. _delay_ms(500);
  312. }
  313. // Turn off the light
  314. PWM_LVL = 0;
  315. // Disable WDT so it doesn't wake us up
  316. WDT_off();
  317. // Power down as many components as possible
  318. set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  319. sleep_mode();
  320. } else {
  321. // Flash 3 times before lowering
  322. hold_pwm = PWM_LVL;
  323. i = 0;
  324. while (i++<3) {
  325. PWM_LVL = 0;
  326. _delay_ms(250);
  327. PWM_LVL = hold_pwm;
  328. _delay_ms(500);
  329. }
  330. // Lower the mode by half, but don't go below lowest level
  331. if ((PWM_LVL >> 1) < STEPDOWN_MINIMUM) {
  332. PWM_LVL = STEPDOWN_MINIMUM;
  333. mode_idx = 0;
  334. } else {
  335. PWM_LVL = (PWM_LVL >> 1);
  336. }
  337.  
  338. }
  339. // Wait 10 seconds before lowering the level again
  340. _delay_ms(10000);
  341. }
  342. #endif
  343. sleep_mode();
  344. }
  345.  
  346. return 0; // Standard Return Code
  347. }
RAW Paste Data