Проект Атом


Данный материал немного не вливается в концепцию сайта, поскольку код в материале есть, а ардуино в материале практически нет… Ну увы…

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

Дабы совместить полезное с полезным, было решено выполнить сию в виде статьи.

Первым делом, разумеется стоял вопрос механики.
За неблаговидными перспективами собственноручного изготовления механики, я приобрел готовую. (Постыдное проявление слабости.)

Это Атом в том виде в котором он есть сейчас:


Внимательный читатель, вне сомнения узнает тележку, уже описанную в предыдущих статьях робокрафтового письма, камрадом DmitryDzz. Также как и робот Митя, выполненный на базе платформы Pirate-4WD Mobile Platform, «Атом» использует возможности этой платформы.

1. Часть первая. Общая концепция.

Pirate-4WD Mobile Platform представляет собой достаточно качественную четырехмоторную тележку, с кучей всяческих крепленичек и рюшечек дырочек, специально предназначенных для электротехнических извратов пользователя.

Подробное описание Pirate-4WD Mobile Platform я оставлю за бортом. Единственно, следует отметить, что платформа полноприводная. По мотору на каждое колесо. По два мотора слева и справа. Разумеется, тут же возникает логичное желание объединить электрически бортовые пары. Желание действительно логичное и элегантное, и потому, видимо, тут же было отметено, как постыдное проявление слабости.

Итого. Механика о четырех моторах и задача ими управлять.

Передо мной стояла задача определения очертаний того изделия, которое я собираюсь разработать… С этим было туго. И туго до сих пор.

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

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

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

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

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


Работа в разгаре.


2. Контроллер Шасси.

Функциональность определилась так:

— Контроллер на ядре AVR. (взял ATmega48)
— Канал для внутрисхемного программирования.
— Драйвера под четыре двигателя (взял 2 штуки L293D)
— Возможность подключения как внешнего логического питания, так и использования в качестве источника логического питания — питание силовой части. (решено при помощи Кренки 7805 и джамперов)
— Возможность подключения энкодеров с тем, чтобы можно было перейти от разомкнутого управления по мощности к замкнутому по скорости.
— Шины. Так как форма связи с главным контроллером неопределена — вопрос достаточно абстрактный. (Сделал выводы под I2C, выводы под USART, а также добавил возможность переключения с помощью джампера, канала USART на схему монтажного ИЛИ.)
— Отладочный светодиод.
— После подсчета ног у ATmega48, выяснилось, что есть лишняя. Посадил на неё возможность внешнего прерывания (ну или просто резервный пин).

Схема:


Больший размер.

Разводка под ЛУТ (Не в масштабе)

Хотел залить lay файл, но… Не понимаю, нельзя что-ли на робокрафт файлы заливать?

Схема основывается на L293D. Соответствующая статья на robocraft есть. Хорошая статья есть здесь.

Фотографии изделия


Выявленные в процессе тестирования и работы проблемы:

— Нерациональное использование ШИМ каналов и таймеров. Подключение каналов модуляции к таймерам в нарисованной мной схеме составила «2-1-1» вместо рационального «2-2-0». Это привело к тому, что пришлось использовать в режиме ШИМ все три таймера контроллера, вместо того, чтобы сэкономить один для сторонних задач.

— Тестирование показало, что драйвера двигателей сильно греются. Это показывает не проработанность вопроса охлаждения. Для драйвера №2 даже пришлось допаять импровизированный радиатор.

В остальном, схема показала свою способность решать поставленные задачи. Я опасался помех на линиях подключения энкодеров, но забегая вперёд, могу сказать, что опасался зря.

Программируется схема через SPI разъём и программно совместимой с Ардуино, увы не является (хотя была у меня такая мысль).


3. Движение по программе.

Код я писал в Code Vision AVR. Это накладывает свои отпечатки. Дело в том, что Code Vision не во всём следует стандартам языка «C», компилит не оптимальный код, и вообще повинен во всех смертных грехах, но и преимуществ у него таки есть. Я его люблю.

Код был примерно таким. (За давностью не сохранилось)
Полный текст программы приводить не буду, тем более, что его уже нету.

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

Блок аппаратной абстракции.

#define E1R OCR2B
#define E1L OCR0B
#define E2R OCR1AL
#define E2L OCR1BL

#define I1RA PORTD.4
#define I1RB PORTB.6

#define I2LB PORTD.6
#define I2LA PORTB.7

#define I1LA PORTD.7
#define I1LB PORTB.0

#define I2RB PORTB.4
#define I2RA PORTB.3

#define LED PORTB.5

Здесь присваиваются выводам понятные мнемоники с тем, чтобы с ними было удобно работать. Следует заметить, что эта таблица зависит не только от структуры контроллера, но и от того, как соединены выводы двигателей.

Настройка таймеров на ШИМ по нужным каналам (Code Vision AVR хорош тем, что настраивает периферию сам, генерируя соответствующий код).

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Phase correct PWM top=0xFF
// OC0A output: Disconnected
// OC0B output: Non-Inverted PWM
TCCR0A=0x21;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Ph. correct PWM top=0x00FF
// OC1A output: Non-Inv.
// OC1B output: Non-Inv.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0xA1;
TCCR1B=0x03;

TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Phase correct PWM top=0xFF
// OC2A output: Disconnected
// OC2B output: Non-Inverted PWM
ASSR=0x00;
TCCR2A=0x21;
TCCR2B=0x04;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

Здесь настроен ШИМ на фазакорректный режим с частотой счета 125000. Счет ведется от 0 до 255, а потом назад до нуля. Частота модуляции таким образом оценивается как 125000/(256*2), что приблизительно равно 244 импульса в секунду. С частотами выше этой частоты драйвера L293D и моторы работать не очень хотят, видимо, в силу высокой индуктивности катушек двигателя.

Основной цикл может быть каким-нибудь таким.

while(1){

     I1RA=1;I1RB=0;
     I1LA=1;I1LB=0;
     I2LA=1;I2LB=0;
     I2RA=1;I2RB=0;
     E1L=120;
     E1R=120;
     E1L=120;
     E1R=120;

delay_ms(4000);

     I1RA=1;I1RB=0;
     I1LA=0;I1LB=1;
     I2LA=0;I2LB=1;
     I2RA=1;I2RB=0;
     E1L=160;
     E1R=160;
     E1L=160;
     E1R=160;

delay_ms(4000);

     I1RA=0;I1RB=1;
     I1LA=0;I1LB=1;
     I2LA=0;I2LB=1;
     I2RA=0;I2RB=1;
     E1L=120;
     E1R=120;
     E1L=120;
     E1R=120;

delay_ms(4000);


}

Такая программа задает движение вперед — поворот налево — назад.

Сохранилось видео одного из самых первых запусков Атома. Как раз с программным движением.

Поворачивает здесь он очень лениво, ибо небыли к тому моменту решены некоторые проблемы с питанием (Стояли дешевые слаботочные батарейки. Сейчас же стоит литий-полимерный аккумулятор и ездиет он не в пример резвее).

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


4. Тупиковый путь. ИК канал.

Давным давно, когда компьютеры были большими, а динозавры маленькими… … … Года два назад… Я изучал возможности ИК диодов и фототранзисторов.

А почему бы не сделать управление тележкой по ИК пульту, подумал я…
Само собой, путь тупиковый, но интересный. Действительно недостатков по сравнению с радиопротоколами дохрена. Но все же почему бы и нет.

Благо, что было с чего начинать. Однажды, в стародавние времена, руководствуясь древними (или не очень) гриммуарами спёртыми через портал брошенный по адресу от http://www.getchip.net, выплавил я из базальта куска приёмник ведический свет незримый зрящий (Приёмник ИК сигнал, по нашему)… Выплавил, поигрался да и забыл.

За схемой я вас отправляю на getchip.

Жалкая подделка тамошнего изделия:

Вот и пригодился приёмничек.

А раз есть приёмник, то нужен передатчик.

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


Больше!
Эмм… Кажется слева черточка лишняя попала…

Пульт ИК управления.

Разъём для внутрисхемника не предусмотрен. Контроллер программируется «методом кроватки» (То бишь вынул-прошил-вставил).

На пульте четыре кнопки, соответственно — вперёд, назад, влево, вправо, а также блок выключателей.

На первом выключателе висит питание схемы (Контроллера, вообще говоря… Но на самом деле — всей схемы.). А остальные пять определяют режим работы пульта.

Поскольку пинов у контроллера еще есть, можно что-нибудь в схему допаять, благо макетка.

На момент написания статьи используются выключатели 2,3,6.
2 — больше скорости.
2 и 3 одновременно — еще больше скорости.
6 — Инфракрасный маяк. (Была у робота схема, используя которую, робот бегал за маяком. Схемка, таки бажно, но работала. В текущей реализации бесперспективна, а потому разобрана и описанию не подлежит.)

5. Часть пятая, в которой Протокол.

Для того, чтобы иметь в распоряжении больше, чем одну команду (Сигнал есть — работает, Нету — не работает), необходимо позаботиться о языке обмена — протоколе передачи.

Для ИК диапазона их придуманы сотни… За справкой опять же на getchip. Способы передачи по ИК каналу.

Возможности физической реализации протокола определяются режимом работы приёмника, или, точнее TSOP, на основе которого он построен. TSOP — это такой хитрый ИК датчик, в который уже вшиты фильтр несущей частоты (у меня на 36кГЦ), детектор, а также АРУ — автоматический регулятор усиления.

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

Благодаря АРУ, штука эта очень чувствительная, а благодаря комбинации фильтра и АРУ — стойка к помехам.

За это приходится расплачиваться ограниченностью режимов работы.

Во-первых принимает она только сигнал частотой 36кГц (на самом деле 36 кГц и некоторую окрестность. Например 38 кГц тоже примет, хотя и не столь уверено), а во-вторых сигнал нельзя слать постоянно. Ибо АРУ решит, что постоянная пульсация — суть помеха…

Отсюда вывод. Слать надо недолго и не часто. Тупо взять и зафутболить USART в ИК канал не получится.

Изучив вопрос, я, как и камрад GetChiper, избрал NEC подобный протокол за его простоту для реализации.

При этом принципе передачи информация кодируется длительностью паузы между импульсами.
Как и в USART Здесь, кроме основной информации должны быть будут СТАРТ и СТОП биты.
Длительность модулированного импульса для TSOP должна примерно равняться 270 мкс (Это у меня. В NEC 560.). Или примерно 300 мкс.
Обозначив это период за T, определим
— единицу как паузу между импульсами от T до 6T,
— ноль от 6T до 12T.
— пауза более 12T считается сбоем системы наведения. срывом передачи.

Задача приёмника формулируется так. Принять байт из ИК канала и положить его в USART. А там уж, кому надо разберуться…

Код приёмника:

#include <tiny13.h>
#include <delay.h>
#define LED PORTB.3
#define TX PORTB.4
#define TSOP PINB.1
#define BIT0 (timer>60)
#define BIT1 (timer<60)
#define BITOVF (timer>120)

int tim2=0;
char c;
int counter;
void putch (char c);
int timer2;
int timer=0;;
bit flag,putflag;
char temp;

void ovf(void)          //Очистка памяти при ошибке
{putflag=0;c=0x00;counter=0;}


interrupt [EXT_INT0] void ext_int0_isr(void) //Прерывание настроено
// на любое изменение на выводе TSOP.
{
        if (TSOP==1)    //Сброс отсчета времени как только
                        //импульс отпустил линию.
        {timer=0;}



else  {                  // Если линию прижало
      if (putflag==0)
        if BIT0 {putflag=1;c=0x00;counter++;} // Если это СТАРТ бит.
                                        //Отмечаем приём СТАРТ бита
                                        // Чистим буфер.
        else ovf();  // Если это не BIT0, то это не СТАРТ - ошибка...

      else           // Если СТАРТ уже был ранее

      {c=c>>1;
       if BIT1 {c|=0x80;}
       counter++;                 // Пишем принятый бит  в буфер

       if (counter>8) {flag=1; temp=c; ovf();}}
  //Если посылка принята, отправляем её на USART установкой флага
        }
}


interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{ timer++;  if BITOVF ovf();timer2++; }
//timer  отсчитывает время для импульсов.
//timer2  отсчитывает время для светодиода.
//Если очень долго нет приёма, наступает BITOVF и система сбрасывается.




//Начало программы

void main(void)
{                 //Инициализация
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
PORTB=0x00;
DDRB=0x00;
DDRB=(1<<3)|(1<<4);
TX=1;
TCCR0A=0x00;
TCCR0B=0x01;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
GIMSK=0x40;
MCUCR=0x01;
GIFR=0x40;
TIMSK0=0x02;
ACSR=0x80;
ADCSRB=0x00;
DIDR0=0x00;
ADCSRA=0x00;
#asm("sei")

// Кончилась Инициализация

while (1)
      { if (timer2>3000) {timer2=0; tim2=1;}; // Хитрое мигание
        if (timer2>5) {tim2=0;};   //светодиодом.
        if (putflag) LED=1; // Слабое, если нет сигнала.
        else LED=tim2;    //Сильное, если есть.

      if (flag==1) {     //Если поднят флаг окончания
      #asm("cli")      // приёма
      putch(temp);     // Отсылаем принятый байт по USART
      flag=0;          // Сбрасываем флаг
      ovf();           // Чистим память.
      #asm("sei")
      }

      }
}

void putch (char c)       // В контроллере ATtiny13 нет USART
{  int i;              //Этот коротенький код
  #define T 111      //Программно его имитирует.

TX=0;
delay_us(T);
for (i=0;i<8;i++)
{TX=c&1;
c=c>>1;
delay_us(T);}
TX=1;
delay_us(T);

}

Код довольно хмурый, но работает просто:
— Дернулась линия — сбросили timer.
— Считаем время. Если больше 12T сбой.

— Если дернулась до сбоя — смотрим, на кого натикало, на 1 или на 0.
— Если это первый принятый бит — это, вероятно Старт бит. Проверяем, равен ли он нулю.
Если равен,
— Даём разрешение на приём посылки. Опять же проверяем сбой по 12T. По импульсу стопбита замыкается последний бит посылки.
— посылка отправляется на USART.

Работа передатчика и того проще

#include <tiny2313.h>
#include <delay.h>

#define delayMicroseconds delay_us

#define LED PORTD.5
#define K_W  PINB.2
#define K_S  PIND.0
#define K_A  PIND.1
#define K_D  PIND.2

#define K_2  PINB.7
#define K_3  PINB.6         //Мнемоники для кнопок
#define K_4  PINB.5
#define K_5  PINB.4
#define K_6  PINB.3

#define IKLED PORTD.6

#define on TIMSK=1              // Включение и выключение модуляции
#define off {TIMSK=0;IKLED=0;}  // Ведется путем запрещения прерывания.
                                // Гениально и просто.

 interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
  if (IKLED) IKLED=0;
  else IKLED=1;                 // Прерывание мигает ИК диодом.
}


 void put(char a)
{on; delayMicroseconds(270);            // Безхитростные функции
off;
if (a==1) delayMicroseconds(270*3);
else delayMicroseconds(270*9);}

void putchar2(char c)
{char i;
put(0);
for (i=0;i<8;i++)
  {                                   // Кладущие биты и байты в канал.
  put(c & 1);
  c=(c>>1);
  }
put(1);                             // Врядли их работа может быть интересной.
delayMicroseconds(270*15);
}



// Declare your global variables here

void main(void)
{
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
PORTA=0xFF;
DDRA=0x00;
PORTB=0xFF;
DDRB=0x00;
PORTD=0xFF;
DDRD=0x20 | 0x40;
TCCR0A=0x02;
TCCR0B=0x01;
TCNT0=0x00;
OCR0A=0x6F;     //OCR0A = 111. 8000000/111=72072, что
                //примерно соответствует удвоенной частоте приемника.
OCR0B=0x00;
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
GIMSK=0x00;
MCUCR=0x00;
TIMSK=0x00;
USICR=0x00;
UCSRB=0x00;
ACSR=0x80;
DIDR=0x00;


off;

LED=0;
    #asm("sei")
while (1)
      {

      LED=1;
      delay_ms(1);
       // Дальше следует страшный опрос кнопок... Страшный...
 // В зависимости от результата в канал кладётся тот или иной символ.
//Если вдруг будете читать - логика инверсная.
      if (K_6){

        LED=0;
        if (K_2)
                {if (!K_W & K_S & K_A & K_D ) putchar2('w');
                 if (K_W & !K_S & K_A & K_D ) putchar2('s');
                 if (K_W & K_S & !K_A & K_D ) putchar2('a');
                 if (K_W & K_S & K_A & !K_D ) putchar2('d');

                 if (!K_W & K_S & !K_A & K_D ) putchar2('q');
                 if (!K_W & K_S & K_A & !K_D ) putchar2('e');
                 if (K_W & !K_S & !K_A & K_D ) putchar2('z');
                 if (K_W & !K_S & K_A & !K_D ) putchar2('c');
                 }

        else   {
        if (K_3) {if (!K_W & K_S & K_A & K_D ) putchar2('W');}
        else {if (!K_W & K_S & K_A & K_D ) putchar2('T');};
                 if (K_W & !K_S & K_A & K_D ) putchar2('S');
                 if (K_W & K_S & !K_A & K_D ) putchar2('A');
                 if (K_W & K_S & K_A & !K_D ) putchar2('D');

                 if (!K_W & K_S & !K_A & K_D ) putchar2('Q');
                 if (!K_W & K_S & K_A & !K_D ) putchar2('E');
                 if (K_W & !K_S & !K_A & K_D ) putchar2('Z');
                 if (K_W & !K_S & K_A & !K_D ) putchar2('C');
                }
                 delay_ms(49);
       }


      else {delay_ms(1); IKLED=1;
      delay_ms(1); IKLED=0;}

      }
}

Вот, собственно и всё по ИК каналу… Осталось только прошивку самому контроллеру шасси под это управление сделать.

Но сперва видео:

Два раза назвал передатчик приёмником… Печалька…

6.Код контроллера шасси,управление мощностью по командам с USART.

Тут без коментариев… Потому что очень просто и однообразно:

#include <mega48p.h>
#include <delay.h>

#include <stdio.h>

char data;
  int timer=0;

#define ENC1 PINC.3
#define ENC2 PINC.2
#define ENC3 PINC.1
#define ENC4 PINC.0

#define E1R OCR2B
#define E1L OCR0B
#define E2R OCR1AL
#define E2L OCR1BL

#define I1RA PORTD.4
#define I1RB PORTB.6

#define I2LB PORTD.6
#define I2LA PORTB.7

#define I1LA PORTD.7
#define I1LB PORTB.0

#define I2RB PORTB.4
#define I2RA PORTB.3

#define LED PORTB.5

#define def 120
#define def_mest 180
#define defpm 40
#define defpb 240

#define mm_def 255
#define m_def 180
#define m_def_mest 255
#define m_defpm 20
#define m_defpb 255

#define defpov 200
#define T 1200

// Timer1 overflow interrupt service routine
interrupt [TIM2_OVF] void timer1_ovf_isr(void)
{
// Place your code here
    timer++;
}

// Declare your global variables here
              void stop (void)
   {
        E1R=0;
        E1L=0;
        E2R=0;
        E2L=0;
        }     ;


void w(void);
void a(void);
void s(void);
void d(void);

void e(void);
void q(void);
void c(void);
void z(void);

void mmW(void);
void mW(void);
void mA(void);
void mS(void);
void mD(void);

void mE(void);
void mQ(void);
void mC(void);
void mZ(void);


void r(void);


interrupt [USART_RXC] void usart_rx_isr(void)
{
timer=0;
data=UDR0;
if (data=='w') {w();}
        if (data=='a') {a();}
        if (data=='s') {s();}
        if (data=='d') {d();}

        if (data=='e') {e();}
        if (data=='q') {q();}
        if (data=='c') {c();}
        if (data=='z') {z();}

        if (data=='T') {mmW();}

        if (data=='W') {mW();}
        if (data=='A') {mA();}
        if (data=='S') {mS();}
        if (data=='D') {mD();}

        if (data=='E') {mE();}
        if (data=='Q') {mQ();}
        if (data=='C') {mC();}
        if (data=='Z') {mZ();}


      if (data=='r') {r();}
      }


void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0xff;
DDRC=0x00;

// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=In Func1=In Func0=In
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=T State1=T State0=T
PORTD=0x00;
DDRD=0xF8;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Phase correct PWM top=0xFF
// OC0A output: Disconnected
// OC0B output: Non-Inverted PWM
TCCR0A=0x21;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Ph. correct PWM top=0x00FF
// OC1A output: Non-Inv.
// OC1B output: Non-Inv.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0xA1;
TCCR1B=0x03;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Phase correct PWM top=0xFF
// OC2A output: Disconnected
// OC2B output: Non-Inverted PWM
ASSR=0x00;
TCCR2A=0x21;
TCCR2B=0x04;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;

// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;

// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x01;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART0 Mode: Asynchronous
// USART Baud Rate: 9600
UCSR0A=0x00;
UCSR0B=0x98;
//UCSR0B=0x08;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x33;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
DIDR1=0x00;

// ADC initialization
// ADC disabled
ADCSRA=0x00;

// SPI initialization
// SPI disabled
SPCR=0x00;

// TWI initialization
// TWI disabled
TWCR=0x00;


#asm("sei")



        I1RA=1;I1RB=0;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=1;I2RB=0;


while (1)
      {


     if (timer>25) {#asm("cli")
     r();
     LED=1;

     #asm("sei")
     }
     else LED=0;

      }
}

void s(void)
{
#asm("cli")
       I1RA=0;I1RB=1;
        I1LA=0;I1LB=1;
        I2LA=0;I2LB=1;
        I2RA=0;I2RB=1;
        E1R=def;
        E1L=def;
        E2R=def;
        E2L=def;
        #asm("sei")}

void w(void)
{
#asm("cli")
       I1RA=1;I1RB=0;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=1;I2RB=0;
        E1R=def;
        E1L=def;
        E2R=def;
        E2L=def;
        #asm("sei")}

void r(void)
{stop();}

 void a(void)
{
#asm("cli")
       I1RA=1;I1RB=0;
        I1LA=0;I1LB=1;
        I2LA=0;I2LB=1;
        I2RA=1;I2RB=0;
        E1R=def_mest;
        E1L=def_mest;
        E2R=def_mest;
        E2L=def_mest;
        #asm("sei")}

void d(void)
{
#asm("cli")
        I1RA=0;I1RB=1;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=0;I2RB=1;
        E1R=def_mest;
        E1L=def_mest;
        E2R=def_mest;
        E2L=def_mest;
        #asm("sei")}

        void e(void)
{
#asm("cli")
        I1RA=1;I1RB=0;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=1;I2RB=0;
        E1R=defpm;
        E1L=defpb;
        E2R=defpm;
        E2L=defpb;
        #asm("sei")}

        void q(void)
{
#asm("cli")
         I1RA=1;I1RB=0;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=1;I2RB=0;
        E1R=defpb;
        E1L=defpm;
        E2R=defpb;
        E2L=defpm;
        #asm("sei")}

        void z(void)
{
#asm("cli")
        I1RA=0;I1RB=1;
        I1LA=0;I1LB=1;
        I2LA=0;I2LB=1;
        I2RA=0;I2RB=1;
       E1R=defpm;
        E1L=defpb;
        E2R=defpm;
        E2L=defpb;
        #asm("sei")}

        void c(void)
{
#asm("cli")
        I1RA=0;I1RB=1;
        I1LA=0;I1LB=1;
        I2LA=0;I2LB=1;
        I2RA=0;I2RB=1;
        E1R=defpb;
        E1L=defpm;
        E2R=defpb;
        E2L=defpm;
        #asm("sei")}


        void mS(void)
{
#asm("cli")
       I1RA=0;I1RB=1;
        I1LA=0;I1LB=1;
        I2LA=0;I2LB=1;
        I2RA=0;I2RB=1;
        E1R=m_def;
        E1L=m_def;
        E2R=m_def;
        E2L=m_def;
        #asm("sei")}

void mW(void)
{
#asm("cli")
       I1RA=1;I1RB=0;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=1;I2RB=0;
        E1R=m_def;
        E1L=m_def;
        E2R=m_def;
        E2L=m_def;
        #asm("sei")}

        void mmW(void)
{
#asm("cli")
       I1RA=1;I1RB=0;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=1;I2RB=0;
        E1R=mm_def;
        E1L=mm_def;
        E2R=mm_def;
        E2L=mm_def;


        #asm("sei")}

 void mA(void)
{
#asm("cli")
       I1RA=1;I1RB=0;
        I1LA=0;I1LB=1;
        I2LA=0;I2LB=1;
        I2RA=1;I2RB=0;
        E1R=m_def_mest;
        E1L=m_def_mest;
        E2R=m_def_mest;
        E2L=m_def_mest;
        #asm("sei")}

void mD(void)
{
#asm("cli")
        I1RA=0;I1RB=1;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=0;I2RB=1;
        E1R=m_def_mest;
        E1L=m_def_mest;
        E2R=m_def_mest;
        E2L=m_def_mest;
        #asm("sei")}

        void mE(void)
{
#asm("cli")
        I1RA=1;I1RB=0;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=1;I2RB=0;
        E1R=m_defpm;
        E1L=m_defpb;
        E2R=m_defpm;
        E2L=m_defpb;
        #asm("sei")}

        void mQ(void)
{
#asm("cli")
         I1RA=1;I1RB=0;
        I1LA=1;I1LB=0;
        I2LA=1;I2LB=0;
        I2RA=1;I2RB=0;
        E1R=m_defpb;
        E1L=m_defpm;
        E2R=m_defpb;
E2L=m_defpm;

        #asm("sei")}

        void mZ(void)
{
#asm("cli")
        I1RA=0;I1RB=1;
        I1LA=0;I1LB=1;
        I2LA=0;I2LB=1;
        I2RA=0;I2RB=1;
       E1R=m_defpm;
        E1L=m_defpb;
        E2R=m_defpm;
        E2L=m_defpb;
        #asm("sei")}

        void mC(void)
{
#asm("cli")
        I1RA=0;I1RB=1;
        I1LA=0;I1LB=1;
        I2LA=0;I2LB=1;
        I2RA=0;I2RB=1;
        E1R=m_defpb;
        E1L=m_defpm;
        E2R=m_defpb;
        E2L=m_defpm;
        #asm("sei")}

Но, это еще пока самые цветочки. Ягодки еще будут.

Ну и, конечно, приведенные программы и схемы оптимальностью не отличаются. Многое можно улучшить.


Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение