PDA

Просмотр полной версии : AVR


Pilot
08.10.2013, 13:15
Здрасти.
Собственно, нужна помощь в создании прошивки для микроконтроллера.
В Atmel AVR написал на С++ программку вращения энкодера.
Сама программка небольшая, и вроде бы ошибок нет, но созданный hex-файл не работает ни на живом контроллере, ни в эмуляции на Proteus.

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

кук
08.10.2013, 14:12
Высылайте, только для это есть свой раздел- Компютеры.

Kino
08.10.2013, 14:15
Вы эмулируете энкодер?
Подробнее давайте.

Pilot
08.10.2013, 15:01
Куда слать?


Эмуляция энкодера - это 4 выключателя, которые нажимаются вручную (мышкой) в нужные положения.

суть затеи - вышел из строя блок управления поворотом вала.
Вал вращается в пределах 180 градусов (приблизительно).
Для отслеживания положения вала имеется 3 концевика, отслеживающих сектор, и еще один концевик, отслеживающий точное позиционирование.

Задатчик - еще 4 кнопки, которыми в зависимости от комбинации выбирается необходимое положение вала.

Программа сравнивает текущие значения задатчика и энкодера, и в зависимости от их состояния доворачиваем электромотор в том или ином направлении, или выдает информацию об ошибке.



Программа написана, ошибок по дебаггеру нет.
Но вот в протеусе и изменений на нажатие кнопок тоже нет...

Kino
08.10.2013, 15:08
можете и сюда файл прикрепить (наверное), или ссылку на него.

Pilot
08.10.2013, 15:16
http://www.ex.ua/878246416461

Наверняка будут вопросы. Если надо - могу перезвонить.

Kino
08.10.2013, 15:52
есть подозрение, что по GOTO программа уходит в ошибку и никогда не возвращается.

я бы избавился от них путем оформления всё в процедуры. ладно, еще посижу-посмотрю.

Pilot
08.10.2013, 15:57
Возможно, я не силен в программировании.
Но хотел бы набраться опыта.

Kino
08.10.2013, 15:59
мда. у меня этой версии студии нет. могу разве что переписать на иаре.

Kino
08.10.2013, 16:07
частота внутрення рц-цепочка на 1Мгц? правильно я понял?
кстати, ресет у вас на массе. должен быть к питанию. возможно у вас всё работает. перепроверьте.

Pilot
08.10.2013, 17:15
С резетом действительно лажанулся. Спасибо.

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

Kino
08.10.2013, 17:23
кстати, диоды в протеусе поменяйте, эти не светятся, можно судить только по уровню на резисторах.
и второе, если кнопки коммутируют питание на пины, то для нормальной симуляции их мк, надо подтянуть через pull-down к массе, иначе, после отпускания кнопки, на входе мк останется лог. 1.

короче, правильно оформи схему, и возможно программа отработает правильно.

Pilot
08.10.2013, 17:53
Так вроде ж в самом начале программы указал подтяжку всех портов через резисторы на массу.

Работу программы проверяю не только в симуляции, но и на живом МК. Благо на работе есть паяльник.

Kino
08.10.2013, 17:58
там нет резисторов на массу, есть только на питание. на вход с нулями это третье состояние.

ладно, если есть живой макет, то начните с простого, отрабатывает ли диод нажатие кнопки.

типа
for(;;)
{
if (PIND0==0)
PORTA = 0xFF
else
PORTA = 0x00;
}

потом дальше бум думать.

Pilot
08.10.2013, 22:39
Я вот как раз и подумал сделать что-то наподобие этого - разбить программу на составляющие, и смотреть как оно работает. Завтра и займусь.

Pilot
09.10.2013, 09:40
стою на асфальте я в лыжи обутый....

текст программы

#include <avr/io.h>

int main()
{
PORTA=0x00; //порт А
DDRA=0xFF;

PORTD=0x00;
DDRD=0x00;
for(;;)
{
{
if (PIND0==0)
PORTA=0xFF;
else
PORTA=0x00;
}
}
}

и та не работает...
первый цикл - диоды погашены, все последующие - диоды включены, независимо от состояния кнопки.
Я даже установил подтягивающий резистор на землю - не помогло.

Может у меня руки кривые, а извилины - прямые?

Kino
09.10.2013, 10:38
а так реакция на пинд0 в реальном железе есть?

http://exfile.ru/441048

Pilot
09.10.2013, 11:29
Есть и в реальном, и в симуляции...

Kino
09.10.2013, 11:50
тогда я хз. что-то не правильно настроено в студии.
скомпилил у себя без изменений.
пробуй.

http://exfile.ru/441062

Pilot
09.10.2013, 11:56
то есть компиляция неправильно идет?

Kino
09.10.2013, 12:12
походу да.

Pilot
09.10.2013, 12:58
тогда я хз. что-то не правильно настроено в студии.
скомпилил у себя без изменений.
пробуй.

http://exfile.ru/441062


если это моя программа - то не фурычит.
после временной задержки выдает не запрограммированную индикацию (portA == 0b00110110),при том даже не отрабатывая положенные шаги.
Моя компиляция работала так-же (после подвешивания резет на +)

А предыдущий файл - это компиляция какого кода?

Kino
09.10.2013, 13:16
а, ну если так-же, то по идее файл собирает правильно.

предыдущая просто цикл.
if (PIND0==0)
PORTA=0xFF;
else
PORTA=0x00;

Pilot
09.10.2013, 13:32
А ты открывал мой проект? Или создавал свой и писал туда мою программу?

Вопрос в том, что компиляция цикла у меня раза в полтора меньше, чем у тебя.
А компиляция программы по размеру такая-же. Может (если открывал мой проект) не перезаписался hex-файл?

Kino
09.10.2013, 13:36
почему?

вот мой.
: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


опкоды разные, но размер подходит.

Pilot
10.10.2013, 09:16
да, похоже что ошибся с объемом кода.
Возможно действительно по разному компилирует.

Поставил 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;
не отрабатывая никакие другие. и оттуда его ничем не выудить...

ошибок, предупреждений нет.

Kino
10.10.2013, 11:39
значит не отрабатывают PIND0. попробуй прочитать пины по другому.
в еще лучше сделать это через switch.

не помню как в студии, в ирае это объявлено как
#define PIND0 0
естественно никогда единице равняться не будет.

вот. так как-то.
if ((PIND & 1 ==1) &&(PIND & 2==0) && (PIND &4 ==0))

Globus
18.10.2013, 18:55
Ничего, я пять копеек вставлю?
Полгодика 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();
}

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

Pilot
20.10.2013, 17:49
5 копеек - это хорошо, но мое понимание еще не дошло до данного кода...
проще говоря - я из этого ничего не понял.
Т.к. мое изучение програмирования МК и вообще С++ ограничивается на данный момент только вот этим одним устройством.
Но за код все равно спасибо - найду на работе час-полтора свободного времени - попробую разобраться с данной записью

Globus
20.10.2013, 19:32
Я тогда пока накидаю недостающих для понимания строк и картинку.
Также добавлю, что у меня биполярный шаговик.
#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/bipolar_step_motor1.jpg
К картинке необходимо добавить, что я использовал МС управления ШД, который при подаче единиц на DIR1 и DIR2 устанавливает одну полярность на обмотках 1 и 2 соответственно, а при "нулях" - противоположную.
PS управляет режимом с пониженным потреблением - обеспечивает удержание ротора в паузах.

Pilot
29.10.2013, 17:36
Начинаю все с начала, в связи с некоторыми изменениями в логике устройства (введение АЦП)

первым делом разбиваю всю программу на подпрограммы, и смотрю как работает.
Первая программа - дешифратор задатчика (порт 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: может кто посоветует более адекватное ПО для написания, отладки и компиляции программы?

Yurasvs
29.10.2013, 19:09
pps: может кто посоветует более адекватное ПО для написания, отладки и компиляции программы?
Для первых шагов (да и не только) я бы очень посоветовал ИмиджКрафт ICC AVR. Сейчас ломаная седьмая версия есть в инете. Совместим с симулятором АВР Студио. Там есть очень удобный так называемый аппликейшн билдер, для быстрой и безошибочной автоматической генерации кода настройки портов, прерываний, таймеров и остальной периферии. Довольно удобная интегрированная среда, есть даже встроенное окно для программирования чипа не отходя от кассы (поддерживает железо Понипрога). Поддерживает также бинарное представление чисел (иногда очень повышает читаемость кода), есть документация на русском языке.
Есть еще Кодевижн, но мне больше нравится ICC, там работающий проект можно создать буквально за несколько кликов мышкой. Ну и конечно IAR, но это для профессионалов, можно позже на него переползти.

Kino
29.10.2013, 21:30
Блин. Надо найти время и запилить вам этот проект. Осталось узнать как.

Вы на функции программу не перевели, у Вас остался 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()

Globus
30.10.2013, 11:26
Pilot, а что в таличке состояний означают "x" и "-"?

Pilot
30.10.2013, 13:48
прочерки означают незадаваемое положение (задатчиком его нельзя выбрать, но в энкодере оно есть)

кресты - что при указанном состоянии прочих ног, состояние данной не учитывается.

Said
30.10.2013, 14:43
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, от этого легче не станет, а код усложнит и займет на порядок больше тактов, описанный выше мною вариант более применим к контроллерам, со статическмими условиями регулятора.

Pilot
30.10.2013, 14:54
длинное сообщение

вот здесь вроде немного понятно:


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 нужный сигнал и могу выполнять следующую процедуру.



Правильно понял?

Said
30.10.2013, 15:03
Условие if (PINB & 0x80 == 0) как по мне не корректно. В данном случае всегда будет ложь, т.к. 0x80 не равно 0 :)
Для успокоения совести напишите:
if ((PINB & 0x80) == 0)
или просто
if !(PINB & 0x80)

Pilot
30.10.2013, 16:20
опять большое письмо

т.е. ты предлагаешь сделать следующим образом:

#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}

Said
30.10.2013, 16:49
Но в таком виде код не пройдет компиляцию, ибо ошибок тьма.
И, если 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);
//зависит от желаемого результата

//.........какой-то код............
}

Pilot
31.10.2013, 09:11
Вот алгоритм работы устройства, чтоб было понятно о чем речь:
http://savepic.su/3712486m.jpg (http://savepic.su/3712486.htm)

Said
31.10.2013, 09:29
Так у Вас все есть, вот четко по алгоритму и действуйте. Просто код старайтесь дедать максимально простым и учитывайте, что необходимы задержки при отработке команд до чтения состояния, причем величина задержек прямопропорциональна инертности исполнительных элементов.

Pilot
31.10.2013, 09:37
И, если GetEncoder разовая функция, то ее нет смысла оформлять отдельной процедурой.


Тут функция должна быть (чтоб не было недоразумения в коде - getcomander) несколько раз, поэтому наверное, все-таки лучше функцией.
И остальные так-же.

#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
\\ продолжаем выполнять основную программу

Pilot
31.10.2013, 14:27
Так у Вас все есть, вот четко по алгоритму и действуйте. Просто код старайтесь дедать максимально простым и учитывайте, что необходимы задержки при отработке команд до чтения состояния, причем величина задержек прямопропорциональна инертности исполнительных элементов.

Да вот я и стараюсь действовать.
Проблема в том, что я не изучал ранее языки программирования (окромя паскаля в 9м классе).
И вот собственно мне стал вопрос изготовления блока управления.
На нем я и решил поучиться столь интересному занятию.

Конечно, как для первой программы у меня возникло дохренадостаточно много проблем:
- программа на операторе IF/ELSE написана вроде как правильно, замечаний в компиляторе нет, но она не работает в контроллере. Вот и обратился за помощью (и заодно - получу новые знания :D, надеюсь)

Said
31.10.2013, 17:40
Ну, судя по представленному Вами алгоритму, вам, кроме if/else, врядли потребуются более изощренные компоненты языка.....

Pilot
31.10.2013, 18:28
только он у меня нихрена не заработал... к сожаленью

Хотя 2 человека, которые пишут на С++, но не программируют контроллеры, сказали, что код правильный

Said
31.10.2013, 18:44
Значит Вы просто где-то промахиваетесь либо с начальной конфигурацией контроллера либо в схеме.

Yurasvs
31.10.2013, 20:32
Фузы правильно зашили?

Kino
31.10.2013, 21:01
не фьюзах дело. настройки где-то кривые. он пишет под avrstudio + winavr.

fox_12
04.11.2013, 14:24
Сорри что вклиниваюсь в интеллектуальную беседу, а, извиняюсь, - более простые программы писали?
Светодиодиком получалось моргать?
К сожалению - из топика не вижу ни полную схему, ни программу. Но пробовали собирать на макете, и вместо датчиков использовать кнопки, а вместо исполнительных инструментов те же светодиоды?
Проблему дребезга контактов концевиков решили?
Все входы и выходы проинициализировали правильно? Ничего у вас в "воздухе" не осталось висеть?

Pilot
05.11.2013, 18:22
попробую переписать программу с внесенными предложениями, и выложу на обозрение.
так-же и схему устройства предоставлю

ЗАПАДЛО
07.11.2013, 17:23
По поводу АВР, подскажите среду ... а то я в ардуине, но хотелось бы устройство перенести в железку. Чтобы было меньше и универсальней.

Yurasvs
07.11.2013, 18:06
Среду чего? Программирования на С? Разные есть. IAR, но он навороченный слишком, новичка может отпугнуть. Codevision демократичнее. Я использую ImageCraft ICC7, очень нравится своей простотой и наличием аппликейшн билдера, автоматически генерирующего правильный код настройки периферии буквально за несколько кликов мышкой.

Kino
07.11.2013, 18:30
Для своих поделок CVAVR самое оно.

А IAR он не навороченный, он как-раз тупо голый. Но у него с оптимизацией более правильно сделано.

Yurasvs
07.11.2013, 18:37
Не знаю, меня оптимизатор ИмиджКрафта очень даже устраивает. Компилил как-то один и тот же код ИАРом и Крафтом, у Крафта код получился меньше. К тому же там есть очень полезная фича "Code Compression", уменьшает размер кода примерно на 12% за счет небольшого снижения скорости работы. Незаменимо, когда проект чуть-чуть не влазит в выбранный чип, а менять чип уже не хочется.

Globus
07.11.2013, 18:57
Вопросы ТС, уточнение по энкодеру (точнее по табличке):
в случае "х" (нельзя задать) на вход МК таки будет приходить 0 или 1?
Также интересен вопрос по "-". Ясно, что не учитывается, какое оно будет реально?
Я вижу в кусках кода включение резисторов подтяжки.. Вероятно, кнопки коротят входы МК на землю, а на разомкнутых контактах будет "1"?

Еще один важный вопрос - в табличке PA5-7 и PB0-3 поданы как исходные данные, а PD2-6 как результат. Да и в программе порты сконфигурированы соответствующим образом.
Однако, я посмотрел внимательно на табличку и увидел закономерность:
кроме строк 6 и 7, PA5-7 однозначно описывают состояния выходов. А для того, чтобы отличить строки 6 и 7, достаточно будет посмотреть состояние PB0.
Выходит, на задатчике достаточно одной кнопки?
Или я что-то не так понял?

Ну и это - там правильно подсказали: не работают почему-то простейшие вещи, так что попробуйте для начала проверить состояние одного пина и в ответ давать 1 или 0 на другой.

Globus
07.11.2013, 19:00
И прошу прощения у ТС, раз заговорили об оптимизации, задам свой вопрос:
Есть поверье, что t = ((t << 7) | (t >> 1)) некоторые компиляторы компилируют в ROR. У меня не вышло такого добиться. Кто-то с этим сталкивался? На чем-то получалось?

Kino
07.11.2013, 20:46
всмысле? всё выражение в один ROR? Такого же не бывает. )

Globus
07.11.2013, 20:58
Ну так по сути это 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 не удалось заставить это понять.

Kino
07.11.2013, 21:10
ну как только ROR если команду ИЛИ тоже надо выполнить.

и в авр нет SHL и SHR, есть LSL и LSR, отличие от ROL и ROR только в переносе старшего бита в младший. В SHL и SHR этого переноса нет.
Только никак не применю к вашему выражению, о котором ходит поверье... )

Globus
07.11.2013, 21:22
На любой восьмибитной переменной результат такой функции:
__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 - да. Это я уже по привычке.

Kino
07.11.2013, 21:47
это наверное сильно надо раздуть прогу, чтобы реально места не хватало. а так, что включена оптимизация, что выключена - по шарабану.

Pilot
08.11.2013, 09:47
Вопросы ТС, уточнение по энкодеру (точнее по табличке):
в случае "х" (нельзя задать) на вход МК таки будет приходить 0 или 1?
Также интересен вопрос по "-". Ясно, что не учитывается, какое оно будет реально?
в случае "х" - состояние на входе может быть как "1", так и "0", но в случае необходимости можно упростить, задав четкие положения кнопок, и тогда "х" будет равен "0"
в строке, где "-" возможно только определить положение энкодера (и индицировать его), но выбрать задатчиком это положение нельзя.
Это конструктивная особенность энкодера, там ввели лишнюю позицию, которая не используется.

Я вижу в кусках кода включение резисторов подтяжки.. Вероятно, кнопки коротят входы МК на землю, а на разомкнутых контактах будет "1"?
Именно так

Еще один важный вопрос - в табличке PA5-7 и PB0-3 поданы как исходные данные, а PD2-6 как результат. Да и в программе порты сконфигурированы соответствующим образом.
Однако, я посмотрел внимательно на табличку и увидел закономерность:
кроме строк 6 и 7, PA5-7 однозначно описывают состояния выходов. А для того, чтобы отличить строки 6 и 7, достаточно будет посмотреть состояние PB0.
Выходит, на задатчике достаточно одной кнопки?
Или я что-то не так понял?
одной кнопки не достаточно для использования всех позиций.
Ее (в данном случае) достаточно только чтоб разделить 6ю и 7ю позиции задатчика, а для остальных позиций используются остальные кнопки тоже.

Ну и это - там правильно подсказали: не работают почему-то простейшие вещи, так что попробуйте для начала проверить состояние одного пина и в ответ давать 1 или 0 на другой.
перепаяю живой макет и буду проверять.
но мне тоже кажется, что проблема в настройках ПО для компиляции.

Pilot
18.11.2013, 18:02
ну в общем, есть вариант (недопиленный пока что) программы без 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)};
}
}
}

Pilot
18.11.2013, 18:22
А вот и старый вариант
Порты другие, но сути не меняет

/*
* 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;
}

}
}