Manual
do
Maker
.
com
O Digispark é viciante, principalmente esse modelo que não necessita de cabo, basta encaixá-lo na USB do computador para programá-lo ou em um carregador de celular para utilizá-lo. O dispositivo é tão pequeno que tive várias ideias pra ele e vou escrevendo conforme possível. Dessa vez, vamos ver como expandir GPIO do Digispark.
Se você ainda não utilizou o Digispark e/ou não o conhece, sugiro esses artigos que escrevi a respeito:
Apesar de tanta praticidade, o lado negativo de seu tamanho reduzido está no conjunto reduzido de recursos, dentre eles, os pinos. E é esse o problema que iremos contornar nesse artigo.
Se você precisa de mais pinos digitais, você pode utilizar um PCF8574 como entrada e saída. Com ele você expande de 8 portas a até 127x8 portas, pois utiliza-se do barramento I²C, de modo que você pode tê-los interconectados.
Com um PCF8574 você pode ter entradas e saídas em apenas 1 circuito e se desejar, pode utilizar interrupção, pois o PCF8574 conta com um pino extra apenas para interrupção. Assim, invés de ficar fazendo polling, você pode deixar a MCU sem processamento e reagindo somente no momento de um evento. Alguns artigos que escrevi sobre o PCF8574:
Se sua necessidade é leitura analógica, do mesmo modo poderá fazê-lo com um módulo ADS1115. Trata-se de um módulo com excelente resolução (16 bits!) e também utiliza-se do barramento I²C. Uma introdução ótima a respeito pode ser vista nesse artigo que escrevi a respeito.
Essa referências anteriormente citadas são ótimas e certamente resolverão qualquer necessidade, mas atualmente o Digispark não precisa de nenhum port da biblioteca I²C do Arduino porque ele já vem funcionando com uma versão compatível do Wire, inclusive você encontra nos exemplo da IDE do Arduino (após configurar o suporte à Digispark, descrito nesse artigo)
Os pinos relacionados ao I²C são Pin0 para SDA e Pin2 para SCK. Sobre a board você encontra um silk com a nomeclatura dos pinos, não tem erro.
Antes que você compre um ADS1115, tenha em mente que o Attiny faz leitura analógica também, só use o ADS1115 para o caso de precisar expandir.
O wiring você já sabe, como citado mais acima; Pin0 para SDA e Pin2 para SCK. Além desses dois, você deve alimentar o PCF8574 com 5V e também conectar o GND.
Um código bastante simples mas que servirá de exemplo é esse a seguir. Você precisará incluir a biblioteca TinyWireM.h, ajustar o endereço do PCF8574 e iniciar a comunicação. A comunicação é por I²C e você terá que iniciar a transmissão, escrever e finalizar a conexão. Quando quiser ler, simplesmente chame o método passando o endereço como referência, então pegue o valor com o método .receive(). Para não ficar repetindo linha, é uma boa opção criar uma função para escrever e uma para ler, só pra facilitar. No exemplo não seria necessário, mas vou deixar pronto para lhe poupar trabalho, ok?
Utilize primeiramente o scanner I²C (dos exemplos da IDE do Arduino para o Digispark) caso não saiba o endereço em que se encontra seu PCF8574. Olhando para o PCF8574 com os pinos voltados para a esquerda, os jumpers todos para a direita representa o endereço 0x20. Caso deseje utilizar mais que um PCF8574 simultaneamente, o scanner ajudará identificá-los, apenas lembre-se de não deixá-los ambos com o mesmo endereço. Vou deixar o código caso tenha preguiça de procurá-lo:
#include <Wire.h>
#include <DigiKeyboard.h>
void setup()
{
Wire.begin();
DigiKeyboard.delay(3000);
DigiKeyboard.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int nDevices;
DigiKeyboard.println("Scanning...");
nDevices = 0;
for (address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
DigiKeyboard.print("I2C device found at address 0x");
if (address < 16)
DigiKeyboard.print("0");
DigiKeyboard.print(address, HEX);
DigiKeyboard.println(" !");
nDevices++;
}
else if (error == 4)
{
DigiKeyboard.print("Unknow error at address 0x");
if (address < 16)
DigiKeyboard.print("0");
DigiKeyboard.println(address, HEX);
}
}
if (nDevices == 0)
DigiKeyboard.println("No I2C devices found\n");
else
DigiKeyboard.println("done\n");
DigiKeyboard.delay(5000); // wait 5 seconds for next scan
}
lembre-se desse artigo no que se refere ao debug do Digispark; ele não tem monitor serial, portanto você deverá abrir um editor de texto qualquer e colocá-lo em foco. O Digispark atuará como um teclado USB e "escreverá" o resultado do scan no editor de texto. Depois de identificar o endereço, adapte-o ao código a seguir.
Um tutorial bem elaborado sobre a manipulação de endereços pode ser vista aqui, recomendo a leitura. Se não estiver com vontade de fazer a leitura desse outro artigo ou já tiver conhecimento o suficiente para interação com o PCF8574, então siga adiante. Apesar desse artigo ser sobre PCF8574 com Raspberry, cito características importantes dele, como por exemplo, para acender um LED você deve aterrá-lo no PCF8574 invés de alimentá-lo a partir do PCF8574 porque o dispositivo não tem corrente suficiente para "drivar" um LED. Como inicialmente todos os pinos do PCF8574 estão em HIGH, você não terá problemas em controlar o LED com estado inicial desligado.
Vou deixar a mesma tabela que montei no artigo supracitado para utilizar com referência para nosso teste.
Addr | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
0xF0 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02 | 0x01 | |
0x20 | ||||||||
0x22 | ||||||||
0x24 | ||||||||
8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
Como você pode notar na tabela, os endereços estão dispostos nas base decimal, hexadecimal e a posição do bit. Na coluna na esquerda "Addr" são os endereços de 3 PCF8574 que utilizei em outro teste. Então, se você quiser acender o LED que está no pino 4 do PCF8574 que está no endereço 0x20, basta enviar 0x08 para 0x20. Vamos ver isso no código?
#include <Wire.h>
void setup()
{
Wire.begin();
}
void loop()
{
Wire.beginTransmission(0x20);
Wire.beginTransmission(0x20);
Wire.send(0b00000000);
Wire.endTransmission();
delay(1000);
Wire.beginTransmission(0x20);
Wire.send(0b00000001);
Wire.endTransmission();
delay(1000);
Wire.beginTransmission(0x20);
Wire.send(0b00000010);
Wire.endTransmission();
delay(1000);
Wire.beginTransmission(0x20);
Wire.send(0b00000011);
Wire.endTransmission();
delay(1000);
}
O código está pra lá de horroroso, mas é só pra mostrar a lógica; inicia a transmissão pro endereço selecionado, envia o dado, encerra a transmissão. Ponto.
Espero que lhe tenha sido útil esse pequeno tutorial.
Inscreva-se no nosso canal Manual do Maker no YouTube.
Também estamos no Instagram.
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.