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

📄 main.c

📁 AVR单片机控制16个不同的LED分时显示组成不同的图案2
💻 C
字号:
/******************************************Added blinking function - after the wheel has started turning, but has been stopped for ~5 secs, and before power_off timeout, flash all of the LEDs (making one more visible at a stop sign/light). - Jonathan Karpick  27 Nov 2007******************************************SpokePOV V1.0 firmwareSpokePOV firmware is distributed under CC license. for more info on CC go to www.creativecommons.orgfor more info on SpokePOV go to www.ladyada.net/make/spokepovCreative Commons DeedAttribution-NonCommercial-ShareAlike 2.5You are free:    * to copy, distribute, display, and perform the work    * to make derivative worksUnder the following conditions:Attribution.   You must attribute the work in the manner specified by the    author or licensor.Noncommercial.    You may not use this work for commercial purposes.Share Alike.    if you alter, transform, or build upon this work, you may    distribute the resulting work only under a license identical to this one.    * for any reuse or distribution, you must make clear to others       the license terms of this work.    * Any of these conditions can be waived if you get permission       from the copyright holder.Your fair use and other rights are in no way affected by the above.A more detailed version of this license is available at:http://creativecommons.org/licenses/by-nc-sa/2.5/legalcode******************************************/#include <avr/io.h>#include <avr/interrupt.h>//#include <avr/signal.h>#include <util/delay.h>#include "main.h"#include "eeprom.h"#define EEMWE   2#define EEWE    1#define ANIMATE 1uint8_t animation_time = 6;volatile uint16_t anim_timer = 0;volatile uint16_t anim_eeprom_offset = 0;#define HALL_DEBOUNCE_THRESH 4  #define BUTTON_DEBOUNCE  100  // in ms#define NUM_PIXELS 256     // max is 255 (since it is 8 bit value)#define STANDBY_TIMEOUT 5       // in seconds#define POWEROFF_TIMEOUT 2*60   // in seconds// address that stores the rotation offset#define EEPROM_ROTATION_OFFSET 0x00// address that stores the mirror flag#define EEPROM_MIRROR 0x01#define EEPROM_ANIMATION 0x02// For blinking mode - JKK#define STOPPED 1#define RUNNING 0volatile uint8_t running_state;volatile uint8_t pause_count;uint8_t mirror;uint8_t fleds[4], bleds[4];  // front and back LEDsvolatile uint8_t hall_debounce;volatile uint16_t sensor_timer;volatile uint8_t stopcomputertx = 0;SIGNAL (SIG_TIMER0_OVF) { // PORTB |= 0x1;  if (hall_debounce != 0xFF)    hall_debounce++;    if (sensor_timer != 0xFFFF)    sensor_timer++;//  PORTB &= ~0x1;}volatile uint16_t curr_eeprom_addr = 0;// gets called once per pixelSIGNAL (SIG_OUTPUT_COMPARE1A) {     // Timer 1 compare A : Pixel timer  uint16_t eepromaddr;  sei();//  PORTB |= 0x2;  eepromaddr = curr_eeprom_addr;  if (sensor_timer < ((F_CPU/NUM_PIXELS)/256 * STANDBY_TIMEOUT)) {        // less than ~5 seconds since last sensor//    PORTA |= 0x1;    eepromaddr %= NUM_PIXELS * 4;    spieeprom_read_into_leds(eepromaddr + anim_eeprom_offset, FRONT);    if (mirror) {      spieeprom_read_into_leds(anim_eeprom_offset + (1024UL-eepromaddr), BACK);    } else {      LATCH_SELECT_PORT |= _BV(BACK);      NOP; NOP; NOP; NOP;      LATCH_SELECT_PORT &= ~_BV(BACK);    }     // make sure no other interrupt tries to write to this address at the same    // time, shut off interrupts. this is very quick, though.       cli();        if (eepromaddr == (curr_eeprom_addr%(NUM_PIXELS*4))) {      curr_eeprom_addr = eepromaddr+4;      }          //curr_eeprom_addr = eepromaddr;    sei();    //    PORTA &= ~0x1;  } else {     //replaced by blinking mode  - JKK//    PORTA |= 0x2;               if (running_state == RUNNING) {        running_state = STOPPED;        fleds[0] = fleds[1] = fleds[2] = fleds[3] = 0x0;        bleds[0] = bleds[1] = bleds[2] = bleds[3] = 0xFF;        pause_count = 0;        OCR1A = 0xFFFF;  // 0.008192 seconds = 122 Hz        TCNT1 = 0;    } else {        pause_count++;        if (pause_count > 30) {  // 1/4 second          fleds[0] = fleds[1] = fleds[2] = fleds[3] = fleds[3] ^ 0xFF;          bleds[0] = bleds[1] = bleds[2] = bleds[3] = bleds[3] ^ 0xFF;          pause_count = 0;        }    }    clock_leds(FRONT);    clock_leds(BACK);    //    PORTA &= ~0x2;  }//  PORTB &= ~0x2;}SIGNAL (SIG_INT0) {  uint16_t timer;  PORTB |= 0x4;  timer = 0;  while (! (BUTTON_PIN & _BV(BUTTON))) {    // while button is still held down    timer++;    _delay_ms(1);//    _delay_ms(1);  }  // button must be held down for a bit  if (timer > BUTTON_DEBOUNCE) {    if (timer < 500) {      // a short button press (less than 1/2 second) resets      // set up watchdog timer that will reset the device for us      WDTCSR = _BV(WDE);      while (1);    } else {      // long button press means shutdown      sensor_timer = 0xFFFF;    }  }  PORTB &= ~0x4;}SIGNAL (SIG_INT1) { // Hall effect sensor   PORTB |= 0x8;     // Toggle B3 on  if (hall_debounce > HALL_DEBOUNCE_THRESH) {    stopcomputertx = 1;#ifdef ANIMATE  if (anim_timer != animation_time) {    anim_timer++;  } else {    anim_timer = 0;    anim_eeprom_offset += 1024;  }#endif    // we know the number of ms since the last hall sensor trigger    // and there are 128 radial 'pixels' per sweep so divide to get    // the necessary ms between the pixel interrupts    // JKK - I think it's actually 256 pixels        // now just make timer1 trigger at that rate!        TCNT1 = 0;        if ((sensor_timer < 0xFF) && (sensor_timer > 0x3)) {      OCR1A = (sensor_timer << 8) | TCNT0;      TCNT0 = 0;      curr_eeprom_addr = 	(internal_eeprom_read(EEPROM_ROTATION_OFFSET) % NUM_PIXELS) * 4;      mirror = internal_eeprom_read(EEPROM_MIRROR);      TCCR1B |= _BV(CS10);      TIMSK |= _BV(OCIE1A);      //for blinking mode - JKK      running_state = RUNNING;    } else {    /*  set_led(2, FRONT);      set_led(2, BACK);      TCCR1B &= ~_BV(CS10);  */      running_state = STOPPED;      fleds[0] = fleds[1] = fleds[2] = fleds[3] = 0x0;      bleds[0] = bleds[1] = bleds[2] = bleds[3] = 0xFF;    }       sensor_timer = 0;  }  hall_debounce = 0;  PORTB &= ~0x8;    // Toggle B3 off}void ioinit(void) {  DDRD = 0x73; // input on PD2 (button), PD3 (sensor), all other output  DDRB = 0xDF; // input on MOSI/DI (for SPI), all others output  // deselect EEPROM  PORTB = _BV(SPIEE_CS);  // turn on pullup for button// and power and pullup for sensor  PORTD = (_BV(BUTTON) | _BV(SENSOR) | _BV(SENSORPOWER))      & ~_BV(FRONT) & ~_BV(BACK);  // and deselect latches  // interrupt on INT1 pin falling edge (sensor triggered) and  // interrupt on INT0 pin falling edge (button press!)  MCUCR = _BV(ISC11) & ~_BV(ISC01) & ~_BV(ISC00) &  ~_BV(ISC10);  // turn on interrupts!  GIMSK = _BV(INT1) | _BV(INT0);  TCCR0A = 0; // normal, overflow (count up to 256 == num pixels)  //TCCR0B = _BV(CS00); // no clock div  TCCR0B = _BV(CS02); // clk/256  TIMSK |= _BV(TOIE0);  // turn on overflow interrupt    // create pixel timer (T1)  TCCR1A = 0;  TCCR1B = _BV(WGM12);  hall_debounce = 0;  sensor_timer = 0;    // for blinking mode - JKK  running_state = RUNNING;}void delay_ms(unsigned char ms){  unsigned short delay_count = F_CPU / 4000;    unsigned short cnt;  asm volatile ("\n"		"L_dl1%=:\n\t"		"mov %A0, %A2\n\t"		"mov %B0, %B2\n"		"L_dl2%=:\n\t"		"sbiw %A0, 1\n\t"		"brne L_dl2%=\n\t"		"wdr\n\t"		"dec %1\n\t" "brne L_dl1%=\n\t":"=&w" (cnt)		:"r"(ms), "r"((unsigned short) (delay_count))		);}void clock_leds(uint8_t select) {  uint8_t *leds;  if (select == FRONT)    leds = fleds;  else    leds = bleds;  spi_transfer(leds[3]);  spi_transfer(leds[2]);  spi_transfer(leds[1]);  spi_transfer(leds[0]);  LATCH_SELECT_PORT |= _BV(select);  NOP; NOP; NOP; NOP;  LATCH_SELECT_PORT &= ~_BV(select);}void set_led(uint8_t led, uint8_t side) {  uint8_t *leds;  if (side == FRONT)    leds = fleds;  else    leds = bleds;  leds[0] = leds[1] = leds[2] = leds[3] = 0xFF;  leds[led/8] = ~_BV(led%8);  clock_leds(side);}void test_leds(void) {  uint8_t i;  for(i=0; i< 33; i++) {    set_led(i, FRONT);    set_led(33-i, BACK);    _delay_ms(50);  }}  int main(void) {  uint8_t buff[16];  uint8_t i, n;  uint8_t cmd;  uint16_t addr;  cmd = MCUSR;  // find out why we reset  // clear reset flags immediately  MCUSR = 0;  // turn on watchdog timer immediately, this protects against  // a 'stuck' system by resetting it  WDTCSR = _BV(WDE) | _BV(WDP2) | _BV(WDP1); // 1 second    ioinit();  if ((cmd & _BV(PORF)) != 0)    test_leds();  // test the LEDs only on power reset  set_led(cmd+2, FRONT);  // show the reason for the last reset  //set_led(2, FRONT);  set_led(2, BACK);  animation_time = internal_eeprom_read(EEPROM_ANIMATION);  sei();    // look for computer commands    while (1) {    sei();    cmd = tx_computer_byte(0);    if (cmd == 0)      break;    else       cli();    sensor_timer = 0;      // overloaded to reset communications timeout    switch (cmd) {    case COMP_CMD_RDEEPROM:    case COMP_CMD_RDEEPROM16:      if  (cmd == COMP_CMD_RDEEPROM16)	n = 16;      else	n = 1;      addr = tx_computer_byte(0);      addr <<= 8;      addr |= tx_computer_byte(0);            if ((addr & 0x8000) != 0) {      	tx_computer_byte(internal_eeprom_read(addr & 0xFF));      } else {		spieeprom_read(addr, buff, n);	for (i=0; i<n; i++) {	  tx_computer_byte(buff[i]);	}      }      tx_computer_byte(COMP_SUCCESS);      break;    case COMP_CMD_WREEPROM:    case COMP_CMD_WREEPROM16:      if (cmd == COMP_CMD_WREEPROM16)	n = 16;      else	n = 1;      addr = tx_computer_byte(0);      addr <<= 8;      addr |= tx_computer_byte(0);      set_led((addr/16)%32,FRONT);       for (i=0; i<n; i++) {	buff[i] = tx_computer_byte(0);      }      tx_computer_byte(COMP_SUCCESS);      if ((addr & 0x8000) != 0) {	internal_eeprom_write(addr & 0xFF, buff[0]);      } else {	spieeprom_write(addr, buff, n);      }      break;    }  }  //WDTCSR = _BV(WDE) | _BV(WDP2); // 1/4 second  while (1) {    PORTD |= 0x1;    asm("wdr");    PORTD &= ~0x1;    if (sensor_timer == 0xFFFF) {      // ~3 minutes since last sensor      // no interrupts until we're done      cli();      // turn off all LEDs      set_led(0, FRONT);      set_led(0, BACK);            // turn off sensor      SENSOR_PORT &= ~_BV(SENSORPOWER);            // deselect EEPROM      SPIEE_CS_PORT |= _BV(SPIEE_CS);      // pull CS high to deselect            //go into sleep mode      // turn off WDT (use interrupt to reset!)      WDTCSR |= _BV(WDCE) | _BV(WDE);      WDTCSR = 0;      MCUCR |= _BV(SM1) | _BV(SM0) | _BV(SE);      sei();      asm("sleep");    }  }  PORTD |= 0x2;}uint8_t tx_computer_byte(uint8_t b) {  uint8_t v;  DDRA = 0x0;           // outputs  DDRB = 0x5F;          // input on MOSI/DI (for SPI), all others output  USICR = _BV(USIWM0) | _BV(USICS1);  USIDR = b;                 // transfer 0x0  USISR = _BV(USIOIF);       // ready  while (! (USISR & _BV(USIOIF)) ) {    asm("wdr");    if (sensor_timer == 0xFFFF) {       stopcomputertx = 1;    }    if (stopcomputertx) {      break;    }  }  v = USIDR;  DDRB = 0xDF;   USICR = 0;  return v;}uint8_t spi_transfer(uint8_t c) {  USIDR = c;  USISR = _BV(USIOIF);  while (! (USISR & _BV(USIOIF))) {    USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC);    //NOP;  // slow down so that the eeprom isnt overwhelmed  }  return USIDR;}uint8_t internal_eeprom_read(uint8_t addr) {  loop_until_bit_is_clear(EECR, EEWE); // wait for last write to finish  EEAR = addr;  EECR |= _BV(EERE);        // start EEPROM read  return EEDR;            // takes only 1 cycle}void internal_eeprom_write(uint8_t addr, uint8_t data) {  loop_until_bit_is_clear(EECR, EEWE); // wait for last write to finish  EEAR = addr;  EEDR = data;  cli();                // turn off interrupts   EECR |= _BV(EEMWE);     // these instructions must happen within 4 cycles  EECR |= _BV(EEWE);  sei();                // turn on interrupts again} 

⌨️ 快捷键说明

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