Fórum témák

» Több friss téma
Fórum » PIC programozása C nyelven, C-Compiler
Lapozás: OK   97 / 153
(#) potyo válasza Wudoou hozzászólására (») Jún 5, 2014 /
 
Próbáld bitenként, hátha jobb lesz.
(#) Wudoou válasza icserny hozzászólására (») Jún 5, 2014 /
 
Ezzel csak az a baj, hogy megtörténhet az is (debug esetén tapasztaltam is), hogy éppen bent van a mérésben, amikor beugrik egy karakter a soros porton. Akkor már hiába tiltanám a mérés_flag-et, nem ér semmit, ugyanis már benne vagyok.
(#) Wudoou válasza watt hozzászólására (») Jún 5, 2014 /
 
Nem szeretek eltérni az ajánlásoktól, mert nem véletlenül írják oda.
Ha nem tiltok megszakítást, javulhat a MODBUS, de romlik a mérés.
(#) potyo válasza Wudoou hozzászólására (») Jún 5, 2014 /
 
Ha bitenként engedélyezed-tiltod a megszakítást, akkor legalább 100kbps sebességet ki kell tudnia szolgálni úgy is a hardvernek gond nélkül. Egy bit ideje minimum 60us, gyakorlatban legyen inkább 80us, akkor is 1/8us=125000bps sebességgel kellene érkeznie az adatnak a soros porton, hogy egy 1wire bit átvitelének ideje alatt beérkezzen egy bájt a modbuson. És akkor még ott van a két bájtos hardveres puffer is, tehát nem tudom elképzelni, hogy ezesetben a bejövő puffer túlcsordulna.
(#) watt válasza Wudoou hozzászólására (») Jún 5, 2014 /
 
Te tudod...
Mellesleg más út, de potyo-nak igaza van...
A hozzászólás módosítva: Jún 5, 2014
(#) Wudoou válasza potyo hozzászólására (») Jún 5, 2014 /
 
A one_wire_reset-tel van a gond, az hosszú.
(#) Hp41C válasza Wudoou hozzászólására (») Jún 5, 2014 /
 
Egy 40MHz -es PIC18 az RCREG-ből egy karakter kivételét el tudja intézni kb. 30-35 utasításcból. Ez kb. 0.35 us. Egy körforgó bufferbe teszi a vett adatokat és elkönyveli, hány van a bufferben, a többi a főprogram dolga. Az adás hasonlóan: A főprogram feltölti a kimenő buffert a távirattal, a megszakításui rutin küldi el a soron következőt. Ez is megoldható kb. ugyanannyi dővel, mint a vétel. Egy adás és egy vétel ideje így belefér a 1-wire toleranciáiba.
Egy 512us időzítést egy timerrel kellene megvalósítani.
A hozzászólás módosítva: Jún 5, 2014
(#) watt válasza Hp41C hozzászólására (») Jún 5, 2014 /
 
Idézet:
„Egy adás és egy vétel ideje így belefér a 1-wire toleranciáiba.”

Ezt mondogatom egy ideje...
(#) Wudoou válasza Hp41C hozzászólására (») Jún 5, 2014 /
 
Én PIC16f886-on írom, 20 mhz-el.
Igen, valóban timerrel kellene, csak már annyit használom a timert, hogy nem tudom, hogyan tegyem még itt is.
Használom a timer1-et a mérések, kiiratások időzítésére.
A timer0-t a modbus utolsó karakter utáni 3,5 karakternyi szünetre.
A timer2-őt PWM-re, szóval hogy gyűrjem bele még a ds-t is?
(#) watt válasza Wudoou hozzászólására (») Jún 5, 2014 /
 
Egy timert több dologra is lehet használni. A Timer0-ba még beférne egy másik időzítő flag beállítása, vagy maga a végrehajtás is, ha pár sor...
(#) potyo válasza Wudoou hozzászólására (») Jún 5, 2014 /
 
Idézet:
„A timer2-őt PWM-re, szóval hogy gyűrjem bele még a ds-t is?”


Pl. valahogy így:

  1. void reset(void)
  2. {
  3.   unsigned char tmr2_regi;
  4.   lab_lehuz();
  5.   tmr2_regi=TMR2;
  6.   while (TMR2-tmr2_regi<100);  // itt húzzuk le a vonalat, persze a 100 helyett ki kell számolni, mennyi legyen
  7.   lab_elereszt();
  8.   tmr2_regi=TMR2;
  9.   while (TMR2-tmr2_regi)<100); // ez csak azért, hogy a presence pulse idejét megvárjuk
  10. }


De ez meg felesleges, mert a reset tarthat tovább, mint az adatlapban megadott minimális érték. A lényeg csak az, hogy ne legyen rövidebb. Tehát belövöd, hogy a legrosszabb esetben se tartson adott időnél rövidebb ideig, aztán ha közben jön megszakítás, akkor kicsit tovább tartja a resetet, az nem probléma.
(#) Wudoou válasza potyo hozzászólására (») Jún 5, 2014 /
 
Akkor ezek szerint a Timer0-t is kiválthatnám?
(#) Wudoou válasza potyo hozzászólására (») Jún 6, 2014 /
 
Lehet, hogy az én struktúrám a rossz. A write_bit és a read_bit is kaptak egy argumentumot, mivel 3 különböző lábon is vannak ds-ek.

A onewire_write_bit
  1. void OW_write_bit(BYTE pin,BYTE val)
  2. {
  3.         DisableAllInterrupts();
  4.         switch(pin)
  5.                 {
  6.                 case 1:
  7.                 OW_HI1();      
  8.                 OW_LO1();                      
  9.                 DelayUs(6);    
  10.                 if (val)
  11.                         OW_HIZ1();
  12.                 DelayUs(70);           
  13.                 OW_HI1();                      
  14.                 DelayUs(10);
  15.                 break;
  16.  
  17.                 case 2:
  18.                 OW_HI2();      
  19.                 OW_LO2();              
  20.                 DelayUs(6);
  21.                 if (val)
  22.                         OW_HIZ2();
  23.        
  24.                 DelayUs(70);   
  25.                 OW_HI2();                      
  26.                 DelayUs(10);
  27.                 break;
  28.                
  29.                 case 3:
  30.                 OW_HI3();      
  31.                 OW_LO3();                      
  32.                 DelayUs(6);    
  33.                 if (val)
  34.                         OW_HIZ3();     
  35.                 DelayUs(70);   
  36.                 OW_HI3();              
  37.                 DelayUs(10);
  38.                 break;
  39.         default: break;
  40.                 }
  41.         ResumeAllInterrupts();
  42. }


A read_bit:
  1. BYTE OW_read_bit(BYTE pin)
  2. {
  3.         BYTE val;
  4.         DisableAllInterrupts();
  5.         switch(pin)
  6.         {
  7.         case 1:
  8.  
  9.         OW_HI1();
  10.         OW_LO1();
  11.  
  12.         DelayUs(6);    
  13.  
  14.         OW_HIZ1();
  15.         DelayUs(10);
  16.  
  17.         val = OW_DATA1;
  18.  
  19.         DelayUs(105);
  20.  
  21.         break;
  22.  
  23.         case 2:
  24.  
  25.         OW_HI2();
  26.         OW_LO2();
  27.  
  28.         DelayUs(6);    
  29.  
  30.         OW_HIZ2();
  31.         DelayUs(10);
  32.  
  33.         val = OW_DATA2;
  34.  
  35.         DelayUs(105);
  36.  
  37.         break;
  38.  
  39.         case 3:
  40.  
  41.         OW_HI3();
  42.         OW_LO3();
  43.  
  44.         DelayUs(6);    
  45.  
  46.         OW_HIZ3();
  47.         DelayUs(10);
  48.  
  49.         val = OW_DATA3;
  50.  
  51.         DelayUs(105);
  52.  
  53.         break;
  54.         default: break;
  55.         }
  56.         ResumeAllInterrupts();
  57.         return val;
  58. }


Vagyis bitenként tiltom a megszakítást.
A resettel bénázok. Nem sikerült a fenti kódod.
A hozzászólás módosítva: Jún 6, 2014
(#) cmdnetwizard hozzászólása Jún 7, 2014 /
 
Sziasztok!
Nem tudom, hogy mennyire off a kérdésem, de Ti milyen fejlesztőkörnyezetet használtok PIC-hez, C nyelven?
Én MPLab-ot használok, de a szerkesztője valami borzalmas...
Üdv.: László
(#) watt válasza cmdnetwizard hozzászólására (») Jún 7, 2014 /
 
Szerintem mi is MPLAB-ot használunk. Nem annyira borzalmas...
(#) potyo válasza cmdnetwizard hozzászólására (») Jún 7, 2014 /
 
Én is MPLAB-ot használok. Valóban nem a legkifinomultabb a szerkesztője, de volt már dolgom rosszabbal is.
(#) zenetom válasza cmdnetwizard hozzászólására (») Jún 7, 2014 /
 
Szia!
MPLAB. Egyszerű, átlátható. Nem tudálékoskodik minden legépelt karakter után, mint az IDE-k egy része.
(#) watt válasza Wudoou hozzászólására (») Jún 7, 2014 /
 
Ennyi a reset. Ide (sem) nem kell megszakítás tiltás...
  1. unsigned char oWire_busreset(void)
  2. {
  3.  oW_Bemenet_Lebeg();                 // bemenetre állítva a portláb
  4.  oW_Kimenet_Lehuzva();               // Reset impulzus elküldése
  5.  delay_us(200);                         // Várakozás 600 µs
  6.  delay_us(200);
  7.  delay_us(200);
  8.  oW_Bemenet_Lebeg();                 // bemenetre állítva a portláb
  9.  delay_us(60);                          // Várakozás 60 us (release)
  10.  if (PORTCbits.RC0 == 1) // Ha nem jön válasz(lehúzás a vonalon), nincs eszköz a buszon
  11.         return 1;                       // <<-error
  12.  delay_us(140);      // Várakozás 540 us a Reset szekvencia lefolyásához.
  13.  delay_us(200);
  14.  delay_us(200);
  15.  return 0;                      //Ha nincs hiba 0-val tér vissza.
  16. }


  1. #define oW_Kimenet_Lehuzva()    TRISCbits.TRISC0=0;     //Kimenet mindig 0 a LAT0-ban!
  2. #define oW_Bemenet_Lebeg()              TRISCbits.TRISC0=1;
A hozzászólás módosítva: Jún 7, 2014
(#) icserny válasza cmdnetwizard hozzászólására (») Jún 7, 2014 /
 
Idézet:
„Én MPLab-ot használok, de a szerkesztője valami borzalmas...”
Configure/Settings menüben beállíthatod, hogy külső szerkesztőt használjon.
(#) Wudoou válasza watt hozzászólására (») Jún 7, 2014 /
 
Kipróbálom, köszönöm.
Viszont koncepciókidolgozásban szeretnék segítséget kérni.

Melyik a jobb megoldás:
A főprogram megszakításokban beállított flageket hajt végre, a megszakítás timer1.
Mikor bizonyos idők lejárnak, megcsináljuk a dolgunkat, pl: kiiratás frissités, mérés...
Ha jön egy karakter a soros porton, egy körforgó pufferba pakoljuk a byteokat (a megszakításban a legelsőt leellenőrizzük, a többit már nem, majd a főprogramban), persze FERR, OERR ellenőrzés után. Ha bármelyik bekövetkezik, üritjük a bejövő puffert és kezdjük elölről.
Itt lenne az első kérdés:
a: Mikor beérkezik 8 byte, akkor flaget 1-be állítjuk jelezvén a főprogramnak, hogy bejött egy keret.
Vagy:
b: Minden karakter között timert futtatunk, amit egy újabb karakter beérkezése esetén resetelünk. Amikor a timer túlcsordul, akkor már valószínüleg több byte nem jön, flag=1;
Itt lenne a második kérdés:
A: A főprogram megvizsgálja az eredeti bejövő puffer tartalmát, ha minden ok, akkor feltölt egy kimenő puffert, amit majd megszakítással elküldünk. Ha elment az összes karakter, akkor ismét lehet fogadni, addig nem.
Vagy:
B:
Átmásoljuk egy másik pufferba a bejövő puffer tartalmát, majd ismét engedélyezzük a soros port olvasás megszakítást, mert a puffer már újra írható, mivel az adatait már lemásoltam egy másikba, nem kell attól félni, hogy jön egy újabb keret és felülírja az eredeti üzenetet.

Ez az egyik verzió.

A másik olyan lenne, hogy egy olyan függvényt írnék, ami rá-ránéz a puffer tartalmára és a különböző állapotoknak megfelelően egy állapotgép változót növelgetne, hogy éppen hogy áll a puffer tartalma.
Kérnék szépen segítséget, mivel bizonytalan vagyok a program szervezésben.
A hozzászólás módosítva: Jún 7, 2014
(#) watt válasza Wudoou hozzászólására (») Jún 7, 2014 /
 
Szerintem az 1. megoldás: ütemezett végrehajtás a Timer megszakításban beálló jelzők szerint. Itt több esemény eltérő időzítése is megoldható, ez az általános.
A MODBUS miatt minden beérkező karakter után 3,5 karakternyi időt kell ellenőrizni és ha lejár, az az üzenet végét jelenti. Tehát ez a megoldás a javasolt. Timer kezdeti érték feltöltéssel, indítással, megszakításban történő lekezeléssel javasolt. Erre elmehet egy timer(nálam a Timer1 szokott lenni)...
Az RS485 egyidőben csak egyik irányba kommunikál. Érvényes vétel után adásra váltunk(választ kell küldeni), tehát a vétel megszakítással szerintem nem kell foglalkozni, de ha nagyon akarod, ki lehet kapcsolni a lekezelés végéig az USART vételt (RCSTA1bits.CREN).

A teljes csomagot kell fogadni, majd lehet ellenőrizni a CRC-t és utána a címet.
A választ is érdemes megszakításban elküldeni, nemrég beszéltünk erről a PIC miértek haladóknak topicban Hp41C-vel.
Idézet:
„Mikor beérkezik 8 byte”

Szerintem nem 8 bájt jön mindig, de egyedi megoldásoknál lehetséges, csak az nem lesz szabványos lekezelés. Viszont a 3,5karakteridő viszgálata és a CRC megoldja a csomag végének detektálását és jóságának ellenőrzését.
(#) Wudoou válasza watt hozzászólására (») Jún 7, 2014 /
 
Akkor nincs értelme lemásolni a bejövő puffert egy usart-tól független pufferba?
Ha a timer1-et használom időzítésekre, ugyanazt hogy tudom használni modbus karakterek közötti idő vizsgálatára?
Idézet:
„Szerintem nem 8 bájt jön mindig”

Bocsánat, azt elfelejtettem mondani, hogy csak a 3. funkciókódot valósítottam meg,
ott 8 bájt jön be:
  1. MODBUS_bejovo.slaveAddress = Bejovo_puffer.adat[0];
  2.         MODBUS_bejovo.functionCode = Bejovo_puffer.adat[1];
  3.         MODBUS_bejovo.startAddress_high = Bejovo_puffer.adat[2];
  4.         MODBUS_bejovo.startAddress_low = Bejovo_puffer.adat[3];
  5.         MODBUS_bejovo.quantity_high = Bejovo_puffer.adat[4];
  6.         MODBUS_bejovo.quantity_low = Bejovo_puffer.adat[5];
  7.         MODBUS_bejovo.chSum_low = Bejovo_puffer.adat[6];
  8.         MODBUS_bejovo.chSum_high = Bejovo_puffer.adat[7];


Egyébként melyik lenne jobb megoldás? A Bejovo_puffer.adat-ot használni, vagy a struktúrát?
A hozzászólás módosítva: Jún 7, 2014
(#) watt válasza Wudoou hozzászólására (») Jún 7, 2014 /
 
Vételkor nem szoktam áttölteni a puffert beszédes nevű változókba, benne ellenőrzöm, belőle töltöm át, illetve benne készítem elő az adatokat küldésre. Küldéskor csak a megfelelő puffer pointerét kell átadnom a TX előkészítő rutinnak (ha több pufferből is küldeni kell, pl. belső óra. Ilyenkor a kevesebb adatot mozgatom át az épp aktuális puffer elejére, hogy a MODBUS protokollnak megfelelő legyen az első néhány bájt).
Úgy is tudod melyikben mi van, még akkor is, ha több funkciót is kiszolgálsz. Emlékeztetőt szoktam írni megjegyzésben, az nem zabálja a memóriát és nem lassít!
A hozzászólás módosítva: Jún 7, 2014
(#) watt válasza Wudoou hozzászólására (») Jún 7, 2014 /
 
Idézet:
„Ha a timer1-et használom időzítésekre, ugyanazt hogy tudom használni modbus karakterek közötti idő vizsgálatára?”

Sajnos külön timert igényel, ha könnyen és pontosan akarod lekezelni a dolgot.
Inkább másik Timerrel old meg az általános időzítéseket. Melyiket mire használod most és milyen megszakítás ütemmel?
Most olvasom vissza, hogy a TImer0-t használod a 3,5 karakteridőre. Ha működik, akkor az is jó...
A hozzászólás módosítva: Jún 7, 2014
(#) Wudoou válasza watt hozzászólására (») Jún 7, 2014 /
 
Hát van némi problémám a lekezeléssel. Ha szigorúan betartom a min. 3,5 karakternyi időt, vagy max 5-öt, akkor nem jó, 10 karakternyi időnél már beugrik.
Szóval a timer2-őt pWM-re, timer1 általános időzítések, timer0 a modbus-ra.
Valahogy így:
  1. while (RCIF)    // soros port dolgai
  2.         {
  3.                
  4.                 if (OERR)
  5.                 {
  6.         // overrun - eldobáljuk a puffer tartalmát, majd reset
  7.                  while (RCIF)
  8.                         {
  9.                          (void)RCREG;
  10.                      CREN = 0;
  11.                      CREN = 1;
  12.                      continue;
  13.                         }
  14.                reset_modbus();
  15.             }
  16.                 frameerr = FERR != 0;
  17.                 cgetchar = RCREG;
  18.             if (frameerr)
  19.                 {
  20.                 // frame error - karakter eldobása    
  21.                   (void)RCREG;
  22.                 reset_modbus();
  23.                 }
  24.                 else
  25.                 {      
  26.         if ( MB_start_flag == 0 && soros_flag == 0 && cgetchar == SLAVE_ADDRESS )
  27.                 {
  28.                 start_t0();
  29.                 Modbus_timeout=0;
  30.                 MB_start_flag=1;                //ezzel elindítunk egy timert
  31.                 Bejovo_puffer.hossz=0;//ezzel jelezzük, hogy megjött az első karakter, vagyis a cím
  32.                 Bejovo_puffer.adat[Bejovo_puffer.hossz++]=cgetchar;     //cím mentése
  33.                 }
  34.                 else if ( MB_start_flag == 1 && soros_flag == 0 )       //itt már meg kellett jönnie e címnek
  35.                 {      
  36.                 reset_t0();
  37.                 Modbus_timeout=0;                              
  38.                 if(Bejovo_puffer.hossz == MAX_BEJOVO_BYTE)
  39.                 {
  40.                      reset_modbus();      //overflow
  41.                 }       //end if
  42.                 Bejovo_puffer.adat[Bejovo_puffer.hossz++]=cgetchar;
  43.                 }               //end else
  44.                 }                       //end else
  45.         }


Ahol Modbus_timeout-tal lehet állítani a timer0 idejét.
MB_start_flag jelzi, hogy mehet a timer0 és vétel közötti szünetről van szó.
Reset_Modbus - ekkor ürítjük a puffer tartalmat, mert egy hibás karakter vétel történt.
És ha a timer0 lejár, akkor soros_flag=1 jelzvéna főprogramnak, hogy mehet a modbus kiértékelés.

Idézet:
„Ha működik, akkor az is jó...”

Esetleg jobb lenne valami más?
A hozzászólás módosítva: Jún 7, 2014
(#) watt válasza Wudoou hozzászólására (») Jún 7, 2014 /
 
Ezt nem értem. Nem megszakításban kezeled le a soros portot?
Ez a kód hol helyezkedik el?
(#) Wudoou válasza watt hozzászólására (») Jún 7, 2014 /
 
Ez a megszakításban. CSak annak egy része.
(#) watt válasza Wudoou hozzászólására (») Jún 7, 2014 /
 
Megszakításban nagyon fura nekem a while, na de lépjünk ezen túl...
A korábban leírtak szerint kellene átírnod a kódot. Minden bejövő karaktert letárolsz a pufferbe, majd kilépsz a megszakításból. Ezt addig, amíg a timeout nem jelzi, hogy vége a csomagnak, ekkor beállítasz egy jelzőt, hogy kész a csomag és a fő ciklusban lekezeled.

A timeoutot mindegy milyen módon állítod elő, csak pontos legyen. A Timer1 azért jobb, mert elindítható, leállítható és fel lehet tölteni kezdő értékkel, így csak akkor szakít meg és csak egyszer, amikor lejárt az idő(viszont fel kell áldozni erre). Ehhez persze a megfelelő osztásokat kell beállítani a bemenetén.
Ha a timer0-al dolgozol, vagy több dologra is használni akarsz egy timert, ott több megszakítás lesz a 3,5karakter alatt, ez kissé erőforrás igényesebb, de nem vészes. Az eredmény lehet ugyanaz...
(#) Wudoou válasza watt hozzászólására (») Jún 7, 2014 /
 
Nekem is az volt, de régebben veled is fórumoztam erről:
Régebbi fórum UART-ról
Itt kaptam a sugallatot, azóta ezt használom.
Hogy érted, hogy
Idézet:
„ott több megszakítás lesz a 3,5karakter alatt”

Most pillanatnyilag 4 MHz-en megyek, 16-os osztó timer0-val ami 0.00409600 sec.
Az 9600-on majdem 4 bájt átvitelének ideje. Ez pont jónak tűnik.
Még annyi lenne a kérdésem, hogy jelezzem a megszakításban, hogy 1. bájtról van szó?
Szóval ahogy írtátok is, nem csinálok a megszakításba vizsgálatot, de az első bájtot ha megvizsgálom, ami ugye a cím, akkor egyből kiderül, hogy nekem jött-e az üzenet, vagy nem.
Kell ezzel foglalkozni, vagy majd a főprogram úgy is kidobja?
A hozzászólás módosítva: Jún 7, 2014
(#) watt válasza Wudoou hozzászólására (») Jún 7, 2014 /
 
Lehet vizsgálni a címet végül is, ezzel nincs semmi baj, de a további bájtokat ettől még fogadni kell, csak nem kell feldolgozni...
Igen, így csak egy megszakítás lesz a Timer0 esetében is, ami jó.
Első bájtot úgy lehet jelezni, hogy beállítasz egy jelzőt, ha bejön egy karakter. Ezt a jelzőt az időtúllépésben törlöd. Tehát, ha a jelző törölve van és jön egy bájt, akkor az az első.
A hozzászólás módosítva: Jún 7, 2014
Következő: »»   97 / 153
Bejelentkezés

Belépés

Hirdetés
XDT.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem