/*
Controladora de mouse implementada utilizando um AtTiny85 e um registrador de
deslocamento (shift register) PISO (Parallel In Serial Out)
Para utilização de um protocolo de comunicação serial com fios diferente
do SPI, orientado a interrupts (interrupt-driven), utilizando apenas 2 linhas de
comunicação, com o SCK e o MOSI compartilhando a mesma linha, através da utilização de
uma técnica de "clock aperiódico", e o MISO e a interrupt request compartilhando
a outra linha.
Esta controladora é o Slave, o Master seria o Arduino UNO no projeto
principal em https://wokwi.com/projects/386223500534727681
Autor: Dante Meira
*/
// Como o Wokwi não tem diodo, a solução é utilizar duas portas NOT encadeadas
// fazendo o papel de diodo, para evitar que a eletricidade flua em sentido indesejado
// Poderiam ser utilizadas portas OR, mas a solução mais barata é
// usar diodos (o 1n4007 custa R$ 0,18 a unidade)
char buffer[5] = {0, 0, 0, 0, 0};
// o buffer de comunicação serial armazena as seguintes informaçôes:
// em 0 - o mouse enviou um sinal para mover o ponteiro uma unidade para cima
// em 1 - o mouse enviou um sinal para mover o ponteiro uma unidade para baixo
// em 2 - o mouse enviou um sinal para mover o ponteiro uma unidade para a direita
// em 3 - o mouse enviou um sinal para mover o ponteiro uma unidade para a esquerda
// em 4 - o mouse enviou um sinal de click
char position = 0;
void setup() {
pinMode(PB0, INPUT);
pinMode(PB1, OUTPUT);
pinMode(PB3, OUTPUT); // clock do shift register
pinMode(PB5, OUTPUT); // latch do shift register
GIMSK = B00100000 ; // habilita interrupts de Pin Change
PCMSK = B00000001 ; // habilita PCINT0
sei(); // habilita interrupts
while(true){ // loop infinito fazendo nada, só aguardando interrupts
asm volatile( "nop \n\t" );
}
}
ISR(PCINT0_vect){ // ISR pin change 0
// checando o shift register para descobrir quem causou a interrupt
if( (digitalRead(PB0)) == HIGH) { // borda subindo
digitalWrite(PB5, LOW);
digitalWrite(PB5, HIGH); // fazendo latch paralelo no shift register
asm volatile( "nop \n\t" );
if( (digitalRead(PB4)) == HIGH) { // lendo D7 no PB4 através de Q7
// interrupt causada pelo Master enviando pulso na linha OUVE (azul)
if(buffer[position] == 0){
digitalWrite(PB1, LOW);
}else{
digitalWrite(PB1, HIGH);
}
buffer[position] = 0;
if(position < 4) { position++; }
} else{
// só continua a checar os outros inputs se a interrupt não foi causada pelo Master
digitalWrite(PB3, HIGH);
digitalWrite(PB3, LOW); // clock para mudar de D7 para D6 na saída Q7
asm volatile( "nop \n\t" );
if( (digitalRead(PB4)) == HIGH) { // lendo D6 no PB4 através de Q7
buffer[1] = 1; // para baixo
position = 0;
// usando a linha "Fala" para avisar o Master que ocorreu um evento de mouse
digitalWrite(PB1, HIGH);
digitalWrite(PB1, LOW);
}
digitalWrite(PB3, HIGH);
digitalWrite(PB3, LOW); // clock para mudar de D6 para D5 na saída Q7
asm volatile( "nop \n\t" );
if( (digitalRead(PB4)) == HIGH) { // lendo D5 no PB4 através de Q7
buffer[2] = 1; // para a direita
position = 0;
// usando a linha "Fala" para avisar o Master que ocorreu um evento de mouse
digitalWrite(PB1, HIGH);
digitalWrite(PB1, LOW);
}
}
digitalWrite(PB3, HIGH);
digitalWrite(PB3, LOW); // clock para mudar de D5 para D4 na saída Q7
asm volatile( "nop \n\t" );
if( (digitalRead(PB4)) == HIGH) { // lendo D4 no PB4 através de Q7
buffer[3] = 1; // para a esquerda
position = 0;
// usando a linha "Fala" para avisar o Master que ocorreu um evento de mouse
digitalWrite(PB1, HIGH);
digitalWrite(PB1, LOW);
}
digitalWrite(PB3, HIGH);
digitalWrite(PB3, LOW); // clock para mudar de D4 para D3 na saída Q7
asm volatile( "nop \n\t" );
if( (digitalRead(PB4)) == HIGH) { // lendo D3 no PB4 através de Q7
buffer[0] = 1; // para cima
position = 0;
// usando a linha "Fala" para avisar o Master que ocorreu um evento de mouse
digitalWrite(PB1, HIGH);
digitalWrite(PB1, LOW);
}
digitalWrite(PB3, HIGH);
digitalWrite(PB3, LOW); // clock para mudar de D3 para D2 na saída Q7
// em D2 poderia ser ligado o botão esquerdo do mouse
digitalWrite(PB3, HIGH);
digitalWrite(PB3, LOW); // clock para mudar de D2 para D1 na saída Q7
// em D1 poderia ser ligado o scroll up da scroll wheel
digitalWrite(PB3, HIGH);
digitalWrite(PB3, LOW); // clock para mudar de D1 para D0 na saída Q7
// em D0 poderia ser ligado o scroll down da scroll wheel
digitalWrite(PB3, HIGH);
digitalWrite(PB3, LOW); // clock para mudar de D0 para DS (nono input) na saída Q7
asm volatile( "nop \n\t" );
if( (digitalRead(PB4)) == HIGH) { // lendo DS no PB4 através de Q7
buffer[4] = 1; // click
position = 0;
// usando a linha "Fala" para avisar o Master que ocorreu um evento de mouse
digitalWrite(PB1, HIGH);
digitalWrite(PB1, LOW);
}
}else{ // borda descendo
digitalWrite(PB5, LOW);
digitalWrite(PB5, HIGH); // fazendo latch paralelo no shift register
}
}
ERC Warnings
not11:OUT: Multi-driven net on pin
not1:OUT: Multi-driven net on pin
not3:OUT: Multi-driven net on pin
not5:OUT: Multi-driven net on pin
not7:OUT: Multi-driven net on pin
not9:OUT: Multi-driven net on pin