![]() |
AVR
Здрасти.
Собственно, нужна помощь в создании прошивки для микроконтроллера. В Atmel AVR написал на С++ программку вращения энкодера. Сама программка небольшая, и вроде бы ошибок нет, но созданный hex-файл не работает ни на живом контроллере, ни в эмуляции на Proteus. Если есть кто в состоянии помочь, то вышлю файлы, и буду безмерно благодарен. |
Высылайте, только для это есть свой раздел- Компютеры.
|
Вы эмулируете энкодер?
Подробнее давайте. |
Куда слать?
Эмуляция энкодера - это 4 выключателя, которые нажимаются вручную (мышкой) в нужные положения. суть затеи - вышел из строя блок управления поворотом вала. Вал вращается в пределах 180 градусов (приблизительно). Для отслеживания положения вала имеется 3 концевика, отслеживающих сектор, и еще один концевик, отслеживающий точное позиционирование. Задатчик - еще 4 кнопки, которыми в зависимости от комбинации выбирается необходимое положение вала. Программа сравнивает текущие значения задатчика и энкодера, и в зависимости от их состояния доворачиваем электромотор в том или ином направлении, или выдает информацию об ошибке. Программа написана, ошибок по дебаггеру нет. Но вот в протеусе и изменений на нажатие кнопок тоже нет... |
можете и сюда файл прикрепить (наверное), или ссылку на него.
|
|
есть подозрение, что по GOTO программа уходит в ошибку и никогда не возвращается.
я бы избавился от них путем оформления всё в процедуры. ладно, еще посижу-посмотрю. |
Возможно, я не силен в программировании.
Но хотел бы набраться опыта. |
мда. у меня этой версии студии нет. могу разве что переписать на иаре.
|
частота внутрення рц-цепочка на 1Мгц? правильно я понял?
кстати, ресет у вас на массе. должен быть к питанию. возможно у вас всё работает. перепроверьте. |
С резетом действительно лажанулся. Спасибо.
НО, программа выдает неправильную индикацию и не реагирует ни на какие действия. Сегодня-завтра перепроверю текст, может что-то найду. |
кстати, диоды в протеусе поменяйте, эти не светятся, можно судить только по уровню на резисторах.
и второе, если кнопки коммутируют питание на пины, то для нормальной симуляции их мк, надо подтянуть через pull-down к массе, иначе, после отпускания кнопки, на входе мк останется лог. 1. короче, правильно оформи схему, и возможно программа отработает правильно. |
Так вроде ж в самом начале программы указал подтяжку всех портов через резисторы на массу.
Работу программы проверяю не только в симуляции, но и на живом МК. Благо на работе есть паяльник. |
там нет резисторов на массу, есть только на питание. на вход с нулями это третье состояние.
ладно, если есть живой макет, то начните с простого, отрабатывает ли диод нажатие кнопки. типа for(;;) { if (PIND0==0) PORTA = 0xFF else PORTA = 0x00; } потом дальше бум думать. |
Я вот как раз и подумал сделать что-то наподобие этого - разбить программу на составляющие, и смотреть как оно работает. Завтра и займусь.
|
стою на асфальте я в лыжи обутый....
текст программы #include <avr/io.h> int main() { PORTA=0x00; //порт А DDRA=0xFF; PORTD=0x00; DDRD=0x00; for(;;) { { if (PIND0==0) PORTA=0xFF; else PORTA=0x00; } } } и та не работает... первый цикл - диоды погашены, все последующие - диоды включены, независимо от состояния кнопки. Я даже установил подтягивающий резистор на землю - не помогло. Может у меня руки кривые, а извилины - прямые? |
|
Есть и в реальном, и в симуляции...
|
тогда я хз. что-то не правильно настроено в студии.
скомпилил у себя без изменений. пробуй. http://exfile.ru/441062 |
то есть компиляция неправильно идет?
|
походу да.
|
Цитата:
если это моя программа - то не фурычит. после временной задержки выдает не запрограммированную индикацию (portA == 0b00110110),при том даже не отрабатывая положенные шаги. Моя компиляция работала так-же (после подвешивания резет на +) А предыдущий файл - это компиляция какого кода? |
а, ну если так-же, то по идее файл собирает правильно.
предыдущая просто цикл. if (PIND0==0) PORTA=0xFF; else PORTA=0x00; |
А ты открывал мой проект? Или создавал свой и писал туда мою программу?
Вопрос в том, что компиляция цикла у меня раза в полтора меньше, чем у тебя. А компиляция программы по размеру такая-же. Может (если открывал мой проект) не перезаписался hex-файл? |
почему?
вот мой. :100000000C945800189518951895189518951895EA :100010001895189518951895189518951895189578 :100020001895189518951895189518951895189568 :100030001895189518951895189518951895189558 :100040001895189518951895189518951895189548 :100050001895189500E00BBB0FEF0ABB00E008BB3A :1000600000E007BB00E005BB07E004BB00E002BB0B :1000700000E001BB0FEF0BBB0FE71AE126E00150D8 :1000800010402040E1F700C0000000E00BBB00E2A0 :100090000BBBAA98A89AA998A898A998DA9ADC9A6A :1000A000DD9AD898D99AAA98F7CF00008895FECF04 :1000B0000FE90DBF00E00EBFC0E8D0E00E9466006F :1000C0000E942A000E9455000C94550001E00895FA :00000001FF :00000001FF а вот твой. :100000000C942A000C9434000C9434000C943400AA :100010000C9434000C9434000C9434000C94340090 :100020000C9434000C9434000C9434000C94340080 :100030000C9434000C9434000C9434000C94340070 :100040000C9434000C9434000C9434000C94340060 :100050000C94340011241FBECFE5D4E0DEBFCDBF29 :100060000E9436000C9450000C9400001BBA8FEFD5 :100070008ABB18BA17BA15BA97E094BB12BA11BA6C :100080008BBB1BBA80E28BBBAA98A89AA998A898A8 :10009000A998DA9ADC9ADD9AD898D99AAA98F7CFD3 :0400A000F894FFCF02 :00000001FF опкоды разные, но размер подходит. |
да, похоже что ошибся с объемом кода.
Возможно действительно по разному компилирует. Поставил avr studio 6 (в связи с тем, что на основном ПК она поломалась) на виртуалку, и там мучаюсь. пошел другим путем - смотрю в дебаггере шаги. Взял из программы кусок кода, и немного укоротил - сделал чисто дешифратор: #include <avr/io.h> int main(void) { DDRA = 0xFF; PORTA = 0b00000000; DDRD = 0x00; PORTD = 0b00000000; for (;;) { if ((PIND0==1)&&(PIND1==0)&&(PIND2==0)) PORTA = 0b00000100; else if ((PIND0==1)&&(PIND1==1)&&(PIND2==0)) PORTA = 0b00110100; else if ((PIND0==0)&&(PIND1==1)&&(PIND2==0)) PORTA = 0b00100100; else if ((PIND0==0)&&(PIND1==1)&&(PIND2==1)) PORTA = 0b00000010; else if ((PIND0==0)&&(PIND1==0)&&(PIND2==1)) PORTA = 0b00000010; else if ((PIND0==1)&&(PIND1==0)&&(PIND2==1)) PORTA = 0b00111100; else PORTA = 0b00000001; } } По шагам, первые 4 (назначение портов) дебаггер отрабатывает, а потом сразу прыгает в строку else PORTA = 0b00000001; не отрабатывая никакие другие. и оттуда его ничем не выудить... ошибок, предупреждений нет. |
значит не отрабатывают PIND0. попробуй прочитать пины по другому.
в еще лучше сделать это через switch. не помню как в студии, в ирае это объявлено как #define PIND0 0 естественно никогда единице равняться не будет. вот. так как-то. if ((PIND & 1 ==1) &&(PIND & 2==0) && (PIND &4 ==0)) |
Ничего, я пять копеек вставлю?
Полгодика uC не ковырял, но вот так удобно: #define cw_pressed !(PIND & 0b00000100) #define ccw_pressed !(PIND & 0b00001000) Потом что-то типа: ISR(INT0_vect){ cli(); _delay_ms(1); ClrBit(PORTD,PS); if(cw_pressed) t = ((t << 7) | (t >> 1)); if(t & 1) SetBit(PORTD,DIR1); else ClrBit(PORTD,DIR1); if(t & 2) SetBit(PORTD,DIR2); else ClrBit(PORTD,DIR2); _delay_ms(1); SetBit(PORTD,PS); sei(); } Только при куче датчиков может прерываний не хватить, но схемотехнически, через диоды, можно все кнопки на одно внешнее прерывание посадить. |
5 копеек - это хорошо, но мое понимание еще не дошло до данного кода...
проще говоря - я из этого ничего не понял. Т.к. мое изучение програмирования МК и вообще С++ ограничивается на данный момент только вот этим одним устройством. Но за код все равно спасибо - найду на работе час-полтора свободного времени - попробую разобраться с данной записью |
Я тогда пока накидаю недостающих для понимания строк и картинку.
Также добавлю, что у меня биполярный шаговик. #define PS PD6 #define DIR1 PD4 #define DIR2 PD5 #define SetBit(Port,bit) Port |= _BV(bit) #define ClrBit(Port,bit) Port &= ~_BV(bit) #define Bit(bit) (1 << (bit)) volatile unsigned char t; void init() { cli(); DDRD=0b01110000; PORTD=0b00001110; ClrBit(MCUCR,ISC01); ClrBit(MCUCR,ISC00); ClrBit(MCUCR,ISC11); ClrBit(MCUCR,ISC10); SetBit(GICR,INT0); SetBit(GICR,INT1); set_sleep_mode(SLEEP_MODE_IDLE); t = 0b11001100; sei(); } int main(void) { init(); while(1); return 0; } http://radiohlam.ru/control/images/b...tep_motor1.jpg К картинке необходимо добавить, что я использовал МС управления ШД, который при подаче единиц на DIR1 и DIR2 устанавливает одну полярность на обмотках 1 и 2 соответственно, а при "нулях" - противоположную. PS управляет режимом с пониженным потреблением - обеспечивает удержание ротора в паузах. |
Начинаю все с начала, в связи с некоторыми изменениями в логике устройства (введение АЦП)
первым делом разбиваю всю программу на подпрограммы, и смотрю как работает. Первая программа - дешифратор задатчика (порт B), для наглядности выводит информацию в унитарном виде на порту D (данные на порту В - третий столбец таблицы, диод на порту D - первый столбец таблицы) прочерки означают незадаваемое положение, кресты - что при указанном состоянии прочих ног, состояние данной не учитывается. #define F_CPU 1000000UL #include <avr/io.h> #include <util/delay.h> int main(void) { PORTA=0b11111111; DDRA=0b00000000; PORTB=0b11111111; DDRB=0b00000000; PORTC=0b00000000; DDRC=0b11111111; PORTD=0b00000000; DDRD=0b11111111; PORTD=0b11111111; _delay_ms(2000); PORTD=0b00000000; while(1) { //Задатчик; //Таблица соответствия состояния энкодера / задатчика положения / индикации положения; // № | PA4 PA5 PA6 | PB0 PB1 PB2 PB3 | PD2-6; // --------------------------------------------------; // 1 | 0 1 1 | 1 1 x 1 | 00010; // 2 | 0 0 1 | 0 1 0 1 | 11010; // 3 | 1 0 1 | 0 1 1 1 | 10010; // 4 | 1 0 0 | x x x 0 | 00001; // 5 | 1 1 0 | - - - - | 00001; // 6 | 0 1 0 | 0 0 x 1 | 11110; // 7 | 0 1 0 | 1 0 x 1 | 00110; com: if (PORTB3==0) { PORTD=0b00001000; } else if(PORTB3==1 && PORTB0==1 && PORTB1==1) { PORTD=0b00000001; } else if(PORTB3==1 && PORTB0==1 && PORTB1==0) { PORTD=0b01000000; } else if(PORTB3==1 && PORTB0==0 && PORTB1==0) { PORTD=0b00100000; } else if(PORTB3==1 && PORTB0==0 && PORTB1==1 && PORTB2==0) { PORTD=0b00000010; } else if(PORTB3==1 && PORTB0==0 && PORTB1==1 && PORTB2==1) { PORTD=0b00000100; } else { goto com; } } } При проверке дебаггером ошибок и замечаний нет, но когда провести пошаговыую проверку, тоон просматривает назначение портов, и замирает. до тела программы не доходит. При проверке в эмуляторе (протеус), ругается на то, что в hex-файле найдена какая-то ошибка. ps: to Глобус 1 - к сожалению с твоим кодом не разобрался 2 - двигатель у меня не шаговый, а коллекторный. pps: может кто посоветует более адекватное ПО для написания, отладки и компиляции программы? |
Цитата:
Есть еще Кодевижн, но мне больше нравится ICC, там работающий проект можно создать буквально за несколько кликов мышкой. Ну и конечно IAR, но это для профессионалов, можно позже на него переползти. |
Блин. Надо найти время и запилить вам этот проект. Осталось узнать как.
Вы на функции программу не перевели, у Вас остался goto. Это не принципиально, но и не функция. Немного теории (совсем чуть-чуть). Регистры портов в авр делятся на три типа, направление, выход и вход, называються соответственно DDRx, PORTx и PINx. Т.е. чтобы выдать на порт значение используем PORT, чтобы считать - используем PIN. Давайте так. Создайте функцию. Типа char GetEncoder(void); И в ней, вместо этого, вызывайте её: m: if (PORTB3==0) { PORTD=0b00001000; } else if(PORTB3==1 && PORTB0==1 && PORTB1==1) { PORTD=0b00000001; } else if(PORTB3==1 && PORTB0==1 && PORTB1==0) { PORTD=0b01000000; } else if(PORTB3==1 && PORTB0==0 && PORTB1==0) { PORTD=0b00100000; } else if(PORTB3==1 && PORTB0==0 && PORTB1==1 && PORTB2==0) { PORTD=0b00000010; } else if(PORTB3==1 && PORTB0==0 && PORTB1==1 && PORTB2==1) { PORTD=0b00000100; } else { goto com; } } } char GetEncoder(void) { if (PINB & 0x80 == 0) { PORTD=0b00001000; return 1; // выход с флагом 1, что сработал по "if (PINB & 0x80 == 0) " } // иначе там единица, продолжаем switch (PINB & 0x0F) { case 0x0B: PORTD=0b00000001; break; case 0x09: PORTD=0b01000000; break; case 0x08: PORTD=0b00100000; break; case 0x0A: PORTD=0b00000010; break; case 0x0E: PORTD=0b00000100; break; default: // если ничего не совпало - возвращаем 2. return 2; break; } в цикле while(1) { char x; x = GetEncoder(); if (x == 1) знач вернулся вернулся по "if (PINB & 0x80 == 0) " или так while (GetEncoder()) == 2) {} // т.е. вызываем GetEncoder, пока не вернется что-то отличное от двойки. } // скобка конца while() |
Pilot, а что в таличке состояний означают "x" и "-"?
|
прочерки означают незадаваемое положение (задатчиком его нельзя выбрать, но в энкодере оно есть)
кресты - что при указанном состоянии прочих ног, состояние данной не учитывается. |
Pilot
Отмечучь и я, чисто в рекомендательном плане. Уберите goto в коде поста №31, оно там ни к чему вообще, while(1) и так выполнится с первой строчки, если не сработает ни одно условие, при этом желательно в конце while поставить небольшую задержку (~100мс), если планируете использовать какие-то дополнительные процедуры. И я б, честно, подобные строки if(PORTB3==1 && PORTB0==1 && PORTB1==1) заменил бы на if (PORTB==0b00001011) Почему? Да потому что оператор if выполнится всего один раз вместо 5 :) Ну или для полноты понимания, при помощи define создайте варианты необходимых условий. Вы хоть код понимать будете ну и помочь будет легче вновь читающим. К примеру #define VAR0 0b00001011 if (PORTB==VAR0)... или if (PORTB & VAR0)... что полностью заменяет if(PORTB3==1 && PORTB0==1 && PORTB1==1) и облегчает чтение. Этим разгрузите код и вероятно облегчите жизнь дебугеру. Конечно, если так можно, а пятой точкой ощущаю, что можно наврняка. Kino, к стати, правильно подсказывает, насчет отдельной процедуры, но по опыту работы с контроллерами, я б нестал использовать такие тяжелые формы как case, от этого легче не станет, а код усложнит и займет на порядок больше тактов, описанный выше мною вариант более применим к контроллерам, со статическмими условиями регулятора. |
Цитата:
char GetEncoder(void) while (GetEncoder()) == 2) { if (PINB & 0x80 == 0) { PORTD=0b00001000; return 1; // выход с флагом 1, что сработал по "if (PINB & 0x80 == 0) " // иначе там единица, продолжаем } // я так понимаю, что если 8-ая нога порта В равна 0, то на выходе порта D будет 00001000, в противном случае идем дальше. switch (PINB & 0x0F) { case 0x0B: PORTD=0b00000001; break; case 0x09: PORTD=0b01000000; break; case 0x08: PORTD=0b00100000; break; case 0x0A: PORTD=0b00000010; break; case 0x0E: PORTD=0b00000100; break; default: return 2; break; // если ничего не совпало - возвращаем 2. } // Здесь, как я понял, определение выражения на 4х ногах порта В (PINB & 0x0F) - (в двоичной =00001111), тех, на которых кнопки задатчика // соответствие входа выхода вроде бы такое: // 1011 - 00000001 // 1001 - 01000000 // 1000 - 00100000 // 1010 - 00000010 // 1110 - 00000100 } // До тех пор, пока будет возвращатся 2, будет выполнятся оператор while. в противном случае опреатор прекращается, я имею на порту D нужный сигнал и могу выполнять следующую процедуру. Правильно понял? |
Условие if (PINB & 0x80 == 0) как по мне не корректно. В данном случае всегда будет ложь, т.к. 0x80 не равно 0 :)
Для успокоения совести напишите: if ((PINB & 0x80) == 0) или просто if !(PINB & 0x80) |
Цитата:
#define com1 0b00001011 #define com2 0b00001010 #define com3 0b00001110 #define com4 0b00000000 #define com6 0b00001000 #define com7 0b00001001 char GetEncoder(void) while (GetEncoder())==2) if PORTB==com1 {PORTD=0b00000001} else if PORTB==com2 {PORTD=0b00000010} else if PORTB==com3 {PORTD=0b00000100} else if PORTB==com4 {PORTD=0b00001000} else if PORTB==com6 {PORTD=0b00100000} else if PORTB==com7 {PORTD=0b01000000} else {return 2} |
Но в таком виде код не пройдет компиляцию, ибо ошибок тьма.
И, если GetEncoder разовая функция, то ее нет смысла оформлять отдельной процедурой. В остальном направление мысли верно. Ну вот как-то так: #define com1 0b00001011 #define com2 0b00001010 #define com3 0b00001110 #define com4 0b00000000 #define com6 0b00001000 #define com7 0b00001001 char GetEncoder(void) { if (PORTB==com1) PORTD=0b00000001; else if PORTB==com2 PORTD=0b00000010; else if (PORTB==com3) PORTD=0b00000100; else if (PORTB==com4) PORTD=0b00001000; else if (PORTB==com6) PORTD=0b00100000; else if (PORTB==com7) PORTD=0b01000000; else return 2; return 0; } int main(void) // главная рутина { //.........какой-то код............ while (GetEncoder()==0) _delay_ms(100); //или //while (GetEncoder()>0) _delay_ms(100); //зависит от желаемого результата //.........какой-то код............ } |
|
Так у Вас все есть, вот четко по алгоритму и действуйте. Просто код старайтесь дедать максимально простым и учитывайте, что необходимы задержки при отработке команд до чтения состояния, причем величина задержек прямопропорциональна инертности исполнительных элементов.
|
Цитата:
И остальные так-же. #define com1 0b00001011 #define com2 0b00001010 #define com3 0b00001110 #define com4 0b00000000 #define com6 0b00001000 #define com7 0b00001001 char GetComander(void) { if (PORTB==com1) com=0b00000001; else if PORTB==com2 com=0b00000010; else if (PORTB==com3) com=0b00000100; else if (PORTB==com4) com=0b00001000; else if (PORTB==com6) com=0b00100000; else if (PORTB==com7) com=0b00100000; else return 2; return 0; } While (GetComander()==2)_delay_ms(100); // если какое-то условие верно, то на выходе получим соответствующее значение, а функция GetComander будет равна 0. Ну и соответственно, пойдет дальнейшее выполнение программы. // если никакое условие не совпадет, то функция GetComander будет равна 2 и повторится через 0,1с. Теперь вторая часть дешифратора, в которой не может быть неоднозначного положения, т.е. если возникает неопознанное значение, то программа должна "выпасть" в ошибку: #define enc1 0bx110xxxx #define enc2 0bx100xxxx #define enc3 0bx101xxxx #define enc4 0bx001xxxx #define enc5 0bx011xxxx #define enc6 0bx010xxxx // где "х" - может быть любым значением (используется отдельно от дешифратора, char GetEncoder(void) { if (PORTA & 0b01110000 ==enc1) enc=0b00000001; else if (PORTA & 0b01110000 == enc2) enc=0b00000010; else if (PORTA & 0b01110000 == enc3) enc=0b00000100; else if (PORTA & 0b01110000 == enc4) enc=0b00001000; else if (PORTA & 0b01110000 == enc5) enc=0b00100000; else if (PORTA & 0b01110000 == enc6) enc=0b00100000; else return 2; return 0; } if (GetEncoder()==2) ERROR \\ переход к подпрограмме ошибки else \\ продолжаем выполнять основную программу |
Цитата:
Проблема в том, что я не изучал ранее языки программирования (окромя паскаля в 9м классе). И вот собственно мне стал вопрос изготовления блока управления. На нем я и решил поучиться столь интересному занятию. Конечно, как для первой программы у меня возникло - программа на операторе IF/ELSE написана вроде как правильно, замечаний в компиляторе нет, но она не работает в контроллере. Вот и обратился за помощью (и заодно - получу новые знания :D, надеюсь) |
Ну, судя по представленному Вами алгоритму, вам, кроме if/else, врядли потребуются более изощренные компоненты языка.....
|
только он у меня нихрена не заработал... к сожаленью
Хотя 2 человека, которые пишут на С++, но не программируют контроллеры, сказали, что код правильный |
Значит Вы просто где-то промахиваетесь либо с начальной конфигурацией контроллера либо в схеме.
|
Фузы правильно зашили?
|
не фьюзах дело. настройки где-то кривые. он пишет под avrstudio + winavr.
|
Сорри что вклиниваюсь в интеллектуальную беседу, а, извиняюсь, - более простые программы писали?
Светодиодиком получалось моргать? К сожалению - из топика не вижу ни полную схему, ни программу. Но пробовали собирать на макете, и вместо датчиков использовать кнопки, а вместо исполнительных инструментов те же светодиоды? Проблему дребезга контактов концевиков решили? Все входы и выходы проинициализировали правильно? Ничего у вас в "воздухе" не осталось висеть? |
попробую переписать программу с внесенными предложениями, и выложу на обозрение.
так-же и схему устройства предоставлю |
По поводу АВР, подскажите среду ... а то я в ардуине, но хотелось бы устройство перенести в железку. Чтобы было меньше и универсальней.
|
Среду чего? Программирования на С? Разные есть. IAR, но он навороченный слишком, новичка может отпугнуть. Codevision демократичнее. Я использую ImageCraft ICC7, очень нравится своей простотой и наличием аппликейшн билдера, автоматически генерирующего правильный код настройки периферии буквально за несколько кликов мышкой.
|
Для своих поделок CVAVR самое оно.
А IAR он не навороченный, он как-раз тупо голый. Но у него с оптимизацией более правильно сделано. |
Не знаю, меня оптимизатор ИмиджКрафта очень даже устраивает. Компилил как-то один и тот же код ИАРом и Крафтом, у Крафта код получился меньше. К тому же там есть очень полезная фича "Code Compression", уменьшает размер кода примерно на 12% за счет небольшого снижения скорости работы. Незаменимо, когда проект чуть-чуть не влазит в выбранный чип, а менять чип уже не хочется.
|
Вопросы ТС, уточнение по энкодеру (точнее по табличке):
в случае "х" (нельзя задать) на вход МК таки будет приходить 0 или 1? Также интересен вопрос по "-". Ясно, что не учитывается, какое оно будет реально? Я вижу в кусках кода включение резисторов подтяжки.. Вероятно, кнопки коротят входы МК на землю, а на разомкнутых контактах будет "1"? Еще один важный вопрос - в табличке PA5-7 и PB0-3 поданы как исходные данные, а PD2-6 как результат. Да и в программе порты сконфигурированы соответствующим образом. Однако, я посмотрел внимательно на табличку и увидел закономерность: кроме строк 6 и 7, PA5-7 однозначно описывают состояния выходов. А для того, чтобы отличить строки 6 и 7, достаточно будет посмотреть состояние PB0. Выходит, на задатчике достаточно одной кнопки? Или я что-то не так понял? Ну и это - там правильно подсказали: не работают почему-то простейшие вещи, так что попробуйте для начала проверить состояние одного пина и в ответ давать 1 или 0 на другой. |
И прошу прощения у ТС, раз заговорили об оптимизации, задам свой вопрос:
Есть поверье, что t = ((t << 7) | (t >> 1)) некоторые компиляторы компилируют в ROR. У меня не вышло такого добиться. Кто-то с этим сталкивался? На чем-то получалось? |
всмысле? всё выражение в один ROR? Такого же не бывает. )
|
Ну так по сути это ROR и есть.
Просто для SHL и SHR в C есть << и >>. А для ROL, ROR нет ничего. Их можно заменить: int rol(int value, int places) { return (value<<places)|(value>>(WORD_LENGTH-places); } int ror(int value, int places) { return (value>>places)|(value<<WORD_LENGTH-places); } Но напрямую это скомпилируется в SHR и SHL для каждой функции. Вот в каких-то интернетах чувак утверждал, что с включенной оптимизацией компилер понял, что это именно ROL и ROR и соптимизировал. Мой gcc не удалось заставить это понять. |
ну как только ROR если команду ИЛИ тоже надо выполнить.
и в авр нет SHL и SHR, есть LSL и LSR, отличие от ROL и ROR только в переносе старшего бита в младший. В SHL и SHR этого переноса нет. Только никак не применю к вашему выражению, о котором ходит поверье... ) |
На любой восьмибитной переменной результат такой функции:
__asm { mov eax,MyVar; rol eax,1; mov MyVar,eax; } абсолютно эквивалентен MyVar = (MyVar << 1 | MyVar >> 7) - (сдвиг влево на один бит) или (сдвиг право на семь бит //перенос старшего бита в младший). Ну или для наглядности: rol 10110110 на 1 даст 01101101 вторая функция даст 00000001 or 01101100, т.е. тот же 01101101 По поводу LSL, LSR - да. Это я уже по привычке. |
это наверное сильно надо раздуть прогу, чтобы реально места не хватало. а так, что включена оптимизация, что выключена - по шарабану.
|
Цитата:
в строке, где "-" возможно только определить положение энкодера (и индицировать его), но выбрать задатчиком это положение нельзя. Это конструктивная особенность энкодера, там ввели лишнюю позицию, которая не используется. Цитата:
Цитата:
Ее (в данном случае) достаточно только чтоб разделить 6ю и 7ю позиции задатчика, а для остальных позиций используются остальные кнопки тоже. Цитата:
но мне тоже кажется, что проблема в настройках ПО для компиляции. |
ну в общем, есть вариант (недопиленный пока что) программы без GoTO (на функциях):
/* * encoder.cpp * * Created: 28.10.2013 16:50:50 * Author: PVD */ #include <avr/io.h> #include <delay/io.h> char com; char comander; char enc; //Задатчик; //Таблица соответствия состояния энкодера / задатчика положения / индикации положения; // № | PA4 PA5 PA6 | PB0 PB1 PB2 PB3 | PD2-6; // --------------------------------------------------; // 1 | 0 1 1 | 1 1 x 1 | 00010; // 2 | 0 0 1 | 0 1 0 1 | 11010; // 3 | 1 0 1 | 0 1 1 1 | 10010; // 4 | 1 0 0 | x x x 0 | 00001; // 5 | 1 1 0 | - - - - | 00001; // 6 | 0 1 0 | 0 0 x 1 | 11110; // 7 | 0 1 0 | 1 0 x 1 | 00110; int GetEncoder(int) { enc=(PORTA & 0b0111000); if (enc==0b01100000) {(PORTD=0b00010000); return 1;} else if (enc==0b01000000) {(PORTD=0b00010110); return 2;} else if (enc==0b01010000) {(PORTD=0b00010010); return 3;} else if (enc==0b00010000) {(PORTD=0b00100000); return 4;} else if (enc==0b00110000) {(PORTD=0b00100000); return 5;} else if (enc==0b00100000) {(PORTD=0b00011110); return 6;} else { PORTD=0b10000000; if (PORTB0==1) {ErrorHi();} else {ErrorLo();} } } int ErrorHi(void) { PORTC=0b00000000; while (PORTA0==0) {PORTC0=1;}; PORTC=0b00000000; PORTD=0b10011110; while (PORTB0==1) { PORTC2=PINB0; if (PINA3==0 && PINC2==0) {(PIND0=0); (PIND1=0);} else if (PINA3==0 && PINC2==1) {(PIND0=0); (PIND1=1);} else if (PINA3==1 && PINC2==0) {(PIND0=0); (PIND1=1);} else (PINA3==1 && PINC2==1) {(PIND0=1); (PIND1=1);} while (PINB7=0) {Manual();} } ErrorLo(); } int ErrorLo(void) { PORTC=0b00000000; while (PORTA0==0) {PORTC1=1}; PORTC=0b00000000; PORTD=0b10000010; while (PORTB0==0) { while (PINB7=0) {Manual();} } ErrorHi(); } int Manual(int) { PORTC2=PINB0; if (PINA3==0 && PINC2==0) {(PIND0=0); (PIND1=0);} else if (PINA3==0 && PINC2==1) {(PIND0=0); (PIND1=1);} else if (PINA3==1 && PINC2==0) {(PIND0=0); (PIND1=1);} else (PINA3==1 && PINC2==1) {(PIND0=1); (PIND1=1);} enc=(PORTA & 0b0111000); if (enc==0b01100000) {PORTD=0b00010000;} else if (enc==0b01000000) {PORTD=0b00010110;} else if (enc==0b01010000) {PORTD=0b00010010;} else if (enc==0b00010000) {PORTD=0b00100000;} else if (enc==0b00110000) {PORTD=0b00100000;} else if (enc==0b00100000) {PORTD=0b00011110;} else PORTD=0b00011110; } int Critical(void) { while (1) { PORTD=0b10000000; _delay_ms(1000); PORTD=0b00000000; _delay_ms(1000); } } while(1) { int main(void) PORTA=0b11111111; DDRA=0b00000000; PORTB=0b11111111; DDRB=0b00000000; PORTC=0b00000000; DDRC=0b11111111; PORTD=0b00000000; DDRD=0b11111111; PORTD=0b11111111; _delay_ms(2000); PORTD=0b00000000; while (1) { { while (PINB7=0) {Manual()}; { com=(PORTB & 0b00001111) while (comander=0) { _delay_ms(100) if (com==0b00001011) comander=1 else if (com==0b00001010) comander=2 else if (com==0b00001110) comander=3 else if (com==0b00000000) comander=4 else if (com==0b00001000) comander=6 else if (com==0b00001001) comander=6 else comander=0; } } if (GetEncoder() < comander) { PORTC=0b00000000; while (GetEncoder() < comander) {PORTC=0b00000001}; while ((GetEncoder() = comander) && (PINA7 = 1)) {PORTC=0b00001001}; PORTC=0b00000000; if (GetEncoder() = comander) {} else {ErrorHi()}; } else if (GetEncoder() > comander) { PORTC=0b00000000; while (GetEncoder() > comander) {PORTC=0b00000010}; while ((GetEncoder() = comander) && (PINA7 = 1)) {PORTC=0b00001010} PORTC=0b00000000; if (GetEncoder() = comander) {} else {ErrorLo()} } else { PORTC2=PINB01; if (PINA3==0 && PINC2==0) {(PIND0=0) (PIND1=0)} else if (PINA3==0 && PINC2==1) {(PIND0=0) (PIND1=1)} else if (PINA3==1 && PINC2==0) {(PIND0=0) (PIND1=1)} else (PINA3==1 && PINC2==1) {(PIND0=1) (PIND1=1)}; } } } |
А вот и старый вариант
Порты другие, но сути не меняет /* * TCCM.cpp * * Created: 16.07.2013 11:20:09 * Author: dombrugov_pv */ #include <avr/io.h> #include <util/delay.h> int main(void) { unsigned char E,C; while(1) { // PA.0 - out - display 4 |green; // PA.1 - out - display 4 |red; // PA.2 - out - display lock |green; // PA.3 - out - display lock |red; // PA.4 - out - display low yellow; // PA.5 - out - display 2 green; // PA.6 - out - display N |green; // PA.7 - out - display N,error |red; // PB.0 - in - commander 2/4; // PB.1 - in - commander H/L; // PB.2 - in - commander Lc; // PB.3 - in - commander N; // PB.4 -; // PB.5 -; // PB.6 -; // PB.7 -; // PC.0 - out - motor UP; // PC.1 - out - motor DOWN; // PC.2 - out - front axle control; // PC.3 -; // PC.4 -; // PC.5 -; // PC.6 -; // PC.7 -; // PD.0 - in - encoder A; // PD.1 - in - encoder B; // PD.2 - in - encoder C; // PD.3 - in - encoder P; // PD.4 -; // PD.5 -; // PD.6 - in - front axle state; // PD.7 - in - motor overload; PORTA=0x00; DDRA=0b11111111; PORTB=0x00; DDRB=0b00000000; PORTC=0x00; DDRC=0b00000111; PORTD=0x00; DDRD=0b00000000; PORTA=0b11111111; _delay_ms(2000); PORTA=0b00000000; START: if ((PIND0==1)&&(PIND1==0)&&(PIND2==0)) // Чтение данных с энкодера; { E=0b000001; // преобразование в унитарный код; PORTA&= ~(1<<2); PORTA&= ~(1<<3); // Вывод информации; PORTA&= ~(1<<4); // о состоянии энкодера; PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else if ((PIND0==1)&&(PIND1==1)&&(PIND2==0)) { E=0b000010; PORTA|=1<<2; PORTA|=1<<3; PORTA&= ~(1<<4); PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else if ((PIND0==0)&&(PIND1==1)&&(PIND2==0)) { E=0b000100; PORTA|=1<<2; PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else if ((PIND0==0)&&(PIND1==1)&&(PIND2==1)) { E=0b001000; PORTA&= ~(1<<2); PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA&= ~(1<<5); PORTA|=1<<6; PORTA|=1<<7; } else if ((PIND0==0)&&(PIND1==0)&&(PIND2==1)) { E=0b010000; PORTA&= ~(1<<2); PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA&= ~(1<<5); PORTA|=1<<6; PORTA|=1<<7; } else if ((PIND0==1)&&(PIND1==0)&&(PIND2==1)) { E=0b100000; PORTA|=1<<2; PORTA|=1<<3; PORTA|=1<<4; PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else { goto ERROR; } if ((PIND6==0)&&(PINC2==0)) // Вывод информации; { // о состоянии; PORTA&= ~(1<<0); // переднего моста; PORTA&= ~(1<<1); } else if ((PIND6==1)&&(PINC2==1)) { PORTA|=1<<0; PORTA|=1<<1; } else { PORTA&= ~(1<<0); PORTA|=1<<1; } READ_C: if (PINB3==1) // Чтение данных с задатчика; { // и преобразование в унитарный код; C=0b001000; } else if ((PINB3==0)&&(PINB1==1)) { C=0b100000; } else if ((PINB3==0)&&(PINB1==0)&&(PINB0==0)) { C=0b000001; } else if ((PINB3==0)&&(PINB1==0)&&(PINB0==1)&&(PINB2==1)) { C=0b000010; } else if ((PINB3==0)&&(PINB1==0)&&(PINB0==1)&&(PINB2==0)) { C=0b000100; } else { goto READ_C; } // Сравнение состояний энкодера и задатчика; if (E<C) // Если состояние энкодера ниже задатчика; UP: { PORTC&= ~(1<<2); PORTC|=1<<0; // Вращение энкодера; PORTC&= ~(1<<1); if ((PIND0==1)&&(PIND1==0)&&(PIND2==0)) // Чтение данных с энкодера; { E=0b000001; // преобразование в унитарный код; PORTA&= ~(1<<2); // Вывод информации о положении энкодера; PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else if ((PIND0==1)&&(PIND1==1)&&(PIND2==0)) { E=0b000010; PORTA|=1<<2; PORTA|=1<<3; PORTA&= ~(1<<4); PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else if ((PIND0==0)&&(PIND1==1)&&(PIND2==0)) { E=0b000100; PORTA&= ~(1<<2); PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else if ((PIND0==0)&&(PIND1==1)&&(PIND2==1)) { E=0b001000; PORTA&= ~(1<<2); PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA&= ~(1<<5); PORTA|=1<<6; PORTA|=1<<7; } else if ((PIND0==0)&&(PIND1==0)&&(PIND2==1)) { E=0b010000; PORTA&= ~(1<<2); PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA&= ~(1<<5); PORTA|=1<<6; PORTA|=1<<7; } else if ((PIND0==1)&&(PIND1==0)&&(PIND2==1)) { E=0b100000; PORTA|=1<<2; PORTA|=1<<3; PORTA|=1<<4; PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else { goto ERROR; } if ((PIND6==0)&&(PINC2==0)) // Вывод информации о состоянии переднего моста; { PORTA&= ~(1<<0); PORTA&= ~(1<<1); } else if ((PIND6==1)&&(PINC2==1)) { PORTA|=1<<0; PORTA|=1<<1; } else { PORTA&= ~(1<<0); PORTA|=1<<1; } // чтение энкодера; if ((E==C)&&(PINA3==1)) // Остановка мотора по достижении заданной поз-ии; { PORTC&= ~(1<<0); PORTC&= ~(1<<1); goto START; } else if ((E>C)||(PIND7==1)) // переход к программе ошибки при пропуске заданного положения; { // или срабатывании токового реле мотора; goto ERROR; } else { goto UP; } } else if (E>C) // Если состояние энкодера выше задатчика; DOWN: { PORTC&= ~(1<<2); PORTC&= ~(1<<0); // Вращение энкодера; PORTC|=1<<1; if ((PIND0==1)&&(PIND1==0)&&(PIND2==0)) // Чтение данных с энкодера; { E=0b000001; // преобразование в унитарный код; PORTA&= ~(1<<2); // Вывод информации о положении энкодера; PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else if ((PIND0==1)&&(PIND1==1)&&(PIND2==0)) { E=0b000010; PORTA|=1<<2; PORTA|=1<<3; PORTA&= ~(1<<4); PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else if ((PIND0==0)&&(PIND1==1)&&(PIND2==0)) { E=0b000100; PORTA&= ~(1<<2); PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else if ((PIND0==0)&&(PIND1==1)&&(PIND2==1)) { E=0b001000; PORTA&= ~(1<<2); PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA&= ~(1<<5); PORTA|=1<<6; PORTA|=1<<7; } else if ((PIND0==0)&&(PIND1==0)&&(PIND2==1)) { E=0b010000; PORTA&= ~(1<<2); PORTA&= ~(1<<3); PORTA&= ~(1<<4); PORTA&= ~(1<<5); PORTA|=1<<6; PORTA|=1<<7; } else if ((PIND0==1)&&(PIND1==0)&&(PIND2==1)) { E=0b100000; PORTA|=1<<2; PORTA|=1<<3; PORTA|=1<<4; PORTA|=1<<5; PORTA&= ~(1<<6); PORTA&= ~(1<<7); } else { goto ERROR; } if ((PIND6==0)&&(PINC2==0)) // Вывод информации о состоянии переднего моста; { PORTA&= ~(1<<0); PORTA&= ~(1<<1); } else if ((PIND6==1)&&(PINC2==1)) { PORTA|=1<<0; PORTA|=1<<1; } else { PORTA&= ~(1<<0); PORTA|=1<<1; } // чтение энкодера; if ((E==C)&&(PIND3==1)) // Остановка мотора по достижении заданной поз-ии; { PORTC&= ~(1<<0); PORTC&= ~(1<<1); goto START; } else if ((E<C)||(PIND7==1)) // переход к программе ошибки при пропуске заданного положения; { // или срабатывании токового реле мотора; goto ERROR; } else { goto DOWN; } } else // Если состояние энкодера соответствует задатчику; { if ((PINB0==1)&&(PINB3==0)) // Управление состоянием переднего моста; { // в установленном состоянии энкодера; PORTC|=1<<2; } } goto START; ERROR: PORTA=0b100000; // Подпрограмма ошибки; if (PINB1==0) // при некорректной работе энкодера; { goto ERR_H; } else { goto ERR_L; } ERR_H: PORTC&= ~(1<<2); // Переключение энкодера; if (PIND7==1) // в состояние РК 2H по сигналу токового реле; { goto ERR_H; } else { while (PIND7==0) { PORTC&= ~(1<<0); PORTC|=1<<1; } } ERR_H2: PORTC&= ~(1<<0); // Вывод информации о положении энкодера на индикатор; PORTC&= ~(1<<1); PORTA&= ~(1<<2); PORTA&= ~(1<<4); PORTA|=1<<5; if ((PIND6==0)&&(PINC2==0)) // Вывод информации о состоянии переднего моста; { PORTA&= ~(1<<0); PORTA&= ~(1<<1); } else if ((PIND6==1)&&(PINC2==1)) { PORTA|=1<<0; PORTA|=1<<1; } else { PORTA&= ~(1<<0); PORTA|=1<<1; } if (PINB1==0) { goto ERR_H2; } else { goto ERR_L; } ERR_L: PORTC&= ~(1<<2); // Переключение энкодера; if (PIND7==1) // в состояние РК 4L по сигналу токового реле; { goto ERR_L; } else { while (PIND7==0); { PORTC|=1<<0; PORTC&= ~(1<<1); } } ERR_L2: PORTC&= ~(1<<0); // Вывод информации о положении энкодера на индикатор; PORTC&= ~(1<<1); PORTA|=1<<2; PORTA|=1<<4; PORTA|=1<<5; if ((PIND6==0)&&(PINC2==0)) // Вывод информации о состоянии переднего моста; { PORTA&= ~(1<<0); PORTA&= ~(1<<1); } else if ((PIND6==1)&&(PINC2==1)) { PORTA|=1<<0; PORTA|=1<<1; } else { PORTA&= ~(1<<0); PORTA|=1<<1; } if (PINB1==1) // Управление состоянием переднего моста; { if (PINB0==1) { PORTC|=1<<2; } else { PORTC&= ~(1<<2); } goto ERR_L2; } else { goto ERR_H; } } } |
Текущее время: 09:41. Часовой пояс GMT +3. |
Перевод: zCarot Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.