Men kechiktirishimMikrosekundlarni aniqroq bera olamanmi?

Men DMX ma'lumotlarini portlatishga harakat qilmoqdaman va u 4us pulslarni talab qiladi. Natijalar bilan ko'p muvaffaqiyatlarga erisha olmadim, chunki Arduinoning qanchalik yaxshi kechikayotganini ko'rib chiqayapman ... Bu erda juda qo'rqinchli ko'rinadi.

Mana, men tezda kam test qildim:

unsigned long ptime;

void setup() {
  Serial.begin(9600);
}

void loop() {
  ptime = micros();
  delayMicroseconds(4);
  Serial.println(micros() - ptime);

  delay(1000); //just to keep the serial monitor from going nuts
}

Va natijalar:

8 4 8 4 4 4 4 8 8 8 8 4 8 8 4 4 8 4 4 4 8 8 8 4 8 4

Men qanchalik adolatli ekanini shunchalik hayratda qoldirdim. Kechiktirmoqchi bo'lgan vaqtim ikki barobarga tushdi, lekin bu 2-qismni ajratishimga to'g'ri kelmaydi!

To'g'ri, izchil natijalarni olish uchun nima qila olaman?

8
micros() to'rt mikrosaniyaga ega.
qo'shib qo'ydi muallif Hugo, manba
Siz UARTga to'g'ridan-to'g'ri kirish o'rniga nima uchun bittagina urishasiz?
qo'shib qo'ydi muallif Ignacio Vazquez-Abrams, manba
Mega to'rtta UART mavjud. Agar siz doimiy ravishda uchta koinotga ega bo'lgan dasturlash uchun doimiy bo'lsangiz ham.
qo'shib qo'ydi muallif Ignacio Vazquez-Abrams, manba
ATmega328PB ning ikkita UARTsi bor.
qo'shib qo'ydi muallif Ignacio Vazquez-Abrams, manba
Bundan tashqari, bir nechta ketma-ket portni, ayniqsa 250 kbit/soniyani bittaga urish, har qanday AVRga qaraganda ko'proq tiyilish talab qiladi.
qo'shib qo'ydi muallif Ignacio Vazquez-Abrams, manba
Bu erda muammo siz qanday o'lchaysiz.
qo'shib qo'ydi muallif Al., manba
Shuning uchun bir nechta mahsulotim bo'lishi mumkin.
qo'shib qo'ydi muallif user26642, manba
Men faqatgina mega bilan sinov qilyapman, chunki hozirda mavjud bo'lgan narsa, yakuniy loyihada ATMEGA328 bo'ladi
qo'shib qo'ydi muallif user26642, manba

5 javoblar

Oldingi javoblarda aytilganidek, haqiqiy muammoingiz emas delayMicroseconds() ning to'g'riligini emas, balki uning aniqligini micros() .

Biroq, sizning haqiqiy savolingizga javob berish uchun ga javob berish uchun aniqroq ma'lumot mavjud delayMicroseconds() ga muqobil: _delay_us() funktsiyasidan AVR-libc aylanishi aniq va, masalan,

_delay_us(1.125);

does exactly what it says. The main caveat is that the argument has to be a compile-time constant. You have to #include in order to have access to this function.

Har qanday turdagi xohishni xohlasangiz, siz to'xtab turishingiz kerak to'g'ri kechikish.

Edit: As an example, if I were to generate a 4 µs pulse on PD2 (pin 19 on the Mega), I would proceed as follows. First, notice that the following code

noInterrupts();
PORTD |= _BV(PD2);  //PD2 HIGH
PORTD &= ~_BV(PD2); //PD2 LOW
interrupts();

makes a 0.125 µs long pulse (2 CPU cycles), because that's the time it takes to execute the instruction that sets the port LOW. Then, just add the missing time in a delay:

noInterrupts();
PORTD |= _BV(PD2);  //PD2 HIGH
_delay_us(3.875);
PORTD &= ~_BV(PD2); //PD2 LOW
interrupts();

and you have a cycle-accurate pulse width. It is worth noting that this cannot be achieved with digitalWrite(), as a call to this function takes about 5 µs.

6
qo'shib qo'ydi

Sizning test natijalaringiz noto'g'ri. delayMicroseconds() aslida juda aniq kechikib turadi (2 yoki 3 mikrosaniyadan ko'proq vaqtni kechiktirish uchun). Siz uning kodini /usr/share/arduino/hardware/arduino/cores/arduino/wiring.c faylida (Linux tizimida yoki boshqa tizimlarda o'xshash yo'lda) tekshirishingiz mumkin.

Biroq, micros() ning o'lchamlari to'rt mikrosaniyadir. (Qarang, masalan, noreferrer"> < kodi> micros() ). Shunday qilib, siz 4 mikrosaniyadan va 8 mikrosaniyadan o'qishni hech qachon ko'rmaysiz. Haqiqiy kechikish 4 mikrosaniyadan bir necha döngü bo'lishi mumkin, lekin sizning kodingiz 8 deb xabar beradi.

micros() natijasini xabar qilish uchun 10 yoki 20 delayMicroseconds (4); bir qatorda chaqiruvni bajaring (kodni takrorlash orqali).

3
qo'shib qo'ydi
Sizningcha, 5 ta 10 ta kechikish haqida nima deysiz? :) Shuni ham yodda tutingki, bitbanging uchun siz to'g'ridan-to'g'ri portdan foydalanishni talab qilishingiz mumkin, ya'ni digitalWrite() ni ishlatishingiz mumkin, bu bir necha mikrosaniyani bajarish uchun amalga oshiriladi.
qo'shib qo'ydi muallif Martin C. Martin, manba
"Yig'ilishni" boshlab, delayMicroseconds() degan ma'noni anglatadimi? Buni yuvarlamaktan ko'ra yaxshiroq deb bilaman. ⇒ Agar noto'g'ri ma'lumot manbasiga kelsak, agar muntazam chizilgan bo'lsa, vaqtni atrofdagi kodga bog'liq. Ko'rish uchun montaj yoki demontaj ro'yxatlarini o'qishingiz mumkin. Mening javobim bo'limiga qarang Arduino Mega 2560 ning PORTB uchun tengligi , bu sizning bittagina loyihangiz bilan bog'liq bo'lishi mumkin.
qo'shib qo'ydi muallif Martin C. Martin, manba
4 kechikish bilan, 32 va 28-chi ... 4 * 10 = 40 aralashmasini olaman.
qo'shib qo'ydi muallif user26642, manba
40 & 44 ... Ammo shunga qarama-qarshilik qilmaslik kerakmi? Men bu yerda nima etishmayapman?
qo'shib qo'ydi muallif user26642, manba

"Arduino" ning kechikkanida qanchalik yaxshi ekanini ko'rmoqchiman ... Bu erda juda dahshatli ko'rinadi.

micros() has a well-documented resolution of 4 µs.

Taymerni sozlash uchun taymerni 0 o'zgartirib (pirovard natijada raqamlarni chiqarib tashlaydi, lekin buning o'rnini qoplay olasiz) piksellar sonini yaxshilashingiz mumkin.

Shu bilan bir qatorda, Timer 1 yoki Timer 2-dan 1 prescaler bilan foydalaning, bu sizga 62,5 ns o'lchamini beradi.


  Serial.begin (9600);
 
-ni tanlang

Shunday bo'lsa-da, sekinlashadi.


8 4 8 4 4 4 4 8 8 8 8 4 8 8 4 4 8 4 4 4 8 8 8 4 8 4

Sizning chiqishingiz, vaqtni boshlash vaqtiga qarab, ba'zan ikkita "kenga" va ba'zan bir marta olishingiz mumkinligi bilan bir vaqtda, micros() ning 4 mklik aniqligiga mos keladi.


Sizning kodingiz o'lchov xatosining qiziqarli misoli. delayMicroseconds (4); 4 ms ga yaqinlashadi. Biroq, siz uni o'lchashga urinishingiz noto'g'ri.

Bundan tashqari, agar interrupt amalga oshsa, intervalni biroz uzaytiradi. To'liq kechikishni xohlasangiz, uzilishlarni o'chirib qo'yishingiz kerak.

2
qo'shib qo'ydi

Osiloskop bilan o'lchanadigan bo'lsak, men shuni topdim:

delayMicroseconds(0) = delayMicroseconds(1) = 4 μs real delay.

So, if you want a 35 μs delay you need:

delayMicroseconds(31);
1
qo'shib qo'ydi

To'g'ri, izchil natijalar olish uchun nima qilishim mumkin?

Arduino ilovasi juda keng tarqalgan, shuning uchun ba'zi ilovalarda samarali bo'lmasligi mumkin. Qisqa kechikishlar uchun bir necha yo'l bor, ularning har biri o'z kamchiliklari bilan.

  1. Nop foydalaning. Har birimiz bitta ko'rsatma, shuning uchun bizdan 16-chi.

  2. To'g'ridan-to'g'ri tcnt0-dan foydalaning.

0
qo'shib qo'ydi
TCNT0 o'qish 1 ta CPU aylanish jarayonini talab qiladi, chunki kutilgan natija 65 tuxum emas, 64 emas.
qo'shib qo'ydi muallif Sprogz, manba