Publicidade:

terça-feira, 2 de junho de 2015

Arduino - Classe para 74HC595 Corrigida


Nesse post (clique aqui) foi mostrado como criar uma classe pra facilitar o uso do registrador de deslocamento 74HC595 com o Arduino.

Apesar de funcionar perfeitamente, a classe ocupava muita memória para armazenar o estados de todas as saídas.

o código abaixo, foi reescrito de forma a ocupar menos memória e ser mais simples. Alguns métodos foram renomeados.

segue código-fonte:


class Expansor74HC595 {
  private:
    int  _pin_clock;
    int  _pin_latch;
    int  _pin_data;
    int  _num_cis;
    byte* _pins;
    int  _auto_send;
  public:
    Expansor74HC595(int pin_clock, int pin_latch, int pin_data, int num_cis){
      _pin_clock        = pin_clock;
      _pin_latch        = pin_latch;
      _pin_data         = pin_data;
      _num_cis          = num_cis;
      _auto_send        = true;
      _pins             = new byte[_num_cis];

      pinMode(_pin_clock,OUTPUT);
      pinMode(_pin_latch,OUTPUT);
      pinMode(_pin_data, OUTPUT);
      clear();
    };
  
    void startWrite() { 
      _auto_send = false; 
    };
    
    void clear() { 
      for (int i=0; i<_num_cis; i++){ 
        _pins[i] = 0b00000000; 
      }
      
      send();  
    };
  
    int read(int pin)  { 
      if (pin >= _num_cis * 8) {return LOW;} 
      
      int pos = pin / 8;
      pin = pin % 8;

            
      return (_pins[pos] & (1 << pin)) != 0;
    };
  
    byte readByte(int num_ci) { 
      return _pins[num_ci];
    };
   
    void send(){
      
      digitalWrite(_pin_latch, LOW); 
      for(int i=_num_cis-1; i>=0; i--) {  shiftOut(_pin_data, _pin_clock, MSBFIRST, readByte(i) );  }
      digitalWrite(_pin_latch, HIGH);
      _auto_send = true;
      
    };
    
    void writeByte(int num_ci, byte b, int first = MSBFIRST) {  
      
      if (first == MSBFIRST){
        byte reversed;
        for(int i=0;i<8;i++){
          reversed |= ((b>>i) & 0b1)<<(7-i);
        }
        b = reversed;
      }
      
      _pins[num_ci] = b; 
      if (_auto_send) { send(); } 
    } ;
    
    void write(int pin, int value) {
      if (pin >= _num_cis * 8) { return; }
      
      int pos = pin / 8;
      pin     = pin % 8;

      if (value){
        _pins[pos] |= (1 << pin);  //set a bit HIGH
      } else {
        _pins[pos] &= ~(1 << pin); //set a bit LOW
      }

      if (_auto_send) { send(); }
    };
};
 

const int PIN_CLOCK = 2; 
const int PIN_LATCH = 3; 
const int PIN_DATA  = 4; 

Expansor74HC595 *exp1;
 
void setup() {
  exp1   = new Expansor74HC595(PIN_CLOCK, PIN_LATCH, PIN_DATA, 3);
  
  Serial.begin(9600);
}
 
void loop() {
  for (byte b=0; b<=255; b++) {                    //i=0-> B00000000   i=255-> B11111111
    exp1->startWrite();
    exp1->writeByte(0, b);
    exp1->writeByte(1, b, LSBFIRST);
    exp1->write(23, HIGH);
    exp1->send();
  
    delay(500);
  }
  
  exp1->clear();
  delay(500); 
}

sábado, 30 de maio de 2015

Arduino - Digitar Texto com Controle Remoto + LCD

No post anterior mostrei como digitar texto em um display LCD com um teclado matricial 4x3. Nesse vídeo mostro como fazer a mesma coisa, mas utilizando um controle remoto.


Código-Fonte:

obs. 01: O Controle remoto utilizado foi o da Claro TV. Caso for usar outro tipo de controle remoto, é necessário descobrir a codificação de cada uma das teclas e fazer as alterações na função get_tecla. Esse controle remoto, retorna dois códigos diferentes para a mesma tecla (em alguns casos), como pode ser visto no código. 

obs. 02: o controle remoto ao ser mantido pressionado, não fica enviando a informação de maneira continua, então o arduino, por um pequeno período de tempo, entende que o botão foi solto e pressionado várias vezes, causando um  comportamento indesejado, por isso foi criada a variável global time_read = 150;  150, significa que 150 milissegundos após o botão ser "solto" a função get_tecla, ainda vai continuar retornando o ultimo caractere pressionado. é possível que em diferentes controles remotos, esse tempo varie. Não fiz nenhum teste com outros controles, mas que for usar, é interessante testar isso antes.

obs. 03: é preciso baixar e instalar a biblioteca IRRemote. Não vou entrar em detalhes aqui de como instalar e configurar a biblioteca, pois uma rápida busca no google, certamente irá ajudar.

#include <IRremote.h> 
const int RECV_PIN = 11;
unsigned long last = millis();
 
IRrecv irrecv(RECV_PIN);
decode_results results;

unsigned long millis_last_read = 0;
char char_last_read = '\0';
unsigned long time_read = 150;

char get_tecla() {
  char c = '\0';
  
  if ( (millis() - time_read) > millis_last_read ){
    if (irrecv.decode(&results)) {
      if (results.value == 2152998656 || results.value == 2153031424){ c = '0'; }  
      if (results.value == 2152998657 || results.value == 2153031425){ c = '1'; }
      if (results.value == 2152998658 || results.value == 2153031426){ c = '2'; }
      if (results.value == 2152998659 || results.value == 2153031427){ c = '3'; }
      if (results.value == 2152998660 || results.value == 2153031428){ c = '4'; }
      if (results.value == 2152998661 || results.value == 2153031429){ c = '5'; }
      if (results.value == 2152998662 || results.value == 2153031430){ c = '6'; }
      if (results.value == 2152998663 || results.value == 2153031431){ c = '7'; }
      if (results.value == 2152998664 || results.value == 2153031432){ c = '8'; }
      if (results.value == 2152998665 || results.value == 2153031433){ c = '9'; }
      if (results.value == 551538735)                                { c = '*'; }
      if (results.value == 2152998666 || results.value == 2153031434){ c = '#'; }
        
      irrecv.resume(); // Receive the next value
      
      millis_last_read = millis();
      char_last_read = c;
    }
  } else {
    c = char_last_read;
  }
  
  //Serial.println(c);
  
  return c;
}
 
 
const char teclas[][12] = {"1 ", "2abc", "3def", "4ghi", "5jkl", "6mno", "7pqrs", "8tuv", "9wxyz", "*", "0", "#"};
const unsigned long time_char = 1200;  //1200 milissegundos pra desconsiderar a ultima tecla
 
class TecladoTelefone{
  private:
    unsigned long _millis_last_char;
    char _last_char;
    String _palavra;
     
    void _set_last_char(char c, int ind_palavra){
      if ( ind_palavra == 1 && _last_char != '\0' ) {
        _palavra += _last_char;
      }
 
      _last_char = c;
      _millis_last_char = millis();
    }
     
    void _back_space(){
      if (_palavra.length() >= 1){
        _last_char = _palavra[_palavra.length()-1];
        _palavra   = _palavra.substring(0, _palavra.length()-1);
      } else {
        _last_char = '\0';
      }
    }
     
  public:
    TecladoTelefone(){
      _millis_last_char = millis();
      _last_char = '\0';
    }
     
    int is_timing(){
      return ( (millis() - time_char) < _millis_last_char );
    }
   
    void add(char c){
      int pos = -1;
       
      if (c == '1'){ pos = 0;}
      if (c == '2'){ pos = 1;}
      if (c == '3'){ pos = 2;}
      if (c == '4'){ pos = 3;}
      if (c == '5'){ pos = 4;}
      if (c == '6'){ pos = 5;}
      if (c == '7'){ pos = 6;}
      if (c == '8'){ pos = 7;}
      if (c == '9'){ pos = 8;}
      if (c == '*'){ pos = 9;}
      if (c == '0'){ pos = 10;}
      if (c == '#'){ pos = 11;}
       
      if (pos == -1){ return; }
       
      if (pos == 9){
        _back_space();
        return;
      }
       
      const char * t = teclas[pos];
       
      if ( is_timing() ) {
         
        int i = 0;
        while (t[i] != '\0'){
          if (_last_char == t[i]){
            _set_last_char(  (t[i+1] == '\0') ? _last_char = t[0] : _last_char = t[i+1] , 0 );
            return ;
          }
          i++;
        }
      }
       
      _set_last_char ( c, 1);
    }
     
    char get_last_char(){ return _last_char; }
     
    String get_palavra( ) {
       
      if (_last_char != '\0') {
        return _palavra + _last_char;
      }
       
      return _palavra;
    }
};
 
 
#include <LiquidCrystal.h> 
  
LiquidCrystal lcd(9, 8, 10, 7, 6, 5); //Configura os pinos do Arduino para se comunicar com o LCD
 
 
TecladoTelefone * teclado;
 
void setup() {
  Serial.begin(9600);
  irrecv.enableIRIn(); 
  teclado = new TecladoTelefone();
  lcd.begin(16, 2); 
}
 
char tecla_anterior = '\0';
 
void loop() {
  char tecla = get_tecla();
   
  if (tecla != tecla_anterior){
    if (tecla) {
      teclado->add(tecla);
    }
  }
   
  tecla_anterior = tecla;
   
  lcd.clear();
  lcd.setCursor(0, 0); 
  lcd.print(teclado->get_palavra());
  lcd.cursor();
  lcd.setCursor(teclado->get_palavra().length() - (teclado->is_timing() ? 1 : 0 ), 0);
  delay(10);
  lcd.noCursor();    
}

sexta-feira, 29 de maio de 2015

Arduino - Teclado 4x3 + texto + lcd

Esse vídeo é continução do vídeo anterior, onde tinha demonstrado como digitar texto com teclado matricial, parecido com de telefone celular.

Vídeo anterior, com mais detalhes sobre a montagem do teclado:
http://fabianoallex.blogspot.com.br/2015/05/arduino-texto-com-teclado-matricial-4x3.html

Nessa versão implementei a função de backspace e mostrei o resultado num display LCD.



código-fonte:


#define col1 10 
#define col2 11 
#define col3 12 
#define lin1 3 
#define lin2 4
#define lin3 5
#define lin4 6 


char get_tecla(){
  int l[]={lin1, lin2, lin3, lin4}; // Array de 4 posições contendo os 4 pinos de linhas
  int i = 0, k = 0, t = 0;
  
  for (i=0; i<4; i++) {
    digitalWrite(lin1,LOW); 
    digitalWrite(lin2,LOW);
    digitalWrite(lin3,LOW);
    digitalWrite(lin4,LOW);
    digitalWrite(l[i],HIGH); 
    
    if(digitalRead(col1)) { t = i*3+1; break; }
    if(digitalRead(col2)) { t = i*3+2; break; }
    if(digitalRead(col3)) { t = i*3+3; break; }
  }
  
  if (t > 0 ){
    if (t >= 1 && t<=9){ return char(t+48);   }  //48--> ASCII: o charactere '1' na tabela ascii é 49º item, o '2' é o 50º item e assim por diante
    if (t==10)         { return '*'; }
    if (t==11)         { return '0'; }
    if (t==12)         { return '#'; }
  }
  
  return '\0';
}


const char teclas[][12] = {"1 ", "2abc", "3def", "4ghi", "5jkl", "6mno", "7pqrs", "8tuv", "9wxyz", "*", "0", "#"};
const unsigned long time_char = 1200;  //1200 milissegundos pra desconsiderar a ultima tecla

class TecladoTelefone{
  private:
    unsigned long _millis_last_char;
    char _last_char;
    String _palavra;
    
    void _set_last_char(char c, int ind_palavra){
      if ( ind_palavra == 1 && _last_char != '\0' ) {
        _palavra += _last_char;
      }

      _last_char = c;
      _millis_last_char = millis();
    }
    
    void _back_space(){
      if (_palavra.length() >= 1){
        _last_char = _palavra[_palavra.length()-1];
        _palavra   = _palavra.substring(0, _palavra.length()-1);
      } else {
        _last_char = '\0';
      }
    }
    
  public:
    TecladoTelefone(){
      _millis_last_char = millis();
      _last_char = '\0';
    }
    
    int is_timing(){
      return ( (millis() - time_char) < _millis_last_char );
    }
  
    void add(char c){
      int pos = -1;
      
      if (c == '1'){ pos = 0;}
      if (c == '2'){ pos = 1;}
      if (c == '3'){ pos = 2;}
      if (c == '4'){ pos = 3;}
      if (c == '5'){ pos = 4;}
      if (c == '6'){ pos = 5;}
      if (c == '7'){ pos = 6;}
      if (c == '8'){ pos = 7;}
      if (c == '9'){ pos = 8;}
      if (c == '*'){ pos = 9;}
      if (c == '0'){ pos = 10;}
      if (c == '#'){ pos = 11;}
      
      if (pos == -1){ return; }
      
      if (pos == 9){
        _back_space();
        return;
      }
      
      const char * t = teclas[pos];
      
      if ( is_timing() ) {
        
        int i = 0;
        while (t[i] != '\0'){
          if (_last_char == t[i]){
            _set_last_char(  (t[i+1] == '\0') ? _last_char = t[0] : _last_char = t[i+1] , 0 );
            return ;
          }
          i++;
        }
      }
      
      _set_last_char ( c, 1);
    }
    
    char get_last_char(){ return _last_char; }
    
    String get_palavra( ) {
      
      if (_last_char != '\0') {
        return _palavra + _last_char;
      }
      
      return _palavra;
    }
};


#include <LiquidCrystal.h> 
 
LiquidCrystal lcd(9, 8, 13, 2, 1, 0); //Configura os pinos do Arduino para se comunicar com o LCD


TecladoTelefone * teclado;

void setup() {
  //Serial.begin(9600);
  
    // colunas INPUT
  pinMode(col1,INPUT);
  pinMode(col2,INPUT);
  pinMode(col3,INPUT);
  
  // linhas OUTPUT 
  pinMode(lin1,OUTPUT); 
  pinMode(lin2,OUTPUT);
  pinMode(lin3,OUTPUT); 
  pinMode(lin4,OUTPUT); 
  
  teclado = new TecladoTelefone();
  
  lcd.begin(16, 2); 
}

char tecla_anterior = '\0';

void loop() {

  char tecla = get_tecla();
  
  if (tecla != tecla_anterior){
    if (tecla) {
      teclado->add(tecla);
    }
  }
  
  tecla_anterior = tecla;
  
  lcd.clear();
  lcd.setCursor(0, 0); 
  lcd.print(teclado->get_palavra());
  lcd.cursor();
  lcd.setCursor(teclado->get_palavra().length() - (teclado->is_timing() ? 1 : 0 ), 0);
  delay(10);
  lcd.noCursor();    
}

domingo, 24 de maio de 2015

Arduino - Texto com teclado matricial 4x3 (teclado de telefone)

Nesse video mostro dois exemplos, no primeiro é mostrado como ligar um teclado matricial de 4 linhas e 3 colunas no Arduino. Nesse exemplo utilizo um teclado feito a partir de um teclado de telefone, que foi cortado, e identificadas as linhas e colunas, furada a placa e soldado um fio pra cada linha e pra cada coluna. A outra extremidade do fio foi soldada em uma placa, para que fosse possível conectar o teclado numa protoboard para entao utilizá-la com o Arduino.

Vídeo



Imagens do teclado





Na imagem abaixo é possível ver como foi feita a ligação. Os fios foram soldados em um placa, os 3 fios brancos são os fios das colunas, e os 4 fios amarelos são os fios das linhas, sendo o fio amarelo mais da direita referente a linha 1, conforme identificado pelo L1 na placa, e mais a esquerda, a coluna 3, conforme identificado pelo C3 na placa. 

Os fios referentes às linhas (fios amarelos) foram ligados diretamente ao Arduino, nos pinos 3, 4, 5 e 6. Os fios referentes às colunas foram ligados na protoboard no qual cada fio é ligado a um resistor de pulldown (10K cada um), e então ligados ao Arduino nos pinos 10, 11 e 12.





Código 01


Nesse código é mostrado como ligar um teclado matricial 4x3 no Arduino.


#define col1 10 
#define col2 11 
#define col3 12 
#define lin1 3 
#define lin2 4
#define lin3 5
#define lin4 6 


char get_tecla(){
  int l[]={lin1, lin2, lin3, lin4}; // Array de 4 posições contendo os 4 pinos de linhas
  int i = 0, k = 0, t = 0;
  
  for (i=0; i<4; i++) {
    digitalWrite(lin1,LOW); 
    digitalWrite(lin2,LOW);
    digitalWrite(lin3,LOW);
    digitalWrite(lin4,LOW);
    digitalWrite(l[i],HIGH); 
    
    if(digitalRead(col1)) { t = i*3+1; break; }
    if(digitalRead(col2)) { t = i*3+2; break; }
    if(digitalRead(col3)) { t = i*3+3; break; }
  }
  
  if (t > 0 ){
    if (t >= 1 && t<=9){ return char(t+48);   }  //48--> ASCII: o charactere '1' na tabela ascii é 49º item, o '2' é o 50º item e assim por diante
    if (t==10)         { return '*'; }
    if (t==11)         { return '0'; }
    if (t==12)         { return '#'; }
  }
  
  return '\0';
}


void setup() {

  // colunas INPUT
  pinMode(col1,INPUT);
  pinMode(col2,INPUT);
  pinMode(col3,INPUT);
  
  // linhas OUTPUT 
  pinMode(lin1,OUTPUT); 
  pinMode(lin2,OUTPUT);
  pinMode(lin3,OUTPUT); 
  pinMode(lin4,OUTPUT); 
  
  Serial.begin(9600); 
}

void loop() {
  if (get_tecla() != '\0'){
    Serial.println( get_tecla() );
  }
}


Código 02

Código referente a digitação de texto através do teclado Matricial.

o Código não está completo, não tendo informado letras Maisúsculas, nem caracteres especiais, mas facilmente adicionados, modificando a constante teclas, introduzindo os demais caracteres que sejam desejados. Também não foi implementado nenhuma função referente a Backspace (para apagar o texto), nem para limpar. Talvez futuramente eu venha implementar essas melhorias no código, e assim que eu for fazendo, vou disponibilzando o código aqui no blog.


#define col1 10 
#define col2 11 
#define col3 12 
#define lin1 3 
#define lin2 4
#define lin3 5
#define lin4 6 


char get_tecla(){
  int l[]={lin1, lin2, lin3, lin4}; // Array de 4 posições contendo os 4 pinos de linhas
  int i = 0, k = 0, t = 0;
  
  for (i=0; i<4; i++) {
    digitalWrite(lin1,LOW); 
    digitalWrite(lin2,LOW);
    digitalWrite(lin3,LOW);
    digitalWrite(lin4,LOW);
    digitalWrite(l[i],HIGH); 
    
    if(digitalRead(col1)) { t = i*3+1; break; }
    if(digitalRead(col2)) { t = i*3+2; break; }
    if(digitalRead(col3)) { t = i*3+3; break; }
  }
  
  if (t > 0 ){
    if (t >= 1 && t<=9){ return char(t+48);   }  //48--> ASCII: o charactere '1' na tabela ascii é 49º item, o '2' é o 50º item e assim por diante
    if (t==10)         { return '*'; }
    if (t==11)         { return '0'; }
    if (t==12)         { return '#'; }
  }
  
  return '\0';
}


const char teclas[][12] = {"1 ", "2abc", "3def", "4ghi", "5jkl", "6mno", "7pqrs", "8tuv", "9wxyz", "*", "0", "#"};
const unsigned long time_char = 1200;  //1200 milissegundos pra desconsiderar a ultima tecla

class TecladoTelefone{
  private:
    unsigned long _millis_last_char;
    char _last_char;
    String _palavra;
    
    void _set_last_char(char c, int ind_palavra){
      if ( ind_palavra == 1 && _last_char != '\0' ) {
        _palavra += _last_char;
      }

      _last_char = c;
      _millis_last_char = millis();
    }
    
  public:
    TecladoTelefone(){
      _millis_last_char = millis();
      _last_char = '\0';
    }
  
    void add(char c){
      int pos = -1;
      
      if (c == '1'){ pos = 0;}
      if (c == '2'){ pos = 1;}
      if (c == '3'){ pos = 2;}
      if (c == '4'){ pos = 3;}
      if (c == '5'){ pos = 4;}
      if (c == '6'){ pos = 5;}
      if (c == '7'){ pos = 6;}
      if (c == '8'){ pos = 7;}
      if (c == '9'){ pos = 8;}
      if (c == '*'){ pos = 9;}
      if (c == '0'){ pos = 10;}
      if (c == '#'){ pos = 11;}
      
      if (pos == -1){ return; }
      
      const char * t = teclas[pos];
      
      if ( (millis() - time_char) < _millis_last_char ) {
        
        int i = 0;
        while (t[i] != '\0'){
          if (_last_char == t[i]){
            _set_last_char(  (t[i+1] == '\0') ? _last_char = t[0] : _last_char = t[i+1] , 0 );
            return ;
          }
          i++;
        }
      }
      
      _set_last_char ( c, 1);
    }
    
    char get_last_char(){ return _last_char; }
    
    String get_palavra( ) {
      return _palavra + _last_char;
    }
};


TecladoTelefone * teclado;

void setup() {
  Serial.begin(9600);
  
    // colunas INPUT
  pinMode(col1,INPUT);
  pinMode(col2,INPUT);
  pinMode(col3,INPUT);
  
  // linhas OUTPUT 
  pinMode(lin1,OUTPUT); 
  pinMode(lin2,OUTPUT);
  pinMode(lin3,OUTPUT); 
  pinMode(lin4,OUTPUT); 
  
  teclado = new TecladoTelefone();
}

char tecla_anterior = '\0';

void loop() {

  char tecla = get_tecla();
  
  if (tecla != tecla_anterior){
    if (tecla) {
      teclado->add(tecla);
    }
  }
  
  tecla_anterior = tecla;
  
  
  Serial.println(teclado->get_palavra());
}