Страница 1 из 2
Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 10:02:49
forfrends
Всем добрый день! Пытаюсь подключить к 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/0 ... -attiny13/
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 10:30:09
Z_h_e
Серва может потреблять большой ток при повороте, может питание просаживается? Попробуйте начертить схему в протеусе и поглядеть виртуальный осциллографом что за сигнал у Вас идет.
Для управления сервой лучше использовать аппаратный ШИМ.
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 10:57:33
forfrends
Знаю что ШИМ было бы лучше, но для меня это темный лес....
По питанию все нормально, точнее, пробовал питать отдельно от 5 вольт - результат тот же. 100% проблема в коде.
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 11:09:10
Z_h_e
forfrends писал(а):но для меня это темный лес....
Это издалека так кажется, на самом деле там только три тополя.
Для поиска ошибки упростите свой код. Выкиньте все лишнее. Оставте только код для какого-то фиксированного положения сервы. Если работает, попробуйте в другом фиксированном положении. Если и это работает, то тогда уже добавляйте обработчик состояния пинов. И мне кажется, будет лучше всего использовать оператор switch, вместо страшной кучи "ифов".
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 11:19:55
Николай_С
Функцию под названием "loop" необходимо переименовать. Компилятор может давать ошибку в случае совпадения имен функций и операторов языка С.
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 13:10:45
COKPOWEHEU
Первый раз слышу про оператор loop в языке Си. Не подскажете где про него можно почитать?
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 15:41:20
forfrends
Это в Ардуино. Там свой язык.
Функцию переименовал - эффекта нет.
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 16:40:47
COKPOWEHEU
В Ардуино не свой язык а обычный avr-g++ с библиотеками.
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 19:29:29
Z_h_e
Вот код. ШИМ аппаратный. Выход ШИМ 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;
}
}
}
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 19:30:26
forfrends
После долгих экспериментов выяснил что проблему вызывает именно "функция" отключающая повторное обращение к серво. Попробую описать словами. В коде я использовал
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 ничего не происходит.
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 19:37:28
Z_h_e
Вот тогда Вам скомпиленный код из выше указанного исходника.
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 19:50:39
forfrends
Хм... та же история. Проверил фьюзы - настроен на 9.6мГц. Пробовал менять на 1.2 - результат тот же. Но код что я писал выше меня, пока, устраивает. Хотя ваш почти в 5 раз меньше места занимает! Круто!
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 19:59:08
Z_h_e
Я пробовал в протеусе, работает.
Вы обратили внимание что выход ШИМ идет с порта PB1?
1.2 МГц, это видимо Вы ставили генератор на 9,6 и делитель на 8. Значение делителя это и есть регистр CLKPR. Так что в моем коде не важно установили Вы делитель на 8 или нет. А вот генератор должен быть 9,6.
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Вс авг 14, 2016 20:23:19
forfrends
Z_h_e, точно, моя ошибка - у меня серва подвешена была к другому пину. Все работает!
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Пн авг 15, 2016 12:13:49
Николай_С
COKPOWEHEU писал(а):Первый раз слышу про оператор loop в языке Си. Не подскажете где про него можно почитать?
Упс!
Прошу прощения. Попутал с VBA. У Си только FOR и WHILE.
Но в любом случае не стоит называть свои функции также как и стандартные операторы языков. Хорошо если "ругнется" компилятор, а вот линковщик может и не ругнуться, а найти ошибку будет значительно сложней.
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Пт мар 09, 2018 07:45:58
tytar
Доброго времени суток!
Помогите разобраться с проблемой.
тини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
Dimon456
Так ШИМ то у вас на PB0 висит, кнопка на PB1,
при чем тут транзисторный ключ и PB4?
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Пт мар 09, 2018 12:00:06
tytar
Транзисторый ключ включает питание для сервы что бы та не жрала батарею так как это все висит на 3х АА батарейках
Добавлено after 2 minutes 28 seconds:
Серва ведёт себя очень странно то отрабатывает то не до конца то вообще крутит в другую сторону
Re: Attiny13 и серво. Помогите найти ошибку в коде.
Добавлено: Пт мар 09, 2018 12:34:19
Dimon456
Попробуйте так:
Спойлер
Код: Выделить всё
// Обработчик прерываний
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
tytar
Вы поменяли значения
TCCR0A = 0x81;
TCCR0B = 0x03;
На какую частоту они сейчас настроены?