Programa C orientado a microcontrolador

Iniciado por Jaimelito, 6 Noviembre 2015, 01:16 AM

0 Miembros y 1 Visitante están viendo este tema.

Jaimelito

Hola, estoy atascado intentando aprender y dando mas que palos de ciego con el lenguaje C orientado a micros atmel.

Alguien en el foro estaria dispuesto a ayudarme a terminar el codigo esta casi listo pero no consigo hacerlo funcionar.
el codigo 1 LED esta correcto y mi intento de duplicar entradas y salidas es el codigo 2 LED y ese es el que no funciona.

http://pastebin.com/u/Jaimelito_

Un saludo.


furciorifa

Podrías en sí poner el problema en código geShi? ya que pastebin está prohibido en mi país, ojalá lo puedas resolver.

Jaimelito


Jaimelito

1LED#define F_CPU 8000000UL

// PWM Mode
#define PHASE 0b00000001
#define FAST  0b00000011

#define BLINK_ON_POWER      // blink once when power is received
                            // (helpful on e-switch lights, annoying on dual-switch lights)
#define VOLTAGE_MON         // Comment out to disable - ramp down and eventual shutoff when battery is low
#define MODES           0,4,10,120,255      // Must be low to high, and must start with 0
#define MODE_PWM        0,PHASE,FAST,FAST,PHASE     // Define one per mode above. 0 tells the light to go to sleep
                             
#define ADC_LOW         130 // When do we start ramping
#define ADC_CRIT        120 // When do we shut the light off
#define ADC_DELAY       188 // Delay in ticks between low-bat rampdowns (188 ~= 3s)

#define MOM_EXIT_DUR    128 // .16ms each

#define FULL_MODE  -1  // A mode of "-1" will be interpreted as Full mode

#include <avr/pgmspace.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/wdt.h> 
#include <avr/eeprom.h>
#include <avr/sleep.h>
//#include <avr/power.h>


#define SWITCH_PIN  PB3     // what pin the switch is connected to, which is Star 4
#define PWM_PIN     PB1
#define VOLTAGE_PIN PB2
#define ADC_CHANNEL 0x01    // MUX 01 corresponds with PB2
#define ADC_DIDR    ADC1D   // Digital input disable bit corresponding with PB2
#define ADC_PRSCL   0x06    // clk/64

#define PWM_LVL1     OCR0B   // OCR0B is the output compare register for PB1

#define DB_PRES_DUR 0b00000001 // time before we consider the switch pressed (after first realizing it was pressed)
#define DB_REL_DUR  0b00001111 // time before we consider the switch released
                               // each bit of 1 from the right equals 16ms, so 0x0f = 64ms

// Switch handling
#define LONG_PRESS_DUR   128 // How many WDT ticks until we consider a press a long press                     

const uint8_t modes[]     = { MODES    };
const uint8_t mode_pwm[] = { MODE_PWM };
volatile int8_t mode_idx = 0;
volatile uint8_t press_duration = 0;
volatile uint8_t low_to_high = 1;
volatile uint8_t in_momentary = 0;

// Debounce switch press value

int is_pressed()
{
    // Keep track of last switch values polled
    static uint8_t buffer = 0x00;
    // Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
    buffer = (buffer << 1) | ((PINB & (1 << SWITCH_PIN)) == 0);
     
    return (buffer & DB_REL_DUR);
}


inline void next_mode() {
    if (++mode_idx >= sizeof(modes)) {
        // Wrap around
        mode_idx = 1;
    } 
}

inline void prev_mode() {
    if (mode_idx == 0) {
        // Wrap around
        mode_idx = sizeof(modes) - 1;
    } else {
        --mode_idx;
    }
}

inline void PCINT_on() {
    // Enable pin change interrupts
    GIMSK |= (1 << PCIE);
}

inline void PCINT_off() {
    // Disable pin change interrupts
    GIMSK &= ~(1 << PCIE);
}

// Need an interrupt for when pin change is enabled to ONLY wake us from sleep.
// All logic of what to do when we wake up will be handled in the main loop.
EMPTY_INTERRUPT(PCINT0_vect);

inline void WDT_on() {
    // Setup watchdog timer to only interrupt, not reset, every 16ms.
    cli();                          // Disable interrupts
    wdt_reset();                    // Reset the WDT
    WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
    WDTCR = (1<<WDIE);               // Enable interrupt every 16ms
    sei();                          // Enable interrupts
}

inline void WDT_off()
{
    cli();                          // Disable interrupts
    wdt_reset();                    // Reset the WDT
    MCUSR &= ~(1<<WDRF);          // Clear Watchdog reset flag
    WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
    WDTCR = 0x00;                   // Disable WDT
    sei();                          // Enable interrupts
}

inline void ADC_on() {
    ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
    DIDR0 |= (1 << ADC_DIDR);                         // disable digital input on ADC pin to reduce power consumption
    ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
}

inline void ADC_off() {
    ADCSRA &= ~(1<<7); //ADC off
}

void sleep_until_switch_press()
{
    // This routine takes up a lot of program memory :(
    // Turn the WDT off so it doesn't wake us from sleep
    // Will also ensure interrupts are on or we will never wake up
    WDT_off();
    // Need to reset press duration since a button release wasn't recorded
    press_duration = 0;
    // Enable a pin change interrupt to wake us up
    // However, we have to make sure the switch is released otherwise we will wake when the user releases the switch
    while (is_pressed()) {
        _delay_ms(16);
    }
    PCINT_on();
    // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
    //set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    // Now go to sleep
    sleep_mode();
    // Hey, someone must have pressed the switch!!
    // Disable pin change interrupt because it's only used to wake us up
    PCINT_off();
    // Turn the WDT back on to check for switch presses
    WDT_on();
    // Go back to main program
}

// The watchdog timer is called every 16ms
ISR(WDT_vect) {

    static uint8_t  adc_ticks = ADC_DELAY;
    static uint8_t  lowbatt_cnt = 0;

    if (is_pressed()) {
        if (press_duration < 255) {
            press_duration++;
        }
         
         

        if (press_duration == LONG_PRESS_DUR) {
            // Long press
            if (mode_idx == 0) {
                // TODO: if we were off, enter strobe mode
                mode_idx = 4;
            } else {
                // if we were on, turn off
                mode_idx = 0;
            }
        }
         
        // Just always reset turbo timer whenever the button is pressed
        //turbo_ticks = 0;
        // Same with the ramp down delay
        adc_ticks = ADC_DELAY;
     
    } else {
         
         
         
        // Not pressed
        if (press_duration > 0 && press_duration < LONG_PRESS_DUR) {
            // Short press
            if (mode_idx == 4) {
                // short-press from strobe goes to second-highest mode
                mode_idx = sizeof(modes)-4;
            }
            else { // regular short press
                if (low_to_high) {
                    next_mode();
                } else {
                    prev_mode();
                } 
            }
        } else {
             
            // Only do voltage monitoring when the switch isn't pressed
        #ifdef VOLTAGE_MON
            if (adc_ticks > 0) {
                --adc_ticks;
            }
            if (adc_ticks == 0) {
                // See if conversion is done
                if (ADCSRA & (1 << ADIF)) {
                    // See if voltage is lower than what we were looking for
                    if (ADCH < ((mode_idx == 1) ? ADC_CRIT : ADC_LOW)) {
                        ++lowbatt_cnt;
                    } else {
                        lowbatt_cnt = 0;
                    }
                }
                 
                // See if it's been low for a while
                if (lowbatt_cnt >= 4) {
                    prev_mode();
                    lowbatt_cnt = 0;
                    // If we reach 0 here, main loop will go into sleep mode
                    // Restart the counter to when we step down again
                    adc_ticks = ADC_DELAY;
                }
                 
                // Make sure conversion is running for next time through
                ADCSRA |= (1 << ADSC);
            }
        #endif
        }
        press_duration = 0;
    }
}

int main(void)

    // Set all ports to input, and turn pull-up resistors on for the inputs we are using
    DDRB = 0x00;
    PORTB = (1 << SWITCH_PIN);

    // Set the switch as an interrupt for when we turn pin change interrupts on
    PCMSK = (1 << SWITCH_PIN);
     
    // Set PWM pin to output

    DDRB = (1 << PWM_PIN);

    // Set timer to do PWM for correct output pin and set prescaler timing
    TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
     
    // Turn features on or off as needed
    #ifdef VOLTAGE_MON
    ADC_on();
    #else
    ADC_off();
    #endif
    ACSR   |=  (1<<7); //AC off
     

     
#ifdef BLINK_ON_POWER
    // blink once to let the user know we have power
    TCCR0A = PHASE | 0b00100000;  // Only use the normal output
    PWM_LVL1 = 60;
    _delay_ms(3);
    PWM_LVL1 = 0;
    _delay_ms(1);
#endif

    // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_until_switch_press();
     
    uint8_t last_mode_idx = 0;
    int8_t real_mode_idx = 0;
     
    while(1) {
        // We will never leave this loop.  The WDT will interrupt to check for switch presses and
        // will change the mode if needed.  If this loop detects that the mode has changed, run the
        // logic for that mode while continuing to check for a mode change.
        if (mode_idx != last_mode_idx) {
            real_mode_idx = mode_idx;
            // The WDT changed the mode.
            if (mode_idx == FULL_MODE) {
                // strobe should use second-highest mode
                real_mode_idx = sizeof(modes) - 4;
            } else if (mode_idx > 0) {
                // No need to change the mode if we are just turning the light off
                // Check if the PWM mode is different
                if (mode_pwm[last_mode_idx] != mode_pwm[mode_idx]) {
                    TCCR0A = mode_pwm[mode_idx] | 0b10100000;  // Use both outputs     
                }
            }
            PWM_LVL1     = modes[real_mode_idx];
            last_mode_idx = mode_idx;
            // Handle strobe mode
            if (mode_idx == FULL_MODE) {
                PWM_LVL1=255;
                TCCR0A=PHASE | 0b00100000;
             
            }
            if (real_mode_idx == 0) {
                _delay_ms(1); // Need this here, maybe instructions for PWM output not getting executed before shutdown?
                // Go to sleep
                sleep_until_switch_press();
            }
        }
    }

    return 0; // Standard Return Code
}

2LED
#define F_CPU 8000000UL
#define PHASE 0b00000001
#define FAST  0b00000011
#define BLINK_ON_POWER     
#define VOLTAGE_MON       
#define MODES           0,4,10,120,255   
#define MODES2          0,2,32,125,255
#define MODE_PWM        0,PHASE,FAST,FAST,PHASE
#define MODE_PWM2        0,PHASE,FAST,FAST,PHASE
#define ADC_LOW         130
#define ADC_CRIT        120
#define ADC_DELAY       188
#define MOM_EXIT_DUR    128
#define FULL_MODE  -1
#include <avr/pgmspace.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/wdt.h> 
#include <avr/eeprom.h>
#include <avr/sleep.h>
//#include <avr/power.h>
#define SWITCH_PIN  PB3   
#define SWITCH_PIN2 PB4   
#define PWM_PIN     PB1
#define PWM_PIN2     PB0
#define VOLTAGE_PIN PB2
#define ADC_CHANNEL 0x01 
#define ADC_DIDR    ADC1D 
#define ADC_PRSCL   0x06 

#define PWM_LVL1     OCR0B 
#define PWM_LVL2     OCR0A 

#define DB_PRES_DUR 0b00000001
#define DB_REL_DUR  0b00001111


#define LONG_PRESS_DUR   128
/*
* The actual program
* =========================================================================
*/

/*
* global variables
*/
const uint8_t modes[]     = { MODES    };
const uint8_t modes2[]     = { MODES2};
const uint8_t mode_pwm[] = { MODE_PWM };
const uint8_t mode_pwm2[] = { MODE_PWM2 };
volatile int8_t mode_idx = 0;
volatile int8_t mode_idx2 = 0;
volatile uint8_t press_duration = 0;
volatile uint8_t press_duration2 = 0;
volatile uint8_t low_to_high = 1;
volatile uint8_t in_momentary = 0;

// Debounce switch press value

int is_pressed()
{
    // Keep track of last switch values polled
    static uint8_t buffer = 0x00;
    // Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
    buffer = (buffer << 1) | ((PINB & (1 << SWITCH_PIN)) == 0);
     
    return (buffer & DB_REL_DUR);
}

int is_pressed2()
{
         // Keep track of last switch values polled
         static uint8_t buffer2 = 0x00;
         // Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
         buffer2 = (buffer2 << 1) | ((PINB & (1 << SWITCH_PIN2)) == 0);
         
         return (buffer2 & DB_REL_DUR);
}

inline void next_mode() {
         if (++mode_idx >= sizeof(modes)) {
                 // Wrap around
                 mode_idx = 1;
         }
}

inline void prev_mode() {
         if (mode_idx == 0) {
                 // Wrap around
                 mode_idx = sizeof(modes) - 1;
                 } else {
                 --mode_idx;
         }
}
inline void next_mode2() {
        if (++mode_idx2 >= sizeof(modes2)) {
                // Wrap around
                mode_idx2= 1;
        }
}

inline void prev_mode2() {
        if (mode_idx2 == 0) {
                // Wrap around
                mode_idx2 = sizeof(modes2) - 1;
                } else {
                --mode_idx2;
        }
}

inline void PCINT_on() {
    // Enable pin change interrupts
    GIMSK |= (1 << PCIE);
}

inline void PCINT_off() {
    // Disable pin change interrupts
    GIMSK &= ~(1 << PCIE);
}

// Need an interrupt for when pin change is enabled to ONLY wake us from sleep.
// All logic of what to do when we wake up will be handled in the main loop.
EMPTY_INTERRUPT(PCINT0_vect);

inline void WDT_on() {
    // Setup watchdog timer to only interrupt, not reset, every 16ms.
    cli();                          // Disable interrupts
    wdt_reset();                    // Reset the WDT
    WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
    WDTCR = (1<<WDIE);               // Enable interrupt every 16ms
    sei();                          // Enable interrupts
}

inline void WDT_off()
{
    cli();                          // Disable interrupts
    wdt_reset();                    // Reset the WDT
    MCUSR &= ~(1<<WDRF);          // Clear Watchdog reset flag
    WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
    WDTCR = 0x00;                   // Disable WDT
    sei();                          // Enable interrupts
}

inline void ADC_on() {
    ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
    DIDR0 |= (1 << ADC_DIDR);                         // disable digital input on ADC pin to reduce power consumption
    ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
}

inline void ADC_off() {
    ADCSRA &= ~(1<<7); //ADC off
}

void sleep_until_switch_press()
{
    // This routine takes up a lot of program memory :(
    // Turn the WDT off so it doesn't wake us from sleep
    // Will also ensure interrupts are on or we will never wake up
    WDT_off();
    // Need to reset press duration since a button release wasn't recorded
    press_duration = 0;
    // Enable a pin change interrupt to wake us up
    // However, we have to make sure the switch is released otherwise we will wake when the user releases the switch
    while (is_pressed()||is_pressed2()) {
        _delay_ms(16);
    }
    PCINT_on();
    // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
    //set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    // Now go to sleep
    sleep_mode();
    // Hey, someone must have pressed the switch!!
    // Disable pin change interrupt because it's only used to wake us up
    PCINT_off();
    // Turn the WDT back on to check for switch presses
    WDT_on();
    // Go back to main program
}

// The watchdog timer is called every 16ms
ISR(WDT_vect) {

    static uint8_t  adc_ticks = ADC_DELAY;
    static uint8_t  lowbatt_cnt = 0;

    if (is_pressed()) {
        if (press_duration < 255) {
            press_duration++;
        }
     if (is_pressed2()) {
             if (press_duration2 < 255) {
                     press_duration2++;
             }
         

        if (press_duration == LONG_PRESS_DUR) {
            // Long press
            if (mode_idx == 0) {
                // TODO: if we were off, enter strobe mode
                mode_idx = 4;
            } else {
                // if we were on, turn off
                mode_idx = 0;
            }
        }
         
                if (press_duration2 == LONG_PRESS_DUR) {
                        // Long press
                        if (mode_idx2 == 0) {
                                // TODO: if we were off, enter strobe mode
                                mode_idx2 = 4;
                                } else {
                                // if we were on, turn off
                                mode_idx2 = 0;
                        }
                }
        // Just always reset turbo timer whenever the button is pressed
        //turbo_ticks = 0;
        // Same with the ramp down delay
        adc_ticks = ADC_DELAY;
     
    } else {
         
         
         
        // Not pressed
        if (press_duration > 0 && press_duration < LONG_PRESS_DUR) {
            // Short press
            if (mode_idx == 4) {
                // short-press from strobe goes to second-highest mode
                mode_idx = sizeof(modes)-4;
            }
            else { // regular short press
                if (low_to_high) {
                    next_mode();
                } else {
                    prev_mode();
                } 
            }
                         if (press_duration2 > 0 && press_duration2 < LONG_PRESS_DUR) {
                                 // Short press
                                 if (mode_idx2 == 4) {
                                         // short-press from strobe goes to second-highest mode
                                         mode_idx2 = sizeof(modes2)-4;
                                 }
                                 else { // regular short press
                                         if (low_to_high) {
                                                 next_mode2();
                                                 } else {
                                                 prev_mode2();
                                         }
                                 }
        } else {
             
            // Only do voltage monitoring when the switch isn't pressed
        #ifdef VOLTAGE_MON
            if (adc_ticks > 0) {
                --adc_ticks;
            }
            if (adc_ticks == 0) {
                // See if conversion is done
                if (ADCSRA & (1 << ADIF)) {
                    // See if voltage is lower than what we were looking for
                    if (ADCH < ((mode_idx == 1) ? ADC_CRIT : ADC_LOW)) {
                        ++lowbatt_cnt;
                    } else {
                        lowbatt_cnt = 0;
                    }
                }
                 
                // See if it's been low for a while
                if (lowbatt_cnt >= 4) {
                    prev_mode();
                    lowbatt_cnt = 0;
                    // If we reach 0 here, main loop will go into sleep mode
                    // Restart the counter to when we step down again
                    adc_ticks = ADC_DELAY;
                }
                 
                // Make sure conversion is running for next time through
                ADCSRA |= (1 << ADSC);
            }
        #endif
        }
        press_duration = 0;
                }
                                 }
                         }
                         }
int main(void)
{     // Set all ports to input, and turn pull-up resistors on for the inputs we are using
    DDRB = 0x00;
    PORTB = (1 << SWITCH_PIN) | (1 << SWITCH_PIN2);

    // Set the switch as an interrupt for when we turn pin change interrupts on
    PCMSK = (1 << SWITCH_PIN) | (1 << SWITCH_PIN2);
     
    // Set PWM pin to output

    DDRB  = (1 << PWM_PIN) | (1 << PWM_PIN2);

    // Set timer to do PWM for correct output pin and set prescaler timing
    TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
     
    // Turn features on or off as needed
    #ifdef VOLTAGE_MON
    ADC_on();
    #else
    ADC_off();
    #endif
    ACSR   |=  (1<<7); //AC off
     

     
#ifdef BLINK_ON_POWER
    // blink once to let the user know we have power
    TCCR0A = PHASE | 0b00100000;  // Only use the normal output
    PWM_LVL1 =60;
    PWM_LVL2 = 60;
    _delay_ms(3);
    PWM_LVL1 = 0;
        PWM_LVL2 = 0;
    _delay_ms(1);
#endif

    // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_until_switch_press();
     
    uint8_t last_mode_idx = 0;
    int8_t real_mode_idx = 0;
uint8_t last_mode_idx2 = 0;
         int8_t real_mode_idx2 = 0;
     
    while(1) {
        // We will never leave this loop.  The WDT will interrupt to check for switch presses and
        // will change the mode if needed.  If this loop detects that the mode has changed, run the
        // logic for that mode while continuing to check for a mode change.
        if (mode_idx != last_mode_idx) {
            real_mode_idx = mode_idx;
            // The WDT changed the mode.
            if (mode_idx == FULL_MODE) {
                // strobe should use second-highest mode
                real_mode_idx = sizeof(modes) - 4;
            } else if (mode_idx > 0) {
                // No need to change the mode if we are just turning the light off
                // Check if the PWM mode is different
                if (mode_pwm[last_mode_idx] != mode_pwm[mode_idx]) {
                    TCCR0A = mode_pwm[mode_idx] | 0b10100000;  // Use both outputs     
                }
            }
            PWM_LVL1     = modes[real_mode_idx];
            last_mode_idx = mode_idx;
            // Handle strobe mode
            if (mode_idx == FULL_MODE) {
                PWM_LVL1=255;
                TCCR0A=PHASE | 0b00100000;
             
      }
                        if (mode_idx2 != last_mode_idx2) {
                                real_mode_idx2 = mode_idx2;
                                // The WDT changed the mode.
                                if (mode_idx2 == FULL_MODE) {
                                        // strobe should use second-highest mode
                                        real_mode_idx2 = sizeof(modes2) - 4;
                                        } else if (mode_idx2 > 0) {
                                        // No need to change the mode if we are just turning the light off
                                        // Check if the PWM mode is different
                                        if (mode_pwm2[last_mode_idx2] != mode_pwm2[mode_idx2]) {
                                                TCCR0A = mode_pwm2[mode_idx2] | 0b10100000;  // Use both outputs
                                        }
                                }
                                PWM_LVL2     = modes2[real_mode_idx2];
                                last_mode_idx2 = mode_idx2;
                                // Handle strobe mode
                                if (mode_idx2 == FULL_MODE) {
                                        PWM_LVL2=255;
                                        TCCR0A=PHASE | 0b00100000;
                                       
                                }

                        if ((real_mode_idx == 0) && (real_mode_idx2 == 0 ) ){
                _delay_ms(1); // Need this here, maybe instructions for PWM output not getting executed before shutdown?
                // Go to sleep
                sleep_until_switch_press();
                          }
   
                        }
                }
        }
    return 0; // Standard Return Code
}