Перейти к содержанию
    

Приемник радиосигнала, для ворот

Добрый день. Хочу сделать привод для ворот. Имеется вот такой приемник и сигнал который он принимает. Микроконтроллер атмега 8. Предполагается использовать таймер для принятия сигнала, он будет отслеживать что приходит на ножку и заносить в массив, затем сохранять его и сравнивать в будущем.

Screenshot_20230822-085557.png

timer2_init{};

masive_signal[];

masive_open[];

masive_close[];

//PIND5 нога куда заведена антена

//PIND2 нога записи сигнала открыть

//PIND3 нога записи сигнала закрыть

while(1)

{

 int size = 10; //по сути ширина сигнала

 ISR(timer2_compa_vect)

{

 int j = 0;

 masive_signal[j] = PIND5;

 j++;

 if(PIND2==1)//если нажата кнопка открыть

 {

 masive_open = new int ;

 //записываем сигнал как открыть

 for (int i = 0; i<size; i++) {masive_open = masive_signal;}

 //заносим в память

 EEPROM.write(0,masive_open);

 delet[]masive_open;

 }

 if(PIND3==1)//если нажата кнопка закрыть

 {

 masive_cloze = new int ;

 //записываем сигнал как открыть

 for (int i = 0; i<size; i++) {masive_cloze = masive_signal;}

 //заносим в память);

 EEPROM.write(1,masive_close);

 delet[]masive_cloze;

 }

}

if(masive_signal == masive_open) команда открыть;

if(masive_signal == masive_close) комана закыть;

 

 

 

 


Вот осциллограммы

 

 

 

1692875346771.jpg

1692875346246.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Работает, определяет? Хорошо.

Хотя конечно лучше декодировать сигнал в двоичную форму (0/1) на основе измеренных длительностей, а потом просто сравнивать получившийся двоичный код в виде некоего числа. 
Ну и в EEPROM лучше не писать каждый раз принятый сигнал. Достаточно одного раза, при "обучении" приемника.

поставил + для нейтрализации. Если человек не умеет, это еще не повод его гнобить и минусовать.

5 часов назад, Дмитрий МВ сказал:
if(PIND2==1)//если нажата кнопка открыть
{
  masive_open = new int ;
  //записываем сигнал как открыть
  for (int i = 0; i<size; i++) {masive_open = masive_signal;}
  //заносим в память
  EEPROM.write(0,masive_open);
  delet[]masive_open;
}

При нажатой кнопке эти действия будут повторяться мильён раз в секунду безостановочно, до тех пор, пока кнопка остается нажатой. Нужно внести дополнительную переменную-флаг ("триггер"), которая будет устанавливаться при первом заходе в это условие и сбрасываться только при отпускании кнопки. А это условие дополнить еще одной проверкой типа if(flag == 0) , то есть, чтобы вход в эту часть кода был только при значении флага = 0, то есть только один раз.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 часов назад, Дмитрий МВ сказал:

Хочу сделать привод для ворот.

https://vorotnet.ru/aksesuary/priemniki/radiopriemnik-vneshnij-dlya-vorot-i-shlagbaumov-furniteh-ge-rcv1

https://profipult.ru/product-category/priemniki-dlya-vorot/

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Vasily_ сказал:

Ну может чел. просто хочет подучить программирование, а это реле та, под руку попалось)))))))))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

извиняюсь за долгое отсутствие, долгий больничный, куча работы накопилось.

вот набросок но куча варнингов, проблемы с записью и чтением из EEPROM. видимо я что то не понимаю. 

 

 

10 minutes ago, Дмитрий МВ said:

извиняюсь за долгое отсутствие, долгий больничный, куча работы накопилось.

вот набросок но куча варнингов, проблемы с записью и чтением из EEPROM. видимо я что то не понимаю. 

#include <avr/io.h>

#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <avr/eeprom.h>
#include "main.h"
void port_ini (void)
{
	DDRD &=~ (1<<2)|(1<<3)|(1<<5)|(1<<6);  DDRD |= (1<<7);
	PORTD &=~ (1<<2)|(1<<3)|(1<<7);        PORTD |= (1<<5)|(1<<6);
	DDRB &=~ (1<<0)|(1<<7);                DDRB |= (1<<1);   
	PORTB &=~ (1<<0);                      PORTB |= (1<<1)|(1<<7);
	DDRC |= (1<<2)|(1<<3)|(1<<5);          PORTC &=~ (1<<2)|(1<<3)|(1<<5);
}
void timer_ini(void)
{
	TCCR1A = 0x00;
	TCCR1B |= (1<<WGM12)// устанавливаем режим СТС (сброс по совпадению)
	|(1<<CS10);            // делитель
	TCNT1 = 0x00;                    // Обнуляем счетный регистр
	OCR1A=833;                    // Настраиваем регистр сравнения 1000000/833=1200
	//CS12	CS11	CS10
	//0		0		0	нет тактирования
	//0		0		1	/1
	//0		1		0	/8
	//0		1		1	/64
	//1		0		0	/256
	//1		0		1	/1024
	//1		1		0	External clock source on T1 pin. Clock on falling edge.
	//1		1		1	1 External clock source on T1 pin. Clock on rising edge.
	
	// Разрешаем прерывание таймера по совпадению с OCR1A
	TIMSK |= (1<<OCIE1A);
}
//заносим в массив входящий сигнал
ISR (TIMER1_COMPA_vect)
{
	massive_signal[i]=data_input;
	i++;
}
int main(void)
{
	timer_ini();
	port_ini();
	sei();
    while (1) 
    {
		if (button_open) 
		{
			flag_button_open;
		}
		if (button_close) 
		{
			flag_button_close;
		}
		if (flag_button_open)
		{
			//копируем массив 
			memccpy(massive_open,massive_signal,'@',10);
			//заносим массив в память
			eeprom_write_block(massive_open,0,10);
			flag_button_open = false;
		}
		if (flag_button_close)
		{
			memccpy(massive_close,massive_signal,'@',10);
			eeprom_write_block(massive_close,1,10);
			flag_button_close = false;
		}
		unsigned int massive_open_memories[10];
		unsigned int massive_close_memories[10];
		eeprom_read_block(massive_open_memories, 0,10);
		eeprom_read_block(massive_close_memories, 1,10);
		if (memcmp (massive_open_memories, massive_signal, 10) == 0)
		{
			open;
		}
		if (memcmp (massive_close_memories, massive_signal, 10) == 0)
		{
			close;
		}
		if (alarm)
		{
			stop;
		}
    }
}

 

 

Изменено пользователем Дмитрий МВ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Несколько замечаний. Сам алгоритм не пытался понять, чисто визуально.

1) вы не приложили main.h, в котором, подозреваю, определены переменные. В заголовочных файлах в 99% случаев нужно делать только объявления (declaration) с префиксом extern, а не определения (definition). Ваш подход приведёт к "непонятным" проблемам, если проект разрастётся до нескольких .c файлов.

2) в обработчике прерывания таймера вы записываете значения (не очень понятно, какие, ну да ладно) в массив без проверки значения 'i'. Это может закончится порчей памяти и очень странными ошибками.

3) eeprom_read_block, eeprom_write_block, memcmp в качестве последнего аргумента используют размер в байтах. 'unsigned int massive[10]' в случае AVR имеет размер 20 байт.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

17 minutes ago, esaulenka said:

Несколько замечаний. Сам алгоритм не пытался понять, чисто визуально.

1) вы не приложили main.h, в котором, подозреваю, определены переменные. В заголовочных файлах в 99% случаев нужно делать только объявления (declaration) с префиксом extern, а не определения (definition). Ваш подход приведёт к "непонятным" проблемам, если проект разрастётся до нескольких .c файлов.

2) в обработчике прерывания таймера вы записываете значения (не очень понятно, какие, ну да ладно) в массив без проверки значения 'i'. Это может закончится порчей памяти и очень странными ошибками.

3) eeprom_read_block, eeprom_write_block, memcmp в качестве последнего аргумента используют размер в байтах. 'unsigned int massive[10]' в случае AVR имеет размер 20 байт.

1) почему dec а не def? В примерах на микроконтроллер везде пишут def.

2) согласен у меня размер массива 10, нужно внести изменения

3) размер в байтах? Спасибо внесу поправку

Изменено пользователем Дмитрий МВ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24 minutes ago, Дмитрий МВ said:

1) почему dec а не def? В примерах на микроконтроллер везде пишут def.

Потому что заголовочный файл может include'иться в несколько .c файлов одновременно. Ваш подход приведёт к образованию нескольких копий переменных, и благоприятный исход всего этого - линкер при компиляции выдаст ошибку (неблагоприятный - накомпилирует чёрт знает что).

24 minutes ago, Дмитрий МВ said:

3) размер в байтах? Разве не размер массива?

Размер массива в байтах, в документации вполне явно написано. Ну и это не с++, компилятор не сможет узнать размер одного элемента.

 

У вас, кстати, с этими eeprom read/write ещё одна ошибка. Надо указывать адреса так, чтобы они не перекрывались. Сейчас massive_open состоит из одного байта, принятого при открытии и "хвоста" из massive_close.

 

Ещё одно "темное" место:

		if (button_open) 
		{
			flag_button_open;
		}
                ...
		if (flag_button_open)
		{
                      ...

Что такое flag_button_open ? если это переменная типа bool, то что происходит в начале?

 

И ещё. Что за магия с memccpy ? Вы точно хотите использовать это вместо обычного memcpy ?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 minutes ago, esaulenka said:

заголовочный файл может include'иться в несколько .c файлов одновременно

Это как? На мониторе один файл .с и один .h 

10 minutes ago, esaulenka said:

документации вполне явно написано.

Да точно, не внимательный был.

15 minutes ago, esaulenka said:

У вас, кстати, с этими eeprom read/write ещё одна ошибка. Надо указывать адреса так, чтобы они не перекрывались. Сейчас massive_open состоит из одного байта, принятого при открытии и "хвоста" из massive_close.

Это где так?

eeprom_write_block(название массива, адрес в памяти куда записать, размер массива в байтах)

18 minutes ago, esaulenka said:

Что такое flag_button_open ? если это переменная типа bool, то что происходит в начале?

Да bool, вначале она объявлена значит равна нулю. 

 

19 minutes ago, esaulenka said:

if (button_open) { flag_button_open; }

Здесь она приравнивается к единице. 

20 minutes ago, esaulenka said:

Что за магия с memccpy ?

Сравнить два массива. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

17 minutes ago, Дмитрий МВ said:

Это как? На мониторе один файл .с и один .h 

А у меня два монитора и несколько проектов, в каждом из которых по полсотни исходных файлов. Вы уж определитесь - у вас всё хорошо, или "куча варнингов, проблемы, я не понимаю".

 

20 minutes ago, Дмитрий МВ said:

Здесь она приравнивается к единице. 

"приравнивается к единице" записывается как "var = 1;", а тут, с высокой вероятностью, написана ерунда.

 

26 minutes ago, Дмитрий МВ said:

Это где так?

eeprom_write_block(название массива, адрес в памяти куда записать, размер массива в байтах)

В вашем коде ДВА вызова eeprom_write_block. Найдите оба и сравните адреса, которые вы туда передаёте.

 

 

21 minutes ago, Дмитрий МВ said:
41 minutes ago, esaulenka said:

Что за магия с memccpy ?

Сравнить два массива. 

Ну ок. Вы даже читать не пытаетесь. Вопросов больше не имею.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Цитата
if (button_open) 
{
    flag_button_open;
}

Неясно, что такое flag_button_open. Если это переменная, вы должны явно написать flag_button_open = 1; или flag_button_open = true;

17 часов назад, Дмитрий МВ сказал:

но куча варнингов,

Какого рода они, что написано, на что указывают? Полагаю, что как минимум, на flag_button_open без правой части - пишется statement has no effect - выражение не имеет эффекта. 
В операторе if() можно не указывать явно, чему равен flag_button_open, поскольку любое значение, отличное от нуля, будет истинным (true). А в других случаях нужно явно указывать, какое значение будет присвоено переменной. То есть, обязательна как левая, так и правая (после знака = ) часть выражения.

 

 

Ну и я уже выше писал - логика работы должна быть триггерной, то есть:

	if(button_open && !flag_button_open) // если нажата кнопка и нет флага триггера
	{
		flag_button_open = true;   // установить триггер
		// Выполнить открытие двери
	}

	if(!button_open)   // если кнопка отпущена
	{
		flag_button_open = false;  // сбросить триггер
	}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще, если это приемник, то тогда зачем в нем нужна обработка кнопок? Разве что это дополнительные кнопки местного открывания изнутри.
В целом, программа может выглядеть следующим образом:

bool isReceiveCommlete;			// флаг завершения приема пакета

#define NUM_TEMPL_PACKS		3	// число известных шаблонов пакета
#define NUM_ELEM_IN_PACK	5	// число элементов в пакете

bool templates[NUM_TEMPL_PACKS][NUM_ELEM_IN_PACK] = {{0, 0, 0, 0, 1},
		{0, 1, 0, 1, 0}, {1, 0, 0, 0, 1}};		// массив шаблонов пакета
bool receivePacket[NUM_ELEM_IN_PACK];			// буфер для приема пакета

/**
 * Инит хардвара (аппаратных модулей)
 */
void HardwareInit()
{
	// Аппаратные модули инициализованы и настроены
}

/**
 * @brief Сравнение принятого пакета с известными шаблонами.
 * @return Номер шаблона, которому соответствует принятый пакет,
 * либо, если соответствие не найдено, значение, большее чем
 * число пакетов
 */
int CompareReceivePacet()
{
	int id = 0;
	/* Сравнение принятого пакета с одним из шаблонов:
	 * повторять инкремент id (номера шаблона) до тех пор, пока
	 * не будет найден совпадающий или не проверятся все шаблоны */
	while((memcmp(receivePacket, templates[id], sizeof(receivePacket)))
			&& (id < NUM_TEMPL_PACKS))
	{
		id++;
	}
	return id;
}

/**
 * @brief
 */
int main(void)
{
	/* Инициализация аппаратных модулей */
	HardwareInit();

	/* Основной цикл работы */
	while(true)
	{
		// Если завершен прием полного пакета по радиоканалу,
		if(isReceiveCommlete)
		{
			// ...сравнить полученный пакет с набором шаблонов
			// и выполнить соответствующее действие
			switch(CompareReceivePacet()) {
			case 0:
				// команда "Стоп!", остановить дверь
				break;
			case 1:
				// команда "Открыть дверь", выполнить открытие
				break;
			case 2:
				// команда "Закрыть дверь", выполнить закрытие
				break;
			default:
				// Неизвестная команда, ничего не делать
				break;
			}
			isReceiveCommlete = false; // сбросить флаг принятого пакета
		}
	}
}

Запись в EEPROM не нужна, я ж уже ранее писал - это лишние действия. Вам нужно просто посмотреть лог. анализатором все принимаемые пакеты, декодировать их по длительностям уровней и внести шаблоны в таблицу в виде последовательностей единиц и нулей. 

Декодировать пакета можно делать, изменяя интервалы между изменениями уровня сигнала и определяя, в какой диапазон они попадают. Исходя из этого, присваивать 0 или 1 очередному биту в пакете. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 hours ago, EdgeAligned said:

Вообще, если это приемник, то тогда зачем в нем нужна обработка кнопок?

Мой хрустальный шар подсказывает, что это кнопки для "запоминания" магической последовательности, и пользователь их должен нажимать примерно один раз в жизни устройства - когда меняет пульт. Насколько это надёжно работает - я не знаю. Скорее всего, не очень.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...