Махальные часы MagicWatch. Часть 2

Не прошло и года с момента зарождения и старта по разработке Махальных Часов…

https://zhevak.wordpress.com/2012/12/26/махальные-часы-magicwatch-часть-1/

… и сегодня вечером поздним вечером «тихо и незаметно» (с) проект был завершен.

Не хочу и не буду оправдываться, чему был обязан столь внушительный долгострой, да и кому это интересно. Главное то, что Евгения Александровна в эти несколько дней снова подняла проект и завершила его. Конечно, ей помогали. Помогал Антон, за что ему спасибо. Ну и я, изредка и по особо тяжелым случаям, прилетал на помощь. Ну, так или иначе, проект завершен. Ура!

Ниже несколько скудных фотографий и «непричесанный» исходный текст программы.

Находясь в руке часы выглядят не особо презентабельно.

DSC00461

Но это не важно! Не забывайте, что это всего-лишь прототип, модель. А основное назначение часов состоит в том чтобы человек создал для себя гаджет на микроконтроллере. Да, это так — это первый почти самостоятельный гаджет у Евгении.

Зато часы отлично работают в полутьме!

DSC00441

Чтобы привести их в действие нужно равномерно махать часами из стороны в сторону. Примерно вот так:

DSC00442

Фотиком очень сложно поймать нужный кадр. Чтобы получить один приличный кадр нам пришлось тупо нащелкать с полсотни. Оставили самые презентабельные.

Вот тут десятки часов вообще оказались «за кадром». Другими словами, сначала произошла индикация цифры и только потом открылся затвор фотика.

DSC00448

А тут сказалась неравномерность движения руки. Когда часы высвечивали десятки-единицы часов, рука двигалась медленнее, чем когда они высвечивали минуты. Поэтому цифры получились разной ширины.

DSC00459

Но все равно, как бы не получалось — выглядит достаточно зрелищно. Правда, чтобы получать вообще идеальные результаты, нужно немножко потренироваться. Какие наши годы!

Далее — техническая часть.

Я ниже привожу текст программы. Евгения дала разрешение на публикацию. Текст программы не причесан, в нем могут присутствовать как баги, так и логические бомбы. Я не вникал и не правил. (У меня и без этого хватает своих дел!) В общем, я так думаю, если кто-то что-то хочет сказать или подправить — welcome!

#include <msp430f2101.h>
#include <stdint.h>

#define LED1 (BIT3)
#define LED2 (BIT4)
#define BTN1 (BIT1)
#define BTN2 (BIT2)
#define BUTTON (BIT7)

volatile int mode; //режим работы
volatile int ch;  //количество часов
volatile int m10;  //десятки минут
volatile int m1;  //единицы минут
volatile int s;  //переменная, отвечающая за счет секунд
volatile int i;
volatile int j;
volatile int delay;  //i, j, delay отвечают за индикацию времени

const int A[11][5] = {

{0xBE, 0xC1, 0xC1, 0xC1, 0xBE},
{0x80, 0x84, 0x82, 0xFF, 0x80},
{0xC2, 0xE1, 0xD1, 0xC9, 0xC6},
{0xA2, 0xC1, 0xC9, 0xC9, 0xB6},
{0x8F, 0x88, 0x88, 0x88, 0xFF},
{0xA7, 0xC5, 0xC5, 0xC5, 0xB9},
{0xBE, 0xC9, 0xC9, 0xC9, 0xB0},
{0x81, 0xF1, 0x89, 0x85, 0x83},
{0xB6, 0xC9, 0xC9, 0xC9, 0xB6},
{0x86, 0xC9, 0xC9, 0xC9, 0xBE},
{0x80, 0x80, 0xA4, 0x80, 0x80}

};

const int B[24] = {0x80, 0xC0, 0xA0, 0xE0, 0x90, 0xD0, 0xB0, 0xF0, 0x88, 0xC8, 0xA8, 0xE8, 0x98, 0xD8, 0xB8, 0xF8, 0x84, 0xC4, 0xA4, 0xE4, 0x94, 0xD4, 0xB4, 0xF4};

void port1_isr(void) __attribute((interrupt(PORT1_VECTOR)));
void port2_isr(void) __attribute((interrupt(PORT2_VECTOR)));
void wdt_isr(void) __attribute((interrupt(WDT_VECTOR)));
void timer_isr(void) __attribute((interrupt(TIMERA0_VECTOR)));


void port1_isr(void)
{
  P1IFG = 0x00;  //сброс флага прерывания
  TACTL = TASSEL0 + MC0 + TACLR;  //тактирование таймера от ACLK, прямой счет, очистка счетчика
}

void wdt_isr(void)
{
  s++;
  if (s == 15)
    {
    s = 0;
    m1++;
    if (m1 == 10)
      {
      m1 = 0;
      m10++;
      if (m10 == 6)
        {
        m10 = 0;
        ch++;
        if (ch == 24)
          ch = 0;
        }
      }
    }
}


void timer_isr(void)
{
  TACCTL0 &= ~CCIFG; //сброс флага прерывания
  __bic_SR_register_on_exit(LPM3_bits);  //"пробуждение" процессора
}


void port2_isr(void)
{
  if ((P2IFG & BTN1) == BTN1)  //определение, какая кнопка была нажата
    {
    P2IFG &= ~BTN1;
    if (mode == 4)  //переход в режим настройки
      {
      mode = 1;
      WDTCTL = WDTPW + WDTHOLD + WDTCNTCL;  //отключение сторожевого таймера
      s = i = j = delay = 0;  //обнуление всех переменных, отвечающих за индикацию времени
      TACTL = TASSEL0 + TACLR;  //отключение таймера
      P1IE = 0x00;  //запрещение прерываний от акселерометра
      }
    else
      mode++;

    if (mode == 4)  //выход из режима настройки
      {
      WDTCTL = WDTPW + WDTTMSEL + WDTCNTCL + WDTSSEL;  //запуск сторожевого таймера
      P1OUT = BUTTON;  //выключение всех светодиодов
      P2OUT = BTN1 + BTN2;  //выключение всех светодиодов
      P1IFG = 0x00;  //сброс флага прерывания от акселерометра. Он мог сработать во время настройки
      P1IE = BUTTON;  //разрешение прерываний от акселерометра
      }
    }

  else
    {
    P2IFG &= ~BTN2;

    switch (mode)
      {
      case 1: if (ch == 23)
                ch = 0;
              else
                ch++;
      break;
      case 2: if (m10 == 5)
                m10 = 0;
              else
                m10++;
      break;
      case 3: if (m1 == 9)
                m1 = 0;
              else
                m1++;
      break;
      default: break;
      }

    }

  if (mode != 4)
    __bic_SR_register_on_exit(LPM3_bits);  //"пробуждение" процессора после завершения обработки прерывания

}

int main(void)
{
  WDTCTL = WDTPW + WDTTMSEL + WDTCNTCL + WDTSSEL;  //интервальный режим сторожевого таймера, обнуление счетчика, тактирование от ACLK
  BCSCTL1 = DIVA1; //делитель 4 для ACLK
  IE1 = WDTIE;  //разрешение прерываний от сторожевого таймера

  P1DIR = 0x7F;  //развернули на выход ножки первого порта, к которым подключены светодиоды 
  P1IE = BUTTON;  //разрешаем прерывания от акселерометра
  P1REN = BUTTON;  //включаем подтягивающий резистор на ножке акселерометра
  P1OUT = BUTTON;  //резистор подтягивает ножку к питанию

  P2DIR = LED1 + LED2;  //развернули на выход ножки второго порта, к которым подключены светодиоды
  P2IE = BTN1 + BTN2;  //разрешаем прерывания от кнопок
  P2REN = BTN1 + BTN2;
  P2OUT = BTN1 + BTN2;

  mode = 1;  //mode = 1 это режим настройки часов
  ch = 0;
  m10 = 0;
  m1 = 0; 
  s = i = j = delay = 0;

  TACCTL0 = CCIE;  //разрешаем прерывания от таймера
  TACCR0 = 0x0010;  //таймер генерирует прерывание при достижении в процессе счета числа 0x0010

  while (1)
  {
    switch (mode)
    {
      case 1:
        P1OUT = B[ch];  //высвечиваем на светодиодах значение переменной ch
        P2OUT = BTN1 + BTN2 + LED1 + LED2;  //при настройке часов горят два красных светодиода
        break;

      case 2:
        P1OUT = B[m10];
        P2OUT = BTN1 + BTN2 + LED1;  //при настройке десятков минут горит первый красный светодиод
        break;

      case 3:
        P1OUT = B[m1];
        P2OUT = BTN1 + BTN2 + LED2;  //при настройке единиц минут горит второй красный светодиод
        break;
      
        default:
        {
          if (delay < 20)  //организуем задержку
            delay++;
          else
          {
            int n;

            switch (j)
            {
              case 0:  //выделяем разряд десятков в переменной ch
                if (ch < 10)
                  n = 0;
                else
                {
                  if (ch < 20)
                    n = 1;
                  else
                    n = 2;
                }
                break;

              case 1:  //выделяем разряд единиц в переменной ch
                if (ch < 10)
                  n = ch;
                else
                {
                  if (ch < 20)
                    n = ch - 10;
                  else
                   n = ch - 20;
                }
                break;

              case 2:
                n = 10;
                break;
                
              case 3:
                n = m10;
                break;
              
              default:
                n = m1;
            }

            if (i < 5)
            {
              P1OUT = A[n][i];
              i++;
            }
            else
            {
              P1OUT = BUTTON;   //выключаем светодиоды
              i++;
              if (i == 7)  //переход к индикации следующего символа
              {
                i = 0;
                j++;
                if (j == 5)
                {
                  j = 0;
                  delay = 0;
                  TACTL = TASSEL0 + TACLR;  //выключение таймера
                }
              }
            }
          }
        }
      }

  __bis_SR_register(LPM3_bits + GIE);  //отправление процессора в "спячку", глобальное разрешение прерываний

  }
}

Еще раз напомню, что я исходник привел в виде «as is».

Помните классику — рассказ «Один байт»?

http://darksanime.org/articles/odinbite.php

Так вот, Евгения столкнулась с тем, что она тоже превысила размер флеш-памяти на 10-20 байт и ей пришлось утаптывать код. Что она делала, я не знаю. Но теперь размер кода составляет 1022 байта. Часы работают. А это на данном этапе — самое главное!

Advertisements

2 responses to “Махальные часы MagicWatch. Часть 2

  1. Установить на вентилятор и будут винтажные часы с ветерком )))

  2. Пропеллерные часы — это хорошо, прикольно. Но они ведь жрут энергию как лошадь, и гудят как самолет. С собой в институт не возьмешь… А так — да, забавно.

    Забавных поделок по жизни хватает. Сейчас, вот, загорелись идеей сделать инфинити-мирроу (infinity mirrow). Просто захотелось. А чтобы было прикольнее — оснастить его датчиком присутствия.

    Представляете картинку — гости уходят, одеваются, прихорашиваются… Зеркало как зеркало! А какая-нибудь дамочка решит поправить свой макияж, или штукатурку проверить, или губы подкрасить… Откроет помаду, поднесет фэйс к зеркалу… Срабатывает датчик, включается подсветка… а вместо зеркала образуется портал в другой мир. К соседям… Подсвеченный мириадами огоньков. А-а-а! Опасно! Засосать ведь может!

    Я где-то не то прочитал, не то даже фотку видел — один чувак такое сделал себе на входную дверь. Ну у них там в заграницах это нормально, А у нас, в пятиэтажке, поставить даже деревянную дверь стремно, не то что вообще стеклянную. Ну в общем, приходят гости, звонят… А на лестничной площадке полумрак… В общем, звонят и… к их взору открывается длинный полутемный тоннель… Типа — Добро пожаловать! Прошу, входите по одному!

    Или зеркало на полу — глубокая шахта. Тоже ничего, стремно-так смотрится. Но на полу стекло царапается очень быстро.

    На потолке тоже прикольно — такая мощная дыра-дымоход на крышу.

    Как-то так.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s