2 de março de 2021

Validador de CPF

Validar números de CPF utilizando um Arduino UNO.


O algoritmo de validação de números de CPF é interessante para trabalharmos o aprendizado em lógica de programação.

Vamos trabalhar essa lógica no Arduino UNO, montando um validador com display LCD e um teclado numérico.

O CPF é composto por 9 números e mais 2 dígitos verificadores que são indicados após uma barra. Totalizando 11 números.

A partir dos 9 primeiros números calculamos quais serão os 2 dígitos verificadores e, dessa forma, podemos identificar se é um valor de CPF válido ou não.

Vamos tratar cada dígito da seguinte forma: ABCDEFGHI-JK. Onde após a barra estão J e K, representando os dígitos verificadores.

Para calcularmos o primeiro dígito verificador (J), devemos multiplicar cada número pelo valor respectivo na tabela abaixo e somar os resultados.

A

B

C

D

E

F

G

H

I

10

9

8

7

6

5

4

3

2

(A x 10) + (B x 9) + (C x 8) + (D x 7) + (E x 6) + (F x 5) + (G x 4) + (H x 3) + (I x 2)

Como exemplo, vamos utilizar os números 5 1 8 1 3 3 7 2 5 - J K

O primeiro número deve ser multiplicado por 10, o segundo número multiplicado por 9, o terceiro número multiplicado por 8, e assim até o número na posição 9, que deverá ser multiplicado por 2.
Os resultados das multiplicações devem ser somados.

(5x10) + (1x9) + (8x8) + (1x7) + (3x6) + (3x5) + (7x4) + (2x3) + (5x2) = 207

O resultado obtido deverá ser dividido por 11, considerando apenas o valor inteiro do resto da divisão.

207 divido por 11 temos como quociente o valor 18 e como resto o valor 9.

O valor do primeiro dígito (J) é: caso o valor do resto da divisão seja 0 ou 1, devemos considerar o valor 0. Caso contrario, subtrai-se o valor obtido de 11. No nosso exemplo, será 11 - 9 = 2.

O nosso exemplo agora é 5 1 8 1 3 3 7 2 5 - 2 K

Para calcularmos o segundo dígito verificador (K), devemos multiplicar cada número pelo valor respectivo na tabela abaixo e somar os resultados. Como fizemos para o primeiro dígito, porém agora temos um número a mais incluído na tabela, o primeiro dígito verificador (J).

A

B

C

D

E

F

G

H

I

J

11

10

9

8

7

6

5

4

3

2

(5x11) + (1x10) + (8x9) + (1x8) + (3x7) + (3x6) + (7x5) + (2x4) + (5x3) + (2x2) = 246

Devemos seguir as mesmas regras do primeiro dígito.

246 divido por 11 temos como quociente o valor 22 e como resto o valor 4.

O valor do segundo dígito (K) é: caso o valor do resto da divisão seja 0 ou 1, devemos considerar o valor 0. Caso contrario, subtrai-se o valor obtido de 11. No nosso exemplo, será 11 - 4 = 7.

Agora temos os dois dígitos verificadores do nosso exemplo: 5 1 8 1 3 3 7 2 5 - 2 7

Outra regra da validação do CPF: os números não podem ser todos iguais.

No projeto foi utilizado um Arduino UNO, um display LCD com módulo I2C e um teclado matricial.


 Segue o esquema elétrico e o código fonte:


 
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
/*---------------------------------------------------------
  Programa : VALIDADOR DE CPF
  Autor    : Fellipe Couto [ http://www.efeitonerd.com.br ]
  Data     : 01/03/2021
  ---------------------------------------------------------*/
#include <LiquidCrystal_I2C.h> //LCD I2C [ https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library ]

LiquidCrystal_I2C lcd(0x3F, 16, 2); //LCD 16x2 no endereço 0x3F
String cpf = ""; //Variável para receber o CPF digitado

/*--- SETUP ---*/
void setup() {
  //Inicializa o lcd
  lcd.begin();
  lcdBegin();
}

/*--- LOOP PRINCIPAL ---*/
void loop() {
  String k = keypad(); //Retorna o valor da tecla pressionada na variável k
  if (k != "" && k != "*" && k != "#") {
    lcd.print(k);
    cpf += k;
    if (cpf.length() == 11) {
      delay(500);
      lcd.setCursor(0, 1);
      if (checkCPF(cpf)) {
        lcd.print(">>>> VALIDO!");
      } else {
        lcd.print(">>>> INVALIDO");
      }
      delay(3000);
      cpf = "";
      lcdBegin();
    }
  }
}

/*--- MENSAGEM PRINCIPAL NO LCD ---*/
void lcdBegin(){
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("CPF: ");
}

/*--- VALIDA O CPF ---*/
bool checkCPF(String cpf) {
  if (cpf.length() != 11) return false;
  int n1 = 0;
  int n2 = 0;
  bool equalNum = true;
  for (int i = 1; i <= 9; i++) {
    n1 += cpf.substring(i - 1, i).toInt() * (11 - i) ;
    n2 += cpf.substring(i - 1, i).toInt() * (12 - i) ;
    if (cpf.substring(i - 1, i).toInt() != cpf.substring(i, i + 1).toInt()) equalNum = false;
  }
  if (equalNum) return false;
  n1 = 11 - (n1 % 11);
  if (n1 > 9) n1 = 0;
  n2 += n1 * 2;
  n2 = 11 - (n2 % 11);
  if (n2 > 9) n2 = 0;
  if (cpf != cpf.substring(0, 9) + String(n1) + String(n2)) return false;
  return true;
}

/*--- RETORNA A TECLA PRESSIONADA NO TECLADO ---*/
String keypad() {
  const int totalLines = 4;   //Total de linhas do teclado
  const int totalColumns = 3; //Total de colunas do teclado
  const int lines[totalLines] = {2, 3, 4, 5};  //Portas de conexão das linhas
  const int columns[totalColumns] = {6, 7, 8}; //Portas de conexão das colunas
  const String keyBoard[totalLines][totalColumns] = { //Disposição das teclas
    {"1", "2", "3"},
    {"4", "5", "6"},
    {"7", "8", "9"},
    {"*", "0", "#"}
  };
  const String keyPressed = "";
  for (int i = 0; i < totalLines; i++) { //Configura os pinos das linhas como saída
    pinMode(lines[i], OUTPUT);
  }
  for (int i = 0; i < totalColumns; i++) { //Configura os pinos das colunas como entrada com pull-up
    pinMode(columns[i], INPUT_PULLUP);
  }

  for (int w = 0; w < totalLines; w++) { //Varre as linhas
    for (int i = 0; i < totalLines; i++) {
      digitalWrite(lines[i], HIGH);
    }
    digitalWrite(lines[w], LOW); //Uma linha LOW por vez
    for (int c = 0; c < totalColumns; c++) { //Varre as colunas
      while (digitalRead(columns[c]) == LOW) {
        keyPressed = keyBoard[w][c];
      }
    }
  }
  delay(50);
  return keyPressed;
}

Um comentário: