⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main copy.c

📁 旋转16个LED灯控制程序
💻 C
📖 第 1 页 / 共 4 页
字号:
    // speed, set a couple of LEDs to let the human know we    // aren't dead yet, and turn off the timer.          set_all(~0x03);          TCCR1B &= ~_BV(CS10);		// no incrementing = no interrupting        // reset the line timers so that when we get a valid spinup,    // they will start clocking the lines across the display        line_timer = SCROLLSPEED;		// delay figure, will trigger wrap    line_shift = 0x0f;				// subcharacter shift, will trigger wrap    cur_line = NUM_LINES-1;			// will wrap to first line      }         // Whether we're displaying or not, we reset sensor_timer so we can  // time the next revolution.      sensor_timer.word = 0;  }    // Finally, reset hall_debounce so we won't execute the timer reset code  // until the Hall Effect sensor hasn't bothered us for a reasonable while.    hall_debounce = 0;    // *** PORTB &= ~0x8;}// Initialize the IO pins on the ATMEL.void ioinit(void) {  // Set the data direction for the PORTD and PORTB pins; see the  // circuit diagram for more information on this.    DDRD = 0x73; // input on PD2 (button), PD3 (sensor), all other output  DDRB = 0xDF; // input on MOSI/DI (for SPI), all others output  // Deselect EEPROM.  Not being an EE, I'm not going to worry about  // how the ATMEL talks to the EEPROM.  It's black magic.    PORTB = _BV(SPIEE_CS);  // Just above, we set PD2 and PD3 to input.  If we now set those  // bits to 1, they set into pullup mode (again, not EE, claim  // ignorance), which is essential for them to work.  We also set  // the SENSORPOWER bit to 1, which sends out little dribbles of  // electrons to the hall effect sensor (see circuit diagram)  //  // Finally, we write 0's to the FRONT and BACK pins, which control  // which bank of 30 LEDs we are talking to.  Having both of these  // on at the same time probably causes horrible things to happen.    PORTD = (_BV(BUTTON) | _BV(SENSOR) | _BV(SENSORPOWER))      & ~_BV(FRONT) & ~_BV(BACK);  // Rather than poll to see when the hall effect sensor and  // button are pressed, we configure an interrupt handler.  If you  // look at the circuit diagram, you'll see that PD3 and PD2, which  // are wired to SENSOR IN and BUTTON IN, do double-duty as INT1  // and INT0.  They are both SUPPOSEDLY set to interrupt on the  // falling edge of a pulse from the devices.  (Page 63)    // POSSIBLE BUG: ISC0{1,0} seems to be being set to 00, not 10  // as ISC1{1,0} is being set to.  So ISC0 will trigger when  // the button interrupt line goes low.  Either this is a bug,  // or the original comment was not correct (likely, IMHO)    MCUCR = _BV(ISC11) & ~_BV(ISC01) & ~_BV(ISC00) &  ~_BV(ISC10);  // Activate the interrupts by setting the General Interrupt Mask  // Register (Page 63)    GIMSK = _BV(INT1) | _BV(INT0);  // The ATMEL has built-in timers that can trigger an interrupt.  // SpokePOV uses them to update the LEDs 256 times per rotation.    // Timer 0 is set to update at a rate system-clock / 256 and  // interrupt when it overflows (8 bit).  This means that it  // triggers every 65536 cycles.    TCCR0A = 0;				// normal, overflow (count up to 256 == num pixels)  TCCR0B = _BV(CS02);		// clk/256  TIMSK |= _BV(TOIE0);		// turn on overflow interrupt    // Timer 1 (T1) is the pixel timer, which is used to update the  // LEDs 256 times per rotation.  It's set up as a normal timer  // as well.  See Page 108&71; it is apparently being set into CTC  // mode 4.  This means that the counter is compared to a 16-bit value  // and interrupts when it reaches this value.  //  // Adjusting this value is how the SpokePOV compensates for  // changes in the rotation speed of the device.  //  // Note that at this point, the timer is initialized, but not  // activated.    TCCR1A = 0;  TCCR1B = _BV(WGM12);  // Clear the debounce values, which I haven't sussed out yet.    hall_debounce = 0;  sensor_timer.word = 0;  }// Turn on a single LED, turning off all the other LEDs//void set_led(uint8_t led) {//  fleds[0] = fleds[1] = fleds[2] = fleds[3] = 0xFF;//  fleds[led >> 3] = ~_BV(led & 0x7F);//  clock_scroll(0);//}// Set all the LEDs on a side to have the same// repeating 8-bit value (ie: 0x00 = all on, 0xFF = all off)// Added by RJW to permit a more comprehensive reset displayvoid set_all(uint8_t blockValue) {  fleds[0] = fleds[1] = fleds[2] = fleds[3] = blockValue;    clock_scroll(0);}int main(void) {  uint8_t cmd;			// the reason we reset  // MCUSR is the MCU Status Register (page 40).  It tells us  // why we reset, and a reset is the only way to get here.    cmd = MCUSR;    // The first order of business is to tell the chip that  // we've got things under control.    MCUSR = 0;    // Turn on watchdog timer immediately, this protects against  // a 'stuck' system by resetting it.    // WDTCSR is the Watchdog Timer Control Register (page 45).  // We set it so that it'll generate a watchdog interrupt  // every second.  The idea is that if things mess up,  // the watchdog will kickstart us.    WDTCSR = _BV(WDE) | _BV(WDP2) | _BV(WDP1); // 1 second    // Initialize the various pins of the ATMEL, and set up  // the interrupts.    ioinit();    // Show that we are active.    set_all(~0x01);  // enable the interrupts.  I think this is not needed  // since it'll immediately be done by the loop, below.    sei();    // Loop until we timeout, at which point the ATMEL is  // put to sleep.  If the communications routine timed  // out, or the user pressed the button for >500ms,  // then sensor_timer will be 0xFFFF and we'll immediately  // sleep.    // Change to for (;;) to see if it makes any difference    for (;;) {      // Reset the watchdog Timer.    //    // QUESTION: What's with toggling the PD0 output line here?    // it doesn't seem to be connected to anything according to    // the circuit diagram...        // *** PORTD |= 0x1;    asm("wdr");    // *** PORTD &= ~0x1;	// If the sensor_timer (incremented by TIMER0) maxes out	// (in about 3 minutes), then sleep everything.	    if (sensor_timer.bytes.high_byte == 0xFF) {            // Avoid pesky interruptions            cli();            // Turn off all LEDs - I guess LED 0 is one of the "invisible ones"            set_all(0xFF);            // Turn off power to the Hall Effect sensor.            SENSOR_PORT &= ~_BV(SENSORPOWER);            // Deselect EEPROM            SPIEE_CS_PORT |= _BV(SPIEE_CS);      // pull CS high to deselect            // Turn off Watchdog (must be restarted when we get the wakeup)      // Wakeup will be via the button interrupt.            WDTCSR |= _BV(WDCE) | _BV(WDE);      WDTCSR = 0;      MCUCR |= _BV(SM1) | _BV(SM0) | _BV(SE);            // Re-enable interrupts so we can get the wakeup!            sei();           // Go into sleep mode            asm("sleep");          } else {          // Do we have dynamic updating to do?            #ifdef DYNAMIC             uint8_t tBytes;						// Number of bytes to transfer                // Use unions to overlay variables and save some space                union {          char *fPtr;						// from pointer          var16bit divisor;					// the divisor for RPM        } a;                union {          char *tPtr;						// to pointer          char *divTable;					// divisor table        } b;                // Update the dynamic data display                switch (dynamicType & 0xF0) {                     #ifdef DYNAMIC_REVCOUNT					// Rev counter compiled in?                        case 0x10:								// Rev counter                          tBytes = 4;							// number of bytes we'll move down below              a.fPtr = (char *)dynamicREV;              break;                                // gets put into dynamicBuffer in reverse order.                      #endif                      #ifdef DYNAMIC_RPM						// RPM counter compiled in?                        case 0x20:                          // CODE NOT YET OPTIMIZED FOR SPACE.                            // Initialize the RPM counter to 0                            dynamicRPM[0]=dynamicRPM[1]=dynamicRPM[2] = '0';                            // Get a copy of the TIMER1 value that we need to divide 732 by                            a.divisor.word = OCR1A;                            // Start out pointing to the SECOND element of the div732 array.              // We need to set to the second one because the min value of the              // OCR1A hibyte (max speed) is 01, and we'll do at most 7 shifts              // before we see a bit.  But there are 8 bits after that that              // might get looked at, so the div732 table must be 8 entries long.              // We also add 2 so that we are pointing at the last byte of each              // entry.                            b.divTable = (char *)(div732+5);				// 3 bytes per entry                            // Shift the divisor to the left and the divtable pointer to the              // right until the high bit of the divisor is set                            while (a.divisor.bytes.high_byte < 0x80) {                               a.divisor.word = a.divisor.word << 1;                b.divTable = b.divTable + 3;                               }                            // Once we have found the high bit, that tells us the fastest              // the device could possibly be rotating.  Any other set bits in              // a.divisor mean that the RPM is lower.  So what we do is clear              // the high bit and add in our partial sums only when the bits              // in the remainder are ** 0 **.  Since we just cleared the              // high bit, it'll get counted.  If all the bits are zero, all              // the sums will be added.                                  // NOTE: could be made smaller by using a.divisor.bytes.high_byte              // below, sacrificing a bit of accuracy at very high speeds.                            a.divisor.word = a.divisor.word & 0x7FFF;                            while (b.divTable > div732) {                              if (a.divisor.bytes.high_byte < 0x80) {                                  // Add in the least significant bit.  Since the table is actual                  // byte values, we don't need to deal with an ascii conversion                                  dynamicRPM[0] = dynamicRPM[0] + pgm_read_byte(b.divTable--);                  if (dynamicRPM[0] > '9') {                    dynamicRPM[0] = dynamicRPM[0] - 10;                    dynamicRPM[1]++;                  }                                  // repeat for second byte...                                  dynamicRPM[1] = dynamicRPM[1] + pgm_read_byte(b.divTable--);                  if (dynamicRPM[1] > '9') {                    dynamicRPM[1] = dynamicRPM[1] - 10;                    dynamicRPM[2]++;                  }                               // and for third, but no carry needed this time                                  dynamicRPM[2] = dynamicRPM[2] + pgm_read_byte(b.divTable--);				  // At this point, we've already subtracted 3 from b.divTable, so we're				  // ready to go for the next loop.								} else {								  // But if we didn't add anything in, we need to shift b.divTable				  				  b.divTable = b.divTable - 3;				  				}								// And finally move to the next bit								a.divisor.word = a.divisor.word << 1;															  }			  			  // And when that's all done, we just set up for the move			  			  tBytes = 3;			  a.fPtr = (char *)dynamicRPM;                            break;                        #endif                      #ifdef DYNAMIC_TIME						// Clock compiled in?                        case 0x30:								// Rev counter                          tBytes = 8;							// number of bytes we'll move down below              a.fPtr = (char *)dynamicTime;              break;                                // gets put into dynamicBuffer in reverse order.                      #endif                      default:								// This will get executed if no dynamic data            tBytes = 0x00;						// and will clear things.                       }                  // If we have bytes to transfer, and if the dynamic display        // is still active, then transfer the bytes into the display                   cli();                   if ( (dynamicType != 0x00) && (tBytes != 0x00) ) {                     b.tPtr = (char *)dynamicPtr;			// we now know dynamicPtr is valid                     // Remember, dynamicPtr points to the last byte, so we          // copy bass ackwards!                       for(;tBytes>0;tBytes--) {            *b.tPtr-- = *a.fPtr++;          }                     }                 #endif          	      sei();               }            }    // *** PORTD |= 0x2;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -