Курс AVR123.nm.ru


Electronic Banner Exchange (ElBE)
 


 

Краткий курс - Самоучитель - AVR - быстрый старт с нуля



Советую читать курс с начала !


Как устроен микроконтроллер AVR

Все задачи-упражнения курса

Язык Си для микроконтроллеров

 

Задача - упражнение  13

 

Цель задачи: 

1)  Создать программу для  микроконтроллера ATmega16
которая будет управлять 8 рулевыми машинками - сервоприводами - SERVO - подключенными к выводам PORTC.  Команды будут приниматься через USART. Например  по интерфейсу rs232 от COM-порта ПК.

Схемы и компоненты для сопряжения МК с COM-портом ПК, так же программы для управления и лога данных смотрите  в  задаче 4   и в  задаче 5

 

 

поиск   GOOGLE   по 
Краткому Курсу AVR

Подставьте слово
и получите результат

 


- Книги и учебники по электронике и микроконтроллерам
   
скачать и читать

- Как и чем прошить МК AVR читайте на странице 7 курса !

- Подробно и с картинками симуляция программы
  в VMLAB рассмотрена в
задаче 3

- АЦП  ATmega16 в 
задаче 9

 

 

Для выполнения задачи необходимы :

- Установленный компилятор CodeVisionAVR

- Установленный эмулятор VMLAB  - Visual Micro Lab

- Data Sheet  - ДШ - паспорт на МК AVR ATmega16

- Знать ХОРОШО теоретический материал курса - до стр. 6

- Выполнить задчачи-упражнения 4 и 5

 

Это нужно не мне - это нужно ВАМ !

Делаем ...

 

SERVO - сервопривод или рулевая машинка - это электромеханическое устройство которое устанавливает ( поворачивает ) свой выходной вал ( либо другой механический параметр - перемещение, момент, скорость ) в соответствии с управляющим сигналом. 

SERVO HiTEC  - параметры и выбор

SERVO Futaba - параметры и выбор

SERVO аксессуары - ServoCity

SERVO для моделей питаются напряжение 4.8 - 6 вольт (обычно "+" это средний красный провод, а земля это черный или коричневый провод).

SERVO для моделей  управляются длительностью импульсов напряжения 3-5 вольт которые повторяются каждый 15-25 мС ( некоторые цифровые рулевые машинки допускают повторение управляющих импульсов каждые 4-5 мС )  до 200 Гц ).

Купить недорого по-почте серво servo рулевые машинки и другие детали для моделизма, создания роботов, различные ракеты, различной техники, беспилотников, БПЛА, ДПЛА, квадрокоптеров и мультикоптеров можно у Семенова Михаила.

Ширина импульса 1500 микро секунд (мкС) соответствует среднему положению вала сервы.  Изменение ширины импульса на 400 мкС обычно соответствует повороту вала сервы на 45 градусов.  На рисунке показаны примерно положения "качалки" servo для ширины управляющих импульсов 1100, 1500, 1900 мкС. 


 

Для "обычных" серво желательно формировать импульсы управления от 1000 до 2000 мкС  чтобы  поворот вала не превысил 60 градусов от среднего положения - это гарантирует сохранность потенциометра ОС (обратной связи) по положению вала внутри SERVO.  Есть специальные сервы с поворотом на 180 град., есть сервы на 3-4 полных оборота и есть сервы неограниченного вращения.

 

- Cкорость поворота вала сервы без нагрузки - в параметрах выше для SERVO Futaba S3003 она составляет 316 градусов в секунду ( 60 град. за 0.19 сек.) при напряжении питания 6 вольт. 

- Момент на валу  сервы Futaba S3003 - 4,1 Кг*См при 6 вольтах питания. Это значит - если на вал установить шкив диаметром 2 См и на шкив намотать нить то серва сможет удерживать или поднимать на нити груз массой 4100 грамм.
 

Произведение момента (Н*М) на скорость вращения (рад/сек) дает мощность в Вт.


SERVO Futaba S3003
 
стоит примерно 13 баксов в розницу. Её ( и другие ) можно переделать в цифровую для управления по шине i2c  и главное с возможностью считывания положения её вала !  Вы можете анимировать вручную ваше устройство, вашего робота и сохранять в компьютер положение всех его SERVO приводов для последующего воспроизведения всего движения. Смотрите бесплатный открытый проект - OpenServo.Org - там схемы, платы, исходники программы для WinAVR, прошивки - всё для самостоятельного повторения на ATmega8, ATmega168

 

Подробней работа и устройство servo и аппаратуры
радиоуправления моделями автомобилей и самолетов
в великолепных статьях портала   RCdesign.ru  

 

Реклама недорогих радиодеталей почтой:

 

Формат команд

Команды управляющие работой servo будут поступать на вход RxD USART ATmega16 в формате который используется servo-контроллерами компаний Pontech, New Micros, Pololu, Net Media, Lynxmotion, Picobytes, Parallax. 

Посылки передаются на скорости 9600 в формате 8N1 и состоят из 3-х байт:

Байт 1 - синхробайт - всегда  байт 255 или 0xFF 
Байт 2 - номер servo - у нас будет от 0 до 7
Байт 3 - позиция в которую поставить серву  - число от 0 до 254.

Если байт 3 равен 127 то наш прибор должен выдавать на соответствующую  серву импульс 1500 мкС ,  Если 0  то импульс 1000 мкС - серва повернет вал максимально против часовой стрелки. Если 254 то импульс 2000 мкС - серва повернет вал максимально по часовой стрелке.


Управлять 8-ю рулевыми машинками с ПК  можно программой скриншот которой ниже  - её можно найти в google и использовать :

 

 

 

Бесплатная программа управления 16 SERVO
с ПК - её раздавали там.           Вот скриншот программы.

Можно скачать резервный архив с программой.

 

 

 

 

Начнем с написания программы принимающей команды с COM порта ПК. 

Если у вашего ПК нет COM-порта, вам поможет микросхема FT232R которая подключается в USB и в ПК возникает виртуальный COM-порт.

Для этого используем материалы задачи 5. Скачайте архив с файлами для CVAVR и VMLAB  -  z5-13.rar   и после распаковки поместите файлы в папку C:\z13

Если у вас нет файла  m8_128.h то скачайте его и поместите в папку C:\CVAVR\inc  компилятора CVAVR.

Запустите CVAVR и откройте проект - cvavr.prj    Выполните компиляцию - она должна пройти без ошибок с одним "вонингом".  

 

Теперь нам нужно внести изменения в текст программы

а) установить скорость USART  9600

Для этого запустите мастер кода CVAVR (серая шестерёнка левее красного жучка в панели инструментов)  и убедитесь что Chip - ATmega16 и частота 11.059 МГц, перейдите на закладку USART и поставьте галочку в Receiver - появятся обычные настройки - скорость должна быть 9600.  Теперь нажмите File -> Program preview и в открывшимся тексте сгенерированной мастером программы скопируйте в буфер строки настройки скорости USART

// USART Baud Rate: 9600
UBRRH=0x00;
UBRRL=0x47;

закройте текст и мастер и вставьте настройки вместо соответствующих
строк в программе. 

б) нужно "закомментировать" - сделать комментариями - не нужные нам
     сейчас примеры вывода информации на USART и на LCD

После строки программы :
// Примеры вывода данных на LCD

вставьте обозначение начала многострочного комментария:

 /*

 Весь текст программы тут стал комментарием,
 т.е. не компилируется теперь.

 
*/
 <- знак конца комментариев  поставьте перед строкой :
     while (1) // бесконечный цикл

Сделайте комментарием и эту строку программы:

// putchar(getchar());

в)  после строки : 
    
#asm("sei"

поместите строку
    
putsf("Hello, world!");  
для проверки вывода данных через USART.

 

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

Вот отредактированный файл  -  usart.c    Вы можете скачать файл, закрыть
CVAVR
и заменить исходник, а потом вновь открыть CVAVR.

 

Приём и распознавание символов по USART

В тексте нашей программы информация поступающая на ножку TxD ATmega16 в USART сохраняется в созданном в задаче 5 буфере размером 100 байт - в нашей задаче наверно хватило бы и 10 , но и 100 не помешает. 

Для хранения принятых команд создадим массив на 8 элементов char с начальным значением 127 - это среднее положение servo. И переменную для выбора элемента массива. После строки программы :

int temp;

напишите :

char servo_poz[8]={127,127,127,127,127,127,127,127};
     //
массив для хранения положения servo
char servo_num = 0;
     // переменная хранит номер servo
  

теперь требуемое положение вала сервы 4  подключенной к ножке PC4 хранится в элементе массива  servo_poz[4]

Пора создать процедуру чтения символов из буфера принятых символов
в бесконечном цикле программы :
 

     
   while (1) // "бесконечный" цикл
{
// Направлять на ножку TXD данные принятые
// на RXD putchar(getchar());

// вы можете печатать символы в левом окне
// терминала в VMLAB и они будут
// появляться в правом окне терминала.

};
 
     

Добавляем в программу цикл
 

     
   while (1) // "бесконечный" цикл программы
{
  // Цикл разбора команд
  while (getchar()== 255)//в этот цикл
  {  // мы попадем ТОЛЬКО когда в буфере 
     // окажется принятый байт 255 - это 0xFF

//
следующий байт - номер серво для которой команда
  servo_num = getchar();
   // для отладки выведем номер серво в USART
   printf("\nS_num %d",servo_num);

// проверим правильность номера servo
  if(servo_num > 7) { // если номер серво больше 7
 
     putsf(" Err_num");  // то это шибка !

 
                  }
  else { //
если номер серво от 0 до 7
// следующий байт - положение вала серво
  servo_poz[servo_num] = getchar();
   // для отладки выведем положение серво в USART
   printf(" Poz %d",servo_poz[servo_num]);
 
       }; // скобка для if ... else
  }
; // скобка для while (getchar
}; // скобка для while (1)
 
     

 

 

Проверим приём по USART в VMLAB

Запустите симулятор VMLAB и откройте проект  C:\z13\vmlab.prj 
и исправьте в файле проекта скорость USART.  Строку :
X1 TTY(115200 8) PD0 PD1 ; терминал

замените на :
X1 TTY(9600 8 0 0 1 2) PD0 PD1  ; терминал

Разместите окна симулятора как вам удобно - мне удобно так :

Выполните компиляцию проекта - "Проджект" - "Ребилд ол" - должна появится надпись как на рисунке выше - "Success! All ready to run" - всё готово к симуляции.

Создайте файл с данными для передачи команд на МК ("как бы" из COM-порта ПК) в симуляторе кнопочкой TX File - см. на рисунке выше !  Откройте редактор "Блокнот" и наберите текст:

1.0e-3 2.0e-2 BIN ; пример передачи в режиме BIN

0A DF 12 E3 98 08 FF FA FB 98 08 FF 01 A3 FF 00 22

98 08 F1 F3 FF 04 53 08 01 E3 22 56 33 13 11 73 55

; строка содержит ошибку FF FA - номер сервы FA больше 7
; но дальше есть команды для установки 
;  servo 1 в 163
- FF 01 A3

;
 servo 0 в 34  - FF 00 22
;  servo 4 в 83  - FF 04 53

;
1.0e-3 - это 1 милиСек. пауза перед отправкой
; на МК следующего байта в строке

; файл для передачи команд

Сохраните файл в папку  C:\z13  под именем 1.TX  и УБЕДИТЕСЬ ,
что расширение именно  .TX  а не .TX.txt  - исправьте.


Теперь запустите симуляцию нажимая на светофор - я жал 4 раза преодолевая сообщения VMLAB про WDT .   Когда симуляция пошла устойчиво - примерно с 33 мСек времени работы ATmega16 - я включил передачу данных из файла 1.TX на ножку RxD МК кнопкой над окном передачи.  Данные были приняты и обработаны и вот что выдал МК  на вывод TxD для отображения в терминале:

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

Вот архив с файлами проекта  z13-2.rar   

 

Итак ...  

Программа принимает команды и сохраняет их в массиве 
servo_poz[8]
    Теперь нужно добавить код настройки
таймеров на выдачу импульсов управления для Servo.

     Настройка таймера рассматривалась в задаче 6

Наверно удобно будет использовать 16 битный таймер ( 16-bit Timer Counter 1 - это стр. 89 даташита ATmega16 ) настроив его на 1 отсчет каждую микросекунду.

 

Делитель ( prescaler factor  1, 8, 64, 256, or 1024 ) тактовой частоты может делить на 1 на 8 и на 64. Значит нам подойдет делитель 8 и частота такта 8 МГц ( желательно кварц и конденсаторы по 22 пФ но можно и внутренний RC генератор использовать ) - укажите это значение частоты в свойствах проекта CVAVR, в тексте программы :

UBRRH=0x00; // USART Baud Rate: 9600
UBRRL=0x33; // 8 MHz

и в файле проекта VMLAB :

.CLOCK 8meg

 

Запустите мастер CVAVR и сделайте такие установки:

Я включил:  1) источник такта - такт МК "System clock"  2) Частота 1 МГц ( там 1000 КГц ) с какой будет считать таймер  3) Прерывание "Interrupt on" по достижению (насчёту) таймером числа в ячейке "Comp. A" - я вписал произвольное число 3FFF.

Теперь посмотрите код мастера - File -> Program Preview  - и комбинацией Alt + C отправьте код в панель заготовок кода "Code Templates" она в CVAVR находится слева.  Закройте код и мастер.

Опустите курсор под текст программы и скопируйте нашу новую заготовку кода в текст программы.  Нам нужно взять из этого куска лишь нужное.

Во-первых скопируйте и поставьте после строки:

#include <lcd.h> // библиотека для LCD

код обработчика прерывания :
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
// Place your code here
}

Во-вторых  весь блок настройки таймера :
// Timer/Counter 1 initialization
//
//

скопируйте и вставьте в программу после строки :
UBRRL=0x33; // 8 MHz

В-третьих  включите прерывание от Таймера 1
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10;


эти 2 строки перенесите под код настройки таймера.
 

Удалите с низу текста программы вставленную заготовку - мы уже взяли
из неё все что было нужно для настройки таймера и прерывания.
 

Теперь настроим PORTC на выход  - добавьте строки :
// PORTC - "0" во все биты регистра.  
PORTC = 0;
// PORTC - все выводы ВЫХоды 

DDRC = 0xFF;

под аналогичными строками настройки  PORTA

Выполните компиляцию "Make the project" - убедитесь что нет ошибок.
Есть только 3 "вонинга" - предупреждения.

 

 

Проверим работу таймера и его прерывания.

Чтобы прерывание от таймера возникало каждые 1500 мкС
нужно записать число 1500 в регистр :

OCR1A = 1500;

конечно нужно закомментировать (отменить, выключить) строки :
// OCR1AH=0x3F;
// OCR1AL=0xFF;


таймер будет считать от нуля по единице каждую микросекунду ( выше мы указали частоту кварца 8 МГц и делитель для таймера 8 ) и при насчёте того числа которое хранится в регистре
OCR1A   должно произойти прерывание, при этом таймер будет считать дальше. Значит в прерывании нужно сразу обнулить таймер чтоб точнее отсчитать следующие 1500 мкС. После строк программы :

// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
// Place your code here

добавим строки :

TCNT1H = 0x00; // обнулить счет таймера
TCNT1L = 0x00;

добавим переключение логического уровня на ножках PORTC :

PORTC ^= 255; // инвертировать регистр PORTC


Выполните компиляцию "Make the project" и запустите симулятор VMLAB - откройте проект  vmlab.prj   и добавьте в файл проекта вывод сигнала ножки PC0 в виртуальный осциллограф SCOPE

.plot V(PC0)

Перекомпилируйте проект - "Ре-билд ол". Затем разверните окно SCOPE и поместите его под окно исходника, предварительно подняв его нижнюю границу.  Поставьте мышкой точку останова левее строчки :   PORTC ^= 255; //    

Запустите симуляцию и после третьего нажатия светофора произойдет прерывание от таймера, я еще раз нажал светофор и снова возникло прерывание таймера и остановка на точке останова - вот картинка :

Вы видите что время с запуска МК прошло 4.1 мС , строчка кода у которой поставлен "брейк поинт" подсвечена голубым - она еще не выполнена !
На PC0 сейчас "1" - значит в следующее мгновение появится "0".

Продолжаем симуляцию... 
Я просимулировал 10 прерываний и получил такую картинку :

Текущее время 19.1 м - если вычесть предыдущее время 4.1 мС то подучится 15 мС на 10 прерываний - т.е. прерывание случается у нас каждые 1.5 мС или 1500 мкС  - как и было задумано.

Как точней измерять время в VMLAB - читайте в задаче 3

 

 

Пора писать код для создания управляющих
импульсов для 8-ми SERVO.

Мы будем управлять сервами последовательно. В прерывании от таймера включаем первую серву и установим время следующего прерывания от таймера (значит и ширину управляющего импульса) в соответствии с командой указанной в массиве  servo_poz[servo_num] , затем выключаем эту серву и включаем следующую. Так делаем для всех 8 servo , а потом отсчитываем остаток времени до общего периода повторения 20 мС. 

Нам понадобятся переменные и константы - их нужно объявить до использования в программе - значит выше обработчика прерывания :

1) переменная индекс на 9 значений или 9 состояний PORTC :

char index_st = 0; // индекс для работы в прерывании 

2) массив констант содержащий эти 9 состояний PORTC :

flash char pc_state[9]={
0b00000001,  // "1" на servo на PC0
0b00000010 // "1" на servo на PC1
0b00000100 // "1" на servo на PC2
0b00001000 // "1" на servo на PC3

0b00010000 // "1" на servo на PC4
0b00100000 // "1" на servo на PC5
0b01000000 // "1" на servo на PC6
0b10000000 // "1" на servo на PC7

0b00000000 };// "0" на всех servo


3) переменная для хранения того сколько еще считать до 20 мС :

unsigned int ctr_last  = 20000;
//
сколько мкС осталось досчитать до 20 мС 

Переместите сюда переменную и массив объявленные в начале этой задачи.

 

Код программы будем писать вместо строки :

PORTC ^= 255; // инвертировать регистр PORTC

в обработчике прерывания от таймера :

// Вывести в PORTC новое состояние
PORTC = pc_state[index_st];

 if (index_st == 8){

  // прерываться после отсчёта остатка времени
 
OCR1A = ctr_last;

  // обновить остаток времени на 20 мС
 
ctr_last = 20000;

  // обнулить индекс
  index_st = 0;
                  }
 else {

// Вычислить длину имп. для сервы и вписать в OCR1A
OCR1A=992+(((
unsigned int)servo_poz[index_st])<<2);

/*
тут servo_poz[index_st] умножается на 4 сдвигом в лево на 2 бита и затем плюсуется к 992. Пример - среднее положение сервы это команда 127, умножим на 4 будет 508, прибавим 992 - получим 1500 мкС - это и есть длина импульса для среднего положения вала servo. 
*/

// Вычесть длину имп. сервы из периода в 20 мС
ctr_last -= OCR1A ;

// увеличить индекс на 1
index_st ++ ;

      };

 

 

Программа готова !  работает ли ?

     Выполните компиляцию "Make the project" - ошибок быть не должно. Запустите симулятор VMLAB - откройте проект  vmlab.prj   и добавьте в файл проекта вывод сигналов всего PORTC в виртуальный осциллограф SCOPE

.plot V(PC0) V(PC1) V(PC2) V(PC3)
.plot V(PC4) V(PC5) V(PC6) V(PC7)

и закомментируйте строку LCD

; Xdisp LCD(16 2 250K)

     Перекомпилируйте проект - "Ре-билд ол". Разверните окно SCOPE  повыше и установите вертикальное разрешение 5 вольт - чтобы видеть все сигналы управления SERVO. 

Запустите симуляцию 4 раза нажав на светофор и после 3-й пачки управляющих импульсов  запустите передачу на МК команд нажав кнопку "TX File" ...

После появления сообщения S_num 4 Poz 83  остановите симуляцию.
Получилось вот так красиво :

Созданный контроллер выполнил команды для трех серво поступившие на вход USART в последовательном формате :

Servo 0 - команда 34   - импульс 1128 мкС
Servo 1 - команда 163 - импульс 1644 мкС
Servo 4 - команда 83   - импульс 1324 мкС 

Расчет для Серво 0 таков :  34 * 4 + 992 = 1128 мкС

На остальные сервы продолжают поступать импульсы шириной 1500 мкС
так как команд на изменения их положения не поступало.

Самостоятельно ! Измерьте ширину импульсов и период
                                        их повторения по описанию в задаче 3


Программа РАБОТАЕТ !

         Задача выполнена.


Вот архив с файлами проекта  z13-3.rar   

 

Все задачи-упражнения курса

 

Как устроен микроконтроллер AVR

 

 



 

          

 

 

 

ключевые слова: программирование микроконтроллеров, как написать программу для микроконтроллера, обучение программированию микроконтроллеров, микроконтроллеры atmega128, как запрограммировать микроконтроллер, как прошить микроконтроллер, отладка программы для AVR, моделирование работы электронных схем, электронные проекты, хобби, язык си для микроконтроллеров, язык программирования си
AT76C712 , AT76C713 , AT90CAN128 , AT90CAN128 Automotive , AT90CAN32 , AT90CAN64 , AT90PWM2 , AT90PWM3 , AT90S1200 , AT90S2313 , AT90S2323 , AT90S2343 , AT90S4433 , AT90S8515 , AT90S8535 , ATmega128 , ATmega1280 , ATmega1281 , ATmega16 , ATmega161 , ATmega162 , ATmega163 , ATmega164 , ATmega165 , ATmega168 , ATmega168 Automotive , ATmega169 , ATmega2560 , ATmega2561 , ATmega32 , ATmega323 , ATmega324 , ATmega325 , ATmega3250 , ATmega329 , ATmega3290 , ATmega406 , ATmega48 , ATmega48 Automotive , ATmega64 , ATmega640 , ATmega644 , ATmega645 , ATmega6450 , ATmega649 , ATmega6490 , ATmega8 , ATmega8515 , ATmega8535 , ATmega88 , ATmega88 Automotive , ATtiny11 , ATtiny12 , ATtiny13 , ATtiny15L , ATtiny2313 , ATtiny25 , ATtiny26 , ATtiny28L , ATtiny45 , ATtiny85
Сайт управляется системой uCoz