• Добро пожаловать на компьютерный форум Tehnari.ru. Здесь разбираемся с проблемами ПК и ноутбуков: Windows, драйверы, «железо», сборка и апгрейд, софт и безопасность. Форум работает много лет, сейчас он переехал на новый движок, но старые темы и аккаунты мы постарались сохранить максимально аккуратно.

    Форум не связан с магазинами и сервисами – мы ничего не продаём и не даём «рекламу под видом совета». Отвечают обычные участники и модераторы, которые следят за порядком и качеством подсказок.

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

    Не знаете, с чего начать? Создайте тему с описанием проблемы – подскажем и при необходимости перенесём её в подходящий раздел.
    Задать вопрос Новые сообщения Как правильно спросить
    Если пришли по старой ссылке со старого Tehnari.ru – вы на нужном месте, просто продолжайте обсуждение.

Нужна подсказка по программе к ШИМ для 2 серво. Язык С, ATtiny13A

  • Автор темы Автор темы Suharev
  • Дата начала Дата начала

Suharev

Новые
Регистрация
23 Фев 2013
Сообщения
1,353
Реакции
44
Баллы
0
Нужна подсказка по программе к ШИМ для 2 серво. Язык С, ATtiny13A

Перейдем от болтовни к реальном примерам. Есть ATtiny13A, есть две сервы HXT900, есть пример использования ШИМ в тиньке. Исходя из этого написал следующее:

Код:
#define F_CPU 9600000UL        // Частота МК 9,6 MHz
#include <avr/io.h>            // Библиотека ввода-вывода "io.h"
#include <util/delay.h>       // Библиотека задержек "delay.h" 


int t1, t2, t; //Тайминг первого и второго выхода, задержка


   int main(void) // начало основой программы
   {
    /*Настраиваем ШИМ на микроконтроллере. Страницы 69-73 в даташите на 
ATtiny13.
    COM0A1-Fast PWM Mode - Сброс ОС0А в момент совпадения, установка ОС0А при 
    достижении счетчиком значения ТОР
    COM0B1-Fast PWM Mode - Сброс ОС0B в момент совпадения, установка ОС0B при 
    достижении счетчиком значения ТОР
    WGM01 - Включаем Fast PWM Mode 3
    WGM00 - Включаем Fast PWM Mode 3
    CS02  - Устанавливаем делитель 256*/
    
   TCCR0A|=(1 << COM0A1)|(1 << COM0B1)|(1 << WGM01)|(1 << WGM00); 
   //Можно вместо этого еще так TCCR0A=A3;
   TCCR0B|=(1 << CS02); //Можно вместо этого еще так TCCR0B=04;
      
   DDRB = 0x03; // выводы PB1,PB0 порта B сконфигурировать как выходы,
// остальные как входы
       
        while (1) {              // Бесконечный цикл

        OCR0A=t1; //Обрабатываем первый выход
           OCR0B=t1; //Обрабатываем второй выход

        //Обработка входов
   
        if ((PINB & (1 << PB2)) == 1)          //Фиксирует 1 на входе 1
        {
            _delay_ms(30);                    //Устранение "дребезга клавиш"
            if ((PINB & (1 << PB2)) == 1)      //Проверяем
            {
                t1 += t;                     //Увеличиваем задержку входа 1
            }
        }  

        if ((PINB & (1 << PB3)) == 1)          //Фиксирует 1 на входе 2
        {
            _delay_ms(30);                    //Устранение "дребезга клавиш"
            if ((PINB & (1 << PB3)) == 1)      //Проверяем
            {
                t1 -= t;                     //Уменьшаем задержку входа 1
            }
        }  

        if ((PINB & (1 << PB4)) == 1)          //Фиксирует 1 на входе 3
        {
            _delay_ms(30);                    //Устранение "дребезга клавиш"
            if ((PINB & (1 << PB4)) == 1)      //Проверяем
            {
                t2 += t;                    //Увеличиваем задержку входа 2
            }
        }  

        if ((PINB & (1 << PB5)) == 1)          //Фиксирует 1 на входе 4
        {
            _delay_ms(30);                    //Устранение "дребезга клавиш"
            if ((PINB & (1 << PB5)) == 1)      //Проверяем
            {
                t2 -= t;                    //Уменьшаем задержку входа 2
            }
        }  

        } // закрывающая скобка бесконечного цикла

   } // закрывающая скобка основной программы
Осталось разобраться как правильно рассчитать задержки, желательно подробно, "для самых маленьких", то биш для меня.
Кстати, я еще не дописал защиту для крайнего левого и правого положения, но это уже мелочи.

PS: Тинек много, можно экспериментировать до посинения.
 
Последнее редактирование:
Да, забыл еще притянуть порты к земле перед циклом.
Почти итоговый вариант:
Код:
#define F_CPU 9600000UL        // Частота МК 9,6 MHz
#include <avr/io.h>            // Библиотека ввода-вывода "io.h"
#include <util/delay.h>       // Библиотека задержек "delay.h" 


int t1, t2, t, tmax, tmin; //Тайминг первого и второго выхода, задержка
                                 //максимальное и минимальное значение


   int main(void) // начало основой программы
   {
    /*Настраиваем ШИМ на микроконтроллере. Страницы 69-73 в даташите на ATtiny13
    COM0A1-Fast PWM Mode - Сброс ОС0А в момент совпадения, установка ОС0А при 
    достижении счетчиком значения ТОР
    COM0B1-Fast PWM Mode - Сброс ОС0B в момент совпадения, установка ОС0B при 
    достижении счетчиком значения ТОР
    WGM01 - Включаем Fast PWM Mode 3
    WGM00 - Включаем Fast PWM Mode 3
    CS02  - Устанавливаем делитель 256*/
    
   TCCR0A|=(1 << COM0A1)|(1 << COM0B1)|(1 << WGM01)|(1 << WGM00); 
   //Можно вместо этого еще так TCCR0A=A3;
   TCCR0B|=(1 << CS02); //Можно вместо этого еще так TCCR0B=04;
      
   DDRB = 0x03; // выводы PB1,PB0 порта B сконфигурировать как выходы, остальные как входы
    
   PORTB &= ~_BV(PB2); //Притянули порт 2 к земле
   PORTB &= ~_BV(PB3); //Притянули порт 3 к земле
   PORTB &= ~_BV(PB4); //Притянули порт 4 к земле
   PORTB &= ~_BV(PB5); //Притянули порт 5 к земле
       
        while (1) {              // Бесконечный цикл

        OCR0A=t1; //Обрабатываем первый выход
        OCR0B=t1; //Обрабатываем второй выход

        //Обработка входов
   
        if ((PINB & (1 << PB2)) == 1)          //Фиксирует 1 на входе 1
        {
            _delay_ms(30);                    //Устранение "дребезга клавиш"
            if ((PINB & (1 << PB2)) == 1)      //Проверяем
            {
                if (t1 < tmax){                //Проверяем на корректность
                t1 += t;}                     //Увеличиваем задержку входа 1
            }
        }  

        if ((PINB & (1 << PB3)) == 1)          //Фиксирует 1 на входе 2
        {
            _delay_ms(30);                    //Устранение "дребезга клавиш"
            if ((PINB & (1 << PB3)) == 1)      //Проверяем
            {
                if (t1 > tmin){
                t1 -= t;}                     //Уменьшаем задержку входа 1
            }
        }  

        if ((PINB & (1 << PB4)) == 1)          //Фиксирует 1 на входе 3
        {
            _delay_ms(30);                    //Устранение "дребезга клавиш"
            if ((PINB & (1 << PB4)) == 1)      //Проверяем
            {
                if (t2 < tmax){
                t2 += t;}                    //Увеличиваем задержку входа 2
            }
        }  

        if ((PINB & (1 << PB5)) == 1)          //Фиксирует 1 на входе 4
        {
            _delay_ms(30);                    //Устранение "дребезга клавиш"
            if ((PINB & (1 << PB5)) == 1)      //Проверяем
            {
                if (t2 > tmin){
                t2 -= t;}                    //Уменьшаем задержку входа 2
            }
        }  

        } // закрывающая скобка бесконечного цикла

   } // закрывающая скобка основной программы
По сути осталось просчитать tmax, tmin, и усредненное состояние.
 
Последнее редактирование:
Еще надо t инициализировать.
 
Опыты дали на выходе хрень и один сожженный серво.
Попытки разобраться в расчетах опять завели меня в тупик, так как нихрена не ясно что откуда берется.
Ответом так никто и не удосужился. Одно из двух, либо никто сам ничего не знает и не понимает и пользуется чужими наработками, либо птицы слишком высокого полета.

Будьте так любезны приземлиться и объяснить как нужно рассчитывать программный ШИМ, что откуда брать и как это калькулировать, например тот же Fast PWM, либо прикройте тему.
 
Вопрос задан не корректно, непонятно что вам объяснять, с чего начинать, как глубоки ваши познания в данном вопросе. Именно по этому и на радиокоте вам никто и не ответил.

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

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

"Рассчитать задержку" - непонятно о чем вы?
 
как глубоки ваши познания в данном вопросе
Если бы были я бы не спрашивал, а значит ноль.
И неужели вместо сервака нельзя было подключить лампочку и шимить ее.
Нет, серв не жалко, а мне нужно видеть наглядно угол отклонения, методом подбора цифр смог добиться +-1,2 градуса в нулевом положении.

Хорошо, напишу что я смог вычитать из даташитов и, как я думаю, понять:
- мне нужен режим Fast PWM.
- разрядность 256.
- в этом режиме в начале цикла ставит на указанный выход "0" пока не отсчитает заранее заданное количество тактов из 255 и устанавливает на выход "1" до конца отсчета.
- мне нужно будет инвертировать этот выход.

Мне нужна частота сигнала 50Гц. Задержка (или ширина импульса) от 0,8мс до 2,2мс (центр 1,5мс) Т.е. от 4% до 11% от ширины сигнала.

Вопрос: как исходя из тактовой частоты процессора и всех этих данных просчитать и сформировать сигнал на определенном выходе используя средства ATtiny13A (внешний кварц не поставить) и язык C (AVR Studio 4)?

В принципе нужный сигнал можно сформировать 555 таймером, что я и делал, и управлять резистором, но это уже садомазо когда это можно решить проще.
 
Последнее редактирование:
Если использовать железный ШИМ, то само ближе к вашей частоте вы получите 73.242Гц (тактовая 4,8МГц, делитель 256) или 36Гц (тактовая 9,6МГц, делитель 1024).
Ну, а программным можно получить и ровно 50Гц.
Дальше считаете 0,8мс: 1/73=0,0137С - период ШИМ, 0,0137/0,0008=256/Х => X=15 - число записанное в компаратор .
Аналогично для 2,2мс: 1/73=0,0137С - период ШИМ, 0,0137/0,0022=256/Х => X=41 - число записанное в компаратор.
А если нужно получить в процентах то уж пересчитайте временные интервалы под 73Гц.
Обоснуйте выбор тактовой.
И обновлять компараторы лучше в прерывании.
 
Не нашел описание вашего сервы, но наше подобный. Понял откуда тактовая. Вобщем сформировать такую частоту можно только программным ШИМом (или ставит внешний генератор/кварц). Можно запустить таймер допустим с прерываниями каждые 0,1мС, а уже в обработчике, сравнивая счетчик прерываний (доп. переменная) и переменную длинны импульса, выводить в порт лог 1 или 0.
 
0,8мс: 1/73=0,0137С - период ШИМ, 0,0137/0,0008=256/Х => X=15 - число записанное в компаратор .
Т.е. все расчеты нужно вести в секундах.

Если использовать железный ШИМ, то само ближе к вашей частоте вы получите 73.242Гц (тактовая 4,8МГц, делитель 256) или 36Гц (тактовая 9,6МГц, делитель 1024).
А эти цифры откуда взяты?

уже в обработчике, сравнивая счетчик прерываний (доп. переменная) и переменную длинны импульса,
Но тогда получается нужно будет поправку на выполняемые такты основной программы, иначе импульс просто "поведет".
 
Можно и поправку, но с учетом задержки на выполнение доп команд в каждом прерывании, импульс не поведет.
Цифра 73... получается так (указано в скобках) 4800000/256=18750 - кол-во приращений таймером в секунду, где 4800000 - тактовая частота 4,8МГц, 256 делитель, теперь 18750/256=73...Гц, где 256 - колво приращений при которых произойдет переполнение счетчика таймера, а 73Гц - частота ШИМа.
Но 73Гц - великовато для сервака - перегреется и сгорит (данный эфект уже получен ) ).
 
Наткнулся еще на одну статью.
Понятно как расчеты делаются, не понятно только как она работает.
Листинг программы:
Код:
#include <avr/io.h>
#include <util/delay.h>

//Что делает эта функция? 
void Wait()
{
    uint8_t i;
    for(i=0;i<50;i++)
    {
        _delay_loop_2(0);
        _delay_loop_2(0);
        _delay_loop_2(0);
    }

}
void main()
{
    //Ну это мне уже понятно, настроки таймеров, в даташите имеется таблица.
    TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);             //NON Inverted PWM
    TCCR1B|=(1<<WGM13)|(1<<WGM12)|(1<<CS11)|(1<<CS10);    //PRESCALER=64 MODE 14(FAST PWM)

    //Вот это, как я понял, задает интервал всего импульса? Т.е. тот самый такт в 20мс при частоте 50Гц.
    ICR1=4999;    //fPWM=50Hz (Period = 20ms Standard).

    DDRD|=(1<<PD4)|(1<<PD5);    //Тоже ясно, выходы.

    while(1)
    {
        //Ну передача значения в OCR1A тоже ясна, с помощью этого задается ширина импульса.
        OCR1A=97;    //0 degree
        Wait();         //Зачем вызываем эту функцию? Что она делает?

        OCR1A=316;    //90 degree
        Wait();

        OCR1A=425;    //135 degree
        Wait();

        OCR1A=535;    //180 degree
        Wait();
    }
}
 
Задержка перед новым значением угла. Если ее убрать то сервак не успеет развернуть ось.
 
Т.е. в данной программе атмега16 используется только для поворота сервы и ничего кроме?
_delay_loop_2(0) - пока не сталкивался с таким оператором, понятно что задержка, но на сколько, учитывая что ему передается ноль, несколько тактов?
 
Да похоже это не библиотечная функция, кто-то сам ее написал. Все функция Wait() должна занимать 1-2С.
Да, чуть не забыл. Обратите внимание в данной программе частота шим задается верхним переделом переполнения таймера (регистр ICR1).
 
Будем пробовать.
 
Назад
Сверху