Программирование ATtiny13

Обсуждаем контроллеры компании Atmel.
Ответить
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

[uquote="BOB51",url="/forum/viewtopic.php?p=3735191#p3735191"]Ежли охота Си освоить - то тинька 13я не самое лучшее из имеющегося.[/uquote]
Как разница на таких простых примерах?

[uquote="BOB51",url="/forum/viewtopic.php?p=3735191#p3735191"]Другое дело - на чистом ассемблере в АВР студии 4.19 - там и симулятор работает
и места будет в достатке, и понятнее на уровне "железа".[/uquote]
Да ну. Не нулевые года на дворе в конце-концов. Симулятор работает и в протеусе прекрасно на C.

Добавлено after 6 minutes 42 seconds:
[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=3735194#p3735194"]между циклами ожидающими отпускания кнопки вставь циклы, ожидающие нажатия...[/uquote]
Всё верно, только чуть поправлю - ожидающие отпускания )

olegue, соб-но вам Ivanoff-iv правильно подсказал - между while ((PINB & (1 << PB1))){}; и while ((PINB & (1 << PB1))){ PORTB^=(1<<PB0); ... у вас нет ничего. Вы нажимаете кнопку раз, переходите ко 2му while, который сразу же не срабатывает, потому что кнопка еще нажата. Ведь кнопка - не сферическая в вакууме, она не моментально отжимается, а нажата сколько-то там времени, которое много больше, чем 3-4 инструкции МК выполнить.
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

NStorm писал(а):Ведь кнопка - не сферическая в вакууме, она не моментально отжимается, а нажата сколько-то там времени, которое много больше, чем 3-4 инструкции МК выполнить.
вот потихоньку уже начинаю это понимать.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 3087
Зарегистрирован: Пт мар 09, 2007 15:01:52
Откуда: Биробиджан

Сообщение radteh »

Правильней проверять кнопку не постоянно, зависая на ней в бесконечном цикле, а в ходе выполнения основной программы. Для простого мигания это не критично, но лучше как можно реже использовать _ms_delay(), это тормозит основную программу.

olegue, проверяй нажатия не в цикле while, а в проверке if. Я вижу примерно следующий алгоритм:

Код: Выделить всё

переменная A = 0
бесконечный цикл {

  если нажата кнопка{
    подождать
    если кнопка всё ещё нажата {присвоить переменной A значение противоположное тому что в ней было}
  }

  если переменная A разрешает мигание {
    включить порт
    подождать
    выключить порт
  }
  иначе {
    выключить порт
  }
}
Но опять же повторюсь что не стоит применять в основном цикле задержки если они действительно не нужны
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

да, кстати, я тоже нахожу довольно трудным управление сразу несколькими вложенными циклами.
Хотя, возможно, это более правильный способ. Но удержать его в голове просто немыслимо пока.
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 3087
Зарегистрирован: Пт мар 09, 2007 15:01:52
Откуда: Биробиджан

Сообщение radteh »

А зачем удерживать в голове если можно нарисовать алгоритм на бумаге?
Реклама
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

olegue, функции и макросы могут помочь визуально сделать код более легко читаемым.
Еще советую - почитайте про конечные автоматы. Очень часто на них реализуются в МК задачи.
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

Вот что у меня получилось с миганеим светодиода
Одно нажатие - включить мигание
Второе нажатие - выключить мигание
Привожу с коментами. Посмотртие. Учел нажатие и отпускание, как и советовали

Код: Выделить всё

#include <avr/io.h>
#include <util/delay.h>
int main(void)
{

DDRB =(1<<PB0);  // это будет выход, т.е на PB0 будет светодиод)
PORTB=(1<<PB1); //(по аналогии с атмегой PB1=1 (подключен подтягивающий резистор), 

while(1)
{
   
      while ((PINB&(1 << PB1))){} //  (Жднем нажатия)
   _delay_ms(20); // Нажали Задержка 20мс. Дребезг
      
       while (!(PINB&(1 << PB1))){ } //  (Жднем отпускания)
   _delay_ms(20); // Отпустили Задержка 20мс Дребезг
      
       while ((PINB&(1 << PB1))){ //  (Жднем нажатия) И входим в цикл Моргания (Моргаем)
           PORTB ^= (1 << PB0);_delay_ms(200);PORTB ^= (1 << PB0);
       }
       _delay_ms(20); // Нажали Задержка 20мс, Дребезг Выходим из цикла моргания. 
       
        while (!(PINB&(1 << PB1))){ } //  (Жднем отпускания)
   _delay_ms(20); // Отпустили и вернулись в начало Задержка 20мс Дребезг
}
}
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

1) моргать не будет... точнее будет, но это глазу не будет видно...
нужно внутри цикла только одно переключение порта оставить.
2) при выходе из моргания светодиод стоит тушить принудительно т.к. если выйти при включенном светодиоде, то он так и останется гореть...
3) в целом для изучения неплохо, но для работы этот код подойдет только если мк кроме мигания ничего не делает - АЛУ всё время занят и ему некогда обрабатывать другие инструкции... если их ему подсовывать через прерывания, то будет немного сбиваться частота мигания светодиодом... (проблема тут в программных задержках делай_мс)
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

Ivanoff-iv писал(а):1) моргать не будет... точнее будет, но это глазу не будет видно...
Как не видно будет . Там задержка 200 мс...??
PORTB ^= (1 << PB0);_delay_ms(200);PORTB ^= (1 << PB0);

Ivanoff-iv писал(а):при выходе из моргания светодиод стоит тушить принудительно т.к. если выйти при включенном светодиоде, то он так и останется гореть...
да, я его гасил, а потом убрал этот код, тут согласен.
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

вот смотри: первая инструкция его (допустим) зажгет, потом ждем, потом гасим, тутже начинается новый виток цикла и светодиод зажигается снова... светодиод будет выключен около десяти тактов или (при тактовой 8 МГц) 1,25 мкс...
(а включен 200мс - т.е. в 160000 раз дольше чем выключен...)
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=3735941#p3735941"]вот смотри: первая инструкция его (допустим) зажгет, потом ждем, потом гасим, тутже начинается новый виток цикла и светодиод зажигается снова... светодиод будет выключен около десяти тактов или (при тактовой 8 МГц) 1,25 мкс...
(а включен 200мс - т.е. в 160000 раз дольше чем выключен...)[/uquote]

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

Кстати, смотрел Таймеры. Ну там конечно, на первых порах можно мозг сломать.
Друг Кота
Аватара пользователя
Сообщения: 15599
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Мигание заметно только до 15Гц.
0,06 секунды на период и больше.
И то... не всяким глазом... А ШПРОТ это все равно покажет.
Лучше раз в пол секунды состояние менять для наглядности.
500 и более миллисекунд.
8)
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

Помогайте опять, хотел было тут уже в прерывания влезьть да не тут то было: асадзи назад.

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


int main(void)
{

DDRB =(1<<PB0);
PORTB=(1<<PB0);

DDRB =(1<<PB1);
PORTB=(1<<PB1);


while (1)
{
PORTB^=(1<<PB0); _delay_ms(500);
PORTB^=(1<<PB1); _delay_ms(500);
// PORTB^=(1<<LED2); _delay_ms(500);


}
}
должно моргать 2 ламоптчик попеременно, но моргает только последняя обьявленная-инициализированная строками DDRB и PORTB
Что опять не так? Если PB1 убираю то тогда мограет pb0, если еще доБавляю pb2, то она моргает - первые 2 нет!
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

порт настроил неправильно
у тебя последующая настройка затирает результат предыдущей
надо так:
ддр=((1<<порт0)|(1<<порт1));
или так
ддр=1<<порт0;
ддр|=1<<порт1;

Добавлено after 2 minutes 32 seconds:
П.С.: ддр здесь взят для примера...
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

Спасибо. Теперь работает
int main(void)
{

DDRB =((1<<PB0)| (1<<PB1) | (1<<PB2));
PORTB=((1<<PB0) | (1<<PB1) | (1<<PB2));



while (1)
{
PORTB^=(1<<PB0); _delay_ms(500);
PORTB^=(1<<PB1); _delay_ms(500);
PORTB^=(1<<PB2); _delay_ms(500);
// PORTB^=(1<<LED2); _delay_ms(500);


}
}
Добавлено after 50 seconds:
можно дальше идти

Добавлено after 52 minutes 49 seconds:
я разобрал вот этот код. Здесь работа с кнопками через програмные прерывания
У меня он почему то не работает. Вероятно где -то ошибка ,но найти ее я немогу
С моей точки здения вроде все правильно написано.

Код: Выделить всё

*/ 

//#define F_CPU 1200000UL
#define LED PB2
#define BUTTON1 PB3 // PCINT3
#define BUTTON2 PB4 // PCINT4

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

// Обработчик прерывания PCINT0
ISR(PCINT0_vect)
{
   _delay_ms (50); // антидребезг (использовать задержки в прерываниях некошерно, но пока и так сойдёт)
  if ( (PINB & (1<<BUTTON1)) == 0 || (PINB & (1<<BUTTON2)) == 0 ) // если нажата одна из кнопок
  {
    PORTB ^= (1<<LED); //переключаем состояние светодиода (вкл./выкл.)
    while ( (PINB & (1<<BUTTON1)) == 0 || (PINB & (1<<BUTTON2)) == 0 ) {} // ждём отпускания кнопки
  }
}

int main(void)
{

  // Пины кнопок
  DDRB &= ~((1<<BUTTON1)|(1<<BUTTON2)); // входы
  PORTB |= (1<<BUTTON1)|(1<<BUTTON2); // подтянуты
  // Пин светодиода
  DDRB |= (1<<LED); // выход
  PORTB &= ~(1<<LED); // выключен
  // Настройка прерываний
  GIMSK |= (1<<PCIE); // Разрешаем внешние прерывания PCINT0.
  PCMSK |= (1<<BUTTON1)|(1<<BUTTON2); // Разрешаем по маске прерывания на ногак кнопок (PCINT3, PCINT4)
  sei(); // Разрешаем прерывания глобально: SREG |= (1<<SREG_I)
    while (1) 
    {
    }
}
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

PORTB^=(1<<PB0); _delay_ms(500); - никогда так не пишите. В одну строчку. Сами потом запутаетесь. Поставили ; - перешли на новую строку. И отступы и форматирование научитесь делать правильно. Это только кажется, что мелочи, но с ними код намного читаемей. https://codebeautify.org/c-formatter-beautifier в помощь

Вот это - "while ( (PINB & (1<<BUTTON1)) == 0 || (PINB & (1<<BUTTON2)) == 0 ) {} // ждём отпускания кнопки" в прерывании не нужно уже. У вас входит в обработчик прерывания при смене состояния порта только. Поэтому ждать отпускания кнопки уже не нужно. И даже очень плохо, в прерывании так нельзя делать. Это хуже чем _delay_ms даже там.

А код так-то рабочий. Что-то не то делаете.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

NStorm писал(а):А код так-то рабочий. Что-то не то делаете.
Полагаю отсутствует

Код: Выделить всё

GIFR |= (1<<PCIF);
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Dimon456, зачем и где? Исходя из описание ручками его мало когда надо выставлять:
When a logic change on any PCINT5:0 pin triggers an interrupt request, PCIF becomes set (one). If the I-bit in SREG and the PCIE bit in GIMSK are set (one), the MCU will jump to the corresponding Interrupt Vector. The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a logical one to it.

В протеусе код, указанный выше, на тини13 работает.
Собутыльник Кота
Аватара пользователя
Сообщения: 2977
Зарегистрирован: Сб май 21, 2016 11:04:52
Откуда: Беларусь

Сообщение olegue »

NStorm писал(а):В протеусе код, указанный выше, на тини13 работает.
т.е Вы у себя попробовали этот код? И все в порядке. Работает?

я тоже даже на 2-ом компьютере уже попробовал и нифига. Что за чертовщина
Я даже попробовал упрощать его до минимума. Все равно ничего. Не могу добиться хоть какой-то работы на прерываниях
Пробовал даже и на INTO настраивать - не получается запустить.
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Да, работает: https://yadi.sk/i/grOfcR6a8E6u5g / https://youtu.be/RkHESK57hRg
Смотрите видео, в чем у вас отличие ищите.
Ответить

Вернуться в «AVR»