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

forfrends
Offline
Зарегистрирован: 24.02.2015

Всем добрый день!  Пытаюсь тодключить к 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);
}

 

forfrends
Offline
Зарегистрирован: 24.02.2015

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

GarryC
Offline
Зарегистрирован: 08.08.2016

В первой ветке при lastPos==false Вы изменяете lastpos=true послк чего у Вас выполняется и вторая ветка с lastPos==true;

Вряд ли Вы хотели такого результата?

forfrends
Offline
Зарегистрирован: 24.02.2015

В общем именно этого я и хотел. В первой ветке идет поворот вправо-влево, а во второй восстановление в 90. Условие  lastPos я использовал для того что бы "не мучить серву": появился сигнал - повернуть серву - перейти к другой ветке и ждать пока сигнал не пропадет. Сигнал пропал - поставить серву в 90 - Перейти к 1-й ветке и ожидать сигнала на поворот.

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

forfrends
Offline
Зарегистрирован: 24.02.2015

Вот рабочий код:

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

Для тех кому сложно, вот код по-проще:

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

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

  while (1)
  {
    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();
    }
    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);
}

 

GarryC
Offline
Зарегистрирован: 08.08.2016

Похоже, у Вас ощибка в строке 37, Вы дважды смотрите состояние пина 4, а должны смотреть пин 4 и пин3

forfrends
Offline
Зарегистрирован: 24.02.2015

Да, там ошибка, вы правы.

Последние два кода рабочие, можно их использовать