Käytän Serial.write()
53 tavun lähettämiseen tietokoneelle. Aikamittaukseen käytän micros()
(ennen ja jälkeen kirjoitustoiminnon). Jokaisen lähetyksen jälkeen on 1 sekunnin viive.
Serial.write()
-toiminnon aika on 532 meitä 1000000 baudinopeudella ja 360 us 9600 baudinopeudella.
Serial.write()
-toiminto on selvästi asynkroninen, koska 53 tavun lähetys 9600 baudinopeudella on 53 * 8/9600 * 1e6 = 44167 us. (Muuten, 1000000 baudinopeuden tapauksessa ei ole niin ilmeistä, että toiminto on asynkroninen.)
Käytän Serial.availableForWrite()
ennen Serial.write()
vahvistaaksesi, että puskurissa on tarpeeksi tilaa (tämä palauttaa joka kerta 63, puskurin koko on oletusarvo 64).
En ymmärrä näitä numeroita. memcpy()
53 tavun kopioiminen vie vain 32 meiltä. Eikö kopiointi sarjapuskuriin ole sama kuin memcpy()
-toiminto? Ja miksi kopiointiaikoissa on eroa, kun siirtonopeus on erilainen? Serial.write () on tulosten mukaan vielä hitaampi korkeammilla siirtonopeuksilla. koko on 64 (SERIAL_TX_BUFFER_SIZE: n mukaan)?
Päivitys: Kiitos vastauksistasi.
Olen kokeillut toista sarjakommunikaatiokirjastoa: https://github.com/greiman/SerialPort
Se näyttää olevan nopeampi kuin alkuperäinen. Käytän 2 tim Mittaukset ja viive koodissa, nämä 3 deltaTimes edustavat koko vaihetta seuraavasti:
writeTime + memcpyTime + delaymicros = computedTime! = realTime
Ensimmäiset 2 kertaa mitataan, delaymicros on teoreettinen viive (900 us), voin laskea vaiheajan näistä. Tämä laskettu askelaika on erilainen kuin reaaliaikainen (mitattu vaiheaika, mitaan myös koko vaiheen). Näyttää siltä, että lisäaika löytyy viiveestä.
SerialPort-kirjasto: 100 + 30 + 900 = 1030! = 1350
writeReal = 100 + 1350 – 1030 = 430
Arduino Sarja: 570 + 30 + 900 = 1500! = 1520
writeReal = 570 + 1520 – 1500 = 590
Sitten mitasin viivemikrosaika (joka on teoriassa 900 meitä), puuttuva aika löytyy sieltä. Ohjelmoin 900 viiveen, mutta todellinen viive oli noin 1200 ensimmäisessä ja 920 toisessa testissä.
Nämä mittaukset voivat todistaa keskeytysten olemassaolon, koska vain kirjoitusfunktioiden mittaaminen ei ”t anna koko kirjoitusaika (varsinkin ladatun sarjakirjaston kanssa). Ladattu kirjasto voi toimia nopeammin, mutta vaatii suuremman TX-puskurin virheiden takia (256 toimii oikein 64: n sijaan).
Tässä on koodi : Käytän checkSum-funktiota sendig-funktiossa (joka on 570-532 = 38 us). Käytän Simulinkiä tietojen vastaanottamiseen ja käsittelyyn.
struct sendMsg1 { byte errorCheck;//1 unsigned long dT1;//4 unsigned long dT2;//4 unsigned long t;//4 unsigned long plus[10];//40 };//53 sendMsg1 msg1; byte copyMsg1[53]; unsigned long time1; unsigned long time2; unsigned long time3; unsigned long time4; void setup() { Serial.begin(1000000); } void loop() { sensorRead(); sendMsg1_f(); //time3 = micros(); delayMicroseconds(900); //time4 = micros(); } void sensorRead() { time3 = micros(); msg1.t = micros(); for (unsigned long i = 0; i < 1; i++) { memcpy((void*)&(copyMsg1[i*sizeof(sendMsg1)]), (void*)&msg1, sizeof(sendMsg1)); } time4 = micros(); msg1.dT2 = time4 - time3; } void sendMsg1_f() { time1 = micros(); msg1.errorCheck = 0; for (int i = 0; i < sizeof(sendMsg1) - 1; i++) { msg1.errorCheck += ((byte*)&msg1)[i]; } Serial.write((byte*)&msg1,sizeof(sendMsg1)); time2 = micros(); msg1.dT1 = time2 - time1; }
Kommentit
- Voitteko antaa koodin, jolla käytit tuloksia?
- 1 tavu puskuria menetetään renkaan puskurin toteuttamisen takia. Täyden puskurin pää voi ’ t osoittaa samassa indeksissä, koska hännän pää on samassa hakemistossa tyhjän puskurin tapaus
An swer
Jos tarkastelet toteutusta:
size_t HardwareSerial::write(uint8_t c) { _written = true; // If the buffer and the data register is empty, just write the byte // to the data register and be done. This shortcut helps // significantly improve the effective datarate at high (> // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) { // If TXC is cleared before writing UDR and the previous byte // completes before writing to UDR, TXC will be set but a byte // is still being transmitted causing flush() to return too soon. // So writing UDR must happen first. // Writing UDR and clearing TC must be done atomically, otherwise // interrupts might delay the TXC clear so the byte written to UDR // is transmitted (setting TXC) before clearing TXC. Then TXC will // be cleared when no bytes are left, causing flush() to hang ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *_udr = c; #ifdef MPCM0 *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); #else *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0))); #endif } return 1; } tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; // If the output buffer is full, there"s nothing for it other than to // wait for the interrupt handler to empty it a bit while (i == _tx_buffer_tail) { if (bit_is_clear(SREG, SREG_I)) { // Interrupts are disabled, so we"ll have to poll the data // register empty flag ourselves. If it is set, pretend an // interrupt has happened and call the handler to free up // space for us. if(bit_is_set(*_ucsra, UDRE0)) _tx_udr_empty_irq(); } else { // nop, the interrupt handler will free up space for us } } _tx_buffer[_tx_buffer_head] = c; // make atomic to prevent execution of ISR between setting the // head pointer and setting the interrupt flag resulting in buffer // retransmission ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { _tx_buffer_head = i; sbi(*_ucsrb, UDRIE0); } return 1; }
Se vastaa periaatteessa kaikkiin kysymyksiin.
Jos puskuri on tyhjä eikä se lähetä mitään, se lähettää merkin suoraan niin, että se on synkronoitu (mutta merkin lähettäminen on paljon nopeampaa kuin toimintojen takaisinkutsut ja niin edelleen)
Ei, et voi käyttää memcpy: tä, koska se vain korvaa puskurin, mutta se ei tee mitään muuta, kuten todella aloittaa tietorekisterin valmiina keskeytä eikä oikea pää- / häntälaskurin asetus (se on pyöreä puskuri, joten voi olla skenaariota, että kirjoitat jotain puskurin ulkopuolelle)
Ja kirjoitusfunktio kutsutaan jokaiselle merkille erikseen (kaikki muut erikoistumiset kirjoituksesta käyttävät tätä)
Jos puskuri on täynnä, se ”odottaa, kunnes toiselle merkille on tilaa.
Vastaa
Kopiointi sarjapuskuriin ei ole sama kuin
, nro.
Sarjapuskuri on pyöreä puskuri . Tämän vuoksi on paljon laskelmia, jotka liittyvät seuraavan merkin sijoittamiseen tarkalleen puskuriin. Se vie aikaa. memcpy()
kopioi vain yhden muistilohkon suoraan toisen päälle. Se ei tarkista, eikä sitä voi kiertää kuin pyöreä puskuri.
Syy siihen, miksi korkeampi baudinopeus näyttää hitaammalta, johtuu siitä, että jokainen merkki on puskurista otettu keskeytyksellä.Mitä korkeampi siirtonopeus, sitä useammin keskeytys laukaistaan, ja sitä enemmän CPU kuluttaa aikaa keskeytyksen käsittelyyn seuraavan merkin lähettämiseksi. Samoin CPU: lla on vähemmän aikaa käsitellä tietojen sijoittamista sarjapuskuriin.
Vastaa
Testattava toiminto on oletettavasti Serial.write(const uint8_t *buffer, size_t size)
. Jos etsit sitä HardwareSerial.h-tiedostosta, näet
using Print::write; // pull in write(str) and write(buf, size) from Print
ja toteutus on Print.cpp-tiedostossa:
/* default implementation: may be overridden */ size_t Print::write(const uint8_t *buffer, size_t size) { size_t n = 0; while (size--) { if (write(*buffer++)) n++; else break; } return n; }
Tämä kirjoittaa tavut yhden yksi ja joka tavu, koko HardwareSerial::write(uint8_t c)
-koodia ajetaan. Tämä sisältää testit koko tai tyhjälle puskurille ja aritmeettinen päivitys _tx_buffer_head
.
Kuten koodin yläpuolella olevassa kommentissa todettiin, olisi ollut mahdollista korvaa tämän erikoistuneella toteutuksella. Periaatteessa voit kopioida lineaarisen puskurin rengaspuskuriin käyttämällä enintään kahta kutsua memcpy()
ja päivittämällä _tx_buffer_head
vain kerran. Se olisi todennäköisesti tehokkaampaa kuin nykyinen toteutus, ainakin puskurikokoille käyttämällesi alueelle (lähellä, mutta vähemmän kuin renkaan puskurikapasiteetti).
Onko se sen arvoista? Ehkä sinun tapauksessasi se olisi. Mutta se voi myös tehdä koodista monimutkaisemman ja vaatia enemmän salamaa. Ja hyöty on todennäköisesti todella pieni ihmisille, jotka kirjoittavat pieniä puskureita. En ole varma, että tällaisen optimoinnin toteuttava vetopyyntö voidaan hyväksyä. Voit kokeilla, jos niin haluat.