всем добрый день, ОЧЕНЬ СРОЧНО, есть Arduino Uno, с него я отправляю электрический цифровой сигнал на приемник который должен будет сделать действие только если я отправлю ему нужную последовательность 1ничек и 0лей.частоту принятие устройства можно настраивать от 5KHz до 50KHz, соответственно отправку тоже можно настроить на нужную частоту. Для отправки и регулирование времени между каждыми сигналами я использовал такую функцию
for (int i = 0 ; i < 4 ; i++) { // повторяется 4 раза
char lettersend[8];
strcpy(lettersend, send[i]); //in the lettersend array we put a symbol array which means each letter
while (nextTimeUs > micros());
digitalWrite(LED_OUT, LOW);
nextTimeUs += on_offTimeUs;
for (int j = 8 ; j > 0 ; j--) {
if (lettersend[j-1] == '1')
{
while (nextTimeUs > micros());
digitalWrite(LED_OUT, HIGH);
nextTimeUs += on_offTimeUs;
}
else {
while (nextTimeUs > micros());
digitalWrite(LED_OUT, LOW);
nextTimeUs += on_offTimeUs;
}
}
while (nextTimeUs > micros());
digitalWrite(LED_OUT, HIGH);
nextTimeUs += 2*on_offTimeUs;
}
f = false;
digitalWrite(LED_OUT, LOW);
проблема в том что на маленьких частотах (от 5 - 30KHz) сигнал правильно отправлчется и аппарат его правильно принимает и выполняет то что нужно, а на более высоких частотах я проанализировал на осциллографе есть погрешности(то есть например на частоте 50KHz период то есть 1 сигнал должен длится 20микросек а на осцилогравфе проказывает что некоторые сигнал отправился с длительностью 16 микросек), поесть присутствует погрешность и я думаю она из за использования micros().
Как решить мою проблему?
Код ваш очень сырой.
В нем много чего можно улучшить.
Убрать digitalWrite() вам уже посоветовали. Ещё можно заменить символьное представление сигнала ( ваши нули и единички) на битлвый массив. А отправку по задержке - на таймер.
Так и есть. Разрешение micros() (на 16MHz) 4мкс. То есть, что 1, что 2, что 3 , всё равно будет 4мкс. Это надо учитывать.
И , если “немного меньше” 20 - это не 19, а 16.
Как вариант, вместо
while (nextTimeUs > micros());
используйте функцию delayMicroseconds().(см # 2)
P.S.
На правильно вставленный код, быстрее получите нужный ответ
Да, нет. У меня цикл на три такта. А мелкие да, нопами.
Я сделал так. Поскольку цикл занимает шесть байтов, я вставляю нопами до шести штук. Если надо больше, то цикл. Но трёхтактовый, а не четырёхтактовый.
Получается, что для 16МГц, до 375 нс у меня разрешение 62.5 нс, а свыше 375 нс разрешение в три раза хуже - 187,5. Ограничение 766 тактов максимум.
При этом мне было важно, чтобы “не меньше”, поэтому все округления у меня не до ближайшего, а до большего.
Спойлер
#ifndef DELAY_NANO_SECONDS
#define DELAY_NANO_SECONDS
//
// Задержка в наносекундах
// Точнее, в тактах контроллера, длящихся не менее указанного количества наносекунд
// При необходимом количестве тактов от 1 до 6 включительно, задержка именно на это количество
// тактов. Если же требуется от 7 до 766 тактов, задержка организуется с точность до 2-х тактов
// (в сторону увеличения).
//
// Всё считается для тактовой частоту FCPU, которая должна быть задана до включения этого файла.
// Если FCPU не была задана, то используется F_CPU
//
// Максимальная задержка - 766 тактов контроллера. В зависимости от частоты это соответствует
//
// Частота(МГц) Наносекунд в 766 тактов
// 1 766 000
// 2 383 000
// 4 191 500
// 8 95 750
// 16 47 875
// 20 38 300
//
namespace nsNanoSecondsDelay_ {
#ifndef FCPU
#define FCPU F_CPU
#endif
// Переводит наносекунды в тики контроллера с избытком
// С плавающей точкой
constexpr double ns2ticksf(const uint16_t ns) { return static_cast<double>(ns) * FCPU * 1e-9; }
// Как целое
constexpr uint32_t ns2ticks(const uint16_t ns) { return ns2ticksf(ns) + 0.99; }
//
// Основной шаблон порождает пустую структуру, которая вызовет ошибку компиляции.
// Например, такая ошибка получится, если при F_CPU равном 16МГц запросить
// задержку в 48000 наносекунд (это выходит за границы применимости)
//
// Все же реально рабочие варианты будут специализированы
//
template<const uint16_t ns, const uint16_t ticks = ns2ticks(ns), const bool oneByte = (ticks < 767)> struct nsDelay{};
//
// Задержки от 1 до 6 тактов включительно специализируются
// непосредственно включением нужного количества операций "nop"
//
#define EXAT_DELAY(mcuTicks, nops) \
template<const uint16_t ns> \
struct nsDelay <ns, mcuTicks, true> { \
static inline void nanoSeconds(void) __attribute__((always_inline)) { \
__asm__ __volatile__ ( nops ); \
} \
};
EXAT_DELAY(1,"nop")
EXAT_DELAY(2,"nop\n\tnop")
EXAT_DELAY(3,"nop\n\tnop\n\tnop")
EXAT_DELAY(4,"nop\n\tnop\n\tnop\n\tnop")
EXAT_DELAY(5,"nop\n\tnop\n\tnop\n\tnop\n\tnop")
EXAT_DELAY(6,"nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop")
//
#undef EXAT_DELAY
//
// Задержки от 7 до 766 тактов включительно
// специализируются через цикл
// ldi r24, N
// L: dec r24
// brne L
// Длительность исполнения цикла: 3*N+1
// Точность от 0 до 2 тактов (с превышением времени задержки)
// Размер цикла - 6 байтов (потому первые шесть и сделаны через nop)
//
template<const uint16_t ns, const uint16_t ticks>
struct nsDelay<ns, ticks, true> {
static inline void nanoSeconds(void) __attribute__((always_inline)) {
__asm__ __volatile__ ("ldi r24,%0\n\t1: dec r24\n\tbrne 1b"::"M"((ticks+1)/3):"r24");
}
};
} // nsNanoSecondsDelay_
#define delayNanoSeconds(n) do { nsNanoSecondsDelay_::nsDelay<n>::nanoSeconds(); } while(false)
#endif // DELAY_NANO_SECONDS
@ЕвгенийП это всё очень интересно. Но вопрос “Как?” уходит на второй план после вопроса “Зачем?”. Это радиолокатор? ФАР? Терминатор? Или того хуже, проект Гайвера? Впрочем, учитывая ваш опыт и знания, последнее маловероятно.
Не, ну если делать так, как у Вас, то не понимаю чем Вас не устраивают системные цикловые решения. В системной библиотеке есть две функции для задержек в тактах : _delay_loop_1 и _delay_loop_2. Живут они в