Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "Wire.h"
- #define DS1307_ADDRESS 0x68
- byte zero = 0x00; //workaround for issue #527
- #ifndef F_CPU
- #define F_CPU 16000000UL // 16 MHz
- #endif
- #include <stdlib.h>
- #include <avr/io.h>
- #include <avr/interrupt.h>
- #include <util/delay.h>
- // arduino redefines int, which bugs out stdio.h (needed for sscanf)
- // see: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1207028702/3
- #undef int
- #include <stdio.h>
- // The number of "pie slices" that make up a single image around the platter
- #define DIVISIONS 0xFF
- // Red pin, on PORTD
- #define RED 3
- // Green Pin, on PORTD
- #define GRN 4
- // Blue pin, on PORTD
- #define BLU 5
- // Macro used to communicate serial status
- #define OK 1
- // Number of pages in frame buffer
- #define PAGES 2
- // Helper macro to build LED values for PORTD
- #define RGB(R,G,B) (R << RED | G << GRN | B << BLU)
- // The timers are configured with the prescaler set to 8, which means every
- // 8 clock cycles equals on tick on the counter. This is a constant to help
- // convert timer cycles back to real time.
- #define FREQ_DIV_8 (F_CPU / 8)
- // Defines how many ticks a millisecond equals on our clock
- #define MILLITICK (FREQ_DIV_8 * .001)
- // I have found that the sensor in my rig is prone to triggering the interrupt
- // immediately after a real signal, likely related to capactive effects. This
- // tricks the system into thinking the platter is suddenly traveling a lot
- // faster, and can cause visible glitches. A 15K RPM drive spins 250 times a
- // second, where a single revolution requires 4ms. 4ms is exactly 8000 timer
- // cycles on our timer, which means anything half of 8000 is going faster than
- // any known HD. If such a value is captured, it is ignored.
- #define SPURIOUS_INT (2 * MILLITICK)
- // Helper macros for frobbing bits
- #define bitset(var,bitno) ((var) |= (1 << (bitno)))
- #define bitclr(var,bitno) ((var) &= ~(1 << (bitno)))
- #define bittst(var,bitno) (var& (1 << (bitno)))
- // It is technically possible to change the number of divisions, even
- // though this is not currently implemented. This const serves as a place
- // holder for future enhancements.
- const unsigned char divisions = DIVISIONS;
- // The current slice being drawn
- volatile unsigned char current_slice;
- // The period of the platter in timer ticks
- int period;
- // The value of the hidden page
- volatile int page_hidden;
- // The value of the visible page
- volatile int page_visible;
- // A flag representing the need for the pages to be flipped
- volatile unsigned char page_flip_flag;
- // The double buffered frame buffer
- unsigned char FrameBuffer[PAGES][DIVISIONS];
- /**
- ** FrameBuffer / Page routines
- **
- ** The framebuffer is double buffered, which allows you to write updates
- ** to the "hidden" page while the code draws from the "visible" page.
- **
- ** page_flip() makes the hidden page the visible page, and vice-versa.
- **
- ** copy_page() allows you to copy the visible page back to the hidden page,
- ** so you don't have to redraw the entire frame if you are just making a
- ** small change.
- **
- ** clear_page() clears the hidden page.
- **
- ** write_page() writes to the hidden page.
- **
- ** See RunStartupDisplay() for a simple example.
- **/
- // sit and wait for the page to be flipped
- void __inline__ wait_for_page_flip(void)
- {
- while (page_flip_flag) {}
- }
- // request a page flip, and wait for the sensor interrupt to flip the page
- void __inline__ flip_page(void)
- {
- page_flip_flag = 1;
- wait_for_page_flip();
- }
- // copy the visible page to the hidden page
- void __inline__ copy_page(void)
- {
- int x;
- for(x = 0; x < divisions; x++)
- {
- FrameBuffer[page_hidden][x] = FrameBuffer[page_visible][x];
- }
- }
- // write a value to the hidden page
- void __inline__ write_page(unsigned char slice, unsigned char val)
- {
- FrameBuffer[page_hidden][slice] = val;
- }
- // clear the hidden page
- void clear_page(void)
- {
- int x;
- for(x = 0; x < divisions; x += 1)
- {
- FrameBuffer[page_hidden][x] = 0;
- }
- }
- // called by the interrupt to flip to the next page
- void __inline__ flip_to_next_page(void)
- {
- if (page_flip_flag)
- {
- page_visible = page_hidden;
- page_hidden = !page_hidden;
- page_flip_flag = 0;
- }
- }
- // Configure the Serial Port, LED Pins, Timers, and Hardware Interrupt
- void SetupHardware(void)
- {
- // setup serial
- //Serial.begin(9600);
- //Serial.print("[");
- // setup output
- pinMode(RED, OUTPUT);
- pinMode(GRN, OUTPUT);
- pinMode(BLU, OUTPUT);
- //Serial.print("L");
- // disable global interrupts
- cli();
- // setup timer0 - 8bit
- // resonsible for timing the LEDs
- TCCR0A = 0;
- TCCR0B = 0;
- // select CTC mode
- bitset(TCCR0A, WGM01);
- // select prescaler clk / 8
- bitset(TCCR0B, CS01);
- // enable compare interrupt
- bitset(TIMSK0, OCIE0A);
- //Serial.print("0");
- // setup timer1 - 16bit
- // responsible for timing the rotation of the platter
- TCCR1B = 0;
- TCCR1A = 0;
- // select prescaler clk / 8
- bitset(TCCR1B, CS11);
- // reset timer
- TCNT1 = 0;
- // enable overflow interrupt
- bitset(TIMSK1, TOIE1);
- //Serial.print("1");
- // configure the platter interrupt PIN
- // int0, on any change
- EICRA = _BV(ISC00);
- //EICRA = _BV(ISC01);
- // Enable the hardware interrupt.
- EIMSK |= _BV(INT0);
- //Serial.print("G");
- // set the rotational period to 0
- period = 0;
- // init pages
- init_pages();
- // enable global interrupts
- sei();
- /*Serial.println("]");
- Serial.flush();
- */
- }
- // Simple animation to demonstrate the system is working
- void RunStartupDisplay(void)
- {
- int color;
- int slice;
- clear_page();
- flip_page();
- for (color = 0; color < 7; color++)
- {
- for (slice = 0; slice < divisions; slice += 2)
- {
- switch(color)
- {
- case 0:
- /* red */
- write_page(slice, _BV(RED));
- write_page(slice+1, _BV(RED));
- break;
- case 1:
- /* green */
- write_page(slice, _BV(GRN));
- write_page(slice+1, _BV(GRN));
- break;
- case 2:
- /* blue */
- write_page(slice, _BV(BLU));
- write_page(slice+1, _BV(BLU));
- break;
- case 3:
- //White
- write_page(slice, RGB(1,1,1));
- write_page(slice+1, RGB(1,1,1));
- break;
- case 4:
- //purple
- write_page(slice, RGB(1,0,1));
- write_page(slice+1, RGB(1,0,1));
- break;
- case 5:
- write_page(slice, RGB(0,1,1));
- write_page(slice+1, RGB(0,1,1));
- break;
- case 6:
- /* black */
- write_page(slice, 0);
- write_page(slice+1, 0);
- break;
- }
- flip_page();
- copy_page();
- }
- }
- clear_page();
- flip_page();
- }
- // Go through all pages of the frame buffer, and set them to 0
- void init_pages(void)
- {
- int page;
- int x;
- for(page = 0; page < PAGES; page += 1)
- {
- for(x = 0; x < divisions; x += 1)
- {
- FrameBuffer[page][x] = 0;
- }
- }
- page_hidden = 0;
- page_flip_flag = 0;
- }
- // Simple test pattern displaying all the available drawable slices.
- void InitTestPattern2(void)
- {
- clear_page();
- int x;
- for(x = 0; x < divisions; x++)
- {
- switch (x % 8)
- {
- case 0:
- write_page(x, RGB(0,0,0));
- break;
- case 1:
- write_page(x, RGB(1,0,0));
- break;
- case 2:
- write_page(x, RGB(0,1,0));
- break;
- case 3:
- write_page(x, RGB(0,0,1));
- break;
- case 4:
- write_page(x, RGB(1,1,0));
- break;
- case 5:
- write_page(x, RGB(1,0,1));
- break;
- case 6:
- write_page(x, RGB(0,1,1));
- break;
- case 7:
- write_page(x, RGB(1,1,1));
- break;
- }
- }
- flip_page();
- }
- void InitTestPattern1(void)
- {
- int x;
- for(x = 0; x < divisions; x++)
- {
- switch (x / (divisions / 8))
- {
- case 0:
- write_page(x, RGB(0,0,0));
- break;
- case 1:
- write_page(x, RGB(1,0,0));
- break;
- case 2:
- write_page(x, RGB(0,1,0));
- break;
- case 3:
- write_page(x, RGB(0,0,1));
- break;
- case 4:
- write_page(x, RGB(1,1,0));
- break;
- case 5:
- write_page(x, RGB(1,0,1));
- break;
- case 6:
- write_page(x, RGB(0,1,1));
- break;
- case 7:
- default:
- write_page(x, RGB(1,1,1));
- break;
- }
- }
- }
- // Top level setup, called by the Arduino core
- void setup(void)
- {
- SetupHardware();
- RunStartupDisplay();
- Wire.begin();
- setDateTime(); //MUST CONFIGURE IN FUNCTION
- }
- // Top level loop, call by the Arduino core
- void loop(void)
- {
- printDate();
- int cmd;
- int slice, value;
- int okval = OK;
- // Simple test pattern displaying all the available drawable slices.
- //InitTestPattern2();
- }
- // This interrupt is called on every pulse of the sensor, which represents
- // one full rotation of the platter. It is responsible for timing the
- // revolution, and for initiating the first draw instance.
- ISR(INT0_vect)
- {
- // Capture the 16bit count on timer1, this represents one revolution
- period = TCNT1;
- // If the period is shorter than our threshold, don't do anything
- if(period < SPURIOUS_INT)
- {
- return;
- }
- // Reset timer1 so it can clock the next revolution
- TCNT1 = 0;
- // Reset timer0 so it can start to accurately paint the slot
- TCNT0 = 0;
- // If there is a page flip request, flip to the next page
- flip_to_next_page();
- // Write out the first slice to the LEDs to PORTD
- PORTD = FrameBuffer[page_visible][0];
- // Divide the time of single platter rotation by the number of drawable
- // divisions
- OCR0A = (period / divisions);
- // Set our current slice to 1, since we just drew slice 0
- current_slice = 1;
- }
- // This interrupt is called every time timer0 counts up to the 8bit value
- // stored in the register "ORC0A", which is configured in INT0 interrupt.
- // It is responsible for drawing out all the slices of the frame buffer
- // during the exact moment the slot is in its proper rotational position.
- // Using a 7200RPM drive with 255 divisions, this interrupt is called
- // 31,200 times a second.
- ISR(TIMER0_COMPA_vect) {
- // Write out the LED value to the Frame Buffer
- PORTD = FrameBuffer[page_visible][current_slice];
- // Increment current slice, making sure to wrap it if it
- // has accidently gotten too large
- current_slice = ((current_slice + 1) % divisions);
- }
- // If the platter spin time overflows timer1, this is called
- ISR(TIMER1_OVF_vect) {
- }
- void setDateTime(){
- byte second = 40; //0-59
- byte minute = 16; //0-59
- byte hour = 21; //0-23
- byte weekDay = 3; //1-7
- byte monthDay = 25; //1-31
- byte month = 4; //1-12
- byte year = 12; //0-99
- Wire.beginTransmission(DS1307_ADDRESS);
- Wire.write(zero); //stop Oscillator
- Wire.write(decToBcd(second));
- Wire.write(decToBcd(minute));
- Wire.write(decToBcd(hour));
- Wire.write(decToBcd(weekDay));
- Wire.write(decToBcd(monthDay));
- Wire.write(decToBcd(month));
- Wire.write(decToBcd(year));
- Wire.write(zero); //start
- Wire.endTransmission();
- }
- byte decToBcd(byte val){
- // Convert normal decimal numbers to binary coded decimal
- return ( (val/10*16) + (val%10) );
- }
- byte bcdToDec(byte val) {
- // Convert binary coded decimal to normal decimal numbers
- return ( (val/16*10) + (val%16) );
- }
- void printDate(){
- // Reset the register pointer
- Wire.beginTransmission(DS1307_ADDRESS);
- Wire.write(zero);
- Wire.endTransmission();
- Wire.requestFrom(DS1307_ADDRESS, 7);
- int second = bcdToDec(Wire.read());
- int minute = bcdToDec(Wire.read());
- int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
- int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
- int monthDay = bcdToDec(Wire.read());
- int month = bcdToDec(Wire.read());
- int year = bcdToDec(Wire.read());
- if(hour > 12)
- {
- hour-=12;
- }
- hour = (divisions * (hour / 12.0) + (divisions / 12.0) * (minute / 60.0));
- minute = (divisions * (minute / 60.0));
- second = (divisions * (second / 60.0));
- for(int i = 0; i <= 255; i++)
- {
- write_page(i, RGB(1,0,1));
- }
- clockNums();
- for(int i = (hour-3); i < (hour + 3); i++)
- {
- write_page(i, RGB(1,0,0));
- }
- for(int i =(minute-2); i < (minute + 2); i++)
- {
- write_page(i, RGB(0,1,0));
- }
- for(int i =(second-1); i< (second+1); i++)
- {
- write_page(i, RGB(1,1,1));
- }
- flip_page();
- clear_page();
- }
- void clockNums()
- {
- for(int i =63; i< (66); i++)
- {
- write_page(i, RGB(0,0,0));
- }
- for(int i = 0; i< (2); i++)
- {
- write_page(i, RGB(0,0,0));
- write_page(255, RGB(0,0,0));
- }
- for(int i = 127; i< 130; i++)
- {
- write_page(i, RGB(0,0,0));
- }
- for(int i = 190; i< 193; i++)
- {
- write_page(i, RGB(0,0,0));
- }
- write_page(22, RGB(0,0,0));
- write_page(43, RGB(0,0,0));
- write_page(85, RGB(0,0,0));
- write_page(106, RGB(0,0,0));
- write_page(149, RGB(0,0,0));
- write_page(170, RGB(0,0,0));
- write_page(213, RGB(0,0,0));
- write_page(234, RGB(0,0,0));
- }
Advertisement
Add Comment
Please, Sign In to add comment