Читатель сигнала

всем добрый день, ОЧЕНЬ СРОЧНО, есть Arduino Uno, с него я отправляю электрический цифровой сигнал на приемник который должен будет сделать действие только если я отправлю ему нужную последовательность 1ничек и 0лей.частоту принятие устройства можно настраивать от 5KHz до 50KHz, соответственно отправку тоже можно настроить на нужную частоту. Для отправки и регулирование времени между каждыми сигналами я использовал такую функцию

void sending() {
digitalWrite(LED_OUT, HIGH);
delay(5);
nextTimeUs = micros();

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().
Как решить мою проблему?

  1. Заменить digitalWrite() на direct port manipulation;
  2. Делать блокирующую отправку с delayMicroseconds() или delay_us()

Код ваш очень сырой.
В нем много чего можно улучшить.
Убрать digitalWrite() вам уже посоветовали. Ещё можно заменить символьное представление сигнала ( ваши нули и единички) на битлвый массив. А отправку по задержке - на таймер.

Сигнал с Ардуино может быть механический?

Ну Олю знаю, Одинничек не знаю. Это из какой интересной книжки честно своровано?
А чего про вставку кода все молчат как партизаны?)

4 раза внимательно перечитал, так и не понял что за сигналы, частоты, куда и откуда. Я один непонятливый?

1 лайк

@belochka , а как Вы синхронизируете передачу и прием?
И чему равна величина on_offTimeUs?

Утащил в закладки.

2 лайка

@belochka , глубоко выдохни и скажи ещё раз более внятно в чём суть кода.

Так и есть. Разрешение micros() (на 16MHz) 4мкс. То есть, что 1, что 2, что 3 , всё равно будет 4мкс. Это надо учитывать.
И , если “немного меньше” 20 - это не 19, а 16.

Как вариант, вместо

while (nextTimeUs > micros());

используйте функцию delayMicroseconds().(см # 2)

P.S.
На правильно вставленный код, быстрее получите нужный ответ

Я не понял только, почему тема называется “Читатель сигнала”, а код приведён “Писателя сигнала”

1 лайк

_delay_us() на самом деле.

Ну, или попросить у меня крутую функцию delayNanoSeconds() – их есть у меня :slight_smile:

Видимо, ТС - тот самый Константин Константинович – «читатель поэзии, амфибрахист».

1 лайк

Я бы ознакомился с крутой функцией)
Не праздного любопытства ради, для общего развития ради.

1 лайк

У меня разрешение менее 250нс(16МГц) не получилось.))

Ну так 4 такта как раз 62.5нс×4=250нс.
Мельче только nop’ами))

Уважаемый Евгений Петрович!
Прошу Вас открыть нам сие чудо, вышеуказанную Вами функцию, за для успокоения неуёмного брожения неокрепшего ума.

Да, нет. У меня цикл на три такта. А мелкие да, нопами.

Я сделал так. Поскольку цикл занимает шесть байтов, я вставляю нопами до шести штук. Если надо больше, то цикл. Но трёхтактовый, а не четырёхтактовый.

Получается, что для 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

Большое спасибо, разберусь позже, сейчас пока времени нет.

Мой вариант попроще, около 4х тактов за один цикл.
Но это для константы. Для переменной пока не пробовал, как компилятор среагирует))

void delay_4X_CPUcycle(uint32_t X)
{
  while (X--);//X = 4 cycles = 1/4us (16MHz)
}

P.S.

Но, возможно, надо ещё погонять, проверить, всегда ли так

@ЕвгенийП это всё очень интересно. Но вопрос “Как?” уходит на второй план после вопроса “Зачем?”. Это радиолокатор? ФАР? Терминатор? Или того хуже, проект Гайвера? Впрочем, учитывая ваш опыт и знания, последнее маловероятно.

Не, ну если делать так, как у Вас, то не понимаю чем Вас не устраивают системные цикловые решения. В системной библиотеке есть две функции для задержек в тактах : _delay_loop_1 и _delay_loop_2. Живут они в

#include <util/delay_basic.h>
1 лайк

Вопрос вижу, и не игнорирую. Вечером или завтра вернусь к нему.