lunes, 14 de octubre de 2013

Anarchist [7x5 led matrix shooter]

The anarchist must be kept safe from the waves of pigs who want to capture him, by throwing molotov cocktails.
LED 7x5 Matrix controlled by a PIC16F876A + joystick and button, powered by USB or 4 AA cased in a little plastic box.

-*-* Photos













*-*- Code

// -*- ANARCHIST:
//     the A-guy is surrounded by the pigs. help him be free.
//


/*
-*- MAIN
 10 inicio
 20 leer movimiento
    21 filtrar (dentro de paredes)
 30 mover chico
    31 dibujar
 40 leer disparo
    41 ejecutar rutina de disparo
    42 destruir cerdos afectados
 60 victoria?
 70 verificar avance de cerdos
 80 derrota?
 90 return


-*-* SCENE
* y0 - - o o o
*    - - o o o
*    - - o o -
*    + - - o o
*    - - o o o
*    - - - - o
* y6 - - - - o
*   x0      x4  <-scene[0..4]

 \***************************************/


volatile unsigned char scene[5];         // a char for each column
volatile signed char a_p;                // anarchist position
volatile signed char cuenta_ciclos;      // for increasing speed as game goes on;
signed char ctrl, movimiento_x,  movimiento_y, ref_x, ref_y, aux_row, aux_col, i, j, a, b, sh, jp;
unsigned int k;                          // counter
signed char disparo, salto, movimiento, collision, victoria, captura;    // FLGS
unsigned char buffer, period_dif, period_ref;         // period <- can control velocity with this
unsigned int score;
/* *************************************** */
/* *************************************** */

void set_ports()
  // initialize control registers and ports
  {
  ADCON1 = 0x00;   // portA is full analog
  TRISA  = 0xFF;   // portA is input
  TRISB = 0x00;    // portB is ROWS
  PORTB = 0x00;    // initialize portB
  TRISC = 0x00;    // portC is COLUMNS ONE  (verde)
  PORTC = 0xFF;    // initialize portC
  }

void read_controls()
  // read analog_val and compares with prev_analog_val
  // sets ctrl01 and ctrl02 according to difference
  {
  a = Adc_Read(0)>>6; // it needs just 4 msb
  if ((a - ref_x) == 0){movimiento_x = 0;}
  else { movimiento_x = (a - ref_x)>0 ? 1: -1; }
  b = Adc_Read(1)>>6; // it needs just 4 msb
  if ((b - ref_y) == 0){movimiento_y = 0;}
  else { movimiento_y = (b - ref_y)>0 ? 1: -1; }

  sh = Adc_Read(2)>>4;
  disparo = (sh > 0) ? 1 : 0;
  jp = Adc_Read(3)>>4;
  salto = (jp > 0) ? 1 : 0;
  }


void show_scene()                        // HOW TO SHOW
  {
  for (i=0; i<=4; i++)       // each column as an array of x
    {
    aux_col = scene[i];     //   put the row vector in column i
    PORTB = aux_col;        //   set the ports
    if (i==0)               //     initialize
      {aux_row = 1;}
    else                    //     shift previous val
      {aux_row = aux_row << 1;}
    PORTC = ~aux_row;
    Delay_ms(1);
    }
  }


void mover_chico_x()
  // actualiza posición del anarquista en funcion del movimiento
  // 1 : inc y, scene[0] <<
  // -1: dec y, scene[0] >>
  // 0 : keep
  {
  if (movimiento_x == 1)
    {
    if (a_p < 6)
      {
      a_p++;
      scene[0] = scene[0]<<1;
      }
    }
  if (movimiento_x == -1)
    {
    if (a_p > 0)
      {
      a_p--;
      scene[0] = scene[0]>>1;
      }
    }
  if (movimiento_x == 0)
    {
    a_p = a_p;
    }
  }


void disparo_routine()
  {
  collision = 0;                                 // initialize
  victoria = 0;
  buffer = 1;
  for (j=0; j<5; j++)                       // sweep the scene
    {
    if (j==0) { show_scene(); }             // if a-guy col just show scene
    // A. shot_propagation_routine
    else
      {
      if ((scene[j] & scene[0]) == scene[0])// B. collision_routine
        {
        scene[j] = scene[j] ^ scene[0];     // i. scene with destruction
        show_scene;
        break;                              // break the for
        }
      else                                  // -*-*traspaso
        {
        buffer = scene[j];
        scene[j] = scene[j] | scene[0];     // i. combine the scene
        show_scene();
        scene[j] = buffer;
        }
      }
    }
  /*
  for (j=1; j<5 ;j++)
    {
    victoria = (victoria | scene[j]);
    }
  if (victoria == 0) {victoria = 1;}
  else {victoria = 0;}
  */
  }


void avance_tirania()
  {
  captura = 0;                                   // capture flag
  for(j=1; j<5; j++)
    {
    if ((j == 1) & (scene[j]!=0)) {captura = 1;} // you lose
    else;
    scene[j] = scene[j+1];                       // else shift policemen and reinforce
    if (j == 4) { scene[j] = 0x7F; }
    else;
    cuenta_ciclos = 0;
    }
  // if (captura == 1): you lose; else continue;
  }

void init_scene()
  {
  scene[0] = 0b00001000;    // here there is an anarchist
  scene[1] = 0b00000000;    //
  scene[2] = 0b00001000;    //
  scene[3] = 0b00011100;    //
  scene[4] = 0b00111110;    // and here the first line of pigs
  a_p = 3;                  // position of anarchy
  victoria = 0;
  disparo = 0;
  cuenta_ciclos = 0;
  period_dif=50;
  }

void victory_routine()
  {
  unsigned int d;
  // begins victory display
  scene[4] = 0x00;
  scene[3] = ((score<<8)>>9);
  scene[2] = 0x00;
  scene[1] = (score>>9);
  scene[0] = 0x00;
  for (d=0; d<200; d++) { show_scene(); }
  PORTC = 0xFF;
  Delay_ms(500);
  for (d=0; d<200; d++) { show_scene(); }
  // end of victory display
  // maintenance routines
  victoria = 0;
  Delay_ms(500);
  init_scene();
  score = 0;
  }

void capture_routine()
  {
  unsigned int d;
  // begins capture display
  scene[4] = 0x00;
  scene[3] = ((score<<8)>>9);
  scene[2] = 0x00;
  scene[1] = (score>>9);
  scene[0] = 0x00;
  for (d=0; d<200; d++) { show_scene(); }
  PORTC = 0xFF;
  Delay_ms(500);
  for (d=0; d<200; d++) { show_scene(); }
  // end of capture display
  // maintenance routines
  captura = 0;
  Delay_ms(500);
  init_scene();
  score = 0;
  }

/* *************************************** */
/* *************************************** */

void main()
  {
  // SETUP
  set_ports();
  ref_x = Adc_Read(0)>>6;
  ref_y = Adc_Read(1)>>6;
  period_dif=50;
  period_ref=12;
  score=0;
  init_scene();                  // 10 init

  // LOOP
  while (1)
    {
    read_controls();             // 20 read controls
    mover_chico_x();             // 30 mover anarquista

    if (disparo==1)              // 40 rutina arrojar_molotov
      {
      disparo_routine();
      }
    else;

    if (victoria==1)             // 50 rutina de la victoria
      {
      victory_routine();
      }
    else;

    if (cuenta_ciclos > period_dif)   // 60 avance de tirania
      {
      avance_tirania();
      score++;
      if (captura == 1)          // 70 rutina de captura
        {
        capture_routine();
        }
      else;
      }
    else;
    cuenta_ciclos++;
    if (((score << 11) >> 11) == 0x10 )
      {
      period_dif -= 1;
      }
    else;
    for (k=0; k<=period_ref; k++)    // 80 dibuja un rato
      {
      show_scene();
      }
    }
  }


*--**-- Video

martes, 8 de octubre de 2013

steampong

steampong is about two cats playing pong in kind of a steampunk universe.
usb powered, 8x8 led matrix, with extra cats that celebrates.

--*--* imgs











--*--*video


--*--* code:

// -*- STEAM_PONG:
//     two cats playing pong with potentiometers.
//    
/*
 -*- MAIN
 10 inicio
 20 leer movimiento
     21 filtrar (dentro de paredes)
 30 mover paletas
 40 mover bola
 50 dibujar
 60 return
*/

/***************************************\
 * scene(8x8 matrix):
 * 0 - - - - - - - -
 *   - - - - - - - -
 *   - - - - + - - -
 *   + - - - - - - -
 *   + - - - - - - +
 *   - - - - - - - +
 *   - - - - - - - -
 * 7 - - - - - - - -
 *   0             7  <-scene[0..7]
 \***************************************/


volatile unsigned char framebuffer_pos = 0x00;
volatile unsigned char scene[8]; // a char for each column

volatile signed char o_x, o_y;          // ball x & y positions
volatile signed char o_dx, o_dy;        // ball x & y directions
volatile signed char i1_p, i2_p;        // players positions
volatile signed char redraw, speed_counter, current_speed;    // 1 if must redraw; increasing speed as game goes on; actual speed; and score.
const char speed_bumper = 10;    // increase speed after this cycles
//const unsigned char d1[] = {0x00, 0x10, 0x20, 0x7f, 0x00}; /* the number 1 */
//const unsigned char d2[] = {0x47, 0x49, 0x49, 0x49, 0x31}; /* the number 2 */

signed char ctrl01, ctrl02, analog_val01, analog_val02, ant_analog_val01, ant_analog_val02, aux_portB, aux_portC, i,j, aux_a, aux_b;
signed char suelta, rebote_paleta, pos;
unsigned int k;                  // counter
unsigned char period=30;         // period <- can control velocity with this

/* *************************************** */
/* *************************************** */

void set_ports()
  // initialize control registers and ports
  {
  ADCON1 = 0x00;   // portA is full analog
  TRISA  = 0xFF;   // portA is input
  TRISB = 0x00;    // portB is ROWS
  PORTB = 0x00;    // initialize portB
  TRISC = 0x00;    // portC is COLUMNS
  PORTC = 0xFF;    // initialize portC
  }

void read_controls()
  // read analog_val and compares with ant_analog_val
  // sets ctrl01 and ctrl02 according to difference
  {
  analog_val01 = Adc_Read(0)>>6; // it needs just 4 msb
  analog_val02 = Adc_Read(1)>>6;
 
  aux_a = analog_val01 - ant_analog_val01;
  aux_b = analog_val02 - ant_analog_val02;

  if (aux_a == 0) ctrl01 = 0;
  else ctrl01 = (aux_a > 0) ? 1 : -1;
  if (aux_b == 0) ctrl02 = 0;
  else ctrl02 = (aux_b > 0) ? 1 : -1;
 
  ant_analog_val01 = analog_val01;
  ant_analog_val02 = analog_val02;
  }

void mover_paletas()
  // actualiza posición de las paletas en función de ctrl0X
  // 1 : inc y, scene <<
  // -1: dec y, scene >>
  // 0 : keep
  {
  if (ctrl01 == 1)
    {
    if (i1_p < 6)
      {
      i1_p++;
      scene[0] = scene[0]<<1;
      }
    }
  if (ctrl01 == -1)
    {
    if (i1_p > 0)
      {
      i1_p--;
      scene[0] = scene[0]>>1;
      }
    }
  if (ctrl01 == 0)
    {
    i1_p = i1_p;
    }

  if (ctrl02 == 1)
    {
    if (i2_p < 6)
      {
      i2_p++;
      scene[7] = scene[7]<<1;
      }
    }
  if (ctrl02 == -1)
    {
    if (i2_p > 0)
      {
      i2_p--;
      scene[7] = scene[7]>>1;
      }
    }
  if (ctrl02 == 0)
    {
    i2_p = i2_p;
    }
  }


void init_scene()
  {
  scene[0] = 0b00011000;    // player 01
  scene[1] = 0b00000000;    //
  scene[2] = 0b00010000;    //
  scene[3] = 0b00000000;    //
  scene[4] = 0b00000000;    //
  scene[5] = 0b00000000;    //
  scene[6] = 0b00000000;    //
  scene[7] = 0b00011000;    // player 02
  i1_p = 3;                 // positions of p1
  i2_p = 3;                 // positions of p2
  o_x = 2;                  // ball x coo
  o_y = 4;                  // ball y coo
  o_dx = 1;                 // ball x dir
  o_dy = 0;                 // ball y dir
  }

void show_scene()
  {
  for (i=0; i<8; i++)       // columns x
    {
    aux_portB = scene[i];   //   put the row vector in column i
    PORTB = aux_portB;      //   set the ports
    if (i==0)               //     initialize
      {aux_portC = 1;}
    else                    //     shift previous val
      {aux_portC = aux_portC << 1;}
    PORTC = ~aux_portC;
    Delay_ms(1);
    }
  }

void point_for_one()
  {
  volatile unsigned char catscene[28] = {0x00, 0x18, 0x24, 0x00,
                                         0x04, 0x02, 0x14, 0x00,
                                         0x20, 0x20, 0x00, 0x14,
                                         0x02, 0x04, 0x00, 0x24,
                                         0x18, 0x00, 0x20, 0x1C,
                                         0x00, 0x04, 0x0A, 0x00,
                                         0x00, 0x00, 0x00, 0x00};
  unsigned int d;
  for (d=0; d<24;d++)
    {
    j = 0;
    while(j<10)
      {
      for (i=d; i<d+8; i++)       // columns x
        {
        aux_portB = catscene[i];   //   put the row vector in column i
        PORTB = aux_portB;      //   set the ports
        if (i==d)               //     initialize
          {aux_portC = 1;}
        else                    //     shift previous val
          {aux_portC = aux_portC << 1;}
        PORTC = ~aux_portC;
        Delay_ms(1);
        }
      j++;
      }
    }
  init_scene();
  }

void point_for_two()
  {
  volatile unsigned char catscene[28] = {0x00, 0x18, 0x24, 0x00,
                                         0x04, 0x02, 0x14, 0x00,
                                         0x20, 0x20, 0x00, 0x14,
                                         0x02, 0x04, 0x00, 0x24,
                                         0x18, 0x00, 0x20, 0x1C,
                                         0x00, 0x0A, 0x04, 0x00,
                                         0x00, 0x00, 0x00, 0x00};
  unsigned int d;
  for (d=0; d<24; d++)
    {
    j = 0;
   
    while(j<10)
      {
      for (i=d; i<d+8; i++)         // columns x
        {
        aux_portB = catscene[i];   //   put the row vector in column i
        PORTB = aux_portB;         //   set the ports
        if (i==d) aux_portC = 1;   //     initialize
        else aux_portC = aux_portC << 1; //     shift previous val
        PORTC = ~aux_portC;
        Delay_ms(1);
        }
      j++;
      }
    }
  init_scene();
  }


void mover_bola()
  // mover bola en función de dx, dy, i1_p, i2_p
  //   41 si golpea pared: pared()
  //   42 si golpea paleta: casos{esquina_up, esquina_dn, simple}
  //   43 si bola suelta: casos{win01, win02, simple}
  {
  // pared
  if (o_y == 0) o_dy = -o_dy;
  if (o_y == 7) o_dy = -o_dy;
 
  // golpe_paleta
  suelta = 0;
  rebote_paleta = 0;
  pos = (o_x == 1) ? i1_p : i2_p;
  if (o_x == 1 || o_x == 6)            // detecta x
    {
    suelta = 1;
    if (o_y == pos || o_y == pos+1)    // rebote normal
      {
      o_dx = -o_dx;
      suelta = 0;
      rebote_paleta = 1;
      }
    else if (o_y == pos-1 && o_dy == 1)// esquina_up
      {
      o_dx = -o_dx;
      o_dy = -o_dy;
      suelta = 0;
      rebote_paleta = 1;
      }
    else if (o_y == pos+2 && o_dy == -1)//esquina_dn
      {
      o_dx = -o_dx;
      o_dy = -o_dy;
      suelta = 0;
      rebote_paleta = 1;
      }
    }
 
  // suelta
  if (suelta)
    {
    if (o_x == 1)                      // *point for 2!
      {
      o_x += o_dx;
      o_y += o_dy;
      point_for_two();
      }
    else                               // *point for 1!
      {
      o_x += o_dx;
      o_y += o_dy;
      point_for_one();
      }
    }
 
  //si fue rebote en paleta ajusta direcciones
  if (rebote_paleta)
      {
      if (o_x == 1 && (ctrl01 == 1)  && (o_dy <  1)) o_dy++;
      if (o_x == 1 && (ctrl01 == -1) && (o_dy > -1)) o_dy--;
      if (o_x == 6 && (ctrl02 == 1)  && (o_dy <  1)) o_dy++;
      if (o_x == 6 && (ctrl02 == -1) && (o_dy > -1)) o_dy--;
      }
   
  // si hay pared después de rebote
  if (o_y == 0 && o_dy == -1) o_dy = -o_dy;
  if (o_y == 7 && o_dy ==  1) o_dy = -o_dy;

  // y finalmente mueve la bolita
  o_x += o_dx;
  o_y += o_dy;
  scene[1]=0x00; scene[2]=0x00; scene[3]=0x00;
  scene[4]=0x00; scene[5]=0x00; scene[6]=0x00;
  scene[o_x] = 0x01<<o_y;
  }


/* *************************************** */
// MAIN

/* *************************************** */

void main()
  {
  // SETUP
  set_ports();
 
  ant_analog_val01 = Adc_Read(0)>>6;
  ant_analog_val02 = Adc_Read(1)>>6;
  init_scene();                  // 10 init

  // LOOP
  while (1)
    {
    read_controls();             // 20 read controls
    mover_paletas();             // 30 mover paletas
    mover_bola();                // 40 mover bola
   
    for (k=0; k<=period; k++)    // 50 dibujar por un rato
      {
      show_scene();
      }
    }
  }

miércoles, 25 de septiembre de 2013

bit$hifter [algorithmic 8bit synthesizer]









Inspired on minimal algorithmic symphonies, this synth-box/noise-machine uses a set of powerful manipulation rules to operate over a stream of 8bit words on PIC16F873A microcontroller. The output of such manipulations is transformed to signal audio by an onboard digital-to-analog converter and buffered to drive both line/headphones output.

The controlls allows to modificate parameters in the manipulation procedures:
  • main wheel stochastocally select operation mode (from available in firmware). the sound pattern generated heavily depends on which procedure generate them so minimal variations of the controll may result in deep changes in sound tonality/patterns
  • wheel a modifyes sampling rate over the bit stream or the velocity of time for generating the patterns
  • wheel b modifyes the bit-shifting performed in post processing stage and acts like a fine tuning of patterns generation
  • volume ctrl controll the sound intensity
Here is a really long jamming with this little noisy beast and a minikaosspad for recording and some effects here and there: 



[DIY |*---*|]:

Build your own bit$hifter!, they are open, free and totally customizable if your interested in experiment with sound patterns. Next there is a list with the components, schematic and mikroC source. Soldering and programming skills requiered.

Material:
  • 1 x PIC16F873A
  • 1 x TLC081 low power opamp
  • 4 x 100 KΩ potentiometers
  • 1 x 20 Mhz xtal resonator
  • 2 x 33 pF capacitors
  • 25 x 1k resistors
  • 10 uF capacitor
  • 1 led
  • male usb power connector
  • 3.5'' audio jack
  • some cable
  • optional pcb circuit and case or protoboard (breadboard) to mount all the things
Schematic:




Code:

/*
Bit$hifter 0.1
--------------

$·device: pic16f873a
$·clock: 20 mhz

$·pic version of minimal algorithmic symphonies 
$·main loop uses A/D 10-bit conversion of A0-A2 as input parameters
$ that changes the way functions are evaluated and post processed.
$.i think the switch-case selector causes the loop to go slower so a different optimized implementation must accelerate the stream generation. 

unsigned long i;
unsigned int aux00, aux01, aux02, other_i;
unsigned char Pot00, Pot01, Pot02;

void main()
  {
  ADCON1 = 0x00;   // porta is in full analogue mode
  TRISA  = 0xFF;   // porta is input
  TRISC = 0;       // port c as output
  PORTC = 0;       // initialize portc  

  
  aux00 = Adc_Read(0);
  aux01 = Adc_Read(1);
  aux02 = Adc_Read(2);
  while (1)
    {
    // preprocess to acceptable ranges
    Pot00 = aux00&0x0F;   // function selector [0..16]
    Pot01 = aux01>>0x02;  // scale range

    Pot02 = aux02>>0x07;  // output shifting [0..7]
    for (i=65535; i<=131027; i+=(1+Pot01))
      {
      switch (Pot00)
        {
        case 0x00:
             other_i=i;
        case 0x01:
             other_i=i&i>>8;
        case 0x02:
             other_i=i*(42&i>>10);
        case 0x03:
             other_i=i|i%255|i%257;
        case 0x04:
             other_i=i>>6&1?i>>5:-i>>4;
        case 0x05:
             other_i=i*(i>>9|i>>13)&16;
        case 0x06:
             other_i=(i&i>>12)*(i>>4|i>>8);
        case 0x07:
             other_i=(i*5&i>>7)|(i*3&i>>10);
        case 0x08:
             other_i=(i*(i>>5|i>>8))>>(i>>16);
        case 0x09:
             other_i=i*5&(i>>7)|i*3&(i*4>>10);
        case 0x0A:
             other_i=(i>>13|i%24)&(i>>7|i%19);
        case 0x0B:
             other_i=(i*((i>>9|i>>13)&15))&129;
        case 0x0C:
             other_i=(i&i%255)-(i*3&i>>13&i>>6);
        case 0x0D:
             other_i=(i&i>>12)*(i>>4|i>>8)^i>>6;
        case 0x0E:
             other_i=i*(((i>>9)^((i>>9)-1)^1)%13);
        case 0x0F:
             other_i=i*(0xCA98>>(i>>9&14)&15)|i>>8;
        default:
             other_i = i* ((i>>11|i>>8)&Pot01&i>>3);
             }
      PORTC = other_i>>Pot02;
      }
    aux00 = Adc_Read(0);
    aux01 = Adc_Read(1);
    aux02 = Adc_Read(2);
    }
  }


Comments:
  • Faster if switch-case replaced.
  • Changing deeper parameters from inside equations causes more interesting variations in sound patterns.
  • It takes a complete for cycle to refresh all parameters, some different loop distribution could add interesting modulations.