Обсуждаем контроллеры компании Atmel.
Ответить

Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 10:02:49

Всем добрый день! Пытаюсь подключить к Attiny13 и сервопривод, но что-то какие-то глюки... Суть работы проста: Установить серву в 90, если на 4 пине логическая "1" то установить серву в 60, если на 3 пине "1" то установить серву в 120. Если на пинах 3 и 4 "0", то установить серву в начальное положение - 90. К пинам 3 и 4 подпаяны резисторы по 20кОм к земле что бы избежать ложных срабатываний. Питается все это от аккумулятора 18650. Заранее оговорюсь: серва нормально работает от 3.3 вольта, проверял на Ардуино ДУЕ! Почему-то серва не хочет нормально позиционироваться. Поворачивается не туда, или вообще не поворачивается... или ровно в 90 не хочет становиться, а стает +- 5-10...
Пишу все это через Ардуино
вот код:
Спойлер
Код:
#include <avr/io.h>
#include <util/delay.h>
byte s=0;
byte pos=90;
boolean lastPos = false;

void setup() { 
  //pinMode(s, OUTPUT);
  DDRB |= (1<<0);
  DDRB &= ~(1<<3);
  DDRB &= ~(1<<4);
  pulseOut(s,pos);
}

void loop() {
  if (lastPos == false) {
    if (PINB & (1<<PINB3)){
      _delay_ms(5);
      if (PINB & (1<<PINB3))
      {
        pulseOut(s, pos - 30);
        lastPos = true;
        _delay_ms(200);
      }
    }
    if (PINB & (1<<PINB4)){
      _delay_ms(5);
      if (PINB & (1<<PINB4))
      {
        pulseOut(s,pos + 30);
        lastPos = true;
        _delay_ms(200);
      }
    }
  }
  if (lastPos == true) {
    if (!(PINB & (1<<PINB4)) && !(PINB & (1<<PINB4))){
      for (byte i=0;i<10;i++){
      pulseOut(s,pos);
      _delay_ms(2);
      }
      lastPos = false;
      _delay_ms(200);
    }
  }
  _delay_ms(20);
}

void pulseOut( byte pin, byte p){
  PORTB |= (1<<0);
  delayMicroseconds(300+p*(2500/180));
  PORTB &= ~(1<<0);
}


Заготовку кода брал здесь: https://arduinodiy.wordpress.com/2015/05/20/servo-on-attiny13/

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 10:30:09

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

Для управления сервой лучше использовать аппаратный ШИМ.

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 10:57:33

Знаю что ШИМ было бы лучше, но для меня это темный лес....
По питанию все нормально, точнее, пробовал питать отдельно от 5 вольт - результат тот же. 100% проблема в коде.

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 11:09:10

forfrends писал(а):но для меня это темный лес....
Это издалека так кажется, на самом деле там только три тополя.

Для поиска ошибки упростите свой код. Выкиньте все лишнее. Оставте только код для какого-то фиксированного положения сервы. Если работает, попробуйте в другом фиксированном положении. Если и это работает, то тогда уже добавляйте обработчик состояния пинов. И мне кажется, будет лучше всего использовать оператор switch, вместо страшной кучи "ифов".

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 11:19:55

Функцию под названием "loop" необходимо переименовать. Компилятор может давать ошибку в случае совпадения имен функций и операторов языка С.

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 13:10:45

Первый раз слышу про оператор loop в языке Си. Не подскажете где про него можно почитать?

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 15:41:20

Это в Ардуино. Там свой язык.
Функцию переименовал - эффекта нет.

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 16:40:47

В Ардуино не свой язык а обычный avr-g++ с библиотеками.

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 19:29:29

Вот код. ШИМ аппаратный. Выход ШИМ PB1. Входа PB3 и PB4 подтянутые к пит. внутр. резистором. Внутренний генератор 9,6МГц. У тиньки 13 счетчик только 8ми битный, что не дает точно выставить ШИМ. Расчетные углы 50, 89, 127 градусов. Частота ШИМ близка к 50Гц.
Спойлер
Код:

#define TopTimer 200
#define angle60 188
#define angle90 186
#define angle120 184

#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)

{   
   CLKPR=0x80;
   CLKPR=1<<CLKPS2;// на 16   
   
   //настройка порта
   DDRB=(1<<PB1);
   PORTB=(1<<PB3)|(1<<PB4);
   
   //настройка ШИМ
   
   
   TCCR0A=(1<<WGM01)|(1<<WGM00)|(1<<COM0B0)|(1<<COM0B1);
   TCCR0B=(1<<WGM02)|(1<<CS01)|(1<<CS00);//предделитель счетчика на 64
   OCR0A=TopTimer; //счетчик будет считать до
   OCR0B=angle90; //устравноить серву в 90
   
   
    while(1)
    {
     uint8_t buf=(PINB>>3)&0x03;   //проверяем сигналы на пинах
      switch (buf){
        case 0:OCR0B=angle90;break;
        case 1:OCR0B=angle60;break;
        case 2:OCR0B=angle120;break;
        default:break;
     }
    }
}
Последний раз редактировалось Z_h_e Вс авг 14, 2016 19:30:38, всего редактировалось 1 раз.

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 19:30:26

После долгих экспериментов выяснил что проблему вызывает именно "функция" отключающая повторное обращение к серво. Попробую описать словами. В коде я использовал lastPos = для того чтобы команда для сервы отправлялась только 1 раз (для экономии батареи и др.). Но эта функция вызывала сбой: серва почему-то не успевала позиционироваться в нужное место. Вот что у меня получилось:
Спойлер
Код:
#include <avr/io.h>
#include <util/delay.h>
const byte servo  =    0;         // Servo pin on ATtiny
int tPulse        = 4000;         // Total pulse length on 1 Mhz clock
int hPulse        =   60;         // High pulse time (60=0deg -> 280=180deg)
boolean lastPosL = false;
boolean lastPosR = false;
boolean lastPosU = false;

void setup() {               
  DDRB |= (1<<0);
  hPulse = 110;
  DDRB &= ~(1<<3);
  hPulse = 170;
  _delay_ms(100);
  pulseOut();
  pulseOut();
  pulseOut();

}

void loop() {
  if (PINB & (1<<PINB3) && lastPosL == false){      //Поворачиваем влево
    lastPosL = true;
    lastPosR = false;
    lastPosU = false;
    hPulse = 133;
    pulseOut();
    pulseOut();
    pulseOut();
  }
  else if (PINB & (1<<PINB4) && lastPosR == false){  //Поворачиваем вправо
    lastPosL = false;
    lastPosR = true;
    lastPosU = false;
    hPulse = 240;
    pulseOut();
    pulseOut();
    pulseOut();
  }
  else if (!(PINB & (1<<PINB3)) && !(PINB & (1<<PINB4)) && lastPosU == false)   //Исходное положение
  {
    lastPosL = false;
    lastPosR = false;
    lastPosU = true;
    hPulse = 170;
    pulseOut();
    pulseOut();
    pulseOut();
    pulseOut();
  }
  delayMicroseconds(500); // Give servo some time to move before giving it a new position
}

void pulseOut(){
  PORTB |= (1<<0);
  delayMicroseconds(hPulse);                // High pulse angle data   
  PORTB &= ~(1<<0);
  delayMicroseconds(tPulse-hPulse);
}

Немного поясню код:
Функция pulseOut() отвечает за управление сервой. Ее вызов и является самой большой проблемой. Если в функциях поворотов влево-вправо-возврат сделать вызов pulseOut() только 1 раз то pulseOut() может сработать не корректно, особенно это касается функции возврата в исходное положение, там нормально не срабатывает вовсе. Я пробовал делать паузу сразу после вызова функции - эффект тот же. pulseOut() работает только если ее вызывать несколько раз подряд. Причем если в самой функции pulseOut() сделать цикл for.. то pulseOut() опять таки работает не корректно. Но же касается и вызова функции из функций поворотов - если ставлю вызов функции pulseOut() в цикл то получаю те же проблемы... Потому я просто написал вызов pulseOut() несколько раз. Работает без проблем. Если знаете из-за чего такая непонятка с работой кода, подскажите пожалуйста, буду очень благодарен.


Z_h_e Спасибо! Буду пробовать! Для меня ШИМ и таймеры пока темный лес...
Z_h_e, похожий код я находил для Attiny2313, но я не смог его переделать для Attiny13 так как не нашел в даташите как настроить предделитель счетчика, и что это за параметр: CLKPR тоже не понял...
Попробовал ваш код - тишина, серва молчит. При подключении "+" к портам 3 и 4 ничего не происходит.
Последний раз редактировалось forfrends Вс авг 14, 2016 19:40:50, всего редактировалось 1 раз.

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 19:37:28

Вот тогда Вам скомпиленный код из выше указанного исходника.
Вложения
Serv.hex
(324 байт) Скачиваний: 653

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 19:50:39

Хм... та же история. Проверил фьюзы - настроен на 9.6мГц. Пробовал менять на 1.2 - результат тот же. Но код что я писал выше меня, пока, устраивает. Хотя ваш почти в 5 раз меньше места занимает! Круто!

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 19:59:08

Я пробовал в протеусе, работает.
Вы обратили внимание что выход ШИМ идет с порта PB1?

1.2 МГц, это видимо Вы ставили генератор на 9,6 и делитель на 8. Значение делителя это и есть регистр CLKPR. Так что в моем коде не важно установили Вы делитель на 8 или нет. А вот генератор должен быть 9,6.

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Вс авг 14, 2016 20:23:19

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

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Пн авг 15, 2016 12:13:49

COKPOWEHEU писал(а):Первый раз слышу про оператор loop в языке Си. Не подскажете где про него можно почитать?

Упс!
Прошу прощения. Попутал с VBA. У Си только FOR и WHILE.
Но в любом случае не стоит называть свои функции также как и стандартные операторы языков. Хорошо если "ругнется" компилятор, а вот линковщик может и не ругнуться, а найти ошибку будет значительно сложней.

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Пт мар 09, 2018 07:45:58

Доброго времени суток!
Помогите разобраться с проблемой.
тини13 + сенсорная кнопка + серво + транзисторный ключ
Тини в повердаун режиме, если коснуться сенсорной кнопки на 6 ногу (PB1) приходит сигнал 0, что бы тинька вышла из сна.
Дальше на это все дело повешано прерывание INT0, в функции которая его обрабатывает пытаюсь ключить транзисторный ключ (нога 3 PB4), потом после этого со значения 150 сервой повернуться до 200 и назад 150, выключить ключ, и заснуть
Если с просыпанием и засыпанием все ок, то с сервой полный треш - серва живет своей жиснь. Никак не могу разобраться как шим и прерывание собрать вместе.

Скорее всего я не до конца понимаю как настраивать и работать с шим для сервы.
Серва Tower ProSG90

Код:
#include <avr/io.h>         // инициализация портов ввода-вывода МК
#include <avr/sleep.h>      // здесь описаны режимы сна
#include <avr/interrupt.h>   // работа с прерываниями
#include <avr/delay.h>      // описание программных задержек
#define F_CPU 1200000UL

#define SERVO PB0


// Обработчик прерываний
ISR(INT0_vect)  // Прерывание по низкому уровню на PB1
{           

   
   while ((PINB & (1 << PB1)) == 0) {}
PORTB |= (1<<PB4);   // Выставить на PB4 - "1"
_delay_ms(50);
   do // Нарастание яркости
    {
      OCR0A = OCR0A + 20;
      _delay_ms(5);
    }
    while(OCR0A!=200);
//    _delay_ms(1000); // Пауза 1 сек.
    do // Затухание
    {
      OCR0A = OCR0A - 20;
      _delay_ms(5);
    }
    while(OCR0A!=100);
//    _delay_ms(1000); // Пауза 1 сек.
   _delay_ms(50);
   PORTB &= ~(1<<PB4); // Выставить на PB4 - "0"
}       


// Основная программа
int main()
{
//
//   PORTB &= ~ (1<<PB4);   // Выставить на PB4 - "0"
//   DDRB |= (1<<PB4);    // Указатель пина
////
   PORTB = 0b11101111;  // Выставить на PB4 - "0"
   DDRB = 0b00010000;  // Указатель пина

   DDRB |= (1 << SERVO);// выходы = 1
   PORTB &= ~(1 << SERVO); // по умолчанию отключены = 0
   
  // Таймер для ШИМ:
  TCCR0A = 0xB1; // режим ШИМ, неинверсный сигнал на выходе OC0A, инверсный - на выходе OC0B
  TCCR0B = 0x02; // предделитель тактовой частоты CLK/8
  TCNT0=100; // начальное значение счётчика
  OCR0A=100; // регистр совпадения A

   // Инициализация прерываний по INT0   
   GIMSK = 0b01000000; // Разрешение прерываний INT0 на входе PB1
   MCUCR = 0b00000000; // при перепаде низком уровне на PB1
   sei(); // Общее разрешение прерываний
     
   // Инициализация режима сна
   set_sleep_mode (SLEEP_MODE_PWR_DOWN);
   while(1)
   {
      sleep_enable();   // разрешение режима сна
      sleep_cpu();   // активация режима сна
   }
}

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Пт мар 09, 2018 10:01:42

Так ШИМ то у вас на PB0 висит, кнопка на PB1,
при чем тут транзисторный ключ и PB4?

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Пт мар 09, 2018 12:00:06

Транзисторый ключ включает питание для сервы что бы та не жрала батарею так как это все висит на 3х АА батарейках

Добавлено after 2 minutes 28 seconds:
Серва ведёт себя очень странно то отрабатывает то не до конца то вообще крутит в другую сторону

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Пт мар 09, 2018 12:34:19

Попробуйте так:
Спойлер
Код:
// Обработчик прерываний
ISR(INT0_vect)  // Прерывание по низкому уровню на PB1
{             
   while ((PINB & (1 << PB1)) == 0) {}
PORTB |= (1<<PB4);   // Выставить на PB4 - "1"
_delay_ms(50);
   do // Нарастание яркости
    {
     OCR0A++;
      _delay_ms(100);
    }
    while(OCR0A!=30);
    do // Затухание
    {
     OCR0A--;
      _delay_ms(100);
    }
    while(OCR0A!=1);
   _delay_ms(50);
   PORTB &= ~(1<<PB4); // Выставить на PB4 - "0"
}       


// Основная программа
int main()
{
   PORTB = 0b11101111;  // Выставить на PB4 - "0"
   DDRB = 0b00010000;  // Указатель пина

   DDRB |= (1 << SERVO);// выходы = 1
   PORTB &= ~(1 << SERVO); // по умолчанию отключены = 0
   
  // Таймер для ШИМ:
  //TCCR0A = 0xB1; // режим ШИМ, неинверсный сигнал на выходе OC0A, инверсный - на выходе OC0B
  //TCCR0B = 0x02; // предделитель тактовой частоты CLK/8
TCCR0A   =   0x81;
TCCR0B   =   0x03;

  TCNT0=0; // начальное значение счётчика
  OCR0A=0; // регистр совпадения A

   // Инициализация прерываний по INT0   
   GIMSK = 0b01000000; // Разрешение прерываний INT0 на входе PB1
   MCUCR = 0b00000000; // при перепаде низком уровне на PB1
   sei(); // Общее разрешение прерываний
     
   // Инициализация режима сна
   set_sleep_mode (SLEEP_MODE_PWR_DOWN);
   while(1)
   {
      sleep_enable();   // разрешение режима сна
      sleep_cpu();   // активация режима сна
   }
}

Re: Attiny13 и серво. Помогите найти ошибку в коде.

Пт мар 09, 2018 12:40:38

Вы поменяли значения
TCCR0A = 0x81;
TCCR0B = 0x03;
На какую частоту они сейчас настроены?
Ответить