Publicidade:

sexta-feira, 5 de abril de 2019

Arduino - Charlieplexing

Nesse vídeo demonstro o funcionamento da técnica de multiplexação de leds chamada Charlieplex.



Código-Fonte:

/*************************************************************************************************************
*******************************BIT ARRAY *********************************************************************
**************************************************************************************************************
mais informações aqui: http://fabianoallex.blogspot.com.br/2015/09/arduino-array-de-bits.html
**************************************************************************************************************/
class BitArray{
  private:
    int _num_bits;   //quantidade de bits a serem gerenciados
    int _num_bytes;  //quantidade de bytes utilizados para armazenar os bits a serem gerenciados
    byte * _bytes;   //array de bytes onde estaram armazenados os bits
  public:
    BitArray(int num_bits){
      _num_bits  = num_bits;
      _num_bytes = _num_bits/8 + (_num_bits%8 ? 1 : 0) + 1;
      _bytes = (byte *)(malloc( _num_bytes * sizeof(byte) ) );
    }
     
    void write(int index, byte value) {
      byte b = _bytes[ index/8 + (index%8 ? 1 : 0) ];
      unsigned int bit = index%8;
      if (value) { b |= (1 << bit); } else { b &= ~(1 << bit);  }
      _bytes[ index/8 + (index%8 ? 1 : 0) ] = b;
    }
     
    void write(byte value) {
      for(int j=0; j<_num_bytes;j++) { _bytes[j] = value ? B11111111 : B00000000;  } 
    }
     
    int read(int index) {
      byte b = _bytes[ index/8 + (index%8 ? 1 : 0) ];
      unsigned int bit = index%8;
      return (b & (1 << bit)) != 0;
    }
 
   ~BitArray(){ free( _bytes ); }
};
/*************************************************************************************************************
*******************************FIM BIT ARRAY *****************************************************************
**************************************************************************************************************/

class Charlieplexing {
  private:
    byte _numPins;       //numero de pinos utilizados
    int  * _pins;        //ponteiro para array com os pinos utilizados
    byte _ledsOnPerGroup;//quantidade de leds de um mesmo grupo que pode ser ligada ao mesmo tempo
    BitArray * _states;     //armazenas o estados do leds
  public:
    Charlieplexing(int * pins, byte numPins, byte _ledsOnPerGroup=2);
    int numLeds() { return _numPins * _numPins - _numPins; }
    void update(int delay_=10, int repeat=1);
    void turnOn(int i);  //liga led i
    void turnOff(int i);  //desliga led i
    void clear();
    byte getState(int i);  //retorna status led i
};

Charlieplexing::Charlieplexing(int * pins, byte numPins, byte ledsOnPerGroup){
  _ledsOnPerGroup = ledsOnPerGroup;
  _numPins = numPins;
  _pins    = pins;
  _states  = new BitArray(numLeds());
}

void Charlieplexing::turnOn(int i){
  if (i < numLeds()){
    _states->write(i, HIGH);
  }
}

void Charlieplexing::turnOff(int i){
  if (i < numLeds()){
    _states->write(i, LOW);
  }
}

byte Charlieplexing::getState(int i){
  if (i < numLeds()){
    return _states->read(i);
  }
}

void Charlieplexing::clear(){
  _states->write(LOW);
}

void Charlieplexing::update(int delay_, int repeat){
  if (repeat <=0) { repeat = 1; }
  for (int q=0; q<repeat; q++) {
    for (int i=0; i<_numPins; i++) {
      digitalWrite(_pins[i], LOW);
      pinMode(_pins[i], OUTPUT);

      byte cont = 0; //conta se há algum led a ser ligado

      for (int j=0;j<_numPins;j++){
        if (i != j) {
          pinMode(_pins[j], INPUT);
          digitalWrite(_pins[j], LOW);
        }
      }

      for (int j=0; j<_numPins; j++) {
        if (i != j) {
          int posLed = 0; 

          if (i>j){
            posLed = i * i - i + 2 * j + 1;  //baseado no calculo do numero triangular
          } else {
            posLed = j * j - j + 2 * i;      //baseado no calculo do numero triangular
          }

          if (_states->read(posLed) == HIGH){
            pinMode(_pins[j], OUTPUT);
            digitalWrite(_pins[j], LOW);
            cont++;
          } 
        }

        if (cont == _ledsOnPerGroup && cont > 0 ) {
          cont = 0;
          digitalWrite(_pins[i], HIGH);
          delay(delay_); 
          digitalWrite(_pins[i], LOW);

          for (int jj=0;jj<=j;jj++){
            if (i != jj) {
              pinMode(_pins[jj], INPUT);
            }
          }
        }
      }
      if (cont > 0){
        cont = 0;
        digitalWrite(_pins[i], HIGH);
        delay(delay_); 
        digitalWrite(_pins[i], LOW);
      }
    }
  }
}



int pins[] = {12, 11, 10, 9, 8};
int qtPins = 5;
int qtLedsOn = 2;

Charlieplexing cp(pins, qtPins, qtLedsOn);  //pinos, qtpinos, qtledsOn


void setup(){
  cp.turnOn(0);
  cp.turnOn(2);
  
  cp.turnOn(4);
  cp.turnOn(8);
  cp.turnOn(14);
  
  cp.turnOn(7);
  cp.turnOn(18);
  
  cp.turnOn(13);
  cp.turnOn(15);
  cp.turnOn(17);
  cp.turnOn(19);
}

void loop() { 
  cp.update(5, 20); //delay, repeat
}

quinta-feira, 7 de março de 2019

Arduino - Várias lâmpadas controladas por um mesmo interruptor

Nesse vídeo mostro como controlar várias lâmpadas através de um único interruptor através do Arduino.

Vídeo


Código-fonte
byte pinL1 = 3;
byte pinL2 = 4;
byte pinL3 = 5;
byte pinL4 = 6;
byte pinBt  = 2;



byte lamp1 = 1;
byte lamp2 = 1;
byte lamp3 = 1;
byte lamp4 = 1;

void setup()
{
  pinMode(pinBt, INPUT_PULLUP); //internal pullup resistor is used to simplify the circuit
  pinMode(pinL1, OUTPUT);
  pinMode(pinL2, OUTPUT);
  pinMode(pinL3, OUTPUT);
  pinMode(pinL4,OUTPUT);
}
 
byte digitalReadOnce(byte val){
  static byte lastVal = LOW;
  static unsigned long m = 0;
  if (lastVal != val && millis() > (m+100) ) { //M+100 -->DEBOUNCING 100ms
    lastVal = val;
    m = millis();
    return lastVal;
  } 
  return LOW;
}
 
int getCommand(){
  static unsigned long m1 = 0;  //millis no momento inicia de pressionar o botão 
  static unsigned long m2 = 0;  //millis após soltar o botão 
  static byte count = 0;
   
  byte r = digitalRead(pinBt);
   
  if (digitalReadOnce(r) == HIGH){
    m1 = millis();
    count++;
  }
   
  if (r == HIGH){
    m2 = millis();
  } else {
    if (! (m2>0 && m2-m1 < 1000) ){  //o botão deve ser pressionado por menos de 1 segundo, senão cancela o comando
      count = 0;
      m1 = 0;
      m2 = 0;
    }
     
    if (m2>0 && millis()-m2 > 1500){  //após a ultima vez pressionado o botao, aguarda 1,5 segundos para finalizar e retornar o comando.
      byte c = count;
      count = 0;
      m1 = 0;
      m2 = 0;
       
      return c;
    }
  }
   
  return 0;
}
 
 
 
void loop() {
  
  if( digitalRead(pinBt) == HIGH ){
    digitalWrite(pinL1, LOW);
    digitalWrite(pinL2,LOW);
    digitalWrite(pinL3,LOW);
    digitalWrite(pinL4,LOW);
  } else {
    digitalWrite(pinL1, lamp1);
    digitalWrite(pinL2,lamp2);
    digitalWrite(pinL3,lamp3);
    digitalWrite(pinL4, lamp4);
  }
   
  int command = getCommand();
 
  if (command == 1){
    lamp1 = !lamp1; 
  }
   
  if (command == 2){
    lamp2 = !lamp2; 
  }
   
  if (command == 3){
    lamp3 = !lamp3; 
  }
   
  if (command == 4){
    lamp4 = !lamp4; 
  }
  
  
   
  
  delay(10);  //apenas utilizado no simulador
}

terça-feira, 14 de novembro de 2017

Arduino - Botão com múltiplas funções

Nesse vídeo mostro como executar em um único botão diversas funções distintas.

Vídeo


Código-fonte
byte inputPin = 10;
byte ledPin = 13;
byte redPin = 6;
byte greenPin = 4;
byte bluePin = 3;


byte digitalReadOnce(byte val){
  static byte lastVal = HIGH;
  static unsigned long m = 0;
  if (lastVal != val && millis() > (m+100) ) { //M+100 -->DEBOUNCING 100ms
    lastVal = val;
    m = millis();
    return lastVal;
  } 
  return HIGH;
}

int getCommand(){
  static unsigned long m1 = 0;  //millis no momento inicia de pressionar o botão 
  static unsigned long m2 = 0;  //millis após soltar o botão 
  static byte count = 0;
  
  byte r = digitalRead(inputPin);
  
  if (digitalReadOnce(r) == LOW){
    m1 = millis();
    count++;
  }
  
  if (r == LOW){
    m2 = millis();
  } else {
    if (! (m2>0 && m2-m1 < 1000) ){  //o botão deve ser pressionado por menos de 1 segundo, senão cancela o comando
      count = 0;
      m1 = 0;
      m2 = 0;
    }
    
    if (m2>0 && millis()-m2 > 1500){  //após a ultima vez pressionado o botao, aguarda 1,5 segundos para finalizar e retornar o comando.
      byte c = count;
      count = 0;
      m1 = 0;
      m2 = 0;
      
      return c;
    }
  }
  
  return 0;
}


void setup() {
  Serial.begin(9600);
  pinMode(inputPin, INPUT_PULLUP); //internal pullup resistor is used to simplify the circuit
  pinMode(bluePin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(ledPin,OUTPUT);
}

void loop() {
  
  int command = getCommand();

  if (command == 1){
    digitalWrite(redPin, !digitalRead(redPin));
  }
  
  if (command == 2){
    digitalWrite(greenPin, !digitalRead(greenPin));
  }
  
  if (command == 3){
    digitalWrite(bluePin, !digitalRead(bluePin));
  }
  
  if (command == 4){
    digitalWrite(redPin, HIGH);
    digitalWrite(greenPin, HIGH);
    digitalWrite(bluePin, HIGH);
  }
  
  if (command == 5){
    digitalWrite(redPin, LOW);
    digitalWrite(greenPin, LOW);
    digitalWrite(bluePin, LOW);
  }
  
  digitalWrite(ledPin, !digitalRead(inputPin));
  
  delay(10);  //apenas utilizado no simulador
}







Comandos via LDR

Baseado no exemplo anterior, foi substituido o botão por um LDR, onde é possível enviar comandos pro Arduino através de luz.

Vídeo:


Código-Fonte:
byte ledPin = 13;
byte redPin = 6;
byte greenPin = 4;
byte bluePin = 3;


boolean hasLightOnce(byte val){
  static boolean lastVal = false;
  static unsigned long m = 0;
  if (lastVal != val && millis() > (m+100) ) { //M+100 -->DEBOUNCING 100ms
    lastVal = val;
    m = millis();
    return lastVal;
  } 
  return false;
}

boolean hasLight(){
  return (analogRead(A0) < 100);
}


int getCommand(){
  static unsigned long m1 = 0;  //millis no momento inicia de pressionar o botão 
  static unsigned long m2 = 0;  //millis após soltar o botão 
  static byte count = 0;
  
  boolean light = hasLight();
  
  if (hasLightOnce(light)){
    m1 = millis();
    count++;
  }
  
  if (light){
    m2 = millis();
  } else {
    if (! (m2>0 && m2-m1 < 1000) ){  //o botão deve ser pressionado por menos de 1 segundo, senão cancela o comando
      count = 0;
      m1 = 0;
      m2 = 0;
    }
    
    if (m2>0 && millis()-m2 > 1500){  //após a ultima vez pressionado o botao, aguarda 1,5 segundos para finalizar e retornar o comando.
      byte c = count;
      count = 0;
      m1 = 0;
      m2 = 0;
      
      return c;
    }
  }
  
  return 0;
}


void setup() {
  Serial.begin(9600);
  pinMode(bluePin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(ledPin,OUTPUT);
}

void loop() {
  
  int command = getCommand();

  if (command == 1){
    digitalWrite(redPin, !digitalRead(redPin));
  }
  
  if (command == 2){
    digitalWrite(greenPin, !digitalRead(greenPin));
  }
  
  if (command == 3){
    digitalWrite(bluePin, !digitalRead(bluePin));
  }
  
  if (command == 4){
    digitalWrite(redPin, HIGH);
    digitalWrite(greenPin, HIGH);
    digitalWrite(bluePin, HIGH);
  }
  
  if (command == 5){
    digitalWrite(redPin, LOW);
    digitalWrite(greenPin, LOW);
    digitalWrite(bluePin, LOW);
  }
  
  digitalWrite(ledPin, hasLight() );
  
  delay(10);  //apenas utilizado no simulador
}






sexta-feira, 3 de novembro de 2017

Arduino - Charlieplex com botões

Demonstração de como utilizar vários botões com poucos pinos através da multiplexação Charlieplex.

Vídeo:



Código-fonte:
#define NUM_PINS 4

const int pins[] = {2,3,4,5};

void init_pins(){
  for (int i = 0; i< NUM_PINS; i++) { 
    pinMode(pins[i], INPUT_PULLUP); 
    digitalWrite(pins[i], HIGH);
  }
}

byte readCharlieplexButons(int pin1, int pin2){
  init_pins();
  pinMode(pin1, OUTPUT);
  digitalWrite(pin1, LOW);
  return !digitalRead(pin2);
}

int getButton(){
  byte index_button = 0;
  for (int i=0; i<NUM_PINS; i++) { 
    for (int j=i+1; j<NUM_PINS; j++) { 
      if (i!=j) { 
        if (readCharlieplexButons(pins[j], pins[i])) {
          return index_button;
        }
        index_button++;
        if (readCharlieplexButons(pins[i], pins[j])) {
          return index_button;
        }
        index_button++;
      }
    }
  }
  return -1;  //-1 --> nenhum botão pressionado
}
  
int getButtonOnce(){
  static int lastVal = -1;
  static unsigned long m = 0;
  int val = getButton();
  if (lastVal != val && millis() > (m+100) ) { //M+100 -->DEBOUNCING 100ms
    lastVal = val;
    m = millis();
    return lastVal;
  } 
  return -1;
}


void setup() { 
  init_pins(); 
  Serial.begin(9600);
}

void loop() { 
  int button = getButtonOnce();
  if ( button >=0){
    Serial.println(button);
  }
  delay(10);   //necessário apenas no simulador.
}