Быстродействие arduino. Чтение ключа от домофона метаком.

fid
Offline
Зарегистрирован: 20.12.2014

Пытаюсь сделать эмулятор  ключа от домофона метаком. Столкнулся с проблемой быстродействием ардуино.

Тайм слот передачи бита от 80 до 200 мкс. В течении тайм слота необходимо 2 раза измерить продолжительность (высокого и низкого уровня тока) сигнала. А у ардуино AnalogRead() — скорость выполнения 110 мкс. В инете нашел способ ускорения ардуино. вот этот ускоритель

#define FASTADC 1

 // defines for setting and clearing register bits
 #ifndef cbi
 #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
 #endif
 #ifndef sbi
 #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
 #endif

 

 #if FASTADC
 // set prescale to 16
 sbi(ADCSRA,ADPS2) ;
 cbi(ADCSRA,ADPS1) ;
 cbi(ADCSRA,ADPS0) ;
 #endif

После применения этого "ускорителя" все норм читается, но перестали выполняться свои функции. ( Для удобства хотел разбить код на несколько кусков и вывести из setup loop на отд. функции и вызывать их из основного цикла). Хотел задать вопрос опытным программистам, что делает этот "ускоритель"? и как вызовать свои функции? 

 

Alex_Sk
Offline
Зарегистрирован: 06.01.2015

Этот код всего лишь устанавливает в трех младших разрядах регистра ADCSRA (одного из регистров управляющих АЦП) комбинацию бит которая переводит АЦП на тактирование частотой 1МГц. При этом AnalogRead() выполняется примерно за 16-18 мкс. Но сделано это чрезмерно замудренно. Проще так:

ADCSRA &= B11111000; // очистить три младших бита
ADCSRA |= B00000100; // установить в них комбинацию 100 что дает делитель 16 и тактовую частоту АЦП 1МГц

Повышение частоты ухудшает точность АЦП но не должно никак влиять на выполнение программы. Ищите в ней ошибки.

fid
Offline
Зарегистрирован: 20.12.2014

Alex_Sk Спасибо!

 

fid
Offline
Зарегистрирован: 20.12.2014

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




const byte z = 73;   // размер массива
int t2[73];    // длительность низкий уровень тока или напряжение на Rcч >  400
int t3[73];    // длительность высокий уровень тока или напряжение на Rcч <  400

void setup()
{

	Serial.begin(9600);

}

void loop()
{
	memset(t2,0,z); // обнуляем массив
	memset(t3,0,z);
	unsigned long t=0;	
	
	while(analogRead(0)>1000) ; // ждем пока нет ключа
	// записываем все что передает ключ .. потом разберем
	for(int i=0; i<z; i++)
	{   ADCSRA &= B11111000; // очистить три младших бита
            ADCSRA |= B00000100; // установить в них комбинацию 100 что дает делитель 16 и тактовую частоту АЦП 1МГц
		
		t= micros();
		while(analogRead(0)>400);
		
		t2[i]= micros() - t; // длительность начало тайм слота  низкий уровень тока
		
		t= micros();
		while(analogRead(0)<400);
		
		t3[i]= micros() - t;	// длительность окончание тайм слота  высокий уровень тока
		
	}
	
	// для отладки наглядность бля
	
	//for(int i=0; i<z; i++)
	//{
		//
		//Serial.print("t2[");
		//Serial.print(i);
		//Serial.print("]= ");
		//Serial.print(t2[i]);
		//
		//Serial.print("          ");
		//Serial.print("t3= ");
		//Serial.print(t3[i]);
		//Serial.print("     ");
		//Serial.print("t2+t3= ");
		//Serial.print(t3[i]+t2[i]);
		//if(   t2[i]>    (t3[i]+t2[i])/2       )
		//{
			//Serial.println("  1");
		//}
		//else
		//Serial.println("  0");
		//
	//}
	//Serial.println("konetc");
	
	
	byte Sinhro =0; // номер  синхро бит в массиве
	byte TipKey=0; // тип ключа метаком 010 должон быть однако
	byte Key[35];
	byte KeyHex[4];
	for(int i=0; i<z; i++)
	{
		if (t3[i]>100 )
		{
			Sinhro=i+1;
			break; // нашли синхро бит? выходим из цикла
		}
	}
	
	byte q = Sinhro+36 ;
	byte m=0;
	for (Sinhro ; Sinhro < q ; Sinhro++)
	{
		if  (  t2[Sinhro] > (t3[Sinhro]+t2[Sinhro])/2       )
		
		Key[m]=1;
		
		else
		Key[m]=0;
		
		m++;
		
	}
	
TipKey= Key[2]<<2  |  Key[1]<<1  | Key[0];
// проверка правильность чтения

   for (int i=0; i<4; i++)
{
		int Valid = ( Key[3 +(i*8)]	+ Key[4 +(i*8)]	+ Key[5 +(i*8)]	+ Key[6 +(i*8)]	+ Key[7 +(i*8)]	+ Key[8 +(i*8)]	+ Key[9 +(i*8)]	) % 2;
		
			if ( Valid == Key[10 +(i*8)] )
			{
				Serial.print("byte N= ");
				Serial.print(i+1);
				Serial.println("valid ");	
			}
			else
			{
			Serial.print("byte N= ");
			Serial.print(i+1);
			Serial.println("ERROR ");	
			}
	
	
}




// собираем из массива байты
for(int k=0; k < 4 ; k++)
{
	KeyHex[k]= Key[9+(k*8)]<<6 | Key[8+(k*8)]<<5 | Key[7+(k*8)]<<4 | Key[6+(k*8)]<<3 | Key[5+(k*8)]<<2 | Key[4+(k*8)]<<1 | Key[3+(k*8)];
	
	
}  



	Serial.println(' ');
	Serial.print("tipKey=");
	Serial.println(TipKey);
	Serial.print("Key=");
	
	for(int k=0; k<4 ; k++)	
	{
		Serial.print(KeyHex[k],HEX);
		Serial.print(' ');
	}
	Serial.println(' ');
	
	
	delay(300);
}

 

fid
Offline
Зарегистрирован: 20.12.2014

 

Alex_Sk
Offline
Зарегистрирован: 06.01.2015

Код устанавливающий делитель частоты для АЦП не нужен в loop() и тем более в цикле в этой программке. Его достаточно один раз выполнить в Setup(). Это уменьшит время цикла и повысит точность определения длительности посылок.

Логику работы не смотрел, но сразу бросается в глаза куча умножений типа i*8 и k*8 в теле циклов при этом сами переменные циклов i и k используются в несколько раз реже. Если умножение на 8 перенести в условия задания циклов а там где надо i и k применить деление то быстродействие повысится. И в случае операнда 8 лучше использовать бинарный сдвиг который выполняется на порядок-два быстрее: i*8 = i<<3 и i/8 = i>>3

fid
Offline
Зарегистрирован: 20.12.2014

Пока на руках клон ключа, завтра будет орг. ключа с которого сделали этот ключ. Сравню результаты и выложу код оптимизированный учитывая рекомендации Alex_Sk. Не так уж и прост это ардуино для начинающего, чем казалось на первый взляд. Еще раз выражаю благодарность Alex_Sk.

fid
Offline
Зарегистрирован: 20.12.2014

Разница длительности тайм слота оригинала и клона небольшая. Оба ключи читаются норм.

			const byte z = 73;   // размер массива
			int t2[73];    // длительность низкий уровень тока или напряжение на Rcч >  400
			int t3[73];    // длительность высокий уровень тока или напряжение на Rcч <  400
			void setup()
			{
				Serial.begin(9600);
				ADCSRA &= B11111000; // очистить три младших бита
				ADCSRA |= B00000100; // установить в них комбинацию 100 что дает делитель 16 и тактовую частоту АЦП 1МГц
			}
			void loop()
			{
				while(analogRead(0)>1000) ; // ждем пока нет ключа
				delay(30);
				// читаем
				memset(t2,0,z); memset(t3,0,z); // обнуляем массив
				unsigned long t=0;
				
				for(int i=0; i<z; i++)
				{
					t= micros();
					while(analogRead(0)>400);
					t2[i]= micros() - t; // длительность начало тайм слота  низкий уровень тока
					
					t= micros();
					while(analogRead(0)<400);
					t3[i]= micros() - t;	// длительность окончание тайм слота  высокий уровень тока
				}
				
				byte Sinhro = 0; // ищем синхробит
				for(int i=0; i<z; i++)
				{
					if (t3[i]>100 )
					{
						if (i<37)
						{
							Sinhro =i+1;
							break; // нашли синхро бит? выходим из цикла
						}
						
					}
				}
				
				
				byte Key[35];
				
				byte q = Sinhro+36 ;
				byte m=0;
				
				for (Sinhro ; Sinhro < q ; Sinhro++)
				{
					if  (  t2[Sinhro] > (t3[Sinhro]+t2[Sinhro]) >> 1)
					Key[m]=1;
					else
					Key[m]=0;
					m++;
				}
				
				bool er=1;
				for (int i=0; i<4; i++)
				{
					
					byte Valid = ( Key[3 +(i<<3)]	+ Key[4 + (i<<3)]	+ Key[5 + (i<<3)]	+ Key[6 + (i<<3)]	+ Key[7 + (i<<3)]
					+ Key[8 + (i<<3)]	+ Key[9 + (i<<3)]	) % 2;
					
					if ( Valid != Key[10 + (i<<3)] )
					{
						Serial.println("ERROR Read ");
						er=0;
						break;
					}
					
				}
				if (er)
				{
					
					
					if ( Key[2]<<2  |  Key[1]<<1  | Key[0] == 2 )
					Serial.println("-METACOM-  K1233KT2");
					
					Serial.print("KEY HEX = ");
					for(int i=0; i < 4 ; i++)
					{
						byte n= i<<3;
						//byte as = ( Key[9+n]<<6 | Key[8+n]<<5 | Key[7+n]<<4 | Key[6+n]<<3 | Key[5+n]<<2 | Key[4+n]<<1 | Key[3+n] );
						Serial.print( Key[9+n]<<6 | Key[8+n]<<5 | Key[7+n]<<4 | Key[6+n]<<3
						| Key[5+n]<<2 | Key[4+n]<<1 | Key[3+n]  , HEX);
						Serial.print(" ");
					}
				}

				Serial.println("  ");
				Serial.println("  ");
				delay(500);


				
			}

 

OlegV
Offline
Зарегистрирован: 26.11.2016

Здравствуйте! Подскажите пожалуйста , на каой Arduino был изготовлен эулятор, к каким выводам подключен считыватель ключей? На схеме для считывания кода ключа нет номинолов элементов.

b707
Offline
Зарегистрирован: 26.05.2017

на три года опоздал с вопросом....

Выводы. к которым подключен эмулятор - очевидны из скетча, смотрите внимательнее.

 

OlegV
Offline
Зарегистрирован: 26.11.2016

Недавно начал осваивать Arduino,в программировании слаб. В какой строке смотреть?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Я Вам настоятельно рекомендую прочитать все строки.

OlegV
Offline
Зарегистрирован: 26.11.2016

Просматривал не однократно. По моим догадкам в этой строке-while(analogRead(0)

OlegV
Offline
Зарегистрирован: 26.11.2016

Какую ардуину можно использовать для данного скетча?

OlegV
Offline
Зарегистрирован: 26.11.2016

Не корректно читает код ключа. Чтение производилось разными считывателями, ускоритель бесполезный, без него результат тот-же. Всем спасибо за помощь!