2011-07-06

Пробуем таймер на атмеге.

И так, данный пост не является рассказом о какой-либо поделке. Это лишь тест, эксперимент, работы с таймером на atmega.

Для начала собираем простенькую схемку:


После чего загружаем туда следующий скетч:

//vim: syntax=c:tabstop=2:softtabstop=2:shiftwidth=2

#define BUTTON 12 // пин для подключения кнопки

#define REGS 4 // количество регистров экрана
int anods[REGS] = {8,9,10,11}; // пины анодов
int pins[] = {0,1,2,3,4,5,6}; // пины семисегментного индикатора
volatile int d[REGS] = {3,3,3,3}; // сюда пишем число для отображения
volatile int reg = 0; // тут сохраняем номер разряда, с которым будет работать обработчик прерывания
volatile int prev_reg = REGS - 1; // тут номер предыдущего обработанного разряда
bool button_state = false; // текущее состояние кнопки
int dig[] = {
 0b01111111,   // чисто - индекс 0
 0b00111111,   // - - индекс 1
 0b00011100,   // градус - индекс 2
 0b01000000,   // 0 - индекс 3
 0b01111001,   // 1 - индекс 4
 0b00100100,   // 2 - индекс 5
 0b00110000,   // 3 - индекс 6
 0b00011001,   // 4 - индекс 7
 0b00010010,   // 5 - индекс 8
 0b00000010,   // 6 - индекс 9
 0b01111000,   // 7 - индекс 10
 0b00000000,   // 8 - индекс 11
 0b00010000,   // 9 - индекс 12
 0b00001000,   // A - индекс 13
 0b00000011,   // b - индекс 14
 0b01000110,   // C - индекс 15
 0b00100001,   // d - индекс 16
 0b00000110,   // E - индекс 17
 0b00001110,   // F - индекс 18
};

ISR(TIMER2_OVF_vect) // вектор прерывания по переполнению
{
 digitalWrite(anods[prev_reg], LOW); // отрубаем аноды матрицы
 int i = 0; // счетчик битов
 for(int mask=1; i<8; mask<<=1) // цикл маски битов
 {
  digitalWrite(pins[i++], (dig[d[reg]] & mask) ? HIGH: LOW); // берем поочередно биты и включаем нужные
 }
 digitalWrite(anods[reg], HIGH); // как выставили все биты катодов, можно включить и анод текущего разряда
 prev_reg = reg; // сохраняем номер зажженного разряда
 reg++; // увеличиваем разряд, что бы в следующий раз его включать
 if(reg == REGS) // если это последний разряд...
  reg = 0; // ... начинаем с начального разряда
}

void setup()
{
 for(int i=0; i < sizeof(pins); i++) // выставим пины в out и погасим сегменты
 {
  pinMode(pins[i], OUTPUT);
  digitalWrite(pins[i], LOW);
 }

 pinMode(12, INPUT); // пин для кнопки поставим в in

 for(int i=0; i < sizeof(anods); i++) // отключим аноды
 {
  pinMode(anods[i], OUTPUT);
  digitalWrite(anods[i], LOW);
 }

 //настраиваем Timer2: делитель /256, WGM mode 0 - по переполнению
 TCCR2A = 0;
 TCCR2B = 1<<CS22 | 1<<CS21;

 //Timer2 включаем прерывание по переполнению
 TIMSK2 = 1<<TOIE2;

 //обнуляем таймер
 TCNT2 = 0;
}

void loop()
{
  delay(100); // чуток подождем :) дребезг кнопки для простоты не обрабатываем
  if(digitalRead(BUTTON) == HIGH && !button_state) // если нажата кнопка и флаг не выставлен (ранее не была нажата) прибавляем в младший разряд единицу
  {
    button_state = true; // флаг выставляем, что кнопка нажата
    d[0]++; // собственно увеличиваем разряд на единицу
    for(int i=0; i<REGS; i++) // далее проверяем переполнение разрядов
    {
      if(d[i] > 12)
      {
        d[i] = 3;
        d[i+1]++;
      }
    }
  }
  else if(digitalRead(BUTTON) == LOW && button_state) // если кнопку отпустили, но ранее она была нажата (флаг выставлен) то...
    button_state = false; // ...убираем флаг
}

И смотрим что вышло... А вышло вроде все хорошо, только вот фигня получается: нажимаем кнопку и видим, что в первом регистре, вместо "1" горит черт знает что, а точнее один лишний сегмент "E". :( Почему? Я не знаю и понять не могу. День колупался - не пойму где лажа. :( Та же фигня на других цифрах. Не на всех правда. Но от этого не легче.

Может кто сказать, где у меня косяк? :) Просьба ногами не бить, ибо пробую писать под микроконтроллеры первые разы. Простенькие программы писал уже, а таймер вот в первый раз решил запрограммировать. :)

UPD: Нашел где косяк. :( Блин, давно на C/C++ не писал, привык к питону, вот и накосячил. :) В общем ошибка грубая и старая как мир! ;) Надо проверять размерность массива, а именно надо заменить:

for(int mask=1; i<8; mask<<=1) // цикл маски битов

на

for(int mask=1; i<sizeof(pins); mask<<=1) // цикл маски битов

и больше никогда так не делать. ;) Ну в принципе наскоро писал, поленился написать полностью, поставил цифрю... За что и огреб. :)

2011-06-29

Осцилограф

Сегодня сделал себе маленький подарок. :) Теперь настраивать что-то после пайки будет значительно удобнее. ;) Вообще приборчик довольно приятный, маленький и удобный. Не "продвинутый мостр" конечно, но для моих нужд - само то. Разве что экранчик мелковат. Но это мелочи. К стати когда смотрел его в инете - совершенно не понравился. :( В руках эта штука выглядит намного приятнее, чем на картинках. ;)


2011-06-09

Автоматическая кормушка для рыбок.


Преамбула.

Периодически мы с семьей, так же как и многие, куда-то уезжаем. За квартиру я не слишком переживаю, так как в подъезде полно "сторожевых бабушек", а вот две собаки и куча рыбок в 200-от литровом аквариуме, хочешь или не хочешь, но требует кормежки. Собак то хоть можно с собой взять, а вот рыбки... Нет, конечно можно пойти и купить готовую автокормушку, но это же не наши методы! :) Раньше у нас оставалась жить наша подруга на время отъезда, а тут вот так вышло, что ей некогда. Значит надо решать проблему.

Постановка задачи.

И так: отъезд через пару дней, плюс к этому сборы и прочее, а рыб надо кормить... То есть на походы в магазины за запчастями времени нет. Значит надо делать исключительно вечером и исключительно из того, что есть под рукой. :) Как следствие конструкция может получиться не только не оптимальной, но и футуристической. :) Задача: осуществить высып корма один раз в день в аквариум. Составные части, как я уже сказал - все что есть дома.

Механика.

С механикой у меня всегда были проблемы. :) Если спаять схему я еще мог, то вот выточить кучу тяг, шарниров и прочей лабуды - на это у меня всегда не хватало терпения. А тут еще ограниченные ресурсы... В общем обшарив квартиру я нашел:
  • пластиковые бутылки
  • просроченную пластиковую карту
  • кучу скрепок
  • деревянную рейку
  • кучу банок из под кофе с шурупами
  • шаговый двигатель от разобранного когда-то дисковода и фототранзистор от него же (или от CD-ROM-а? уже не помню)
  • моторчик от игрушки
  • плата с микроконтроллером аналогом arduino купленная для "разобраться с атмегой"
  • десяток резисторов, транзисторов, проводов, макетная плата и микросхема L293D
Ну что ж. Не густо, но и не пусто. :) Сначала сделал станину скрутив вместе 3 куска рейки, которые образовали лежащую букву "Т" с поднятой вверх планкой. На ней закрепим бутылку, горлышком внизу, у которой отрежем дно. Туда будем засыпать корм.


Между горлом и нижней планкой оставим зазор. В этом зазоре будет ходить планка из старой пластиковой карты и большой скрепки. У скрепки делаем петлю примерно на одной третьей длинны. Вокруг этой петли она будет поворачиваться. На длинный конец скрепки крепим клеем-расплавом пластину, вырезанную из карточки, а на короткий конец была закреплена резинка (хотелось пружинку, но нужной не нашлось). Из проболоки изгибаем скобку вокруг червячного вала шагового двигателя. К ней крепим второй конец резинки.
Корм из горла будет своим ходом сыпаться на планку, а скрепка и пластинка из карточки будут отгребать его по сторонам и скидывать в аквариум.




Банка на противоположном конце служит исключительно противовесом.

После создания этого "чуда" я засыпал корм и проверил как он его разгребает. Все бы ничего, но корм, которым мы кормим рыб, представляет из себя довольно легки хлопья, которые порой просто застревают в горле бутылки из за своей легкости, не смотря на ширину вышеупомянутого горла. Пришлось добавить на верхушку бутылки моторчик от старой игрушки со "стиркой", насаженной на вал в качестве эксцентрика. Этот "вибратор" вполне себе обеспечивает ссыпание застрявшего корма. :) Правда издает довольно громкий жужжащий звук (вот она твоя сирена, Юрка!) ;)


С механикой вроде все. Теперь...

Электроника.

Тут все проще: всю логику водружаем на ATmega, так как это просто и удобно. :) К тому же очень гибко.
Лирическое отступление. В свое время, когда я изучал микроэлектронику,  о микроконтроллерах можно только мечтать. Всю логику, как правило, делали на мелкой "рассыпухе". Во первых это было довольно затратно по времени. А во вторых, если ты ошибся в разработке самой схемы и ее логике, то в последствии что-то изменить было очень трудно, а порой и вообще не возможно без полной переделки схемы. Тут же все просто прекрасно: если надо что-то поправить - просто правим программу и все! :)
Осталось лишь управление. Тут нам поможет  L293D и несколько транзисторов КТ815. L-ка - это универсальная микросхема для управления двигателями. Схем включения в инете - пруд пруди! Я взял схему с сайта arduino, прямо из документации к библиотеке для управления шаговыми двигателями.
Так как второй микросхемы для вибромотора не было, пришлось вообще взять просто транзистор в качестве ключа. ;) Все это было смонтировано на монтажной плате без пайки. Вот что получилось:
Провода, к стати, были выдраны из куска старой "витой пары". :)

Фотодатчик я установил внутрь аквариума, под самой лампой, что бы вся система срабатывала при включении света. Дело в том, что на лампах у нас уже стоит таймер, который их включает утром и выключает вечером. Вот по включению и будем кормить. :) И не спрашивайте, почему я не сделал кормление просто при включении таймера! ;) Это не наш метод. :)))

Программное обеспечение.

Ну тут даже стыдно что-то размещать! :))) Был взят пример из комплекта arduino "blink", для включения вибры, пример оттуда же, для управления шаговым двигателем и вс е. :) Алгоритм предельно простой:

  1. Читаем цифровой вход с фото датчика.
  2. Если стал HIGH:
  • включаем на 4 секунды вибру
  • отключаем и ждем 2 секунды
  • гоним шаговый двигатель на другой край (я взял колличество шагов с запасом, что бы под конец еще и пробуксовывал немного, ибо нет обратной связи)
После чего цикл повторяем. :) Все! :)

Вот примерно то, что в итоге получилось:
From AVR
Послесловие.
Недельные испытания показали (судя по тому, что рыбы выжили), что система вполне себе жизнеспособна. :) Есть правда побочный эффект: если раньше при жужжании вибро-двигателя рыбы начинали стрематься и разбегаться, то теперь если дома что-то громко жужжит они сломя голову летят к кормушке. :)))

Планирую полностью все переделать: поставить блок реального времени, индикатор, сделать новую механику, а так же перевести управление светом тоже на эту систему. Соответственно оформить это все на самостоятельной плате, а не на ардуине.

2011-06-02

Вступление.

К сожалению в силу своего гнусного характера я не так уж много делаю чего-то "молотком и отверткой". Но иногда все же делаю. ;) Но так, что бы это было быстро и сейчас! :)))

В этот блог я буду выкладывать все о своих "не программных" поделаках, в отличии от блога ~/bin. Поэтому блог так и назвал: "Do it now!", а по русски: "Сделай это сейчас!" :) Вообще было бы правильнее назвать DIY (do it yourself), но "сделай сам" не очень подходит, так как надо "здесь и сейчас"! ;) Поэтому DIN. :)

Но в первую очередь к созданию этого блога меня подтолкнул мой новый большой поэкт автоматического стола для маджонга. Не знаю что выйдет из этой идеи, зреет она давно, но лишь недавно я облазил инет в поисках нужной информации и решился начать что-то делать. В общем время покажет, что из этого всего выйдет. :)