Страница 2 из 2

Re: Автосигнализация постоянно срабатывает от помех

Добавлено: Вт дек 20, 2016 22:37:14
Nerevarine1810
Перевел код брелка в двоичный вид (100 бит). На досуге накидал что мог. Естественно, в отладчике работает отлично. В железе пока что тоже нет особых претензий, за 5 минут теста такая картина: сигналка рядом "буянит" релюшками, а светодиод не горит, значит не будет пропускать к декодеру. Нажимаю на пульт - загорается светодиод. Все как и планировалось. Пока МК подсоединил параллельно к DATA. Надо будет потестить и поиграть со значениями в первом FOR (где несколько проверок на ноль), чтобы пульт срабатывал стабильно (сейчас то с первого раза, то с пятого). Опять же, наверняка есть более эффективный способ, но и так работает. Код сырой, надо немного улучшить + добавить коды брелков. Тут даже не придется сравнивать 2-3 раза, вместо этого длинная проверка нулевого уровня в начале.
Спойлер

Код: Выделить всё

#define F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>

unsigned char massiv[101];		// Принимаемый массив кода брелка
unsigned char i_massiv = 0;		// Его индекс

int main(void) {
/*	Задействую порт B, прием сигнала на вывод 7
	Индикация окончания приема вывод 0
	(на нем будет светодиод через резистор).
	Остальные порты на вход + подтягивающий резистор
	против наводок
*/
	DDRB &= 0;
	DDRB |= (1<<0);
	PORTB |= 0b11111111;
	PORTB &= ~(1<<7);
	PORTB &= ~(1<<0);

	for (int i = 0; i < 101; i++) {					// Запись массива левыми числами
	massiv[i_massiv] = i_massiv;
	i_massiv++;
	}

	i_massiv = 0;

    while (1) {
		if (PINB == 0b01111110) {					// Проверка нуля на 7 ножке
			for (int i = 0; i < 9; i++) {			// Проверяем 9 раз по 800мкс = 720мкс (10мс разрыв между кодами)
				if (PINB == 0b11111110) break;		// Если '1', то прервать проверку
				_delay_us(800);
				if (i == 8) i_massiv = 1;			// Если успешно, условный переход на запись данных в массив
			}
			
			if (i_massiv == 1) {					// Сам условный переход
				i_massiv = 0;
				while (PINB != 0b01111110);			// Ждем первой '1' (оставшаяся время до кода)
				_delay_us(170);						// Задержка в пол импульса
				for (int i = 0; i < 101; i++) {		// Запись данных в массив
					massiv[i] = PINB>>7;
					_delay_us(340);
				}
			}
		}
		if (massiv[97] == 1) PORTB |= (1<<0);		// Собственно, записался ли код ('1' точно должна быть на 97 месте моего кода)
		//if (massiv[97] == 0) PORTB |= (1<<0);		// Проверка общая, вообще ли записывает что то в массив (0 или 1)
    }
	return 0;
}
И да, "unsigned char i_massiv" выкину вообще, он не нужен, тот переход условный во внутрь цикла проверки нуля помещу. Так же избавлюсь от проверок PIN всех ненужных портов. Ну это все ближе к воскресению))
Ну в простейшем случае - подаём на вывод INT
Хотел сначала, но будет куча прерываний ложных + еще счетчик задействовать. И как эти "кривые" импульсы определить? Думаю, сложнее получилось бы)) А тут простая логика, проще. А что проще - то надежнее :) А UART - насколько помню нужна скорость для него. 1/длит импульса = 2900 бит/с. Ближайшая стандартная 2400 бод. А хотя же там можно регистрами любую выставить. Да, как вариант. Но тут как - сначала надо полностью принять байт, сравнить его и только потом вынести вердикт, записывать все дальше или заново проверять первый байт.

Пока дописывал сообщение, обнаружил баг у себя (светодиодик загорелся). Оказывается, к ночи эфир очищается и уровень 0 стоит достаточно долго. Вот и срабатывает. Получается, что проверка на 0 проходит и идет запись в массив. Надо добавить дальше одну проверку на первые импульсы. Да и хотя, когда добавлю код брелка, он не совпадет с записанным массивом, поэтому не особо и баг получается) Но чтобы лишний раз массив не записывался добавлю проверку.

И да, поле деятельности (пока что камень Atmega8A). То, что конденсатор мятый - знаю. Китайцы таким прислали :))
СпойлерИзображение

Re: Автосигнализация постоянно срабатывает от помех

Добавлено: Ср дек 21, 2016 14:44:36
roman.com
Ну в целом всё верно)) Один момент - на МК надо поставить кварц. Иначе при изменении температуры (зимой-летом) частота выборок (семплов) будет не совпадать с частотой импульсов пульта.. Уже проходили..))

В простом UART есть логика обнаружения ложного старт-бита. В даташите так и написано:
1- в исходном состоянии - на входе UART высокий уровень.
2- при появлении низкого уровня включается логика обнаружения старт-бита. МК проверяет (по семплам) действительно ли это старт-бит (или просто помеха).
3- если старт-бит не обнаружен (т.е. помеха), возвращаемся к пункту 1.
4- после обнаружения действительного старт-бита включается логика обнаружения последующих битов и записи последующих битов в буфер приёмника (в нашем случае запись в массив).
...
Но определение по одному биту - это малоэффективно.

Поэтому обычно для синхронизации используют не один бит, а синхро байт. МК начинает запись в буфер приёмника (в нашем случае запись в массив), после того как найдёт синхробайт... или несколько синхробайт. По этому принципу работают практически все радиомодули. При этом ошибок меньше)) Как пишут в даташитах: буфер приёмника (в нашем случае запись в массив) не заполняется шумом.

А ещё я обычно использую не одну проверку импульса (семпл), а много проверок каждого импульса, как во всех современных радио модулях. При этом точность определения импульсов заметно выше... соответственно и ошибок меньше. Только нужно чтобы МК в пульте и приёмнике были с кварцами. А кстати... пульт у нас с кварцем?

Жаль что код - не манчестер)) Я обычно использую манчестер... тоже по семплам, только я семплы считаю иначе (манчестер это позволяет). У меня МК работает с шумами))
3.jpg
(193.23 КБ) 600 скачиваний
Короче.. всё ясно. Осталось дописать и оптимизировать код. ))
:tea:

Re: Автосигнализация постоянно срабатывает от помех

Добавлено: Ср дек 21, 2016 21:40:20
Nerevarine1810
Оптимизировал я, конечно, по полной :)))
А кстати... пульт у нас с кварцем?
Да, с кварцем) Сегодня убил немало времени на связь пульта с МК - черт пойми что происходит. Видимо косяк с алгоритмом. Это на чем застрял. Код был похож принимаемый на теоретический, но всегда где-то появлялась помеха и битики пропадали нужные. Код для интереса, отладочный типа. Запись в EPPROM для анализа. Синхронизация такова - ищем длительность 10мс низкого уровня, потом ждем переход из 0 в 1. Сразу же задержка в пол импульса и считывание всех импульсов через их длительность.
Спойлер

Код: Выделить всё

volatile unsigned long long massiv_L = 0;		// Принимаемый массив кода брелка
volatile unsigned long long massiv_H = 0;

volatile unsigned long long OFF_L = 0xEEE88888EEE88E88; // EE E8 88 88 EE E8 8E 88
volatile unsigned long long OFF_H = 0x0000000EEEE8EE8E; // 00 00 00 0E EE E8 EE 8E


while (1) {
	if (!(PINB & (1<<7))) {							// Проверка нуля на 7 ножке
		for (i = 0; i < 78; i++) {					// Проверяем 9 раз по 800мкс = 720мкс (10мс разрыв между кодами)
			if (PINB & (1<<7)) break;				// Если '1', то прервать проверку
			_delay_us(125);
			if (i == 77) {							// Если успешно, условный переход на запись данных в массив
				while (!(PINB & (1<<7)));			// Ждем первой '1' (оставшаяся время до кода)
				_delay_us(177);						// Задержка в половину импульса
				for (i = 0; i < 101; i++) {			// Запись данных в массив
					if (i > 35) {
						massiv_L = massiv_L << 1;
						massiv_L |= (PINB>>7)<<0;
						_delay_us(355);
					}
					else {
						massiv_H = massiv_H << 1;
						massiv_H |= (PINB>>7)<<0;
						_delay_us(355);
					}
				}
				i = 8;
				
				eeprom_write_dword(&DATA1, (massiv_L>>32));
				eeprom_write_dword(&DATA2, massiv_L>>16);
				
				
				//if ((massiv_H == OFF_H) || (massiv_L == OFF_L)) PORTB |= (1<<0);
				
				//eeprom_write_dword(&DATA2_L, massiv_H>>4);
				//eeprom_write_dword(&DATA2_H, massiv_H<<4);
				
				PORTB |= (1<<0);
				//massiv_H = OFF_H; massiv_L = OFF_H;
				//if ((massiv_H == OFF_H) && (massiv_L == OFF_L)) eeprom_write_dword(&DATA_L, massiv_H);
				_delay_ms(500);
				PORTB &= ~(1<<0);
			}
		}
	}
}
*/
После долгих размышлений пришла мысль все в край упростить - проблема же с шумами? Так и надо чтобы их не было и все. Реализация на транзисторном ключе, управляемым МК (опять же четко отслеживаем интервал 10мс между последовательностями импульсов, и если этот интервал соблюдается - открыть транзистор). Через транзистор данные из DATA попадут на штатный МК, в момент передачи помех нет. А при помехах он будет закрыт (тестил день - не было срабатываний). А если эфир будет чист, то и транзистор будет всегда включен. Вот что получилось, для ATtiny13A:
Спойлер

Код: Выделить всё

#define F_CPU 1000000

#include <avr/io.h>
#include <util/delay.h>

int main (void) {
	DDRB |= (1<<0);					// Задействую порт B, прием сигнала на вывод 7
	PORTB &= ~((1<<5) | (1<<0));	// Вывод 0 на транзисторный ключ

    while (1) {
		if (!(PINB & (1<<5))) {				// Проверка нуля на 7 ножке
			for (char i = 0; i < 80; i++) {	// Проверяем 78 раз по 125мкс = 9,75мс (10мс разрыв между кодами)
				if (PINB & (1<<7)) break;	// Если '1', то прервать проверку
				_delay_us(125);
				if (i == 79) {				// Если успешно, условный переход на запись данных в массив
					PORTB |= (1<<0);		// Открыть транзистор
					_delay_ms(300);			// Время нескольких кодов брелка
					PORTB &= ~(1<<0);		// Закрыть транзистор
				}
			}
		}
	}
	return 0;
}
Наверно до этого дошел из-за усталости. В этом решении даже кварц не нужен.

А Ваши идеи хороши, для серьезных проектов такие и следует использовать. Буду иметь ввиду. Завтра куплю МК и в пт наверно все соберу. Выходные потестить надо будет и к пн поставлю обратно на авто. Пока такие планы :)

Re: Автосигнализация постоянно срабатывает от помех

Добавлено: Чт дек 22, 2016 14:25:34
roman.com
Идею проверять каждый импульс только один раз можно использовать в самодельном ИК пульте или когда сигнал идёт по проводам, да ещё в экранированном кабеле и только на небольшое расстояние)). При передачи кодов с помощью ИК пультов шумов нет. На выходе фотоприёмника (TSOP) никаких шумов нет.
С радио каналом этот номер не прокатит)) Потому, что у нормального радиприёмника всегда на выходе есть шумы. Поэтому проверять только один раз каждый импульс - не эффективно. На эти "грабли" многие уже наступали, когда пытались использовать простые алгоритмы при передачи по радиоканалу)) Вот почему все современные радио модули проверяют много раз каждый импульс. Тогда всё работает чётко)). :tea:
Nerevarine1810 писал(а):Синхронизация такова - ищем длительность 10мс низкого уровня, потом ждем переход из 0 в 1. Сразу же задержка в пол импульса и считывание всех импульсов через их длительность.
для интерса сделал то же самое в протеусе))
Синхронизация такова - ищем длительность 4мс высокого уровня, потом ждем переход из 1 в 0 - старт бит. После этого считывание всех семплов в массив, с задержками через таймер (таймер тактируется от кварца, поэтому все задержки получаем с кварцевой точностью). Всё работает))
2.jpg
(59.02 КБ) 381 скачивание
Причём сами импульсы могут быть "ломанные" и даже с шумами (в разумных пределах конечно)... Всё равно МК находит синхро...))
Всё работает))
3.jpg
(58.4 КБ) 598 скачиваний
Nerevarine1810 писал(а):Реализация на транзисторном ключе
Ну можно и так... Теоретически можно и без ключа)). Сигнал с приёмника (DATA) МК пропускает через себя...

Примерно так:
1- МК ищет синхро. При этом выход МК отключен. PORTB.0=0;
2- МК находит синхро. При этом выход МК отключен. PORTB.0=0;
3- МК ждёт старт-бит (1). while(PORTB.7==0); При этом выход МК отключен. PORTB.0=0;
4- МК находит страрт-бит (1). МК переходит в режим повторителя. PORTB.0=PORTB.7; Сигнал с приёмника (DATA) проходит на штатный декодер.

А вообще... я бы наверное просто разбил весь код на семплы и записал в массив семплы. Всего кодов в пульте не много.. массив будет маленький))
Т.е. по сути я бы просто "оцифровал" весь код пульта и хранил бы "цифровую копию" в EPPROM для анализа. В этом случае ни одна помеха мимо нас не проскочит! )) :))) Например вот так:
1.jpg
(105.68 КБ) 208 скачиваний
:tea:
У нас код 40 мс. Разбиваем заждый импульс например на 8 семплов (или больше). Получаем 320 семплов.

Далее... супер мощный алгоритм))) :)))

Кратко:
1- ждём первый импульс (например переход от 0 к 1). while(PORTB.7==0);
2- задежка по таймеру... сравниваем семпл №0 с массивом №0. Если не совпадает, то переходим к пункту 1.
if (PORTB.7 != x[0]; ) {goto mesto_1;};
3- задежка по таймеру... сравниваем семпл №1 с массивом №1. Если не совпадает, то переходим к пункту 1.
if (PORTB.7 != x[1]; ) {goto mesto_1;};
...
...
...
320- задежка по таймеру... сравниваем семпл №320 с массивом №320. Если не совпадает, то переходим к пункту 1.
if (PORTB.7 != x[320]; ) {goto mesto_1;};

Если все принятые сепмлы совпали, то МК выдаёт на выводе PORTB.0 копию принятого кода.

Если в ходе проверки хоть один семпл не совпал... то начинаем всё сначала))
код ошибка.png
(34.57 КБ) 382 скачивания
Короче... никаких синхронизаций не нужно.)) Оцифровываем и проверяем все импульсы "на ходу" ...))
Ну прям сигнальный процессор получается )) :)))

Это простой линейный алгоритм. Если кодов несколько, то получим ветвящийся алгоритм. Для оптимизации алгоритма можно использовать FOR и всякие подпрограммы... ))

Один недостаток... этот алгоритм работает только при хорошем сигнале (без шумов). Это ограничивает максимальный радиус действия пульта, но зато всё супер надёжно))

Re: Автосигнализация постоянно срабатывает от помех

Добавлено: Пт дек 23, 2016 00:17:54
Nerevarine1810
Сигнал с приёмника (DATA) МК пропускает через себя...
Точно, вот вообще все упростили, остался МК и малюсенький нехитрый код)
для интереса сделал то же самое в протеусе)) ... Всё работает))
Так вот, теоретически да. Видать, временные издержки не совпали, использовал библиотечную функцию, может надо было счетчик...
по сути я бы просто "оцифровал" весь код пульта и хранил бы "цифровую копию"
А вот это уже хорошая идея) Только я вот решил избавится от массива, так как один символ (0 или 1) занимает минимум байт памяти МК. В моем алгоритме ушло бы пол килобайта на 4 кода брелка :shock: . Расточительство) Поэтому поступил так: задал переменную long long, это и получился массив из 64 бит (теперь одно значение занимает один бит, у нас то двоичный код). Возможно, где то косяк из-за этого, с битовыми сдвигами или масками... Не знаю в общем.
Ну прям сигнальный процессор получается ))
Да да)) Есть второй блок, первый пока по простому сделаю, чтобы работал, а не дома валялся. А со вторым можно будет поэкспериментировать позже, в любое свободное время)

Re: Автосигнализация постоянно срабатывает от помех

Добавлено: Пт дек 23, 2016 13:16:34
roman.com
Nerevarine1810 писал(а):со вторым можно будет поэкспериментировать позже, в любое свободное время
Ничего нового мы не изобрели)) По этому принципу работает цифровой осциилограф..))

Вот например так выглядит сигнал приёмника (DATA) на простом аналоговом осциллографе:
3.jpg
(13.26 КБ) 404 скачивания
Цифровой осциллограф "оцифровывает" сигнал приёмника:
1.jpeg
(29.83 КБ) 384 скачивания
На экране цифрового осциллографа мы видим "цифровую копию" этого сигнала, с частотой дискретизации (семплов) 100 кГц:
5.jpg
(94.81 КБ) 409 скачиваний
Я просто предложит использовать этот же принцип для обработки сигнала на МК... Вот и всё)) Разница только в том, что по сравнению с цифровым осциллографом, у МК меньше тактовая частота, меньше память и соответственно меньше скорость обработки сигнала. Поэтому мы просто уменьшили частоту семплов для МК))
Nerevarine1810 писал(а):Видать, временные издержки не совпали, использовал библиотечную функцию, может надо было счетчик...
Для обработки сигнала важно точно выдерживать временные интервалы:
2.jpg
(234.86 КБ) 392 скачивания
Для этого лучше использовать таймеры/счётчики. Тут на сайте даже статейка есть.. так сказать "для начинающих" )) ...
http://radiokot.ru/circuit/digital/game/65/
Там показали как лучше делать семплы:
4.jpg
(154.31 КБ) 391 скачивание
Только, повторяю, онин семп на один бит - для радиоканала этого мало. Надо минимум 8...16. А вообще, чем больше семплов, тем лучше)) Количество семплов ограничена только вычислительной возможностью МК. ))
Nerevarine1810 писал(а):решил избавится от массива, так как один символ (0 или 1) занимает минимум байт памяти МК. В моем алгоритме ушло бы пол килобайта на 4 кода брелка
Eсли верить даташиту, то например у ATmega8 память... цитата из даташита: "8 Кбайт внутрисистемно программируемой Flash памяти"
Т.е. на четыре кода пульта хватит)) :))) Если МК больше ничем заниматься не будет... поэтому какая разниза сколько мы заняли памяти))
Хотя, я обычно использую в своих программах битовые операции. Да, я обычно записываю данные в переменные, побитно.))

Re: Автосигнализация постоянно срабатывает от помех

Добавлено: Пт дек 23, 2016 18:12:06
Nerevarine1810
Для этого лучше использовать таймеры/счётчики
За идею благодарность приношу :) Раньше никогда им не пользовался, поэтому в расчет и не брал. Теперь же знаю, что это надежный и точный вариант подсчета времени (особенно очень мизерного). На будущее пригодится)
например у ATmega8
Камень этот только для опыта) В конечном случае все на ATtiny13 соберу (Мегу8 жалко для такой цели ничтожной :))) ), у него уже 1кб флеша и вроде 512 байт оперативки (а массивы я в оперативке определял, вот и хватало бы только-только). Да и плюс ко всему проги на СИ много больше памяти занимают, чем на асме)
Ничего нового мы не изобрели))
Зато обобщили все уже известное, "разжевали" так сказать)

Re: Автосигнализация постоянно срабатывает от помех

Добавлено: Чт янв 12, 2017 20:40:17
Nerevarine1810
В общем все сделал) Attiny не прошить моим USBisp и решил использовать Мегу8. Жалко было ее пустую использовать, так прикрутил DS18B20 и сдвоенный семисегментный индикатор. Все прилагается, в архиве файлы проектов для AVRStudio 7 и Proteus 8.3. Код дублирую сюда)
Спойлер

Код: Выделить всё

#define F_CPU 1000000UL

#define DQ_IN  DDRB &= ~(1<<7)
#define DQ_OUT DDRB |= (1<<7)
#define S_DQ   PORTB |= (1<<7)
#define C_DQ   PORTB &= ~(1<<7)
#define DQ     PINB & (1<<7)

#include <avr/io.h>
#include <util/delay.h>

void init_ds18b20(void);			// Инициализация
unsigned char readbyte(void);		// Прочитать байт
void writecommand(unsigned char);	// Отправить байт
unsigned char readtemp(void);		// Функция получения температуры в десятичном виде
void Clear ();						// Высокий уровень на всех используемых выводах
void Vivod();						// Вывод на сдвоенный семисегментик
void Signal();						// Выдача сигнала со входа на декодер

/////////////////////////////////////////////////////////////////////////////////////////
void send_H0 () {
	PORTD &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
}
void send_H1 () {
	PORTD &= ~((1<<1) | (1<<2));
}
void send_H2 () {
	PORTD &= ~((1<<0) | (1<<1) | (1<<3) | (1<<4) | (1<<6));
}
void send_H3 () {
	PORTD &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6));
}
void send_H4 () {
	PORTD &= ~((1<<1) | (1<<2) | (1<<5) | (1<<6));
}
void send_H5 () {
	PORTD &= ~((1<<0) | (1<<2) | (1<<3) | (1<<5) | (1<<6));
}
void send_H6 () {
	PORTD &= ~((1<<0) | (1<<2) | (1<<3) | (1<<4) | (1<<5) | (1<<6));
}
void send_H7 () {
	PORTD &= ~((1<<0) | (1<<1) | (1<<2));
}
void send_H8 () {
	PORTD &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5) | (1<<6));
}
void send_H9 () {
	PORTD &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | (1<<6));
}
void send_H () {
	PORTD &= ~(1<<7);
}
/////////////////////////////////////////////////////////////////////////////////////////
void send_L0 () {
	PORTC &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
}
void send_L1 () {
	PORTC &= ~((1<<1) | (1<<2));
}
void send_L2 () {
	PORTC &= ~((1<<0) | (1<<1) | (1<<3) | (1<<4));
	PORTB &= ~(1<<2);
}
void send_L3 () {
	PORTC &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3));
	PORTB &= ~(1<<2);
}
void send_L4 () {
	PORTC &= ~((1<<1) | (1<<2) | (1<<5));
	PORTB &= ~(1<<2);
}
void send_L5 () {
	PORTC &= ~((1<<0) | (1<<2) | (1<<3) | (1<<5));
	PORTB &= ~(1<<2);
}
void send_L6 () {
	PORTC &= ~((1<<0) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
	PORTB &= ~(1<<2);
}
void send_L7 () {
	PORTC &= ~((1<<0) | (1<<1) | (1<<2));
}
void send_L8 () {
	PORTC &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
	PORTB &= ~(1<<2);
}
void send_L9 () {
	PORTC &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5));
	PORTB &= ~(1<<2);
}
void send_L () {
	PORTB &= ~(1<<1);
}
/////////////////////////////////////////////////////////////////////////////////////////

unsigned char des;
unsigned char temper;
unsigned char s;
unsigned int i;

int main(void)
{
	DDRB |= (1<<3) | (1<<2) | (1<<1); 
	DDRB &= ~(1<<0);					// Прием сигнала на вывод 0
	DDRC |= 0x3F;
	DDRD |= 0xFF;
	PORTB &= ~((1<<3) | (1<<0));		// Вывод сигнала на вывод 3
	volatile char u = 0;				// Вспомогательная переменная
	Clear();
	while(1)
	{
		if (PINB & (1<<4))				// Проверка ключа в замке зажигания (если вставлен ВКЛ термометр)
		{
			temper = readtemp();
			Clear();
			Vivod();
			u = 1;
		}
		
		for (unsigned long i = 0; i < 1000000; i++)	// Прием данных примерно 30 сек
		{
			Signal();

			if (!(PINB & (1<<4)))
			{
				Clear();
				u=0;
			}
			else
			{
				if (u == 0) break;
			}
		}
	}
	
	return 0;
}

void init_ds18b20(void)
{
	DQ_OUT;
	C_DQ ;
	_delay_us(600);
	S_DQ;
	_delay_us(50);
	DQ_IN;
	while(DQ);
	_delay_us(240);
	DQ_OUT;
	S_DQ;
	_delay_us(100);
}

unsigned char readbyte(void)
{
	unsigned char i = 0, data = 0;
	DQ_OUT;
	for (i=0; i<8; i++)
	{ C_DQ ;
		data >>= 1;
		_delay_us(3);
		S_DQ;
		DQ_IN;
		_delay_us(12);
		if(DQ)
		data |= 0x80;
		DQ_OUT;
		S_DQ;
		_delay_us(45);
		_delay_us(5);
	}
	return(data);
}

void writecommand(unsigned char data)
{
	unsigned char i;
	for(i=0; i<8; i++) {
		C_DQ;
		_delay_us(15);
		if(data & 0x01)
		S_DQ;
		else
		C_DQ;
		_delay_us(45);
		data >>= 1;
		S_DQ;
		_delay_us(2);
	}
}

unsigned char readtemp(void)
{
	unsigned char a, b, tt;
	init_ds18b20();
	// Convert
	writecommand(0xCC);
	writecommand(0x44);
	_delay_ms(800);
	init_ds18b20();
	// Read Scratch memory area
	writecommand(0xCC);
	writecommand(0xBE);
	a = readbyte();
	b = readbyte();
	init_ds18b20();

	des = 0;
	des = ((a & 0x0F) * 625) / 100;
	
	tt = 0;
	if (!(b>>7)) {
		// если положительная температура
		tt = ((b << 4) | (a >> 4));
	}
	else {
		// если отрицательная
		tt = ((b << 4) | (a >> 4));
		tt = (~tt + 1) & (0xFF);
		tt |= (1<<7);	// Обозначение минуса
	}
	
	if (des < 10)
	{
		if (des < 5) des = 0;
		else des = 1;
	}
	else
	{
		if ((tt & 0x80) == 0x80) 
		{
			tt &= ~(1<<7);
			if ((des % 10) < 5) des /= 10;
			else des = (des/10)+1;
			tt--; des = (10-des)%10;
			if (tt > 3)
			{
				if (des > 4) tt++;
			}
			tt |= (1<<7);
		}
		else
		{
			if ((des % 10) < 5) des /= 10;
			else des = (des/10)+1;
			if (tt > 3)
			{
				if (des > 4) tt++;
			}
		}
		
	}

	return(tt);
}

void Clear ()
{
	PORTB |= (1<<1) | (1<<2);
	PORTC |= 0x3F;
	PORTD |= 0xFF;
}

void Vivod()
{
	if ((temper & 0x80) == 0x80) {	// Если отрицательная T
		temper &= ~(1<<7);
		send_L();
	}
	
	if (((temper / 10) == 0) & ((temper % 10) < 4)) {
		send_H();
		
		switch (temper % 10) {
			case 1: send_H1 (); break;
			case 2: send_H2 (); break;
			case 3: send_H3 (); break;
			//case 4: send_H4 (); break;
			//case 5: send_H5 (); break;
			//case 6: send_H6 (); break;
			//case 7: send_H7 (); break;
			//case 8: send_H8 (); break;
			//case 9: send_H9 (); break;
			
			default: break;
		}

		switch (des) {
			case 1: send_L1 (); break;
			case 2: send_L2 (); break;
			case 3: send_L3 (); break;
			case 4: send_L4 (); break;
			case 5: send_L5 (); break;
			case 6: send_L6 (); break;
			case 7: send_L7 (); break;
			case 8: send_L8 (); break;
			case 9: send_L9 (); break;
			default: send_L0 (); break;
		}
	}
	else {
		switch (temper / 10) {
			case 1: send_H1 (); break;
			case 2: send_H2 (); break;
			case 3: send_H3 (); break;
			case 4: send_H4 (); break;
			case 5: send_H5 (); break;
			case 6: send_H6 (); break;
			case 7: send_H7 (); break;
			case 8: send_H8 (); break;
			case 9: send_H9 (); break;
			default: break;
		}

		switch (temper % 10) {
			case 1: send_L1 (); break;
			case 2: send_L2 (); break;
			case 3: send_L3 (); break;
			case 4: send_L4 (); break;
			case 5: send_L5 (); break;
			case 6: send_L6 (); break;
			case 7: send_L7 (); break;
			case 8: send_L8 (); break;
			case 9: send_L9 (); break;
			default: send_L0 (); break;
		}
	}
}

void Signal()
{
	do
	{
		if (!(PINB & (1<<0)))						// Проверка нуля на 0 ножке
		{
			for (i = 0; i < 21; i++)				// Проверяем 85 раз по 125мкс (11мс разрыв между кодами)
			{
				if (PINB & (1<<0))					// Если попалась 1, то прервать и подать 0
				{
					PORTB &= ~(1<<3);
					break;
				}
				_delay_us(500);

				if (i == 20)
				{
					_delay_ms(36);					// Пропустить импульсы одного кода
					for (i = 0; i < 99; i++)		// Вторая проверка нулей
					{
						if (PINB & (1<<0))
						{
							PORTB &= ~(1<<3);
							break;
						}
						_delay_us(100);
					}								// Конец второй проверки нулей
					
					for (i = 0; i < 2500; i++)		// Копирование входа на выход
					{
						s = (PINB & 0x01);
						if ((s % 2) == 1) PORTB |= (1<<3);
						else PORTB &= ~(1<<3);
					}
					PORTB &= ~(1<<3);
					break;							// Отправили код и выходим
				}
			}
		}
		break;
	} while (1);
}

Re: Автосигнализация постоянно срабатывает от помех

Добавлено: Вс янв 15, 2017 15:30:39
roman.com
Пойдёт))

датчик... https://masterkit.ru/zip/ds18b20-rus.pdf

можно ещё что-нить повесить на МК)) Что бы не пустую использовать..))