Обсуждаем контроллеры компании Atmel.
Ответить

Светодиодный тетрис для кота

Вс июл 22, 2018 11:43:36

Всем привет!

Я собирал его по материалам одноименной статьи. Собирал ли еще кто его? У одного ли меня всегда присутствует логическая единица на выходе PORTC6?

Изображение

Исходник:

Спойлер
Код:
/* author: Daniel Hassel
 *   www.dhassel.de
 *
 * Last change: 2012-11-10
 */

#ifndef F_CPU
#define F_CPU 16000000
#endif

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



volatile uint32_t matrix[10];
volatile uint8_t disp_counter;

volatile uint32_t spielfeld[10];
volatile uint32_t neuerStein[10];

volatile uint8_t zufall;
volatile uint8_t currentStein;
volatile int8_t posX;
volatile int8_t posY;
/*#################################################################################################
##############      MAIN      ###################################################################
##################################################################################################*/


void initialisiere()
{

   //Grundbeschaltung
   DDRA = 0xff;
   PORTA = 0xff;
   DDRB = 0xff;
   PORTB = 0x00;
   DDRC = 0xff;
   PORTC = 0xff;
   DDRD = 0xf0;
   PORTD = 0xff;

   for (uint8_t i=0; i<10; i++)
   {
      matrix[i]=0;
      spielfeld[i]=0;
      neuerStein[i]=0;
   }
   disp_counter=0;

   zufall=TCNT0;

  //Timer0 fuer Anzeige

  TCCR0 = (1<<CS01);//|(1<<CS00); //Prescaler 8   
  TIMSK |= (1<<TOIE0);

  //Timer1 fuers Spiel
  TCCR1A = 0;
  TCCR1B = (1<<CS12);//|(1<<CS10);
  TIMSK |= (1<<TOIE1);

  sei();
}

uint8_t setNewStein(uint8_t piece)
{
   currentStein=piece;
   for (uint8_t i=0; i<10; i++)
   {
      neuerStein[i]=0;
   }

   switch(piece)
   {
      case 0:
         if (posX<0||posX>8||posY<0||posY>18)
            return 0;
         neuerStein[posX]=0xc0000;
         neuerStein[posX+1]=0xc0000;
         break;
      case 1:
         if (posX<1||posX>7||posY<0||posY>19)
            return 0;
         neuerStein[posX-1]=0x80000;
         neuerStein[posX]=0x80000;
         neuerStein[posX+1]=0x80000;
         neuerStein[posX+2]=0x80000;
         break;
      case 2:
         if (posX<0||posX>9||posY<2||posY>18)
            return 0;
         neuerStein[posX]=0x3c0000;
         break;
      case 3:
         if (posX<1||posX>8||posY<1||posY>19)
            return 0;
         neuerStein[posX-1]=0x80000;
         neuerStein[posX]=0x180000;
         neuerStein[posX+1]=0x80000;
         break;
      case 4:
         if (posX<0||posX>8||posY<1||posY>18)
            return 0;
         neuerStein[posX]=0x1c0000;
         neuerStein[posX+1]=0x80000;
         break;
      case 5:
         if (posX<1||posX>8||posY<0||posY>18)
            return 0;
         neuerStein[posX-1]=0x80000;
         neuerStein[posX]=0xc0000;
         neuerStein[posX+1]=0x80000;
         break;
      case 6:
         if (posX<1||posX>9||posY<1||posY>18)
            return 0;
         neuerStein[posX]=0x1c0000;
         neuerStein[posX-1]=0x80000;
         break;
      case 7:
         if (posX<1||posX>8||posY<0||posY>18)
            return 0;
         neuerStein[posX-1]=0xc0000;
         neuerStein[posX]=0x80000;
         neuerStein[posX+1]=0x80000;
         break;
      case 8:
         if (posX<0||posX>8||posY<1||posY>18)
            return 0;
         neuerStein[posX]=0x1c0000;
         neuerStein[posX+1]=0x40000;
         break;
      case 9:
         if (posX<1||posX>8||posY<1||posY>19)
            return 0;
         neuerStein[posX-1]=0x80000;
         neuerStein[posX]=0x80000;
         neuerStein[posX+1]=0x180000;
         break;
      case 10:
         if (posX<0||posX>8||posY<1||posY>18)
            return 0;
         neuerStein[posX]=0x100000;
         neuerStein[posX+1]=0x1c0000;
         break;
      case 11:
         if (posX<1||posX>8||posY<0||posY>18)
            return 0;
         neuerStein[posX-1]=0x80000;
         neuerStein[posX]=0x80000;
         neuerStein[posX+1]=0xc0000;
         break;
      case 12:
         if (posX<0||posX>8||posY<1||posY>18)
            return 0;
         neuerStein[posX]=0x1c0000;
         neuerStein[posX+1]=0x100000;
         break;
      case 13:
         if (posX<1||posX>8||posY<1||posY>19)
            return 0;
         neuerStein[posX-1]=0x180000;
         neuerStein[posX]=0x80000;
         neuerStein[posX+1]=0x80000;
         break;
      case 14:
         if (posX<0||posX>8||posY<1||posY>18)
            return 0;
         neuerStein[posX]=0x40000;
         neuerStein[posX+1]=0x1c0000;
         break;
      case 15:
         if (posX<1||posX>8||posY<1||posY>19)
            return 0;
         neuerStein[posX-1]=0x80000;
         neuerStein[posX]=0x180000;
         neuerStein[posX+1]=0x100000;
         break;
      case 16:
         if (posX<0||posX>8||posY<1||posY>18)
            return 0;
         neuerStein[posX]=0x180000;
         neuerStein[posX+1]=0xc0000;
         break;
      case 17:
         if (posX<1||posX>8||posY<1||posY>19)
            return 0;
         neuerStein[posX-1]=0x100000;
         neuerStein[posX]=0x180000;
         neuerStein[posX+1]=0x80000;
         break;
      case 18:
         if (posX<0||posX>8||posY<1||posY>18)
            return 0;
         neuerStein[posX]=0xc0000;
         neuerStein[posX+1]=0x180000;
         break;

      default:
         return 0;
   }   

   for (uint8_t i=0; i<10; i++)
   {
      neuerStein[i]=neuerStein[i]>>posY;
   }

   return 1;
}

uint8_t conflict()
{
   uint8_t valid=1;

   for (uint8_t i=1; i<10; i++)
   {   
      if ((neuerStein[i])&spielfeld[i])
         valid=0;
   }
   return !valid;
}


int main (void) {

   initialisiere();   //alle Standardinitalisierungen

   while(1){

   //Taster
   if (!(PIND&0x08)) //links
   {
      uint8_t valid=1;

      if (neuerStein[9]!=0)
         valid=0;
      for (uint8_t i=1; i<10; i++)
      {   
         if ((neuerStein[i-1])&spielfeld[i])
            valid=0;
      }
      if (valid)
      {
         for (uint8_t i=9; i>0; i--)
         {   
            neuerStein[i]=neuerStein[i-1];
         }
         neuerStein[0]=0;
         posX++;
      }
      for (uint8_t i=0; i<10; i++)
      {
         matrix[i]=spielfeld[i]|neuerStein[i];
      }
      zufall=TCNT0;
      _delay_ms(85);
   }

   if (!(PIND&0x02)) //rechts
   {
      uint8_t valid=1;

      if (neuerStein[0]!=0)
         valid=0;
      for (uint8_t i=0; i<9; i++)
      {   
         if ((neuerStein[i+1])&spielfeld[i])
            valid=0;
      }
      if (valid)
      {
         for (uint8_t i=0; i<9; i++)
         {   
            neuerStein[i]=neuerStein[i+1];
         }
         neuerStein[9]=0;
         posX--;
      }
      for (uint8_t i=0; i<10; i++)
      {
         matrix[i]=spielfeld[i]|neuerStein[i];
      }
      zufall=TCNT0;
      _delay_ms(85);
   }


   if (!(PIND&0x01)) //runter
   {
      TCNT1=0xff00;
      zufall=TCNT0;
      _delay_ms(40);
   }

   if (!(PIND&0x04)) //drehen
   {
      switch (currentStein)
      {
         case 1:
            if (!setNewStein(2) || conflict())
               setNewStein(1);
         break;
         case 2:
            if (!setNewStein(1) || conflict())
               setNewStein(2);
         break;
         case 3:
            if (!setNewStein(4) || conflict())
               setNewStein(3);
         break;
         case 4:
            if (!setNewStein(5) || conflict())
               setNewStein(4);
         break;
         case 5:
            if (!setNewStein(6) || conflict())
               setNewStein(5);
         break;
         case 6:
            if (!setNewStein(3) || conflict())
               setNewStein(6);
         break;
         case 7:
            if (!setNewStein(8) || conflict())
               setNewStein(7);
         break;
         case 8:
            if (!setNewStein(9) || conflict())
               setNewStein(8);
         break;
         case 9:
            if (!setNewStein(10) || conflict())
               setNewStein(9);
         break;
         case 10:
            if (!setNewStein(7) || conflict())
               setNewStein(10);
         break;
         case 11:
            if (!setNewStein(12) || conflict())
               setNewStein(11);
         break;
         case 12:
            if (!setNewStein(13) || conflict())
               setNewStein(12);
         break;
         case 13:
            if (!setNewStein(14) || conflict())
               setNewStein(13);
         break;
         case 14:
            if (!setNewStein(11) || conflict())
               setNewStein(14);
         break;
         case 15:
            if (!setNewStein(16) || conflict())
               setNewStein(15);
         break;
         case 16:
            if (!setNewStein(15) || conflict())
               setNewStein(16);
         break;
         case 17:
            if (!setNewStein(18) || conflict())
               setNewStein(17);
         break;
         case 18:
            if (!setNewStein(17) || conflict())
               setNewStein(18);
         break;
      }
      for (uint8_t i=0; i<10; i++)
      {
         matrix[i]=spielfeld[i]|neuerStein[i];
      }
      zufall=TCNT0;
      _delay_ms(200);
   }
   //spiel vorbei
   if (!(TIMSK & (1<<TOIE1)))
   {
      uint32_t x=1;
      for (uint8_t i=0; i<20; i++)
      {
         for (uint8_t j=0; j<10; j++)
         {
            matrix[j]|=x;
         }
         x=x<<1;
         _delay_ms(100);
      }
   }
   }//while   
}

//==================
      //INTERRUPTVEKTOR Timer1
ISR(TIMER1_OVF_vect)
{
   //muss ein neuer stein her?
   uint8_t neu=1;
   //kann der stein noch weiter runter??
   uint8_t down=1;

   for (uint8_t i=0; i<10; i++)
   {   
      if (neuerStein[i]!=0)
         neu=0;
      if ((neuerStein[i]>>1)&spielfeld[i])
         down=0;
      if ((neuerStein[i]&0x00001))
         down=0;
   }
   if (neu)
   {
      //erst nach zu loeschenden zeilen suchen...
      for (uint8_t i=0; i<20; i++)
      {
         uint32_t x=0x1<<i;
         if ((spielfeld[0]&x) && (spielfeld[1]&x) && (spielfeld[2]&x) &&
            (spielfeld[3]&x) && (spielfeld[4]&x) && (spielfeld[5]&x) &&
            (spielfeld[6]&x) && (spielfeld[7]&x) && (spielfeld[8]&x) &&
            (spielfeld[9]&x))
         {
            for (uint8_t j=0; j<10; j++)
            {
               uint32_t z=0xfffff;
               spielfeld[j]=((spielfeld[j]&(z<<(i+1)))>>1) | (spielfeld[j]&(z>>(20-i)));
            }
            i--; //da feld runtergeschoben
         }
      }
      //neuen stein generieren
      switch(zufall&0x0f)
      {
         case 0:
            posX=4;posY=0;
            setNewStein(0);
            break;
         case 1:
            posX=4;posY=0;
            setNewStein(1);
            break;
         case 2:
            posX=4;posY=2;
            setNewStein(2);
            break;
         case 3:
            posX=4;posY=1;
            setNewStein(3);
            break;
         case 4:
            posX=4;posY=1;
            setNewStein(4);
            break;
         case 5:
            posX=4;posY=0;
            setNewStein(5);
            break;
         case 6:
            posX=4;posY=1;
            setNewStein(6);
            break;
         case 7:
            posX=4;posY=0;
            setNewStein(7);
            break;
         case 8:
            posX=4;posY=1;
            setNewStein(8);
            break;
         case 9:
            posX=4;posY=1;
            setNewStein(9);
            break;
         case 10:
            posX=4;posY=0;
            setNewStein(10);
            break;
         case 11:
            posX=4;posY=1;
            setNewStein(11);
            break;
         case 12:
            posX=4;posY=1;
            setNewStein(12);
            break;
         case 13:
            posX=4;posY=1;
            setNewStein(13);
            break;
         case 14:
            posX=4;posY=1;
            setNewStein(14);
            break;
         case 15:
            posX=4;posY=1;
            setNewStein(15);
            break;
         case 16:
            posX=4;posY=1;
            setNewStein(16);
            break;
         default:
            posX=4;posY=0;
            setNewStein(0);
            break;
      }
      for (uint8_t i=0; i<10; i++)
      {
         matrix[i]=spielfeld[i]|neuerStein[i];
      }
         //verloren - timer anhalten
      if (conflict())
         TIMSK &= ~(1<<TOIE1);
   }
   else
   {
      if (down)
      {
         posY++;
         //stein stufe runter und anzeigen
         for (uint8_t i=0; i<10; i++)
         {
            neuerStein[i]=neuerStein[i]>>1;
            matrix[i]=spielfeld[i]|neuerStein[i];
         }
      }
      else
      {
         //stein aufs spielfeld schreiben
         for (uint8_t i=0; i<10; i++)
         {
            matrix[i]=spielfeld[i]=spielfeld[i]|neuerStein[i];
            neuerStein[i]=0;
         }
      }
   }
}

//==================
      //INTERRUPTVEKTOR Timer0
ISR(TIMER0_OVF_vect)
{
   PORTA  = 0xff;
   PORTC  = 0xff;
   PORTD |= 0xf0;
   PORTB &= 0x01;
   uint32_t col=matrix[disp_counter];   
   uint8_t porta_cpy=0;
   uint8_t x=col>>12;
   //alle bytes invertiert und fuer porta "verdreht"
   if (x & 0x01)
      porta_cpy|=0x80;
   if (x & 0x02)
      porta_cpy|=0x40;
   if (x & 0x04)
      porta_cpy|=0x20;
   if (x & 0x08)
      porta_cpy|=0x10;
   if (x & 0x10)
      porta_cpy|=0x08;
   if (x & 0x20)
      porta_cpy|=0x04;
   if (x & 0x40)
      porta_cpy|=0x02;
   if (x & 0x80)
      porta_cpy|=0x01;
   
   PORTA=~(porta_cpy);
   PORTC=~(col>>4);
   PORTD=(~(col<<4))|0x0f;

   switch(disp_counter)
   {
   case 0: PORTB|=0x0a;   
         break;
   case 1: PORTB|=0x12;
         break;
   case 2: PORTB|=0x22;
         break;
   case 3: PORTB|=0x42;
         break;
   case 4: PORTB|=0x82;
         break;
   case 5: PORTB|=0x84;
         break;
   case 6: PORTB|=0x44;
         break;
   case 7: PORTB|=0x24;
         break;
   case 8: PORTB|=0x14;
         break;
   case 9: PORTB|=0x0c;
         break;
   }
   disp_counter++;
   if (disp_counter==10)
      disp_counter=0;
}
//==================

Re: Светодиодный тетрис для кота

Вт июл 24, 2018 07:19:30

Кроме вас и автора-немца - никто не собирал. Даже якобы автор вами приведенной статьи и-то не доделал.

Re: Светодиодный тетрис для кота

Чт июл 26, 2018 21:41:44

Кроме вас и автора-немца - никто не собирал. Даже якобы автор вами приведенной статьи и-то не доделал.


Скорее он переделал. Дело в том, что данный девайс вполне себе отображает тетрис, разве что в нем фигуры не переворачиваются по нажатию кнопки. Из нареканий имею ровно два:
1. Не гаснет строка (видно на фото)
2. При движении фигур вниз и при отображении застывших внизу фигур не светится 7-ой столбец (на фото это тоже заметно).

Заполненные строки стираются. Фигуры в процессе полета вниз без проблем двигаются вправо-влево и ускоренно вниз по соответствующим нажатиям.

Видео записать могу, как вернусь из отпуска.

Re: Светодиодный тетрис для кота

Чт июл 26, 2018 23:02:27

Когда не светятся/не гаснут строки/столбцы в матричной схеме, то логично поискать сначала неисправность в разводке/распайке этой схемы. Вытащите микросхему, прозвоните транзисторы. Если не помогает, попробуйте прошить и поставить другой корпус МК, вдруг порты погорели. Хотя седьмой столбец сидит на интерфейсе внутрисхемного программирования, так что если программатор сигнатуру МК правильно читает, то скорее всего дело не в порте, а в обвязке матрицы.

Re: Светодиодный тетрис для кота

Пт июл 27, 2018 08:07:12

Когда не светятся/не гаснут строки/столбцы в матричной схеме, то логично поискать сначала неисправность в разводке/распайке этой схемы. Вытащите микросхему, прозвоните транзисторы.


Делал. Увы, транзисторы в норме, схема в Альтиуме адекватна схеме автора.

Если не помогает, попробуйте прошить и поставить другой корпус МК, вдруг порты погорели.


Три МК сменил - результат один и тот же.

Хотя седьмой столбец сидит на интерфейсе внутрисхемного программирования, так что если программатор сигнатуру МК правильно читает, то скорее всего дело не в порте, а в обвязке матрицы.


Я склоняюсь к мысли о том, что автор тетриса заложил в версию для повторения ошибку в коде, согласно которой в процессе игры одна из строк светится всегда, а один из столбцов не светится. Аргумент такому предположению: если довести игру до состояния, когда новые падающие сверху элементы тетриса уже негде разместить на экране, т.е. GAME OVER, то засвечиваются все светодиоды матрицы. Если нажать на кнопку сброса, то гаснут на короткий интервал времени все светодиоды.
Последний раз редактировалось kotarnold Пт июл 27, 2018 08:15:56, всего редактировалось 1 раз.

Re: Светодиодный тетрис для кота

Пт июл 27, 2018 08:11:17

попробуй поменять ноги (или отцепить от своей ноги и прицепить к соседней в довесок) - если ошибка программная - строки тоже съедут.
а осциллографа нет?
или свою тестовую прошивку сваять, чтобы пробегала по строчкам/столбцам?

Re: Светодиодный тетрис для кота

Пт июл 27, 2018 08:35:12

попробуй поменять ноги (или отцепить от своей ноги и прицепить к соседней в довесок) - если ошибка программная - строки тоже съедут.


Спасибо, попробую)

Re: Светодиодный тетрис для кота

Пт июл 27, 2018 09:43:29

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

Да ладно... скорее всего накодил как смог и забил, надоело :)) Я так синтезатор частоты делал ради интереса - через год такие баги исправил, что сам в шоке, а если бы никто не повторял так и не исправил бы :)

Re: Светодиодный тетрис для кота

Пт июл 27, 2018 10:48:01

...Три МК сменил - результат один и тот же.

У меня сотрудник 5-й контроллер менял, пока не остановили... У меня глаза чуть из орбит не повылазили! Но он всё объяснил. По своей логике.)))

Re: Светодиодный тетрис для кота

Пт июл 27, 2018 14:02:21

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

Re: Светодиодный тетрис для кота

Пт июл 27, 2018 23:02:39

Приеду домой через неделю - покопаюсь.

Re: Светодиодный тетрис для кота

Пт авг 03, 2018 17:47:29

Вернулся из отпуска. Пока отдыхал - еще пара строк отвалилась. Пока так:

Re: Светодиодный тетрис для кота

Пт авг 03, 2018 18:52:32

Стопудово монтаж кривой. Ошибки в программе со временем не меняются :)

Re: Светодиодный тетрис для кота

Пт авг 03, 2018 19:24:29

меняются, если их так запрограммировать :) (но это не тот случай)

Re: Светодиодный тетрис для кота

Пт авг 03, 2018 19:29:57

...Три МК сменил - результат один и тот же.

У меня сотрудник 5-й контроллер менял, пока не остановили...Но он всё объяснил. По своей логике.)))

У меня "попалось"- тестер для сервомашинок- с одним МК (Мега8) - работает нормально, а сдругим (такая же Мега8) - НЕ работает.. Точнее- работает, но сервомашинка его "не видит"- тактовая частота НИЖЕ- не 8 МГц, а 1 (типа "по умолчанию"), хотя фьюзы стоят на 8..

Re: Светодиодный тетрис для кота

Пт авг 03, 2018 19:46:21

ARV писал(а):Ошибки в программе со временем не меняются :)
Флеш с плавающими затворами. Со временем заряд исчезает и появляются ошибки. :)

Re: Светодиодный тетрис для кота

Пт авг 03, 2018 19:52:15

Проверили бы исходник благо он не сложный. Или в протеусе смоделировали бы

Re: Светодиодный тетрис для кота

Пт авг 03, 2018 20:11:08

ARV писал(а):Ошибки в программе со временем не меняются :)
Флеш с плавающими затворами. Со временем заряд исчезает и появляются ошибки. :)
это у вас юмор такой острый?

Re: Светодиодный тетрис для кота

Пт авг 03, 2018 20:28:32

Из даташита на ATmega8.
– Write/Erase Cycles: 10,000 Flash/100,000 EEPROM
– Data retention: 20 years at 85°C/100 years at 25°C

Прошивка обычно хранится годами, но в случае дефектной флеш памяти (или 1500 раз перезаписанной) может сильно увеличится утечка на некоторых плавающих затворах, что со временем приведет к искажению данных. Т. е. прошивка МК может со временем измениться.

Re: Светодиодный тетрис для кота

Пт авг 03, 2018 20:48:59

А если учесть что МК с алиэкспресса могут быть отбраковкой основного производства, то запросто может сыпаться флеш)
Хотя конечно судя по приведённым данным скорей всего косяки в монтаже.
Ответить