Skapa ett programvalsystem i C

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

För ett ganska bra tag sen gjorde jag (i mina ögon) klart mjukvaran. Riggade upp kretsen på ett prototypkort och programmerade.
Givetvis går det inte som planerat - inget händer.

Det bästa tipset jag fått när det gäller att felsöka i koden är att bryta ner i delar, och se till att varje enskild funktion fungerar som tänkt. Satt flertalet timmar och försökte göra det men jag tror inte jag är skapt för att programmera, det blir bara rörigare. Jag rörde till i koden så vida pass att jag fick återgå till originalprogrammet igen.
I förhoppning att slutföra det här, eller i alla fall känna att jag är "på väg", finns det någon vänlig själ som kan hjälpa mig på traven? Gissningsvis så blir det svårt i och med ett (i mina ögon) stort program och väldigt PIC-specifikt. Blir riktigt besviken på mig själv att så många projekt bara ligger pga oklar kod.

Kod: Markera allt

/************************************************************
*                         HEADLAMP                          *
*                                                           *
* MCU: PIC12F1840                                           *
* S/W version: 0.1                                          *
* Creator: Magnus                                           *
*                                                           *
* I/O: PORT     PIN No        Function                      *
*      RA0      7             Buzzer                        *
*      RA1      6             Indicator LED, RED            *
*      RA2      5             LED output                    *
*      RA3      4             Pushbutton                    *
*      RA4      3             Batt voltage (ADC AN3)        *
*      RA5      2             Indicator LED, GREEN          *
*      VDD      1             Batt power                    *
*      VSS      8             GND                           *
*                                                           *
* TODO: CLOCK                                               *
*           Internal OSC 8 Mhz.......................OK!    *
*       I/Os                                                *
*           RA0, RA1, R2, RA5 outputs................OK!    *
*           RA3, RA4 inputs..........................OK!    *
*         TYPE                                              *
*             RA3 Digital, RA4 Analog................OK!    *
*       PWM (1 kHz)..................................       *
*       TIMER x 3                                           *
*         Timer0 = Basic timer.......................OK!    *
*         Timer1 = SoftPWM timer for buzzer..........OK!    *
*         Timer2 = Timer dedicated to PWM-module.....OK!    *
*       ADC..........................................       *
*                                                           *
* ONGOING:                                                  *
*                                                           *
************************************************************/

#include <stdint.h>

#define BUTTON_R PORTA.B3
#define BUTTON_W LATA.B3
#define G_LED_R PORTA.B5
#define G_LED_W LATA.B5
#define R_LED_R PORTA.B1
#define R_LED_W LATA.B1
#define BUZZER_R PORTA.B0
#define BUZZER_W LATA.B0

void init(){

   // Setup of oscillator clock. 8MHz to be used as Fosc
   OSCCON = 0b01110010;

   // Setup of I/O:s
   PORTA = 0;
   TRISA = 0b00011000;
   ANSELA = 0b00010000;      // Turn on Analog SELect for RA4
   ADCON0 = 0b00001111;
   ADCON1 = 0b00100011;

   // Setup of internal voltage reference, 2.048V will be used
   FVRCON = 0b10000010;

   // Setup of interrupts
   INTCON.GIE = 1;
   INTCON.PEIE = 1;
   INTCON.TMR0IE = 1;
   PIR1 = 0;                 // Clear all interrupt flags
   PIE1.TMR1IE = 0;
   T1CON = 0x01;             // Enable T1
   INTCON.IOCIE = 1;
   IOCAN.IOCAN0 = 1;

   // Setup of basic timer to be used with debounce and counter, rollover at 9,9ms
   OPTION_REG = 0b00000110;          // 1/128 Prescaler
   TMR0 = 100;                       // Pre-set value

   // Setup of basic timer to be used with buzzer, frequency at 1,5kHz
   TMR1H = 0xFC;
   TMR1L = 0x18;

   // Setup of PWM
   CCP1CON = 0b00111100 ;    // ..00.... Use 8 bit res, 11 = use the two LSB's
                             // ....1100 P1A Active High, P1B Active High
   PR2 = 0xFF;               // PWM period (100)
   CCPR1L = 0xFF;
   T2CON = 0b00000111;       // T2 on with prescaler set to 64
}

uint8_t buttonStatus;
uint8_t pushRegistered;
uint8_t buzzdurationCounter;
uint16_t battcheckCounter;

enum processorStates {
   ERROR,
   RUNNING,
   GOTO_SLEEP,
   RECOVER
};

enum lampFunctions {
   OFF,
   LED_HIGH,
   LED_LOW
};

enum buzzLengths {
   SHORT,
   LONG
};

enum processorStates processorState = GOTO_SLEEP;
enum lampFunctions lampFunction = OFF;
enum buzzLengths buzzLength = SHORT;

/***********************************************************************/

void setSleep(){

   TRISA = 0b00111111;             // Set all I/O:s to inputs
   FVRCON.FVREN = 0;               // Turn off Voltage reference
   VREGCON = 0x03;                 // Use low power sleep
   if(!buttonStatus){              // Only put to sleep when button has been released
     processorState = RECOVER;
     asm sleep;
   }
}

/***********************************************************************/

uint8_t get_voltage(){

   uint8_t voltage_level = 0;

   if(FVRCON.FVRRDY){
      voltage_level = ADRESH;
      ADCON0.GO = 1;
   } else {
      processorState = ERROR;
   }

   return voltage_level;

}

/***********************************************************************/

void recover_from_sleep(){

   uint8_t startupVoltage = 0;

   TRISA = 0b00011000;             // Restore all I/O:s
   IOCAF.IOCAF3 = 0;               // Reset the IOC flag bit
   FVRCON.FVREN = 1;               // Enable Internal Voltage reference

   while(!FVRCON.FVRRDY){}

   startupVoltage = get_voltage();

   if(startupVoltage >= 190) {
      processorState = RUNNING;
   } else {
      processorState = ERROR;
   }
}

/***********************************************************************/

void do_buzz(enum buzzLengths buzzLength){

   switch(buzzlength){
      case SHORT:
         PIR1.TMR1IE = 1;
         buzzdurationCounter = 60;              // Minimum 50 as base value
         break;
      case LONG:
         PIR1.TMR1IE = 1;
         buzzdurationCounter = 90;              // Minimum 50 as base value
         break;
      default:
        processorState = ERROR;
        break;
   }
}

/***********************************************************************/

void battcheck(){

   uint8_t batt_level = 0;
   batt_level = get_voltage();
   
   // Check voltage each 2 minute. Decrease interval av make a buzz below 3,6V
   // (225 ADC value). Turn of LED and put lamp in ERROR state below 3V (187 ADC value))
   
   if(batt_level >= 226) {
      battcheckCounter = 0;                    // New battcheck every 2 min
   }
   else if((batt_level <= 225) && (batt_level >= 200)) {
      do_buzz(SHORT);
      battcheckCounter = 6000;                 // New battcheck and buzz every minute
   }
   else if((batt_level <= 199) && (batt_level >= 189)) {
      do_buzz(SHORT);
      battcheckCounter = 9000;                 // New battcheck and buzz every 30 sec
   }
   else if((batt_level <= 188) && (batt_level >= 187)) {
      do_buzz(LONG);
      battcheckCounter = 11900;                // New battcheck and buzz every sec
   }
   else if(batt_level <= 186) {
      processorState = ERROR;
   }
}

/***********************************************************************/

void steady(){

   if(buttonStatus && (!pushRegistered)){              // When button has been debounced
      pushRegistered = 1;                              // and not been registered yet then
                                                       // do the following.
      lampFunction = (lampFunction + 1);
      
      if(lampFunction >= 3){
         lampFunction = 0;
      }
   }
   
   switch(lampFunction) {
      case OFF:
        processorState = GOTO_SLEEP;
        break;
      case LED_HIGH:
        CCPR1L = 0xFF;                            // PWM at 100% DC
        if(12000 <= battcheckCounter) {           // 12000 = 10ms x 2 min
           battcheck();
        }
        break;
      case LED_LOW:
        CCPR1L = 0x7F;                            // PWM at 50% DC
        if(12000 <= battcheckCounter) {           // 12000 = 10ms x 2 min
           battcheck();
        }
      default:
        processorState = ERROR;
        break;
   }
}

/***********************************************************************/

void warning(){

   R_LED_W = 1;

}

/***********************************************************************/

void interrupt(){

   if(INTCON.TMR0IF) {                            // This interrupt occurs each 10ms
                                                  // and is only turned off in sleep
      static uint8_t debounceCounter;
      
      battcheckCounter++;

      INTCON.TMR0IF= 0;                           // Reset interruptflag
      TMR0 = 100;                                 // Pre-set timer value
      debounceCounter <<= 1;
      debounceCounter |= BUTTON_R;

      if (debounceCounter == 0x00) {              // Om byte:n endast innehåller 0:or
          buttonStatus = 1;                       // så sätt status till 1
      }
      else if (debounceCounter == 0xFF) {         // Om byte:n endast innehåller 1:or
               buttonStatus = 0;                  // så sätt status till 0
               pushRegistered = 0;
      }
      
      if(PIR1.TMR1IE){
         
         buzzdurationCounter--;
         if(50 >= buzzdurationCounter){
            PIR1.TMR1IE = 0;
         }
      }
   }
   
   if(PIR1.TMR1IF) {                            // If enabled, this interrupt occurs
                                                  // with a freq of 2kHz
      PIR1.TMR1IF = 0;
      TMR1H = 0xFC;
      TMR1L = 0x18;
      BUZZER_W &= ~BUZZER_W;

   }
}

/***********************************************************************/

void main(void) {

   init();

   while(1){

     switch(processorState) {
        case ERROR:
          warning();
          break;
        case RUNNING:
          steady();
          break;
        case GOTO_SLEEP:
          setSleep();
          break;
        case RECOVER:
          recover_from_sleep();
          break;
        default:
          warning();
          break;
      }
   }
}
Användarvisningsbild
abcabc
Inlägg: 188
Blev medlem: 13 september 2014, 21:59:16

Re: Skapa ett programvalsystem i C

Inlägg av abcabc »

Jag ser inga speciellt fel.
Man ser speciellt god kunskap i C med bra kommentarer, include, struct, enum, uniom, typer och uint_8t mm på ett rätt sätt.
Du tycks vara en professionell tränad programmerare, men även sådana kan ju fråga om råd här.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Det var väldigt snällt av dig. Speciellt då jag lärt mig allt från EF.
Jobbar verkligen inte professionellt med det här.

Jag undrar inte om någon kan se något fel utan vägledning om hur jag kan bryta ner just det här programmet i smådelar för att felsöka.
janno
Inlägg: 403
Blev medlem: 11 oktober 2009, 07:34:45
Ort: Västerås

Re: Skapa ett programvalsystem i C

Inlägg av janno »

Mitt förslag är att blinka/tända lysdioder (jag gör hög/låg ibland runt en rutin eller bara i början, då kan man mäta tider) när olika saker händer. Är det saker som händer ofta så sätter jag dit oscilloskopet för att titta vad som händer och mäta med det. Fast du kanske inte har någon utgång ledig som kan användas för debugging?
Har jag bara en utgång ledig så flyttar jag min debug blinkning längre o längre fram i koden tills den uppför sig som den borde. I värsta fall lånar jag en utgång som ska användas för något annat tills jag kommit så långt att den ordinarie funktionen måste testas. Med lite tur och eftertanke kan man använda nån annan pinne när den funktionen testas.
Testa allt även sånt som du är säker på fungerar, har varit med om att min init() hänger programmet.

/J
Användarvisningsbild
Mickecarlsson
EF Sponsor
Inlägg: 3743
Blev medlem: 15 april 2017, 18:06:15
Ort: Malmö
Kontakt:

Re: Skapa ett programvalsystem i C

Inlägg av Mickecarlsson »

Disclaimer:
Jag har "bara" programmerat Arduinos och har inte mycker erfarenhet i ren pic-programmerad.
Din processorState, Du sätter den till GOTO_SLEEP sen kollar du i rutinen setSleep om en knapp inte är aktiv, då sätter du state RECOVER och gör asm sleep.
Vaknar inte programmet då direkt?

I din interruptrutin som du kallar var 10 ms har du en 16-bits räknare "battcheckCounter++;" den äts upp på lite över 5 minuter.

Micke
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Tack för era svar.
Det var ungefär så jag försökte göra janno, men det blev för rörigt. Ska se om jag hinner göra ett nytt försök ikväll och kanske har lite mer specifika problem att framföra istället.

@Mickecarlsson:
Min avsikt är att när MCU:n ska ner i sleep så kallas denna funktion. Sleep:en ska enbart utföras efter man släppt knappen.
Det sista den gör inann läggdags är att sätta state:n till RECOVER då jag vill att den ska vakna med det satt. I och med att programmet aldrig hinner gå tillbaka till while(1)-loopen innan sleep så bör RECOVER inte göra någon skillnad. Det är i alla fall min avsikt.

Visst körs inte programmet när processorn sover?

Kod: Markera allt

void setSleep(){

   TRISA = 0b00111111;             // Set all I/O:s to inputs
   FVRCON.FVREN = 0;               // Turn off Voltage reference
   VREGCON = 0x03;                 // Use low power sleep
   if(!buttonStatus){              // Only put to sleep when button has been released
     processorState = RECOVER;
     asm sleep;
   }
}
janno
Inlägg: 403
Blev medlem: 11 oktober 2009, 07:34:45
Ort: Västerås

Re: Skapa ett programvalsystem i C

Inlägg av janno »

Jag läste lite i databladet och sleep fortsätter med instruktionen efter sleep när den vaknar. Om GIE är aktiv kommer den sedan köra avbrottsrutinen annars fortsätter den köra koden i huvudprogrammet.
Går PICn i sleep? Om det finns en externt avbrott väntande kommer sleep att köras som en NOP.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Uppskattar verkligen att ni tar er tid.

asm sleep; är sista instruktionen i den funktionen så bör den fortsätta till huvudprogrammet efter sleep. Nästa steg där blir den sk RECOVER där den återställer allt.
GIE aktiverar jag vid init och bibehåller alltid aktiv, eller det är är i alla fall avsikten. Jag rör i alla fall inte denna bit i INTCON-registret mer.

Hmmmmmm, vart har jag lagt in att "ett tryck" ska väcka maskineriet? Nu blir jag alldeles mörkrädd.

EDIT: Ursäkta, glömmer svara på frågorna.
Ja den verkar gå i sleep för när jag tar bort min "bort-kommentering" för sleep-funktionen så blir allt svart, och förblir så.

EDIT2: OK, IOCAN.IOCAN0 = 1; ändrat till IOCAN.IOCAN3 = 1; för att låta knappen aktivera en Interrupt-On-Change-flagga. Gjorde tyvärr ingen skillnad men tror att detta är en del jag absolut inte lyckats med.
Bifogar koden som den ser ut med ändringarna.

Kod: Markera allt

/************************************************************
*                         HEADLAMP                          *
*                                                           *
* MCU: PIC12F1840                                           *
* S/W version: 0.1                                          *
* Creator: Magnus                                           *
*                                                           *
* I/O: PORT     PIN No        Function                      *
*      RA0      7             Buzzer                        *
*      RA1      6             Indicator LED, RED            *
*      RA2      5             LED output                    *
*      RA3      4             Pushbutton                    *
*      RA4      3             Batt voltage (ADC AN3)        *
*      RA5      2             Indicator LED, GREEN          *
*      VDD      1             Batt power                    *
*      VSS      8             GND                           *
*                                                           *
* TODO: CLOCK                                               *
*           Internal OSC 8 Mhz.......................OK!    *
*       I/Os                                                *
*           RA0, RA1, R2, RA5 outputs................OK!    *
*           RA3, RA4 inputs..........................OK!    *
*         TYPE                                              *
*             RA3 Digital, RA4 Analog................OK!    *
*       PWM (1 kHz)..................................       *
*       TIMER x 3                                           *
*         Timer0 = Basic timer.......................OK!    *
*         Timer1 = SoftPWM timer for buzzer..........OK!    *
*         Timer2 = Timer dedicated to PWM-module.....OK!    *
*       ADC..........................................       *
*                                                           *
* ONGOING:                                                  *
*                                                           *
************************************************************/

#include <stdint.h>

#define BUTTON_R PORTA.B3
#define BUTTON_W LATA.B3
#define G_LED_R PORTA.B5
#define G_LED_W LATA.B5
#define R_LED_R PORTA.B1
#define R_LED_W LATA.B1
#define BUZZER_R PORTA.B0
#define BUZZER_W LATA.B0

void init(){

   // Setup of oscillator clock. 8MHz to be used as Fosc
   OSCCON = 0b01110010;

   // Setup of I/O:s
   PORTA = 0b00000010;
   TRISA = 0b00011000;
   ANSELA = 0b00010000;      // Turn on Analog SELect for RA4
   ADCON0 = 0b00001111;
   ADCON1 = 0b00100011;

   // Setup of internal voltage reference, 2.048V will be used
   FVRCON = 0b10000010;

   // Setup of interrupts
   INTCON.GIE = 1;
   INTCON.PEIE = 1;
   INTCON.TMR0IE = 1;
   PIR1 = 0;                 // Clear all interrupt flags
   PIE1.TMR1IE = 0;
   T1CON = 0x01;             // Enable T1
   INTCON.IOCIE = 1;
   IOCAN.IOCAN3 = 1;

   // Setup of basic timer to be used with debounce and counter, rollover at 9,9ms
   OPTION_REG = 0b00000110;          // 1/128 Prescaler
   TMR0 = 100;                       // Pre-set value

   // Setup of basic timer to be used with buzzer, frequency at 1,5kHz
   TMR1H = 0xFC;
   TMR1L = 0x18;

   // Setup of PWM
   CCP1CON = 0b00111100 ;    // ..00.... Use 8 bit res, 11 = use the two LSB's
                             // ....1100 P1A Active High, P1B Active High
   PR2 = 0xFF;               // PWM period (100)
   CCPR1L = 0xFF;
   T2CON = 0b00000111;       // T2 on with prescaler set to 64
}

uint8_t buttonStatus;
uint8_t pushRegistered;
uint8_t buzzdurationCounter;
uint16_t battcheckCounter;

enum processorStates {
   ERROR,
   RUNNING,
   GOTO_SLEEP,
   RECOVER
};

enum lampFunctions {
   OFF,
   LED_HIGH,
   LED_LOW
};

enum buzzLengths {
   SHORT,
   LONG
};

enum processorStates processorState = GOTO_SLEEP;
enum lampFunctions lampFunction = OFF;
enum buzzLengths buzzLength = SHORT;

/***********************************************************************/

void setSleep(){

   TRISA = 0b00111111;             // Set all I/O:s to inputs
   FVRCON.FVREN = 0;               // Turn off Voltage reference
   VREGCON = 0x03;                 // Use low power sleep
   if(!buttonStatus){              // Only put to sleep when button has been released
     processorState = RECOVER;
     asm sleep;
   }
}

/***********************************************************************/

uint8_t get_voltage(){

   uint8_t voltage_level = 0;

   if(FVRCON.FVRRDY){
      voltage_level = ADRESH;
      ADCON0.GO = 1;
   } else {
      processorState = ERROR;
   }

   return voltage_level;

}

/***********************************************************************/

void recover_from_sleep(){

   uint8_t startupVoltage = 0;

   TRISA = 0b00011000;             // Restore all I/O:s
   IOCAF.IOCAF3 = 0;               // Reset the IOC flag bit
   FVRCON.FVREN = 1;               // Enable Internal Voltage reference

   while(!FVRCON.FVRRDY){}

   startupVoltage = get_voltage();

   if(startupVoltage >= 190) {
      processorState = RUNNING;
   } else {
      processorState = ERROR;
   }
}

/***********************************************************************/

void do_buzz(enum buzzLengths buzzLength){

   switch(buzzlength){
      case SHORT:
         PIR1.TMR1IE = 1;
         buzzdurationCounter = 60;              // Minimum 50 as base value
         break;
      case LONG:
         PIR1.TMR1IE = 1;
         buzzdurationCounter = 90;              // Minimum 50 as base value
         break;
      default:
        processorState = ERROR;
        break;
   }
}

/***********************************************************************/

void battcheck(){

   uint8_t batt_level = 0;
   batt_level = get_voltage();
   
   // Check voltage each 2 minute. Decrease interval av make a buzz below 3,6V
   // (225 ADC value). Turn of LED and put lamp in ERROR state below 3V (187 ADC value))
   
   if(batt_level >= 226) {
      battcheckCounter = 0;                    // New battcheck every 2 min
   }
   else if((batt_level <= 225) && (batt_level >= 200)) {
      do_buzz(SHORT);
      battcheckCounter = 6000;                 // New battcheck and buzz every minute
   }
   else if((batt_level <= 199) && (batt_level >= 189)) {
      do_buzz(SHORT);
      battcheckCounter = 9000;                 // New battcheck and buzz every 30 sec
   }
   else if((batt_level <= 188) && (batt_level >= 187)) {
      do_buzz(LONG);
      battcheckCounter = 11900;                // New battcheck and buzz every sec
   }
   else if(batt_level <= 186) {
      processorState = ERROR;
   }
}

/***********************************************************************/

void steady(){

   if(buttonStatus && (!pushRegistered)){              // When button has been debounced
      pushRegistered = 1;                              // and not been registered yet then
                                                       // do the following.
      lampFunction = (lampFunction + 1);
      
      if(lampFunction >= 3){
         lampFunction = 0;
      }
   }
   
   switch(lampFunction) {
      case OFF:
        processorState = GOTO_SLEEP;
        break;
      case LED_HIGH:
        CCPR1L = 0xFF;                            // PWM at 100% DC
        if(12000 <= battcheckCounter) {           // 12000 = 10ms x 2 min
           battcheck();
        }
        break;
      case LED_LOW:
        CCPR1L = 0x7F;                            // PWM at 50% DC
        if(12000 <= battcheckCounter) {           // 12000 = 10ms x 2 min
           battcheck();
        }
      default:
        processorState = ERROR;
        break;
   }
}

/***********************************************************************/

void warning(){

   R_LED_W = 0;

}

/***********************************************************************/

void interrupt(){

   if(INTCON.TMR0IF) {                            // This interrupt occurs each 10ms
                                                  // and is only turned off in sleep
      static uint8_t debounceCounter;
      
      battcheckCounter++;

      INTCON.TMR0IF= 0;                           // Reset interruptflag
      TMR0 = 100;                                 // Pre-set timer value
      debounceCounter <<= 1;
      debounceCounter |= BUTTON_R;

      if (debounceCounter == 0xFF) {              // Om byte:n endast innehåller 1:or
          buttonStatus = 1;                       // så sätt status till 1
      }
      else if (debounceCounter == 0x00) {         // Om byte:n endast innehåller 0:or
               buttonStatus = 0;                  // så sätt status till 0
               pushRegistered = 0;
      }
      
      if(PIR1.TMR1IE){
         
         buzzdurationCounter--;
         if(50 >= buzzdurationCounter){
            PIR1.TMR1IE = 0;
         }
      }
   }
   
   if(PIR1.TMR1IF) {                            // If enabled, this interrupt occurs
                                                  // with a freq of 2kHz
      PIR1.TMR1IF = 0;
      TMR1H = 0xFC;
      TMR1L = 0x18;
      BUZZER_W &= ~BUZZER_W;

   }
}

/***********************************************************************/

void main(void) {

   init();

   while(1){

     switch(processorState) {
        case ERROR:
          warning();
          break;
        case RUNNING:
          steady();
          break;
        case GOTO_SLEEP:
          setSleep();
          break;
        case RECOVER:
          recover_from_sleep();
          break;
        default:
          warning();
          break;
      }
   }
}
hummel
Inlägg: 2259
Blev medlem: 28 november 2009, 10:40:52
Ort: Stockholm

Re: Skapa ett programvalsystem i C

Inlägg av hummel »

Kör du programmet i simulatorn? Där borde du lösa det enkelt.
janno
Inlägg: 403
Blev medlem: 11 oktober 2009, 07:34:45
Ort: Västerås

Re: Skapa ett programvalsystem i C

Inlägg av janno »

I databladet star detta:
For the device to wake-up through an interrupt event, the corresponding interrupt enable bit must be enabled. Wake-up will occur regardless of the state of the GIE bit. If the GIE bit is disabled, the device continues execution at the instruction after the SLEEP instruction. If the GIE bit is enabled, the device executes the instruction after the SLEEP instruction, the device will then call the Interrupt Service Routine. In cases where the execution of the instruction following SLEEP is not desirable, the user should have a NOP after the SLEEP instruction.

Jag markerade en del some kan ha betydelse i vissa fall. Du kanske ska ha en "asm nop" direkt efter sleep.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Har gjort ett par försök att förstå mig på det i mikroC Pro for PIC men aldrig riktigt förstått hur det fungerar.

@janno: Ska testa samt läsa lite!
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Lade till en nop efter sleep. Gjorde dock ingen skillnad men håller med om att den ska nog vara där, så låter den kvarstå.

Testade debuggern och den "hänger sig" vid while(!FVRCON.FVRRDY){} nedan. Kan det vara så enkelt? Eller blir det kanske dumt då inte debuggern automagiskt sätter denna bit?

Kod: Markera allt

void recover_from_sleep(){

   uint8_t startupVoltage = 0;

   TRISA = 0b00011000;             // Restore all I/O:s
   IOCAF.IOCAF3 = 0;               // Reset the IOC flag bit
   FVRCON.FVREN = 1;               // Enable Internal Voltage reference

   while(!FVRCON.FVRRDY){}

   startupVoltage = get_voltage();

   if(startupVoltage >= 190) {
      processorState = RUNNING;
   } else {
      processorState = ERROR;
   }
}
kodar-holger
EF Sponsor
Inlägg: 916
Blev medlem: 26 maj 2014, 12:54:35
Ort: Karlskoga

Re: Skapa ett programvalsystem i C

Inlägg av kodar-holger »

Jag har inte följt den här tråden och borde kanske läst tillbaka lite för att förstå din kod bättre men kastar mig ut på djupt vatten ändå.

Det är inte världens största program direkt. Typ 1/1000 av vad ett stort program är, men redan på den här nivån är det svårt att förstå vad det är tänkt att göra. Så lägg gärna en stund på att skriva ett inlägg som förklarar hur du tänkt att det skall fungera. Det är dessutom en del i felsökningen för när man försöker förklara hur man tänkt för någon annan kommer man ofta på själv vart det är fel. Vi kan ju alla läsa din kod så det är alltså inte en förklaring av vad du gör utan vad du tänkt göra och varför.

På andras inlägg verkar ju sleep vara en mina och det kan jag tänka mig. Kan du till att börja med förhindra att den går i sleep? På den stund jag läste koden inbillar jag mig att det bara är att kommentera bort setSleep() anropet i main så skall allt fungera som tänkt bortsett från att man aldrig går i sleep.

Kod som man är osäker på hur och om den fungerar burkar man singelstega sig igenom. Typ svårt på ett inbäddat system i den här klassen men simulatorer brukar vara bra alternativ även om man missar hårdvarukopplingen. Så vitt jag minns har mplab inbyggd simulator men du körde visst inte den...

Har man ingen simulator får man vara det själv. Enkelstega koden i huvudet. Tänk efter rad för rad vad som händer där. Jobbigare när man kör med interrupt eftersom man måste fundera på ett antal race-conditions där interrupten uppdaterar delade variabler.

När ingen dubugger är tillgänglig är det printf-debuggning som gäller. Den inbäddade varianten är att allokera en eller flera ut-pinnar till att visa tillstånd. Ex.vis kunde du sätta en pinne till 1 när du går in i interruptrutinen och släcka den när du går ut. Då kan du se med ditt oscilloskop om du får interrupt alls och i den takt du förväntar dig.

C-kompilatorer vill gärna optimera koden som genereras. Det innebär att variabler kanske inte uppdateras när man tror att dom gör det. Speciellt slår det mot kod som körs i interrupt. "volatile"-märkning av variabler hjälper mot sånt för då kan kompilatorn förstå att den här variabel läser någon annan än bara den här rutinen så jag måste verkligen skriva till den. Kan du ha drabbats av sånt i din interruptrutin? Kompilera med optimering avslaget och se om det gör någon skillnad.

Sen ett par specifics utan att kunna plattformen utantill:

din steady()-rutin ser ut att anropas gång på gång på gång när man inte är i sleep eller på väg ur sleep. Om ingen knapp är nedtryckt innebär det så vitt jag förstår att PWM-registren skrivs om hela tiden. Fungerar det? Alltså jag vet inte, jag har inte läst databladet. Kan det vara så att räknaren nollas eller vad som nu händer hela tiden så att du inte får nån PWM-signal ut?

Sen blir man ju påmind om vilket äckligt språk C är. Ett riktigt programspråk (Ada) hade aldrig tillåtit det här:

Kod: Markera allt

      lampFunction = (lampFunction + 1);
     
      if(lampFunction >= 3){
         lampFunction = 0;
      }
Det där fungerar och är säkert i de flesta C-programmerares ögon helt acceptabelt. Men lampFunction är en enum. Behandla den som det hela tiden. Du förutsätter att din enum genereras så att OFF = 0, LED_LOW=1 och LED_HIGH=2 men du har inte deklarerat den så. Det kan man men för att ge en kompilator friheten att optimera så bör man inte göra det. Och eftersom du bara har dessa tre tillstånd borde du inte referera till det fjärde.

Kod: Markera allt

      if(lampFunction < LED_HIGH){
         lampFunction++;
      }else{
         lampFunction=OFF;
      }
Användarvisningsbild
ecenier
Inlägg: 1104
Blev medlem: 13 december 2007, 17:51:42
Ort: Älvsjö
Kontakt:

Re: Skapa ett programvalsystem i C

Inlägg av ecenier »

Detta stämmer väl inte,

Kod: Markera allt

#define BUTTON_R PORTA.B3
#define BUTTON_W LATA.B3
#define G_LED_R PORTA.B5
#define G_LED_W LATA.B5
#define R_LED_R PORTA.B1
#define R_LED_W LATA.B1
#define BUZZER_R PORTA.B0
#define BUZZER_W LATA.B0
Det borde väl vara RA# överallt där det står B#.

Men jag är inte hemma på just den här varianten av C.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Nej, inte här. B står för Bit så tex PORTA.B3 skulle säkert kunna skrivas som PORT.RA3 i andra IDE:er.

@kodar-holger:
Återkommer till dig senare men tack så länge!
Skriv svar