Microchip'i C keel
#1
Õpin seda ja tekkis tüüpiline algaja küsimus. Neti abiga palju targemaks ei saanud. Küsimus on andmetüüpide konverteerimises.
Saan DS1337-kellalt aja ja tahan moodustada faili nimega yyyy-mm-dd.csv (aasta-kuu-päev).
Hüva, kellalt saadav aasta on WORD tüüpi, muu aga BYTE:
Kood:
typedef struct
{
    BYTE    tm_control;
    BYTE    tm_status;
    BYTE    tm_sec;
    BYTE    tm_min;
    BYTE    tm_hour;
    BYTE    tm_wday;
    BYTE    tm_mday;
//    BYTE    tm_mon_cent;
    WORD    tm_year;
    BYTE    tm_mon;
    BYTE    tm_yday;
    BYTE    tm_isdst;
} timetype;
Ilmselt peab ajad muundama stringideks ja siis nad kokku liitma. Proovisin:
Kood:
char FailiName[32];                            // logifaili nime moodustamiseks
char *pFailiName;                            // viit faili nimele
char * itoa( int value,char * string );

pFailiName=FailiName;    // viitab failinime arrayle
FailiName=(itoa ((DS_Aeg->tm_year,pFailiName);//+"-"+(itoa (DS_Aeg->tm_mon,pFailiName)+(itoa (DS_Aeg->tm_mday,pFailiName));
//esialgu testin vaid aastanumbri konvertimist

....

logFile = FSfopenpgm(FailiName+".csv","w"); // see töötab kui anda ette stringikonstant nt logi.csv
.....
Syntax error reas kus FailiName moodustatakse.
Mida paganat... ???
Vasta
#2
Failinime moodustamisel on äkki järgmisest näitest abi:
Kood:
#include <string.h>

int main(char** args, int argc) {
    char fileName[255];
    int year = 2012;
    int month = 6;
    int day = 7;
    sprintf(&fileName, "%4d-%2d-%2d.cvs", year, month, day);
}

See võib mitte kompileeruda, mul pole hetkel C-kompilaatorit käepärast, et seda kontrollida ja ei kasuta C-d väga tihti.

Kui sa pead silmas seda rida, kus sa teed FileName + ".csv", siis üldiselt (kui just Microchip pole mingit erandit teinud) C-s on stringid char-i massiivid, "+"-märgiga neid omaval kokku liita ei saa, selleks on meetod "strcat". Ilmselt kahe konstandi korral "+" siiski töötab.

Vasta
#3

FailiName=(itoa ((DS_Aeg->tm_year,pFailiName);

Tundub et sulgusid on puudu.
Vasta
#4
Tänud nõu andmast, probleem on lahendatud. Osa oli sellest, et ma ei saa ikka C bürokraatiale (minu meelest) pihta ja osa oli C18 erinippides.
Lõplik koodilõik tuli säärane:
Kood:
...
char FailiName[32];                            // logifaili nime moodustamiseks
....
                        rtc_get (DS_Aeg);                            // vaatame kella, WORD year, BYTE - muud aja muutujad
                        year=DS_Aeg->tm_year;
                        month=DS_Aeg->tm_mon;
                        day=DS_Aeg->tm_mday;
                        hours=DS_Aeg->tm_hour;
                        minutes=DS_Aeg->tm_min;
                        seconds=DS_Aeg->tm_sec;
                        itoa (year,FailiName);
                        btoa (month,tmpstr);
                        strcatpgm2ram (FailiName, "-");
                        strcat (FailiName, tmpstr);
                        btoa (day,tmpstr);
                        strcatpgm2ram (FailiName, "-");
                        strcat (FailiName, tmpstr);
                        strcatpgm2ram (FailiName, ".csv");
                        strcpypgm2ram(fo_mode,"a");
                           logFile = FSfopen(FailiName, fo_mode);        // avame faili appendiks või kui sellise nimega veel pole siis tekitame
                        btoa (hours,FailiName);                        // kirjutab: hh:mm:ss power restored, muutuja FailiName taaskasutamine :)
                        btoa (minutes,tmpstr);
                        strcatpgm2ram (FailiName, ":");
                        strcat (FailiName, tmpstr);
                        strcatpgm2ram (FailiName, ":");
                        btoa (seconds,tmpstr);
                        strcat (FailiName, tmpstr);
                        strcatpgm2ram (FailiName, ",Power restored \r\n");
                        FSfwrite((const void*)&FailiName[0],1,sizeof(FailiName),logFile);  
...

Selgub, et 18-seeria puhul tuleb kasutada *pgm funtsiooni (strcatpgm2rm jne) sest muidu ei suudeta flashist asja RAMi lugeda (ilmselt ei kasutata siis TBLRD*+ asmi käsku. Miks aga see on vajalik info liigutamisel RAMi sees, pole selge. Igatahes nii netis soovitati ja nii toimis ka.
Ma ei saa aru...räägitakse ju, et C-s on kõik lihtne ja eriti mugav...?
Vasta
#5
(07-06-2012, 08:45 PM)felch Kirjutas: Selgub, et 18-seeria puhul tuleb kasutada *pgm funtsiooni (strcatpgm2rm jne) sest muidu ei suudeta flashist asja RAMi lugeda (ilmselt ei kasutata siis TBLRD*+ asmi käsku. Miks aga see on vajalik info liigutamisel RAMi sees, pole selge. Igatahes nii netis soovitati ja nii toimis ka.
Ma ei ole küll Microchipi C kompilaatori spetsialist, seega järgnev on vaid mingi tõenäosusega paika pidav jutt:

See konkreetne kompilaator paneb tähele, et:
1. strcatpgm2rm teine argument on tüüpi "const char*" - ehk et viitab read-only mälualale.
2. ":" on fikseeritud string, mida kasutatakse ainult strcatpgm2rm teise argumendina.
Pannes kokku 2 pluss 2 (ehk tehes lihtsat konstantide kasutuse analüüsi), leiabk kompilaator, et ":" võib paigutada RAM-i asemel flash'i.

(07-06-2012, 08:45 PM)felch Kirjutas: Ma ei saa aru...räägitakse ju, et C-s on kõik lihtne ja eriti mugav...?
Eks igal asjal mõned kitsaskohad, millesse eriti alustades võib kinni jääda või ebaefektiivselt teha. Aga kui ka edaspidi tunned C-s millestki puudust, kriba ikka siia; ma ei ütle, et ma kõike oskan, aga mitme peale ikka hea lahenduse leiab.

Stringitöötlus on ka Basicuga võrreldes suhteliselt algelisemal tasemel. Kui leiad sprintf kasutamise võimaluse üles nagu kasutaja Mtj soovitas, siis saad oma koodijupi märksa lühemaks.

Eraldi muutujaid "year", "month" jt. ei pea ka tegema, võib ka otse kasutada "DS_Aeg->tm_year" jne.
Vasta
#6
Mikronkontrolleri jaoks on sprintf vb. liiga ressursinõudlik, kui sul seda funktsiooni just palju tarvis pole. Selline tähelepanek ka veel, et DS1337 hoiab suuremaid numbreid BCD formaadis. Võrreldes kümnendnendsüsteemiga on neid tunduvalt lihtsam ja odavam stringiks teisendada. Võrdlemiseks ja tehte tegemiseks on samas vaja eraldi funktsioone. Microchip-i teek <math.h> peaks sisaldama ka mingeid funktsioone BCD formaadis numbritega manipuleerimiseks, aga ka nende ise kirjutamine pole eriti keeruline. Sinu juhul vb. mingi järgmine lahendus oleks mõistlikum (eeldusel, et tm_year, tm_month ja tm_day on BCD formaadis):
Kood:
// ...
char[15] fileName = "2000-00-00.csv";
    // See siin on kahtlane rida. Ma ei tea, kas niivisi saab antud
    // C-versioonis stringi algväärtustada. Asja mõte on see, et teed
    // kõigepealt tõmmisest koopia mällu ja siis asendad seal vajalikel
    // postisioonidel olevad sümbolid, nagu allpool tehakse
char[2] = 0x30 + ((DS_Aeg->tm_year) >> 4);
    // "10 Year" -> Ascii char (+ 0x30 ehk '0')
char[3] = 0x30 + ((DS_Aeg->tm_year) & 0xF);
    // "Year" -> Ascii char (+ 0x30 ehk '0')
char[5] = 0x30 + ((DS_Aeg->tm_month) >> 4);
    // "10 Month" -> Ascii char (+ 0x30 ehk '0')
char[6] = 0x30 + ((DS_Aeg->tm_month) & 0xF);
    // "Month" -> Ascii char (+ 0x30 ehk '0')
// ... Edasi jätka siit ise

Loomulikult makrode ja funktsioonide kasutamine on alati lubatud, tulemus oleks igatahes loetavam. Ja mul endiselt pole C-kompilaatorit käepärast, niiet ei tea, kas toodud näida ka copy-paste meetodis toimib.
Vasta
#7
Natuke kogemust sellest PICi sprintf-st.

On C-s kirjutatud PICi programmi üks lõik.
(Kogu C teksti pikkus 837 rida.)
Kood:
A=input_buffer[0];
    if(A=='T'){
      Algseisu();
      if(mUSBUSARTIsTxTrfReady()){
        sprintf(output_buffer, (const far rom char*)"%c", 'X');
        mUSBUSARTTxRam((byte*)output_buffer,strlen(output_buffer));
      }
    return;
Transleeritud kujul sai sellest programmist 47 kb hex,
mille listingu sama lõik näeb välja nii:
Kood:
203:       Algseisu();
  1D18    DE47     RCALL 0x19a8
204:       if(mUSBUSARTIsTxTrfReady()){
  1D1A    0101     MOVLB 0x1
  1D1C    5101     MOVF 0x1, W, BANKED
  1D1E    E12B     BNZ 0x1d76
205:       sprintf(output_buffer, (const far rom char*)"%c", 'X');
  1D20    0E58     MOVLW 0x58
  1D22    6EE6     MOVWF 0xfe6, ACCESS
  1D24    6AE6     CLRF 0xfe6, ACCESS
  1D26    0E36     MOVLW 0x36
  1D28    6E14     MOVWF 0x14, ACCESS
  1D2A    0E42     MOVLW 0x42
  1D2C    6E15     MOVWF 0x15, ACCESS
  1D2E    6A16     CLRF 0x16, ACCESS
  1D30    C014     MOVFF 0x14, 0xfe6
  1D32    FFE6     NOP
  1D34    C015     MOVFF 0x15, 0xfe6
  1D36    FFE6     NOP
  1D38    C016     MOVFF 0x16, 0xfe6
  1D3A    FFE6     NOP
  1D3C    0E5D     MOVLW 0x5d
  1D3E    6EE6     MOVWF 0xfe6, ACCESS
  1D40    0E01     MOVLW 0x1
  1D42    6EE6     MOVWF 0xfe6, ACCESS
  1D44    EC37     CALL 0x446e, 0
  1D46    F022     NOP
  1D48    6E17     MOVWF 0x17, ACCESS
  1D4A    0E07     MOVLW 0x7
  1D4C    5EE1     SUBWF 0xfe1, F, ACCESS
  1D4E    5017     MOVF 0x17, W, ACCESS
206: mUSBUSARTTxRam((byte*)output_buffer,strlen(output_buffer));
  1D50    0101     MOVLB 0x1
  1D52    0E5D     MOVLW 0x5d
  1D54    6F02     MOVWF 0x2, BANKED
  1D56    0E01     MOVLW 0x1
  1D58    6F03     MOVWF 0x3, BANKED
  1D5A    0E5D     MOVLW 0x5d
  1D5C    6EE6     MOVWF 0xfe6, ACCESS
  1D5E    0E01     MOVLW 0x1
  1D60    6EE6     MOVWF 0xfe6, ACCESS
  1D62    ECA9     CALL 0x4752, 0
  1D64    F023     NOP
  1D66    52E5     MOVF 0xfe5, F, ACCESS
  1D68    52E5     MOVF 0xfe5, F, ACCESS
  1D6A    CFF3     MOVFF 0xff3, 0x106
  1D6C    F106     NOP
  1D6E    0101     MOVLB 0x1
  1D70    6B07     CLRF 0x7, BANKED
  1D72    0E01     MOVLW 0x1
  1D74    6F01     MOVWF 0x1, BANKED
207:       }
208:       return;
  1D76    EF19     GOTO 0x2632
  1D78    F013     NOP
209:       }
See buffer viidi siis üle USB tagasi PC-sse ja töödeldi seal.
(Viidi log faili Smile )
Selle PICi hex faili asm logi pikkus on 12656 rida.
Ruumi kokkuhoiu mõttes ma kõike siia ei toonud.
Vasta
#8
sprintf on üks tihedamini taasleiutatud jalgrattaid. Googeldage "minimal sprintf implementation" ja kindlasti leiate midagi enda vajadustele ja lubatud flash'i mahule sobivat. Standardis on ära toodud müriaad formaatimise võimalusi ja sestap on standardne funktsioon kole flashimahukas, aga kui kasutate ainult "%s", "%d" ja "%x"-i, siis võib ka kilobaidi või paariga hakkama saada.

Edu!
Vasta
#9
(11-06-2012, 01:13 PM)andrei Kirjutas: sprintf on üks tihedamini taasleiutatud jalgrattaid.
kui kasutate ainult "%s", "%d" ja "%x"-i, siis võib ka

Vaatasin sinna C18 sisse ja
sprintf kutsub välja vfprrintf.c
Seal see on kõik võimalused kenasti kirjas.
Kui nüüd seal natuke "koristada" siis võib küll ruumi juurde saada.
Tapselt samuti on seal siinuse jaoks sincos funktsioon,
mida annaks vajadusel natuke täiendada.

Aga äkki annaks sinna PICi külge sokutada üks mälupulk,
nii 300 GB (Smile) ja sealt võtta kõik vajalik.
Piisaks ju ka 300 MB aga uhkus ei anna ju häbeneda.

Vasta
#10
Ma leidsin, et C18 sprintf ei toeta float arve Sad Seda on manuaalis ka otse öeldud.
Vasta


Alamfoorumi hüpe:


Kasutaja, kes vaatavad seda teemat: 1 külali(st)ne