Технический форум по робототехнике.
Michael_K » 22 июл 2011, 22:54
1. Оптимизация тут по большому счету ни при чем. Если компилятор должен что-то знать, а вы ему не говорите - это неоднозначность.
2. Например операция t1 = channel[current_channel]; не атомарная.
3. Ок
4. Что за компилятор?
По сути вот эти ваши "значения скачет" и "условия иногда срабатывает" - это же типичные симптомы.
А фразу "похоже, это глюк компилятора" в 95% случаев нужно понимать как "Я не умею объяснить компилятору, чего я от него хочу".
Последний раз редактировалось
Michael_K 22 июл 2011, 22:56, всего редактировалось 1 раз.
HarryStar » 22 июл 2011, 22:58
Хм... нашел таки как минимум 1 неоднозначность...и посерьезнее, чем неатомарность указанной вами строки. Спасибо, что обратили внимание.
Ща подумаю, как переделать.
Компилятор CVAVR, я писал вначале
Добавлено спустя 1 минуту 46 секунд:
Но кстати, убрав while в майне снимаются все неоднозначности, правда пропадает доп функционал, но фиг с ним, сейчас попробую...
Michael_K » 22 июл 2011, 22:58
HarryStar писал(а):Хм... нашел таки как минимум 1 неоднозначность...и посерьезнее, чем неатомарность указанной вами строки. Спасибо, что обратили внимание.
Ну
Сами понимаете - отлаживать чужой код, глядя в текст - занятие неблагодарное.
Рад, что хоть так неделикатно натолкнул на мысль
HarryStar » 22 июл 2011, 23:15
Убрал цикл из майна - результат тот же.
Попробовал вынести все вычисления в обработчик внешнего прерывания, убрав т.о. все возможные неоднозначности. Тоже самое.
Например если в обработчике сделать так
if(PIND & 0b01000000)
{
channel_start[2] = t; // Старт импульса
channel_end[1] = t; // Стоп импульса
channel[1] = channel_end[1] - channel_start[1];
if(channel[1]>1995) channel[1] = 1995; // ПРОБЛЕМНОЕ МЕСТО
return;
}
if(PIND & 0b00100000)
{
channel_start[3] = t; // Старт импульса
channel_end[2] = t; // Стоп импульса
channel[2] = channel_end[2] - channel_start[2];
return;
}
То один канал где нет проверки будет нормально работать, а где есть значение будет скакать от текущего к максимуму.
Буду копать дальше, но пока вообще не понятно почему так происходит. Причем число можно поставить любое, например if(channel[1]>65000) channel[1] = 1995; результат тот же. Это условие иногда срабатывает, хотя это невозможно.
dccharacter » 22 июл 2011, 23:25
Michael_K, я, конечно, преклоняюсь, но нифига не понял
(((
Harry Star, если ты убрал тот самый цикл, то в конце программы происходит ресет - естественно там все скачет.
Добавлено спустя 5 минут 48 секунд:Слуш, я так и не увидел переменных channel[] и current_channel, зато увидел, что ты смотришь результат через i2c. Ну так я тебе 102% вероятности даю, что у тебя глюк в i2c.
HarryStar » 22 июл 2011, 23:35
Если вы намекаете на while(1); в конце программы, то у меня он есть и я это писал, читайте внимательнее. Никакого ресета не происходит.
I2C совершенно не причем, хотя результат я смотрю через него, да.
После некоторых экспериментов я выяснил, что такое происходит когда значение таймера переходит 0xFFFF между измерениями.
Например:
channel_1_start = 65000; // Время старта импульса
channel_1_end = 700; // Время окончания импульса
Должно получится в беззнаковом варианте channel_1 = 700 - 65000 = 1235
А получается что условие channel_1 > 1995 истинно
Michael_K » 22 июл 2011, 23:41
Да, непонятно...
А вы точно, сто процентов уверены, что прерывание только один раз срабатывает при переходе от одного импулься к следующему?... Я бы, честно, на это не особо расчитывал. Так в жизни не бывает - два строго одновременных события.
Добавлено спустя 4 минуты 32 секунды:HarryStar писал(а):Должно получится в беззнаковом варианте channel_1 = 700 - 65000 = 1235
А получается что условие channel_1 > 1995 истинно
Ага. Только вы таймер в начале прерывания масштабируете.
Тогда нужно маску накладывать после вычитания. На четыре старших бита, если я правильно понимаю смысл.
Последний раз редактировалось
Michael_K 22 июл 2011, 23:44, всего редактировалось 2 раз(а).
HarryStar » 22 июл 2011, 23:42
Ну так как условие прерывания any change, то прерывание срабатывает когда импульс заканчивается, а потом еще раз, когда следующий стартует. Разница по времени между ними = времени выполнения обработчика, этим можно пренебречь. В условиях же я отлавливаю только начала импульсов.
Большинство китайских передатчиков выдают сервоимпульсы именно последовательно, но например futaba стартует все импульсы одновременно, там пришлось бы алгоритм посложнее писать, но я делал под свои приемники, там именно так.
В принципе можно от этого перехода избавится, если на старте первого импульса обнулять показания таймера. Тогда 8й импульс заканчивается до 0xFFFF и перехода не происходит. Но все равно непонятно почему так получается.
=DeaD= » 22 июл 2011, 23:43
Если есть уарт - попробуйте просто вывести result из вот такого:
t1=1995;
t1 = (t1-975)/4;
unsigned char result = (unsigned char)t1;
Michael_K » 22 июл 2011, 23:43
чуть выше дописал.
HarryStar » 22 июл 2011, 23:45
Таймер я преобразую к микросекундам (чтоб нагляднее было). И соответственно проверки все делаю в микросекундах, так что вроде ничего там не надо накладывать.
2 Деад: Уарта нет, прведенный вами пример работает корректно, выдает 255
Michael_K » 23 июл 2011, 00:01
надо надо.
Вот у вас таймер = 0xFFF0
t = 0x0FFF Start = 0x0FFF
Потом таймер равен, допустим, 0x0010
t = 0x0001 Stop = 0x0001
Вычитаем Stop - Start = 0x0001 - 0x0FFF = ?
Типа должно два получится? А получается 0xF002 (!) почему-то.
Если таймеры вычитать без масштабирования, то все правильно:
0x0010 - 0xFFF0 = 0x0020
Добавлено спустя 33 секунды:HarryStar писал(а):чтоб нагляднее было
Фигассе
Добавлено спустя 10 минут 25 секунд:HarryStar писал(а):В условиях же я отлавливаю только начала импульсов.
Это ошибка. Вы в условиях проверяете состояния порта в момент любого изменения на любой ноге. Это вовсе не "я отлавливаю начала импульсов".
Представьте, как сработает ваш обработчик, если спад импульса не совпадает с фронтом следующего. Он либо отработает два условия подряд, либо выполнит последний пункт неожиданно.
Но причина скачков - это масштабирование таймера, как я писал выше.
Последний раз редактировалось
Michael_K 23 июл 2011, 00:17, всего редактировалось 1 раз.
HarryStar » 23 июл 2011, 00:16
Про таймер совершенно точно! Огромное спасибо. Делал чтоб значения были в микросекундах, а что переход через ноль получается неправильный даже не сообразил. Тогда надо сначала вычитать, а потом масштабировать.
Про импульсы. В любой момент времени на ножках либо 0 на всех, либо 1 на каком-то одном. Другого варианта там нет, я все честно промерил осциллографом. Поэтому когда я отлавливаю 1 в каком то бите - это именно старт импульса. На конкретно этом приемнике это так. Метод не универсальный конечно, но пока так оставлю, т.к. других приемников у меня нет. Есть 5 штук разных и все так работают.
Michael_K » 23 июл 2011, 00:21
Я бы, несмотря на это, ужесточил условия.
Например так
if (PORTD == 0b00100000)
Тогда неоднозначностей не будет (кроме последнего условия, но оно не повлияет на результат).
Мало-ли, может быть у вас фронты завалятся - они это запросто сделают при первом же удобном случае (Например, из-за длины проводов, их индуктивности, паразитных емкостей, сопротивления контактов, разницы в питании - из-за чего угодно).
Последний раз редактировалось
Michael_K 23 июл 2011, 00:24, всего редактировалось 1 раз.
HarryStar » 23 июл 2011, 00:24
Ну в принципе да, можно тогда все в switch запихать. Еще раз спасибо за помощь.
Завтра выложу видео с этим модулем, сейчас уже темно снимать.