Hello there
I recently finished making a led cube 5x5x5 inspired by this site: h.t.t.p.://courses.cit.cornell.edu/ee476/FinalProjects/s2008/pae26_rwc28/pae26_rwc28/index
I'm trying to convert this program (which is made for a ATMEL32 microchip) to work on a PIC16F877. The main difference is that I use the PORTB for the columns and PORTD for the ground layers and I don't use the accelerometter because I couldn't find one.
Here is the program:
Code:#include <pic.h> #include <delay.h> flash unsigned char letters[78] = { //A 0b00001111, 0b00010100, 0b00001111, //B 0b00011111, 0b00010101, 0b00001111, //C 0b00011111, 0b00010001, 0b00010001, //D 0b00011111, 0b00010001, 0b00001111, //E 0b00011111, 0b00010101, 0b00010101, //F 0b00011111, 0b00010100, 0b00010100, //G 0b00011111, 0b00010011, 0b00011011, //H 0b00011111, 0b00000100, 0b00011111, //I 0b00010001, 0b00011111, 0b00010001, //J 0b00010001, 0b00011111, 0b00010000, //K 0b00011111, 0b00000100, 0b00011011, //L 0b00011111, 0b00000001, 0b00000001, //M 0b00011111, 0b00001000, 0b00011111, //N 0b00011111, 0b00001110, 0b00011111, //O 0b00011111, 0b00010001, 0b00011111, //P 0b00011111, 0b00010100, 0b00011100, //Q 0b00011111, 0b00010011, 0b00011111, //R 0b00011111, 0b00010110, 0b00011101, //S 0b00011101, 0b00010101, 0b00010111, //T 0b00010000, 0b00011111, 0b00010000, //U 0b00011111, 0b00000001, 0b00011111, //V 0b00011110, 0b00000001, 0b00011110, //W 0b00011111, 0b00000010, 0b00011111, //X 0b00011011, 0b00000100, 0b00011011, //Y 0b00011000, 0b00000111, 0b00011000, //Z 0b00011001, 0b00010101, 0b00010011 }; flash unsigned char numbers[30] = { //0 0b00011111, 0b00010001, 0b00011111, //1 0b00010001, 0b00011111, 0b00000001, //2 0b00010011, 0b00010101, 0b00011101, //3 0b00010101, 0b00010101, 0b00011111, //4 0b00011100, 0b00000100, 0b00011111, //5 0b00011101, 0b00010101, 0b00010111, //6 0b00011111, 0b00010101, 0b00010111, //7 0b00010001, 0b00010010, 0b00011100, //8 0b00011111, 0b00010101, 0b00011111, //9 0b00011101, 0b00010101, 0b00011111 }; //Current frame info, and acceleration data float a_x, a_y; //Current converted accelerations float bias_a_x, bias_a_y; //Calculated biases of x and y axis accelerometers unsigned char data_ready; //Flag indicating acceleration conversions ready unsigned char intro_pos; //Current position in the introduction string (scrolled) unsigned char intro_string[133]; //Buffer to hold all columns representing intro string unsigned char cur_frame[25]; //Buffer for current frame (25 columns - each bytes //5 least significant bits represent the five LEDs in a //column which are on if bit is 1, and off if bit is 0 unsigned char temp_convert[25]; //Buffer for a frame to use as temporary storage //Animation states #define INTRO_STRING 0 #define ALTERNATING_HORIZONTAL_PLANES 1 #define PLANE_TRANSITION 2 #define CENTER_LINE_TO_VERTICAL_PLANE 3 #define VERTICAL_PLANE_TO_ALL 4 #define ALL_TO_NONE 5 unsigned char animation_state; //Current animation state unsigned char animation_count; //Count variable for use with //animation updating unsigned char animation_temp; //Another useful variable to use //when animating, temporary state unsigned char plane_sequence[4] = {0x11,0x0a,0x04,0x0a}; //Sequence of column values for use //in the alternating planes animation unsigned char temp_frame[25]; //Temporary frame buffer to keep frame //state between animation updates //A/D Conversion #define IDLE 0 #define CONVERTING_X 1 #define CONVERTING_Y 2 unsigned char conversion_stage; //Conversion state variable unsigned char ADC_accel_x; //Reading from the ADC converter for X acceleration unsigned char ADC_accel_y; //Reading from the ADC converter for Y acceleration //Temp variables (made global for faster allocation in method) unsigned char i, temp; unsigned int count; //Scheduling timer variables #define DISPLAY_TIME 16 unsigned char display_count; //Scheduling variable for display task //Scheduled at ~ 60Hz (62.5Hz) //Method prototypes void display_task(void); //Display task void initialize(void); //Initialization routine void calibrate_sensors(void); //Sensor calibration routine void init_intro(flash char* str); //Intro string initialization - takes a string and //converts it to column values for display /** * Timer interrupt code running at 1000 Hz (ms tick). **/ interrupt [TIM0_COMP] disp_int(void) { //Decrement display count each millisecond (used to schedule display task) if (display_count > 0) display_count--; } /** * ADC done interrupt, allows us to do one conversion after the other (accel_x,accel_y) **/ interrupt [ADC_INT] adc_int(void) { if (conversion_stage == CONVERTING_Y) { ADC_accel_y = ADCH; //Grab the converted value of Y_Accel conversion_stage = CONVERTING_X; //Update conversion stage ADMUX |= 0x01; //Switch conversion channel to A1 (x-accel) ADCSR &= 0xef; //Clear interrupt flag (just to be safe) ADCSR |= 0x40; //Start a new conversion } else if (conversion_stage == CONVERTING_X) { ADC_accel_x = ADCH; //Grab the converted value of X_Accel conversion_stage = IDLE; //Update conversion stage ADMUX &= 0xf8; //Clear conversion channel back to A0 (y-accel) ADCSR &= 0xef; //Clear interrupt flag (just to be safe) data_ready = 1; //Now we have both converted values, data is ready } } /** * Main loop. **/ void main(void) { initialize(); //Main loop while(1) { //Schedule tasks if (display_count == 0) display_task(); } } /** * All the functionality is in this display task. It keeps animation/demo state and fills in * a frame buffer with the current LEDs to be lit in this frame (this is called once every 16mS * for a refresh rate of about 62.5Hz). The method also grabs acceleration values if they are * ready from the conversion task (which converts both x and y acceration channels and then sets * a flag) and then checks whether the acceration values are near +- gravity whose values were * found with experimentation. If so, we flip the frame on its side left or right to keep the * same orientation of the frame with respect to the ground. **/ void display_task(void) { display_count = DISPLAY_TIME; //Reschedule this task //We are displaying the demo opening string if (animation_state == INTRO_STRING) { //Render appropriate frame right side up (current 5 columns for all //rows) offset by our current position in this prerendered string for (i = 0; i < 5; i++) { cur_frame[i] = intro_string[intro_pos+i]; cur_frame[i+5] = intro_string[intro_pos+i]; cur_frame[i+10] = intro_string[intro_pos+i]; cur_frame[i+15] = intro_string[intro_pos+i]; cur_frame[i+20] = intro_string[intro_pos+i]; } count++; //Use count to slow update (12*16mS = 192mS between scrolling updates) if (count > 12) { count = 0; intro_pos += 1; //If we are at the end of the string, set animation_temp with its next value and //switch to first animation state "ALTERNATING_HORIZONTAL_PLANES" if (intro_pos > 128) { animation_temp = 0x11; animation_state = ALTERNATING_HORIZONTAL_PLANES; } } } //We are displaying two horizontal planes moving up and down opposite each other else if (animation_state == ALTERNATING_HORIZONTAL_PLANES) { //Render frame right side up (all columns get same value) for (i = 0; i < 25; i++) { cur_frame[i] = animation_temp; } count++; //Count slows update (again 192mS between updates) if (count > 12) { count = 0; animation_count++; //Use this count to clock through the animation sequence animation_temp = plane_sequence[animation_count & 0x03]; //Once we have done the animation a few times (and get to just a middle plane) if (animation_count == 0x1f) { animation_temp = 0; animation_count = 0; animation_state = PLANE_TRANSITION; } } } else if (animation_state == PLANE_TRANSITION) //Horizontal plane to front to back (middle) line { //Render frame right side up //First clear the frame for (i = 0; i < 25; i++) { cur_frame[i] = 0x00; } //Then turn on the appropriate middle LEDs (out *animation_count* turned off) for (i = animation_temp; i < 5-animation_temp; i++) { cur_frame[i] = 0x04; cur_frame[i+5] = 0x04; cur_frame[i+10] = 0x04; cur_frame[i+15] = 0x04; cur_frame[i+20] = 0x04; } count++; //Count slows update (192mS between updates) if (count > 12) { count = 0; animation_count++; //Clock through animation sequence //Once the plane has turned to front to back line, switch animation states //Want to then turn front to back line into a vertical plane on the middle //LEDs from front to back if (animation_count == 3) { animation_temp = 0x04; //First value for the plane animation_count = 0; animation_state = CENTER_LINE_TO_VERTICAL_PLANE; } else { animation_temp = animation_count; } } } else if (animation_state == CENTER_LINE_TO_VERTICAL_PLANE) //Front to back line to vertical plane { //Render frame right side up for (i = 0; i < 25; i++) { cur_frame[i] = 0x00; } cur_frame[2] = animation_temp; cur_frame[7] = animation_temp; cur_frame[12] = animation_temp; cur_frame[17] = animation_temp; cur_frame[22] = animation_temp; count++; //Count slows update (192mS between updates) if (count > 12) { count = 0; animation_count++; //Clock through animation sequence //Update the next value to use for the center columns switch (animation_count) { case 1 : animation_temp = 0x0e; break; case 2 : animation_temp = 0x1f; break; case 3 : animation_temp = 2; animation_count = 0; animation_state = VERTICAL_PLANE_TO_ALL; //Next animation state break; } } } else if (animation_state == VERTICAL_PLANE_TO_ALL) //Transition from vertical plane to all lit { //Render frame right side up for (i = 0; i < 25; i++) { cur_frame[i] = 0x00; } //Turn all LEDs on for all columns front to back for inner 1+2*animation_temp LEDs for (i = animation_temp; i < 5-animation_temp; i++) { cur_frame[i] = 0x1f; cur_frame[i+5] = 0x1f; cur_frame[i+10] = 0x1f; cur_frame[i+15] = 0x1f; cur_frame[i+20] = 0x1f; } count++; //Count slows update (15*16mS = 240mS between updates) if (count > 15) { count = 0; animation_count++; //Clock through the animation (set animation_temp //appropriately for next display frame) switch (animation_count) { case 1 : animation_temp = 1; break; case 2 : animation_temp = 0; break; case 3 : animation_temp = 0; animation_count = 0; animation_state = ALL_TO_NONE; //Initialize the temporary frame with the current one (all on) for (i = 0; i < 25; i++) temp_frame[i] = cur_frame[i]; break; } } } else if (animation_state == ALL_TO_NONE) //Spiral to none lit { //Render frame right side up for (i = 0; i < 25; i++) cur_frame[i] = temp_frame[i]; count++; //Count slows update (192mS between updates) if (count > 12) { count = 0; animation_count++; //Clock animation //This is the update seqence for the all lit cube spiralling inwards to //none, turning off columns as we spiral, given the following column //orientation looking at the cube from above: // 0 1 2 3 4 // 5 6 7 8 9 // 10 11 12 13 14 // 15 16 17 18 19 // 20 21 22 23 24 //The sequence of columns to turn off is: // {0,1,2,3,4,9,14,19,24,23,22,21,20,15,10,5,6,7,8,13,18,17,16,11,12} //First 5 we count from 0 if (animation_count < 6) { temp_frame[animation_count-1] = 0x00; } //Next four we count by fives from 9 (simplified below) else if (animation_count < 10) { temp_frame[animation_count*5 - 21] = 0x00; } //Next four we count down by ones from 23 else if (animation_count < 14) { temp_frame[33-animation_count] = 0x00; } //Next 3 we count down by fives from 15 else if (animation_count < 17) { temp_frame[(17-animation_count)*5] = 0x00; } //Next 3 we count up by ones from 6 else if (animation_count < 20) { temp_frame[animation_count - 11] = 0x00; } //Next 2 we count up by fives from 13 else if (animation_count < 22) { temp_frame[(animation_count - 20) * 5 + 13] = 0x00; } //Next 2 we count down by ones from 17 else if (animation_count < 24) { temp_frame[39 - animation_count] = 0x00; } //For the final two we count up by ones from 11 else { temp_frame[animation_count - 13] = 0x00; } //Once we have gone through all the columns, go to next state if (animation_count == 25) { animation_temp = 0; animation_count = 0; animation_state = INTRO_STRING; //Back to intro string intro_pos = 0; //Make sure we are at first position } } } //If conversion data is ready, clear flag, get accelerations, start next conversion if (data_ready) { data_ready = 0; //Clear data ready bit //Convert the sampled 8-bit values to accelerations +/- 74/g (x) and 77/g (y) a_x = -((float)ADC_accel_x - bias_a_x); a_y = -((float)ADC_accel_y - bias_a_y); //Start a new conversion conversion_stage = CONVERTING_Y; ADCSR |= 0x40; } //Now flip frame sideways as necessary if (a_x > 65.0) //We are on +x side, scroll up, come up with frame { //Convert this frame to left is bottom (zero bits of all become last column, etc) //First columns bit is first bit etc for (i = 0; i < 5; i++) { temp = 5*i; //Last column (all first bits in order) temp_convert[temp+4] = (cur_frame[temp+0] & 0x01) | ((cur_frame[temp+1] << 1) & 0x02) | ((cur_frame[temp+2] << 2) & 0x04) | ((cur_frame[temp+3] << 3) & 0x08) | ((cur_frame[temp+4] << 4) & 0x10); //Second to last column (all second bits in order) temp_convert[temp+3] = ((cur_frame[temp+0] >> 1) & 0x01) | (((cur_frame[temp+1] >> 1) << 1) & 0x02) | (((cur_frame[temp+2] >> 1) << 2) & 0x04) | (((cur_frame[temp+3] >> 1) << 3) & 0x08) | (((cur_frame[temp+4] >> 1) << 4) & 0x10); //... temp_convert[temp+2] = ((cur_frame[temp+0] >> 2) & 0x01) | (((cur_frame[temp+1] >> 2) << 1) & 0x02) | (((cur_frame[temp+2] >> 2) << 2) & 0x04) | (((cur_frame[temp+3] >> 2) << 3) & 0x08) | (((cur_frame[temp+4] >> 2) << 4) & 0x10); //... temp_convert[temp+1] = ((cur_frame[temp+0] >> 3) & 0x01) | (((cur_frame[temp+1] >> 3) << 1) & 0x02) | (((cur_frame[temp+2] >> 3) << 2) & 0x04) | (((cur_frame[temp+3] >> 3) << 3) & 0x08) | (((cur_frame[temp+4] >> 3) << 4) & 0x10); //First column (all fifth bits in order) temp_convert[temp+0] = ((cur_frame[temp+0] >> 4) & 0x01) | (((cur_frame[temp+1] >> 4) << 1) & 0x02) | (((cur_frame[temp+2] >> 4) << 2) & 0x04) | (((cur_frame[temp+3] >> 4) << 3) & 0x08) | (((cur_frame[temp+4] >> 4) << 4) & 0x10); } //Replace frame for (i = 0; i < 25; i++) { cur_frame[i] = temp_convert[i]; } } else if (a_x < -65.0) //We are on -x side, scroll down come up with frame { //Convert this frame to left is top (zero bits of all become first column, etc) //Last columns bit is first bit etc for (i = 0; i < 5; i++) { temp = 5*i; //First column (all first bits in reverse order) temp_convert[temp+0] = (cur_frame[temp+4] & 0x01) | ((cur_frame[temp+3] << 1) & 0x02) | ((cur_frame[temp+2] << 2) & 0x04) | ((cur_frame[temp+1] << 3) & 0x08) | ((cur_frame[temp+0] << 4) & 0x10); //Second column (all second bits in reverse order) temp_convert[temp+1] = ((cur_frame[temp+4] >> 1) & 0x01) | (((cur_frame[temp+3] >> 1) << 1) & 0x02) | (((cur_frame[temp+2] >> 1) << 2) & 0x04) | (((cur_frame[temp+1] >> 1) << 3) & 0x08) | (((cur_frame[temp+0] >> 1) << 4) & 0x10); //... temp_convert[temp+2] = ((cur_frame[temp+4] >> 2) & 0x01) | (((cur_frame[temp+3] >> 2) << 1) & 0x02) | (((cur_frame[temp+2] >> 2) << 2) & 0x04) | (((cur_frame[temp+1] >> 2) << 3) & 0x08) | (((cur_frame[temp+0] >> 2) << 4) & 0x10); //... temp_convert[temp+3] = ((cur_frame[temp+4] >> 3) & 0x01) | (((cur_frame[temp+3] >> 3) << 1) & 0x02) | (((cur_frame[temp+2] >> 3) << 2) & 0x04) | (((cur_frame[temp+1] >> 3) << 3) & 0x08) | (((cur_frame[temp+0] >> 3) << 4) & 0x10); //Fifth column (all fifth bits in reverse order) temp_convert[temp+4] = ((cur_frame[temp+4] >> 4) & 0x01) | (((cur_frame[temp+3] >> 4) << 1) & 0x02) | (((cur_frame[temp+2] >> 4) << 2) & 0x04) | (((cur_frame[temp+1] >> 4) << 3) & 0x08) | (((cur_frame[temp+0] >> 4) << 4) & 0x10); } //Replace frame for (i = 0; i < 25; i++) { cur_frame[i] = temp_convert[i]; } } //Render the frame //Go through each column turning on appropriate lights of current frame (strobe) for (i = 0; i < 25; i++) { //Do the bottom 3 layers temp = 0x00; if (cur_frame[i] & 0x01) { temp |= 0x01; } if (cur_frame[i] & 0x02) { temp |= 0x02; } if (cur_frame[i] & 0x04) { temp |= 0x04; } PORTB = temp >> 2; if (i < 24) { PORTD = i | (temp << 6); } else { PORTD = 0x38 | (temp << 6); } delay_us(200); //Delay for 200uS to allow light to hit eyes //Disable the columns PORTD = PINC & 0xdf; PORTD = PINC | 0x18; //Disable the grounding (make grounding controls 1) PORTD = PINC & 0x3f; PORTB = PINB & 0x00; //Do the top 2 layers temp = 0x00; if (cur_frame[i] & 0x08) { temp |= 0x08; } if (cur_frame[i] & 0x10) { temp |= 0x10; } PORTB = temp >> 2; if (i < 24) { PORTD = i | (temp << 6); } else { PORTD = 0x38 | (temp << 6); } delay_us(200); //Delay for 200uS to allow light to hit eyes //Disable the columns PORTD = PINC & 0xdf; PORTD = PINC | 0x18; //Disable the grounding (make grounding controls 1) PORTD = PINC & 0x3f; PORTB = PINB & 0x00; } } /** * Initialize the microcontroller. **/ void initialize(void) { // LED Cube Control Ports // DDRC.0 = Decoder control bit 0 (LSB) // DDRC.1 = Decoder control bit 1 // DDRC.2 = Decoder control bit 2 // DDRC.3 = Decoder control bit 3 // DDRC.4 = Decoder control bit 4 (MSB) // DDRC.5 = 25th column // DDRC.6 = Bit 0 of led ground // DDRC.7 = Bit 1 of led ground // DDRB.0 = Bit 2 of led ground // DDRB.1 = Bit 3 of led ground // DDRB.2 = Bit 4 of led ground DDRB = 0x07; DDRD = 0xff; PORTB = 0x00; PORTD = 0x18; //set up timer 0 TIMSK=2; //turn on timer 0 cmp match ISR OCR0 = 249; //set the compare re to 250 time ticks //prescalar to 64 and turn on clear-on-match TCCR0=0b00001011; //Set up scheduling variables display_count = DISPLAY_TIME; //Set up current state data_ready = 0; //init the A to D converter (maybe do 10-bit and low noise stuff if necessary) //channel zero/ left adj /INTERNAL Aref ADMUX = 0b11100000; //enable ADC and set prescaler to 1/128*16MHz=125,000 (may want this faster) //and clear interupt enable ADCSR = 0b10001111; //Do calibration of ADC calibrate_sensors(); //Initialize the landscape with strings init_intro(" ECE476 FINAL PROJECT DEMO "); //Must be less than 33 chars in length count = 0; intro_pos = 0; animation_state = INTRO_STRING; #asm sei #endasm //Start a new conversion conversion_stage = CONVERTING_X; ADCSR |= 0x40; } /** * Calibrate the sensors (simply find the initial zeros of the two accelerometers * by averaging over three readings). We assume that the cube is started in the * right side up state and not on its side although this may partially work for * if it is started on its side as well. **/ void calibrate_sensors(void) { ADMUX &= 0xf8; //MUX to channel 0 (y-axis) ADCSR |= 0x40; //Start conversion while (!(ADCSR & 0x10)); ADCSR &= 0xef; //Clear interrupt flag bias_a_y = (float)ADCH; ADCSR |= 0x40; //Start conversion while (!(ADCSR & 0x10)); ADCSR &= 0xef; //Clear interrupt flag bias_a_y += (float)ADCH; ADCSR |= 0x40; //Start conversion while (!(ADCSR & 0x10)); ADCSR &= 0xef; //Clear interrupt flag bias_a_y += (float)ADCH; bias_a_y /= 3; ADMUX |= 0x01; //MUX to channel 1 (x-axis) ADCSR |= 0x40; //Start conversion while (!(ADCSR & 0x10)); ADCSR &= 0xef; //Clear interrupt flag bias_a_x = (float)ADCH; ADCSR |= 0x40; //Start conversion while (!(ADCSR & 0x10)); ADCSR &= 0xef; //Clear interrupt flag bias_a_x += (float)ADCH; ADCSR |= 0x40; //Start conversion while (!(ADCSR & 0x10)); ADCSR &= 0xef; //Clear interrupt flag bias_a_x += (float)ADCH; bias_a_x /= 3; ADMUX &= 0xf8; //Reset MUX channel back to 0 } /** * Initialize an array of columns to be displayed given a flash * string to display at the start. **/ void init_intro(flash char* str) { unsigned char index; //Initialize the string to all zero (off) for (i = 0; i < 133; i++) { intro_string[i] = 0x00; } //For each character in the string, look up the representation in our //flash table and set the columns appropriately for (i = 0; i < 33; i++) { if (str[i] >= 'A' && str[i] <= 'Z') { index = 3 * (str[i] - 'A'); //Offset into representation array for letters intro_string[i*4+1] = letters[index]; intro_string[i*4+2] = letters[index+1]; intro_string[i*4+3] = letters[index+2]; } else if (str[i] >= '0' && str[i] <= '9') { index = 3 * (str[i] - '0'); //Offset into representation array for numbers intro_string[i*4+1] = numbers[index]; intro_string[i*4+2] = numbers[index+1]; intro_string[i*4+3] = numbers[index+2]; } } }
Please help.
Thanks
Sorry for my english
Last edited by WingedPanther; 03-30-2009 at 04:17 AM. Reason: add code tags (the # button)
What issues are you having with it?
Note: please use code tags (the # button) when posting code.
The problem with the code is that is made for ATMEL32 chip. I use a PIC16F877 on my cube. I heard that I need to "port" the code so that it can work on the PIC chip. In the ATmel ports C and B are used and I need ports B and D. After I get the working program I will make the HEx out of it and transfer it in the PIC chip.
The problem is that i have tried replacing the ports in the code but doesn't work. Or I'm doing something wrong.
Dear stuffy:
I am Jaradat from Holy Land (Jerusalem).I have a graduation Project exactly similar to ur project:5*5*5 Led cube.could you please to send me a full schematic and framewire of the project as soos as you can.
I hope u respond with me at my email : (abu_eljoooj@hotmail.com)
thanks.
M.Jaradat
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks