Manual
do
Maker
.
com
Escrevi 2 artigos sobre esse multiplexador; o primeiro, fazendo leitura analógica; o segundo, leitura digital. Acontece que estava convicto de que o Arduino Pro Micro teria a mesma disposição do Arduino Leonardo, mas ledo engano, já que com isso tenho a oportunidade de mostrar a migração do código feito no Arduino Leonardo. Como faltou o GPIO 11 no Arduino Pro Micro, tive que reavaliar a situação.
Arduino é o nome da placa de prototipagem, infelizmente confundido até os dias de hoje com a MCU, que é Atmel. Sabendo o nome da MCU (está escrito sobre ela, seja qual for), basta procurar no Google pelo datasheet. O link do datasheet, para os interessados.
O grande susto foi quando, ao perceber a diferença, ter olhado para o pinout do Arduino Pro Micro, e perceber que o número de GPIO é menor, além de distribuídos em poucos bits. Por sorte, os pinos analógicos estão na sequência, do 0 ao 3 - digo, no registrador PORTF. Desse modo foi possível manter o código "econômico" dos artigos anteriores, mudando apenas o registrador. Mas primeiro tive que me certificar de que seria possível utilizar o ADC como pino de saída digital. No datasheet:
A importância dos bits em sequência se dá ao fato de estarmos utilizando bitwise para configurar os pinos, e também para selecionar o canal do CD74HC4067. De outro modo, seria mais viável utilizar as funções da API do Arduino, mas o código cresceria um bocado.
Quando procurei pela sequência de pinos no mesmo registrador, me deparei também com a ausência de dois bits: PF2 e PF3.
É a primeira vez que preciso ler o datasheet de um Atmega, no caso, para me certificar do fato de não ter os bits PF2 e PF3. No datasheet está claro que não está no pinout, mas o bit obviamente existe, senão o registrador não iria até PF7.
Tendo resolvido essas questões, e coincidentemente a sequência sendo a mesma do PORTB (os 4 bits mais significativos), só tive que mudar a nomenclatura. Daqui em diante, os artigos relacionados serão feitos no Arduino Pro Micro, com base no código que segue:
#define READ_MUX_PIN 9
uint16_t pb_values = 0;
void handler(uint8_t value){
//agora não tem propósito, mas essa função fará sentido em outro artigo
Serial.print(value,BIN);
Serial.print(" - ");
Serial.println(pb_values);
}
uint8_t getValues(){
for (uint8_t i=0;i<16;i++){
PORTF |= (i<<4);
delay(1);
pb_values = digitalRead(READ_MUX_PIN);
Serial.print("C");
Serial.print(i);
Serial.print(":");
handler(pb_values);
PORTF &= ~(i<<4);
delay(1);
}
}
void setup() {
DDRF = 0xF<<4;
PORTF &= ~(0xF<<4);
pinMode(READ_MUX_PIN,INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
getValues();
delay(2000);
}
Pode usar o PORTB tranquilamente, o registrador é o mesmo para o atmega328p:
Esse multiplexador extremamente barato você encontra na Eletrônica Mangili, que tem outros itens interessantes em sua lista, mas o link direto para o multiplexador é esse.
Para fazer o teste de OUTPUT, coloquei um LED em VCC e GND ao pino 0 do multiplexador. Criei um código simples incrementado ao disposto mais acima, com a função handler fazendo a interação. Ao abrir o monitor serial, coloque "nenhum final de linha" na caixa de seleção do rodapé. Se digitar 0, o LED deve se acender. Se digitar outro número (até 9), devolverá o estado do pino. Se não tiver colocado GND em nenhum pino, qualquer número maior que 0 deve retornar 1. Se estiver com algum pino menor que 9 deve retornar 0.
Como coloquei apenas o pino 0 com um LED, fiz uma lógica na função loop() para acender o LED se digitar 0. Quando o número for maior que 0, o LED se apagará.
#define ENABLE_MUX_PIN 8
#define READ_MUX_PIN 9
uint16_t pb_values = 0;
void handler(bool do_read,uint8_t channel, bool turn_on){
if (do_read){
Serial.println("reading...");
pinMode(READ_MUX_PIN,INPUT_PULLUP);
//pinMode(ENABLE_MUX_PIN,INPUT);
//digitalWrite(ENABLE_MUX_PIN,LOW);
PORTF |= (channel<<4);
delay(1);
pb_values = digitalRead(READ_MUX_PIN);
Serial.println(pb_values);
PORTF &= ~(channel<<4);
return;
}
if (!turn_on){
PORTF |= (channel);
}
else{
PORTF &= ~(channel);
}
pinMode(READ_MUX_PIN,OUTPUT);
digitalWrite(READ_MUX_PIN,LOW);
pinMode(ENABLE_MUX_PIN,OUTPUT);
digitalWrite(ENABLE_MUX_PIN,LOW);
}
uint8_t getValues(){
for (uint8_t i=0;i<16;i++){
PORTF |= (i<<4);
delay(1);
pb_values = digitalRead(READ_MUX_PIN);
Serial.print("C");
Serial.print(i);
Serial.print(":");
Serial.println(pb_values);
PORTF &= ~(i<<4);
delay(1);
}
}
void setup() {
DDRF = 0xF<<4;
PORTF &= ~(0xF<<4);
pinMode(READ_MUX_PIN,INPUT_PULLUP);
pinMode(ENABLE_MUX_PIN,OUTPUT);
Serial.begin(9600);
delay(1000);
}
void loop() {
//getValues();
if (Serial.available()){
uint8_t value = Serial.read()-48;
if (value == 0){
handler(false, 0, true);
}
else{
handler(true, value, false);
}
}
delay(2000);
}
Primeiro, não é possível acionar mais de um pino de uma vez. Lembre-se que essa placa é um multiplexador. Se houver a necessidade de manter continuamente o estado de mais de um pino, use um PCF8574, por exemplo.
Já se a intenção é só ligar diversos LEDs de uma vez, basta fazer um loop nos canais desejados com delay bem baixo. É como fazemos no display de 7 segmentos. A impressão de que estarão ligados todos ao mesmo tempo se chama POV (Persistence Of Vision).
Como deixei o mapa de pinos do Leonardo, fica como referência também o do Arduino Pro Micro:
Até a próxima!
Revisão: Ricardo Amaral de Andrade
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.