Sida 2 av 2

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 14:01:09
av newbadboy
Lyckades få till det men ärligt talat utan att ha jättekoll på vad jag hittat på eg.


Kod: Markera allt

#include "SSD1306driver_lite.h"  // include SSD1306 OLED display driver source code

#define BTN LATC.F5
#define OUT LATC.F4
#define EN4 LATC.F7
#define EN3 LATB.F4
#define EN2 LATC.F1
#define EN1 LATA.F2

#define SSD1306_SOFT_I2C
#define SSD1306_128_64

char PrintOut[5];
float Temp, TempOut, Vbat, Adc1, Adc2, Adc3, Adc4;


// Software I2C connections
sbit Soft_I2C_Scl           at RB7_bit;
sbit Soft_I2C_Sda           at RB5_bit;
sbit Soft_I2C_Scl_Direction at TRISB7_bit;
sbit Soft_I2C_Sda_Direction at TRISB5_bit;
// End Software I2C connections


void NTC_Lookup(){
            if(Temp<365)
               TempOut=10;
            if((365<=Temp)&&(Temp<414))
                    TempOut=15;
            if((414<=Temp)&&(Temp<465))
                    TempOut=20;
            if((465<=Temp)&&(Temp<511))
                    TempOut=25;
            if((511<=Temp)&&(Temp<559))
                    TempOut=30;
            if((559<=Temp)&&(Temp<604))
                    TempOut=35;
            if((604<=Temp)&&(Temp<646))
                    TempOut=40;
            if((646<=Temp)&&(Temp<686))
                    TempOut=45;
            if((686<=Temp)&&(Temp<722))
                    TempOut=50;
            if((722<=Temp)&&(Temp<755))
                    TempOut=55;
            if((755<=Temp)&&(Temp<785))
                    TempOut=60;
            if((785<=Temp)&&(Temp<812))
                    TempOut=65;
            if((812<=Temp)&&(Temp<836))
                    TempOut=70;
            if((836<=Temp)&&(Temp<858))
                    TempOut=75;
            if((858<=Temp)&&(Temp<875))
                    TempOut=80;
            if((875<=Temp)&&(Temp<893))
                    TempOut=85;
            if((893<=Temp)&&(Temp<908))
                    TempOut=90;
            if((908<=Temp)&&(Temp<922))
                    TempOut=95;
            if((922<=Temp)&&(Temp<934))
                    TempOut=100;
            if((934<=Temp)&&(Temp<944))
                    TempOut=105;
            if((944<=Temp)&&(Temp<953))
                    TempOut=110;
            if((953<=Temp)&&(Temp<961))
                    TempOut=115;
            if((961<=Temp)&&(Temp<968))
                    TempOut=120;
            if((968<=Temp)&&(Temp<974))
                    TempOut=125;
}


void Adc_Read_All(){
           Temp=ADC_Read(4);    //ANA4
           Delay_ms(10);
           NTC_Lookup();

           Vbat=ADC_Read(5);    //ANA5
           Delay_ms(10);
           Vbat=(Vbat*88)/10000;

           Adc1=ADC_Read(16);   //CH1
           if(Adc1<20)          //filter
              Adc1=0;
           Delay_ms(10);
           Adc1=(Adc1*60)/10000;
           
           Adc2=ADC_Read(18);   //CH2
           if(Adc2<20)
              Adc2=0;
           Delay_ms(10);
           Adc2=(Adc2*49)/10000;
           
           Adc3=ADC_Read(14);   //CH3
           if(Adc3<20)
              Adc3=0;
           Delay_ms(10);
           Adc3=(Adc3*39)/10000;
           
           Adc4=ADC_Read(22);   //CH4
           if(Adc4<20)
              Adc4=0;
           Delay_ms(10);
           Adc4=(Adc4*56)/10000;
}
       
void Display_Out(){
           
           SSD1306_Color = 1;
           SSD1306_TextSize(1);
          
           sprintf(PrintOut, "%.2f", Vbat);
           SSD1306_GotoXY(1, 8);
           SSD1306_Print(PrintOut);
           
           sprintf(PrintOut, "%.0f", TempOut);
           SSD1306_GotoXY(1, 16);
           SSD1306_Print(PrintOut);
           

           sprintf(&PrintOut, "%.3f", Adc1);
           SSD1306_GotoXY(1, 24);
           PrintOut[4]=0;
           SSD1306_Print(PrintOut);
           

           sprintf(PrintOut, "%.3f", Adc2);
           SSD1306_GotoXY(1, 32);
           PrintOut[4]=0;
           SSD1306_Print(PrintOut);


           sprintf(PrintOut, "%.3f", Adc3);
           SSD1306_GotoXY(1, 40);
           PrintOut[4]=0;
           SSD1306_Print(PrintOut);
           
           sprintf(PrintOut, "%.3f", Adc4);
           SSD1306_GotoXY(1, 48);
           PrintOut[4]=0;
           SSD1306_Print(PrintOut);

           SSD1306_Display();
           
           delay_ms(2000);
           SSD1306_ClearDisplay();   // clear the buffer
}


Init_main(){
       OSCCON1=0B00000001;
       OSCFRQ=0b00000110;         // set internal oscillator to 16MHz
       OSCTUNE=0b00000000;


       
       ANSELA=0b00110000;         // configure all PORTS
       ANSELB=0b01000000;
       ANSELC=0b01000101;
       TRISA=0b00110000;
       TRISB=0b01000000;
       TRISC=0b01100101;

       delay_ms(1000);     // wait a second
       Soft_I2C_Init();  // initialize I2C communication
       
       SSD1306_Begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS);
       SSD1306_Display();
       delay_ms(2000);
       SSD1306_ClearDisplay();   // clear the buffer

       ADC_Init();

       EN1=1;
       EN2=1;
       EN3=1;
       EN4=1;

}


// main function
void main(){
     Init_main();
     while(1){
          ADC_Read_All();
          Delay_ms(10);
          Display_Out();
     }
}

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 14:06:29
av johano
"%.3f" säger att du vill ha talet skrivet med tre decimaler.

float Adc1=12345.987654321;

kommer alltså dels skrivas som "12345.987" och samtidigt flöda över din buffer PrintOut[5]

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 14:14:18
av newbadboy
ja sen har jag även delat med 10000 istället för multiolicerat med 1000 i Adc_Read_all() funktionen.

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 14:27:18
av johano
Den här ser också lite konstig ut, är det verkligen avsikten att skicka _adressen_ av buffertpekaren??

"sprintf(&PrintOut, "%.3f", Adc1);"

Borde väl iofs gett en kompilatorvarning kan jag tycka.

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 14:28:05
av newbadboy
Nix .Inga varningar men & behövs inte så den tar jag bort. Tackar

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 14:36:16
av Icecap
Med &Buffer avses adressen på den tilltänkta minneslokation.
Om man har en buffer som är definierat på rätt sätt (typ u_int8_t Buffer[]) räcker det såklart att bara ange 'Buffer' då det i verkligheten ger adressen till Buffer.

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 15:07:20
av johano
newbadboy skrev:Nix .Inga varningar men & behövs inte så den tar jag bort. Tackar
Det är ju inte så att "den inte behövs", typ som om '&' vore något "extra attribut"
man kan klämma dit ibland för att få lite mer fjong i koden(!)

sprintf(&PrintOut, ...) innebär _något helt annat_ än sprintf(PrintOut, ...) och om det "fungerade"
så beror det på ren tur(*) och är en bugg som kommer bita förr eller senare.

Jag hoppas att du inte skriver ett styrsystem till en respirator.

* egentligen är det otur att det fungerade - det hade varit bättre med "stor svart rök" direkt vid såna här fel.
Min kompilator varnar direkt för detta, så jag tycker det låter konstigt att du inte fått någon varning på detta.

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 16:19:34
av Icecap
Om kompilern varnar eller inte beror på vilka settings man använder.
De kan ställas till att varna om allt - men å andra sidan kan det ge mindre erfarna programmörer skrämselshicka.

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 18:08:35
av TomasL
sprintf är väl en av de funktioner man inte skall använda, eftersom den inte är säker.
printf() is unsafe if you do not KNOW that the size of the input is safe. For example, if you are printing strings that you know from other places are no longer than 99 chars into a 120 char array, where the formatting itself adds no more than 20 characters then you are safe.

The difficulty, of course, is to judge whether the format and input is within range or not. You may for example want to format a floating point value, and you expect it to fit in %6.6f, but for some reason the value is greater than 999999, so the resulting string is longer than the format expects [and bear in mind that negative numbers take up one extra space, so a negative, large enough, number would also produce the same type of problem].

sprintf certainly has the ability to overflow.
Man får aldrig varningar om syntaxen är korrekt, men data är fel.

Re: Sprintf omvandling blir inte som jag tänkt mig

Postat: 4 september 2019, 18:30:31
av mounte
Ska ju inte lägg näsan allt för mycket i blöt (off topic med andra ord), men tänkte bara säga att din lookup-tabell (som gör det den ska väldigt effektivt) kan rationaliseras på många sätt.
För att inte dra det för långt så kan man t.ex. dr nytta av att det är en serie som ökar genom t.ex.:

Kod: Markera allt

const int limits[] = {
0, 365, 414, 465, 511, 559, 604, 646, 686, 722, 755, 785, 
812, 836, 858, 875, 893, 908, 922, 934, 944, 953, 961, 968, 974
};
const int results[] = {
-1, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70,
75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, -1
};

int NTC_Lookup(int temp_in) {
  int i = 0;
  while(temp_in >= limits[++i]);
  return results[i];
}
I de flesta fall får du nog något sämra prestanda med denna koden men den är enklare att underhålla.
Sedan om du har fallet med en serie som kan approximeras med en funktion så kan du implementera den matematiska funktionen.

Värt att notera för prestanda-freaks är följande: binär sökning / bisection fungerar nog riktigt fint för att inte behöva traversera listan hela tiden.
Not 2. Om man vet att temperaturen inte förändras drastiskt så kan man börja med att söka från den gräns man använde senast.
newbadboy skrev:Lyckades få till det men ärligt talat utan att ha jättekoll på vad jag hittat på eg.


Kod: Markera allt

#include "SSD1306driver_lite.h"  // include SSD1306 OLED display driver source code

#define BTN LATC.F5
#define OUT LATC.F4
#define EN4 LATC.F7
#define EN3 LATB.F4
#define EN2 LATC.F1
#define EN1 LATA.F2

#define SSD1306_SOFT_I2C
#define SSD1306_128_64

char PrintOut[5];
float Temp, TempOut, Vbat, Adc1, Adc2, Adc3, Adc4;


// Software I2C connections
sbit Soft_I2C_Scl           at RB7_bit;
sbit Soft_I2C_Sda           at RB5_bit;
sbit Soft_I2C_Scl_Direction at TRISB7_bit;
sbit Soft_I2C_Sda_Direction at TRISB5_bit;
// End Software I2C connections


void NTC_Lookup(){
            if(Temp<365)
               TempOut=10;
            if((365<=Temp)&&(Temp<414))
                    TempOut=15;
            if((414<=Temp)&&(Temp<465))
                    TempOut=20;
            if((465<=Temp)&&(Temp<511))
                    TempOut=25;
            if((511<=Temp)&&(Temp<559))
                    TempOut=30;
            if((559<=Temp)&&(Temp<604))
                    TempOut=35;
            if((604<=Temp)&&(Temp<646))
                    TempOut=40;
            if((646<=Temp)&&(Temp<686))
                    TempOut=45;
            if((686<=Temp)&&(Temp<722))
                    TempOut=50;
            if((722<=Temp)&&(Temp<755))
                    TempOut=55;
            if((755<=Temp)&&(Temp<785))
                    TempOut=60;
            if((785<=Temp)&&(Temp<812))
                    TempOut=65;
            if((812<=Temp)&&(Temp<836))
                    TempOut=70;
            if((836<=Temp)&&(Temp<858))
                    TempOut=75;
            if((858<=Temp)&&(Temp<875))
                    TempOut=80;
            if((875<=Temp)&&(Temp<893))
                    TempOut=85;
            if((893<=Temp)&&(Temp<908))
                    TempOut=90;
            if((908<=Temp)&&(Temp<922))
                    TempOut=95;
            if((922<=Temp)&&(Temp<934))
                    TempOut=100;
            if((934<=Temp)&&(Temp<944))
                    TempOut=105;
            if((944<=Temp)&&(Temp<953))
                    TempOut=110;
            if((953<=Temp)&&(Temp<961))
                    TempOut=115;
            if((961<=Temp)&&(Temp<968))
                    TempOut=120;
            if((968<=Temp)&&(Temp<974))
                    TempOut=125;
}


void Adc_Read_All(){
           Temp=ADC_Read(4);    //ANA4
           Delay_ms(10);
           NTC_Lookup();

           Vbat=ADC_Read(5);    //ANA5
           Delay_ms(10);
           Vbat=(Vbat*88)/10000;

           Adc1=ADC_Read(16);   //CH1
           if(Adc1<20)          //filter
              Adc1=0;
           Delay_ms(10);
           Adc1=(Adc1*60)/10000;
           
           Adc2=ADC_Read(18);   //CH2
           if(Adc2<20)
              Adc2=0;
           Delay_ms(10);
           Adc2=(Adc2*49)/10000;
           
           Adc3=ADC_Read(14);   //CH3
           if(Adc3<20)
              Adc3=0;
           Delay_ms(10);
           Adc3=(Adc3*39)/10000;
           
           Adc4=ADC_Read(22);   //CH4
           if(Adc4<20)
              Adc4=0;
           Delay_ms(10);
           Adc4=(Adc4*56)/10000;
}
       
void Display_Out(){
           
           SSD1306_Color = 1;
           SSD1306_TextSize(1);
          
           sprintf(PrintOut, "%.2f", Vbat);
           SSD1306_GotoXY(1, 8);
           SSD1306_Print(PrintOut);
           
           sprintf(PrintOut, "%.0f", TempOut);
           SSD1306_GotoXY(1, 16);
           SSD1306_Print(PrintOut);
           

           sprintf(&PrintOut, "%.3f", Adc1);
           SSD1306_GotoXY(1, 24);
           PrintOut[4]=0;
           SSD1306_Print(PrintOut);
           

           sprintf(PrintOut, "%.3f", Adc2);
           SSD1306_GotoXY(1, 32);
           PrintOut[4]=0;
           SSD1306_Print(PrintOut);


           sprintf(PrintOut, "%.3f", Adc3);
           SSD1306_GotoXY(1, 40);
           PrintOut[4]=0;
           SSD1306_Print(PrintOut);
           
           sprintf(PrintOut, "%.3f", Adc4);
           SSD1306_GotoXY(1, 48);
           PrintOut[4]=0;
           SSD1306_Print(PrintOut);

           SSD1306_Display();
           
           delay_ms(2000);
           SSD1306_ClearDisplay();   // clear the buffer
}


Init_main(){
       OSCCON1=0B00000001;
       OSCFRQ=0b00000110;         // set internal oscillator to 16MHz
       OSCTUNE=0b00000000;


       
       ANSELA=0b00110000;         // configure all PORTS
       ANSELB=0b01000000;
       ANSELC=0b01000101;
       TRISA=0b00110000;
       TRISB=0b01000000;
       TRISC=0b01100101;

       delay_ms(1000);     // wait a second
       Soft_I2C_Init();  // initialize I2C communication
       
       SSD1306_Begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS);
       SSD1306_Display();
       delay_ms(2000);
       SSD1306_ClearDisplay();   // clear the buffer

       ADC_Init();

       EN1=1;
       EN2=1;
       EN3=1;
       EN4=1;

}


// main function
void main(){
     Init_main();
     while(1){
          ADC_Read_All();
          Delay_ms(10);
          Display_Out();
     }
}