Advertisement
dragonflydiy

C source code for 9 LED blinkie

Aug 7th, 2017
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.29 KB | None | 0 0
  1. // this is the code for the 8 LED, Tiny85 blinkie developed for Duckon's Free For All build-a-blinkie
  2. // PWM code and excellent comments taken straight from http://matt16060936.blogspot.com/2012/04/attiny-pwm.html
  3. //
  4. // John Ridley
  5. // 2014-02-05
  6. // http://johnridley.blogspot.com
  7.  
  8. // effective brightness levels are 0, powers of 2 up through 128. 255 isn't really effectively brigher than 128, save battery power.
  9.  
  10. #define F_CPU 2000000
  11.  
  12. #include <avr/io.h>
  13. #include <avr/sleep.h>
  14. #include <avr/interrupt.h>
  15. #include <avr/pgmspace.h>
  16. #include <util/delay.h>
  17.  
  18. // button tracking
  19. int button_down_count = 0;
  20.  
  21. // Modes: 0 = rotation, higher than that = run one pattern
  22. volatile int button_mode = 1; // this is changed by the button within the ISR
  23. volatile int current_mode = 1; // this follows button_mode when the main code reacts
  24. int max_mode = 2;
  25.  
  26.  
  27.  
  28. // this is used for timing patterns. It gets incremented every time the display driver
  29. // completes a cycle
  30. // about 132 per second
  31. volatile int loops = 0;
  32.  
  33.  
  34. // display buffer
  35. volatile unsigned char displaybuffer[9];
  36.  
  37. // some forward declarations
  38. void power_off(void);
  39.  
  40. ///////////////////////////////////////////////////////////////////////////////////////////////////
  41. // pattern subroutines here
  42. // call ExitCheck often, leave when it returns 1
  43.  
  44. // set loops to 0 before beginning a function that will call this
  45. int ExitCheck()
  46. {
  47. if (button_mode != current_mode)
  48. return 1;
  49. if (loops > 8000)
  50. return 1;
  51. return 0;
  52. }
  53.  
  54. void ClearDisplay()
  55. {
  56. for (int x=0; x<9; x++)
  57. displaybuffer[x] = 0;
  58. }
  59.  
  60. // call when mode switches, it will indicate the new mode for 1 second
  61. void ModeSwitchPattern()
  62. {
  63. for (int x=0; x<9; x++)
  64. {
  65. if ((current_mode & (1<<x)) > 0)
  66. displaybuffer[x] = 255;
  67. else
  68. displaybuffer[x] = 0;
  69. }
  70. loops = 0;
  71. while (loops < 132)
  72. {
  73. if (ExitCheck())
  74. return;
  75. }
  76. }
  77.  
  78.  
  79. /**********************************************************************/
  80. void KnightRider()
  81. {
  82. int foo = 0;
  83. int dotpos = 0;
  84. int direction = 1;
  85. int x;
  86.  
  87. loops = 0;
  88. ClearDisplay();
  89.  
  90. for (;;)
  91. {
  92. _delay_ms(5);
  93. for (x=0; x<9; x++)
  94. if (displaybuffer[x]>0 && displaybuffer[x] < 250)
  95. displaybuffer[x] -=10;
  96. if (foo++ > 20)
  97. {
  98. displaybuffer[dotpos] = 200;
  99. if (direction == 1)
  100. if (dotpos == 8)
  101. {
  102. dotpos = 7;
  103. direction = -1;
  104. }
  105. else
  106. dotpos++;
  107. else
  108. if (dotpos == 0)
  109. {
  110. dotpos = 1;
  111. direction = 1;
  112. }
  113. else
  114. dotpos--;
  115. foo = 0;
  116. displaybuffer[dotpos] = 250;
  117. }
  118. if (ExitCheck())
  119. return;
  120. }
  121. }
  122.  
  123.  
  124. /**********************************************************************/
  125. // simple chase
  126. void chase()
  127. {
  128. ClearDisplay();
  129. while(1)
  130. {
  131. for (int x=0; x<9; x++)
  132. {
  133. if (x == 0)
  134. displaybuffer[8] = 0;
  135. else
  136. displaybuffer[x-1] = 0;
  137. displaybuffer[x] = 255;
  138. _delay_ms(50);
  139.  
  140. if (ExitCheck())
  141. return;
  142. }
  143. }
  144. }
  145.  
  146. // center weighted throb
  147. void centerThrob()
  148. {
  149. loops = 0;
  150. int ctrVal = 0; // goes to 1024, overflow goes to next LED over, next LED over also gets 1/2 of brigher LED
  151. int carryVal, curval, offset;
  152. int direction = 1;
  153. while (1)
  154. {
  155. _delay_ms(100);
  156. if (direction == 1)
  157. {
  158. if (ctrVal > 1023)
  159. {
  160. direction = -1;
  161. }
  162. else
  163. ctrVal += 64;
  164. } else {
  165. if (ctrVal < 1)
  166. {
  167. direction = 1;
  168. }
  169. else
  170. ctrVal -= 64;
  171. }
  172. // now do the display
  173. carryVal = ctrVal;
  174. offset = 0;
  175. while (offset < 5)
  176. {
  177. if (offset > 0)
  178. curval = displaybuffer[4+offset-1] / 4;
  179. if (carryVal > 255)
  180. curval += 255;
  181. else
  182. curval += carryVal;
  183.  
  184. if (curval > 255)
  185. curval == 255;
  186.  
  187. carryVal -= curval;
  188.  
  189. displaybuffer[4+offset] = curval;
  190. displaybuffer[4-offset] = curval;
  191.  
  192. offset++;
  193. }
  194.  
  195. // if (ExitCheck())
  196. // return;
  197. }
  198. }
  199.  
  200. void LEDTEST()
  201. {
  202. #define LEDTESTDELAY 100
  203. int x,y;
  204. #if 0
  205. for (x=0; x<9; x++)
  206. {
  207. displaybuffer[x] = 128;
  208. _delay_ms(LEDTESTDELAY);
  209. displaybuffer[x] = 0;
  210. }
  211. #endif
  212. for (y=0; y<8; y++)
  213. for (x=0; x<9; x++)
  214. {
  215. switch(y)
  216. {
  217. case 0: displaybuffer[x] = (unsigned char)1; break;
  218. case 1: displaybuffer[x] = (unsigned char)2; break;
  219. case 2: displaybuffer[x] = (unsigned char)4; break;
  220. case 3: displaybuffer[x] = (unsigned char)8; break;
  221. case 4: displaybuffer[x] = (unsigned char)16; break;
  222. case 5: displaybuffer[x] = (unsigned char)32; break;
  223. case 6: displaybuffer[x] = (unsigned char)64; break;
  224. case 7: displaybuffer[x] = (unsigned char)128; break;
  225. }
  226.  
  227. // displaybuffer[x] = 1<<y;
  228. _delay_ms(LEDTESTDELAY);
  229. // displaybuffer[x] = 0;
  230. }
  231. for (y=0;y<3; y++)
  232. {
  233. for (x=0; x<9; x++)
  234. displaybuffer[x] = 128;
  235. _delay_ms(LEDTESTDELAY);
  236. for (x=0; x<9; x++)
  237. displaybuffer[x] = 0;
  238. _delay_ms(LEDTESTDELAY);
  239. }
  240. }
  241.  
  242. // VU Meter utility function: set level
  243. void vulevel(short level)
  244. {
  245. for (short x=0; x<9; x++)
  246. {
  247. if (x <= level)
  248. displaybuffer[x] = 255;
  249. else
  250. displaybuffer[x] = 0;
  251. }
  252. }
  253. void vumeter()
  254. {
  255. loops = 0;
  256.  
  257. short currentlevel = 0;
  258. while (1)
  259. {
  260. }
  261. }
  262.  
  263. /**********************************************************************/
  264.  
  265.  
  266. void SetupDisplayInterrupt()
  267. {
  268. // TCCR0A = 0b00000000; // Normal Mode
  269. // TCCR0B = 0b00000010; // Div 32 Prescaler
  270.  
  271.  
  272. /*
  273. Control Register A for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
  274. TCCR0A is 8 bits: [COM0A1:COM0A0:COM0B1:COM0B0:unused:unused:WGM01:WGM00]
  275. 2<<COM0A0: sets bits COM0A0 and COM0A1, which (in Fast PWM mode) clears OC0A on compare-match, and sets OC0A at BOTTOM
  276. 2<<COM0B0: sets bits COM0B0 and COM0B1, which (in Fast PWM mode) clears OC0B on compare-match, and sets OC0B at BOTTOM
  277. 3<<WGM00: sets bits WGM00 and WGM01, which (when combined with WGM02 from TCCR0B below) enables Fast PWM mode
  278. */
  279. TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
  280.  
  281. /*
  282. Control Register B for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
  283. TCCR0B is 8 bits: [FOC0A:FOC0B:unused:unused:WGM02:CS02:CS01:CS00]
  284. 0<<WGM02: bit WGM02 remains clear, which (when combined with WGM00 and WGM01 from TCCR0A above) enables Fast PWM mode
  285. 1<<CS00: sets bits CS01 (leaving CS01 and CS02 clear), which tells Timer/Counter-0 to not use a prescalar
  286. */
  287. TCCR0B = 0<<WGM02 | 1<<CS00;
  288.  
  289. /*
  290. Control Register for Timer/Counter-1 (Timer/Counter-1 is configured with just one register: this one)
  291. TCCR1 is 8 bits: [CTC1:PWM1A:COM1A1:COM1A0:CS13:CS12:CS11:CS10]
  292. 0<<PWM1A: bit PWM1A remains clear, which prevents Timer/Counter-1 from using pin OC1A (which is shared with OC0B)
  293. 0<<COM1A0: bits COM1A0 and COM1A1 remain clear, which also prevents Timer/Counter-1 from using pin OC1A (see PWM1A above)
  294. 1<<CS10: sets bit CS11 which tells Timer/Counter-1 to not use a prescalar
  295. */
  296. TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
  297.  
  298. /*
  299. General Control Register for Timer/Counter-1 (this is for Timer/Counter-1 and is a poorly named register)
  300. GTCCR is 8 bits: [TSM:PWM1B:COM1B1:COM1B0:FOC1B:FOC1A:PSR1:PSR0]
  301. 1<<PWM1B: sets bit PWM1B which enables the use of OC1B (since we disabled using OC1A in TCCR1)
  302. 2<<COM1B0: sets bit COM1B1 and leaves COM1B0 clear, which (when in PWM mode) clears OC1B on compare-match, and sets at BOTTOM
  303. */
  304. GTCCR = 1<<PWM1B | 2<<COM1B0;
  305.  
  306. // enable interrupts
  307. TIMSK = (1<<TOIE0); // Timer Mask: Enable interrupt on Timer 0 overflow
  308.  
  309. /*
  310. Port B Data Direction Register (controls the mode of all pins within port B)
  311. DDRB is 8 bits: [unused:unused:DDB5:DDB4:DDB3:DDB2:DDB1:DDB0]
  312. 1<<DDB4: sets bit DDB4 (data-direction, port B, pin 4), which puts PB4 (port B, pin 4) in output mode
  313. 1<<DDB1: sets bit DDB1 (data-direction, port B, pin 1), which puts PB1 (port B, pin 1) in output mode
  314. 1<<DDB0: sets bit DDB0 (data-direction, port B, pin 0), which puts PB0 (port B, pin 0) in output mode
  315.  
  316. JRR also want PB2 set as output for bank select
  317. */
  318. DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0 | 1<<DDB2;
  319. }
  320.  
  321. /*
  322. program entry-point
  323. */
  324. int main()
  325. {
  326. SetupDisplayInterrupt();
  327. sei(); // Global enable Interrupts
  328.  
  329. displaybuffer[0] = 0;
  330. displaybuffer[1] = 0;
  331. displaybuffer[2] = 0;
  332. displaybuffer[3] = 0;
  333. displaybuffer[4] = 0;
  334. displaybuffer[5] = 0;
  335. displaybuffer[6] = 0;
  336. displaybuffer[7] = 0;
  337. displaybuffer[8] = 0;
  338.  
  339.  
  340. displaybuffer[0] = 1;
  341. while (1)
  342. {
  343. displaybuffer[3] = 1;
  344. _delay_ms(1000);
  345. displaybuffer[3] = 0;
  346. _delay_ms(1000);
  347. }
  348.  
  349. while (1)
  350. LEDTEST();
  351.  
  352. centerThrob();
  353.  
  354. while (1)
  355. {
  356. if (button_mode != current_mode)
  357. {
  358. current_mode = button_mode;
  359. ModeSwitchPattern(); // this displays the current mode in binary for 1 second
  360. }
  361. else
  362. {
  363. switch (current_mode)
  364. {
  365. case 1:
  366. KnightRider();
  367. break;
  368. case 2:
  369. chase();
  370. break;
  371. }
  372. }
  373. }
  374. return 0;
  375. }
  376.  
  377.  
  378. // **********************************************************
  379. // *** DISPLAY HANDLER
  380. // **********************************************************
  381. // This gets called on timer interrupt
  382. // this also detects button presses
  383. ISR(TIM0_OVF_vect)
  384. {
  385. static short loopcount=0;
  386.  
  387. unsigned char DDRval = 0;
  388.  
  389. if (loopcount == 0)
  390. {
  391. // **** Display bank 0 ****
  392.  
  393. // we are coming off of bank 2 where
  394. // all banks off when switching to avoid flicker
  395. DDRB = 0; // tristate everything
  396.  
  397. DDRval = 1<<DDB2; // value to tristate PB3, turn PB2 on as output
  398.  
  399. // set bank 0 values
  400. if (displaybuffer[0] > 0)
  401. {
  402. OCR0A = displaybuffer[0];
  403. DDRval |= 1<<DDB0;
  404. }
  405. if (displaybuffer[1] > 0)
  406. {
  407. OCR0B = displaybuffer[1];
  408. DDRval |= 1<< DDB1;
  409. }
  410. if (displaybuffer[2] > 0)
  411. {
  412. OCR1B = displaybuffer[2];
  413. DDRval |= 1<<DDB4;
  414. }
  415.  
  416. TCNT0 = 0; // Restart PWM timer
  417. TCNT1 = 0; // Restart PWM timer
  418. // switch back to bank 0
  419. // tristate PB3, turn PB2 on and set it low
  420. PORTB = 0; // bank 0
  421. DDRB = DDRval;
  422. }
  423.  
  424. if (loopcount == 10)
  425. {
  426. // **** Display bank 1 ****
  427.  
  428. // all banks off when switching to avoid flicker
  429. // DDRB = 0;
  430. DDRval = 1<<DDB2; // value to tristate PB3, turn PB2 on as output
  431.  
  432. // set bank 1 values
  433. if (displaybuffer[3] > 0)
  434. {
  435. OCR0A = (unsigned char)(256-displaybuffer[3]);
  436. // DDRval |= 1<<DDB0;
  437. }
  438. if (displaybuffer[4] > 0)
  439. {
  440. OCR0B = 256-displaybuffer[4];
  441. DDRval |= 1<< DDB1;
  442. }
  443. if (displaybuffer[5] > 0)
  444. {
  445. OCR1B = 256-displaybuffer[5];
  446. DDRval |= 1<<DDB4;
  447. }
  448.  
  449.  
  450. TCNT0 = 0; // Restart PWM timer
  451. TCNT1 = 0; // Restart PWM timer
  452. // switch back to bank 0/1
  453. // tristate PB3, turn PB2 on and set it low
  454. PORTB = 1<<2; // bank 1
  455. DDRB = DDRval;
  456. }
  457.  
  458. if (loopcount == 20)
  459. {
  460. // **** Display bank 2 ****
  461.  
  462. // all banks off when switching to avoid flicker
  463. // DDRB = 0;
  464. DDRval = 1<<DDB3; // value to tristate PB2 and turn PB3 on as output
  465.  
  466. // set bank 2 values
  467. if (displaybuffer[6] > 0)
  468. {
  469. OCR0A = displaybuffer[6];
  470. DDRval |= 1<<DDB0;
  471. }
  472. if (displaybuffer[7] > 0)
  473. {
  474. OCR0B = displaybuffer[7];
  475. DDRval |= 1<< DDB1;
  476. }
  477. if (displaybuffer[8] > 0)
  478. {
  479. OCR1B = displaybuffer[8];
  480. DDRval |= 1<<DDB4;
  481. }
  482.  
  483.  
  484. TCNT0 = 0; // Restart PWM timer
  485. TCNT1 = 0; // Restart PWM timer
  486. // switch to bank 2
  487. // tristate PB2, turn PB3 on and set it low
  488. PORTB = 0;
  489. DDRB = DDRval;
  490. }
  491.  
  492. loopcount++;
  493.  
  494. if (loopcount == 30)
  495. {
  496. // this is a good place to read the switch
  497. DDRB = 0x00; // all pins to input
  498. PORTB = 0x01; // PB0 pull-up on
  499. _delay_ms(1);
  500. if ((PINB & 0x01) == 0) // button on = 0 on PB0
  501. {
  502. // if button has been down for a long time, power off
  503. if (button_down_count++ == 100)
  504. {
  505. button_down_count = 0;
  506. power_off(); // then shut off until the button is pressed
  507. }
  508. } else {
  509. // if button down count is > 100 then we're returning from power down, ignore button activity on first release.
  510. // if button is now up and was down long enough for it to not be a bounce but not long enough to be power off, switch modes
  511. if ((button_down_count > 5) && (button_down_count < 101))
  512. {
  513. if (button_mode == max_mode)
  514. button_mode = 1;
  515. else
  516. button_mode++;
  517. }
  518. button_down_count = 0;
  519. }
  520. PORTB = 0; // don't leave the pull-up on
  521.  
  522.  
  523.  
  524. // finally, recycle back to beginning of display cycle
  525. loopcount = 0;
  526. loops++;
  527. }
  528. }
  529.  
  530.  
  531. // **********************************************************
  532. // *** BUTTON PRESS HANDLING
  533. // **********************************************************
  534. //Setup pin change interrupt used to wake from sleep
  535. void init_pcint(void)
  536. {
  537. GIMSK |= 1<<PCIE; //Enable Pin Change Interrupt
  538. PCMSK |= 1<<PCINT0; //Watch for Pin Change on Pin5 (PB0)
  539. }
  540.  
  541. //Pin Change Interrupt
  542. ISR(PCINT0_vect)
  543. {
  544. sleep_disable();
  545. GIMSK &= ~(1<<PCIE); //Disable the interrupt so it doesn't keep flagging
  546. PCMSK &= ~(1<<PCINT0);
  547. }
  548.  
  549.  
  550.  
  551.  
  552. // turn off and wait for button press
  553. void power_off(void)
  554. {
  555. cli();
  556. TIMSK &= ~(1<<TOIE0); //Turn off the timer (overflow) interrupt
  557.  
  558. // wait for the button to be released
  559. DDRB = 0x0; // PB0 to input mode
  560. PORTB = 0x01; // pull-up active
  561. while ((PINB & 0x01) == 0);
  562. _delay_ms(50); // debouncing
  563.  
  564. // go into power down mode until the button gets pressed again
  565. gotosleep:
  566. init_pcint(); // set up pin change interrupt
  567. set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  568.  
  569. sei(); // enable interrupts (so we can come back alive again when the button is pressed)
  570. sleep_mode();
  571. // interrupts will be disabled when we get back from here but RETI at the end of this function will enable interrupts
  572.  
  573. // detect double click
  574. _delay_ms(50); // debounce button press
  575.  
  576. while ((PINB & 0x01) == 0); // wait for button release
  577. _delay_ms(50); // debounce button release
  578. for (int x=0; x<500; x++) // 1/2 second to press button again
  579. {
  580. if ((PINB & 0x01) == 0) // button was pressed again
  581. goto wakeup;
  582. _delay_ms(1);
  583. }
  584. // no subsequent button press, false alarm
  585. goto gotosleep;
  586.  
  587. wakeup:
  588. button_down_count = 101; // don't switch modes upon release.
  589. SetupDisplayInterrupt(); // put interrupts back to run mode
  590. // _delay_ms(200);
  591. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement