Premesso che delle classi in C++ ho una conoscenza rudimentale, ho scritto una classe per gestire un link bit-sincrono/tempo-asincrono 4 fili (tx, rx, handshake) tra due Arduini (poi si può discutere sulla sensatezza, ma non è questo il quesito):
class Link4F
{
private:
byte ce_pin; // comando entrante
byte cu_pin; // comando uscente
byte tx_pin;
byte rx_pin;
byte blink_pin; // indica attivita` link, 255 non usato
byte master; // 1 master, 0 slave
byte txByte; // byte da trasmettere
boolean txByteBusy; // true = in trasmissione
byte rxByte; // byte ricevuto
boolean rxByteReady; // true = byte pronto
byte txBit_st; // stato processo trasmissione byte
byte txBit_cnt; // contatore processo trasm. byte
byte txBit_par; // bit di parita` pari in trasmissione
byte rxBit_st; // stato processo ricezione byte
byte rxBit_cnt; // contatore processo ricez. byte
byte rxBit_par; // bit di parita` pari in ricezione
byte blink_st; // stato processo blink attivita`
uint16_t blink_cnt; // contatore processo blink attivita`
byte syn_st; // stato sincronismo link
void syncMaster(); // handshake lato master
void syncSlave(); // handshake lato slave
void txBit(); // ricezione bit ad ogni fronte
void rxBit(); // trasmissione bit ad ogni fronte
void blink_(); // lampeggio per attivita` link
public:
void update(); // da chiamare continuamante
boolean rxAvailable(); // true se arrivato byte
boolean txAvailable(); // true se possibile trasmettere
void write(byte); // inizia trasmissione di un byte
byte read(); // legge byte arrivato
Link4F(byte, byte, byte, byte, byte, byte);
};
//-------------------------------------------------------------------------
Link4F::Link4F(byte cu, byte ce, byte tx, byte rx, byte blk, byte ma)
{
ce_pin = ce;
cu_pin = cu;
tx_pin = tx;
rx_pin = rx;
master = ma;
blink_pin = blk;
digitalWrite(cu, ma); // master parte con CU = 1, slave 0
pinMode(cu, OUTPUT);
pinMode(ce, INPUT);
digitalWrite(tx, 1); // tx pin inizialmente HIGH
pinMode(tx, OUTPUT);
pinMode(rx, INPUT);
if(blk != 255) pinMode(blk, OUTPUT);
rxByteReady = false;
txByteBusy = false;
txBit_st = 0;
rxBit_st = 0;
blink_st = 0;
blink_cnt = 600;
syn_st = ma; // master parte con stato 1
}
//-------------------------------------------------------------------------
void Link4F::write(byte n)
{
txByte = n;
txByteBusy = true;
}
//-------------------------------------------------------------------------
byte Link4F::read()
{
rxByteReady = false;
return rxByte;
}
//-------------------------------------------------------------------------
boolean Link4F::rxAvailable()
{
return rxByteReady;
}
//-------------------------------------------------------------------------
boolean Link4F::txAvailable()
{
return !txByteBusy;
}
//-------------------------------------------------------------------------
void Link4F::txBit()
{
switch(txBit_st)
{
case 0:
if(txByteBusy)
{
digitalWrite(tx_pin, 0); // start bit
txBit_par = 0;
txBit_cnt = 8;
txBit_st = 1;
}
break;
case 1:
if(txBit_cnt > 0)
{
byte b = (txByte & (1 << (txBit_cnt - 1))) != 0;
txBit_par ^= b;
digitalWrite(tx_pin, b);
txBit_cnt--;
}
else
{
digitalWrite(tx_pin, txBit_par); // parita` pari
txBit_st = 2;
}
break;
case 2:
digitalWrite(tx_pin, 1); // stop bit
txByteBusy = false;
txBit_st = 0;
}
}
//-------------------------------------------------------------------------
void Link4F::rxBit()
{
byte in = digitalRead(rx_pin);
switch(rxBit_st)
{
case 0:
if(in == 0) // se ricevuto start bit
{
rxBit_cnt = 8;
rxBit_par = 0;
rxBit_st = 1;
}
break;
case 1:
if(rxBit_cnt > 0)
{
rxByte = (rxByte << 1) | in;
rxBit_par ^= in;
rxBit_cnt--;
}
else
rxBit_st = (rxBit_par ^ in) ? 0 : 2;
break;
case 2:
if(in == 1) rxByteReady = true;
rxBit_st = 0;
}
}
//-------------------------------------------------------------------------
void Link4F::syncMaster() {
byte in = digitalRead(ce_pin);
if(syn_st == 0 && in == 0)
{
txBit();
blink_();
rxBit();
digitalWrite(cu_pin, 1);
syn_st = 1;
}
else if(syn_st == 1 && in == 1)
{
txBit();
blink_();
rxBit();
digitalWrite(cu_pin, 0);
syn_st = 0;
}
}
//-------------------------------------------------------------------------
void Link4F::syncSlave() {
byte in = digitalRead(ce_pin);
if(syn_st == 0 && in == 1)
{
txBit();
blink_();
rxBit();
digitalWrite(cu_pin, 1);
syn_st = 1;
}
else if(syn_st == 1 && in == 0)
{
txBit();
blink_();
rxBit();
digitalWrite(cu_pin, 0);
syn_st = 0;
}
}
//-------------------------------------------------------------------------
void Link4F::blink_()
{
if(blink_pin != 255 && --blink_cnt == 0)
{
blink_cnt = 600;
blink_st ^= 1;
digitalWrite(blink_pin, blink_st);
}
}
//-------------------------------------------------------------------------
void Link4F::update() {
if(master) syncMaster(); else syncSlave();
}
Funziona, posso creare un link con:
Link4F Link(CU_PIN, CE_PIN, TX_PIN, RX_PIN, BLINK_PIN, 1);
E usarne i metodi:
update
rxAvailable
txAvailable
write
read
Però i metodi usano delle variabili statiche. Cosa succede se creo più istanze? Vengono trattate come variabili di istanza indipendenti, o sono comuni a tutte le istanze della classe?
Poi, i due metodi write
e read
mi vengono evidenziati come nomi speciali, c'è qualche controindicazione ad usarli?
Per curiosità ho misurato che il link "a vuoto" genera spontaneamente una frequenza di handshake di poco più di 12kHz, pari a 24kbit/s full duplex.