@MarekR22: brak testów
Łatwo się pisze a w sumie ciekaw jestem w jaki sposób podszedł byś do pisania testów funkcji, których zadaniem jest dekodowanie kodu RC5 czy programowania potencjometru głośności. A to w sumie "ideowo" 90% tego programu.
Bez symulowania urządzenia albo zbudowania warstwy abstrakcji dla sprzętu słabo to widzę. Pisanie symulatora urządzenia raczej jest całkowicie bez sensu. 100 razy lepiej poświęcić czas na testy rzeczywistych urządzeń. Inna sprawa to to, że program i tak już zajmuje 85% dostępnej pamięci więc dodanie jakiejkolwiek kolejnej abstrakcji raczej by spowodowało, że nie zmieści się do uC.
Dekodowanie RC5
/*
Biblioteka dekodująca kod RC-5 bez uzycia przerwań i timera.
UWAGA - funkcja receiveRC5 jest kodem "blokującym" na czas dekodowania/odczytu sygnału z pilota
więc w przypadku poolingu należy brać to pod uwagę.
MTSz 2018
Testowane jedynie przy FCPU = 8 000 000 Hz
*/
#define REMOTE_RC5_PORT PIND
#define REMOTE_RC5_PIN_VALUE bit_5_value
class classRemoteRC5{
public:
static const uint16_t SHORT_IMPULSE_TIME_MIN = 444 ;
static const uint16_t SHORT_IMPULSE_TIME_MAX = 1333 ;
static const uint16_t LONG_IMPULSE_TIME_MIN = 1334 ;
static const uint16_t LONG_IMPULSE_TIME_MAX = 2222 ;
static const uint16_t IMPULSE_TIMEOUT = 2223 ;
static const uint16_t IMPULSE_TIME_SHORT = 1 ;
static const uint16_t IMPULSE_TIME_LONG = 2 ;
static const uint16_t IMPULSE_TIME_ERROR = 0xff ;
static const uint16_t DECODE_ERROR = 0xffff ;
volatile uint16_t value ;
volatile uint8_t command ;
volatile uint8_t address ;
volatile uint8_t toggle ;
bool isFrameBegin(){
if ( ( REMOTE_RC5_PORT & REMOTE_RC5_PIN_VALUE ) == 0 ) return true ;
return false ;
}
uint8_t getChangeTime() {
uint16_t time = 0 ;
uint8_t cuurPinValue = REMOTE_RC5_PORT & REMOTE_RC5_PIN_VALUE ;
while ( ( REMOTE_RC5_PORT & REMOTE_RC5_PIN_VALUE ) == cuurPinValue ){
_delay_us(55);
time = time + 50 ;
if ( time >= IMPULSE_TIMEOUT ) return IMPULSE_TIME_ERROR ; // timeout
}
if ( ( time > SHORT_IMPULSE_TIME_MIN ) && ( time < SHORT_IMPULSE_TIME_MAX ) ) return IMPULSE_TIME_SHORT ;
if ( ( time > LONG_IMPULSE_TIME_MIN ) && ( time < LONG_IMPULSE_TIME_MAX ) ) return IMPULSE_TIME_LONG ;
return IMPULSE_TIME_ERROR;
}
uint16_t readFrame() {
//
// getValue uruchamiamy po wykryciu pierwszego opadającego zbocza z TSOP.
// musi być wywołana tak aby załapać się na SHORT_IMPULSE_TIME_MIN
//
uint8_t impulseType = 0 ;
//////////////////////////////////////////////////////////////////////////////////////////////////////
// teraz w zależności od długości przychodzących impulów będę
// dekodował kolejne 12 bitów danych
//
uint8_t i = 0 ;
uint8_t lastState = 0 ;
uint8_t nextBit = 0 ;
value = 0 ;
for ( i=0; i<13; i++ ){
lastState = ( REMOTE_RC5_PORT & REMOTE_RC5_PIN_VALUE ) ;
impulseType = getChangeTime();
if ( impulseType == IMPULSE_TIME_ERROR ) return DECODE_ERROR ;
if ( lastState == 0 ){
if ( impulseType == IMPULSE_TIME_SHORT ) nextBit = 1 ;
if ( impulseType == IMPULSE_TIME_LONG ) nextBit = 0 ;
}else{
if ( impulseType == IMPULSE_TIME_SHORT ) nextBit = 0 ;
if ( impulseType == IMPULSE_TIME_LONG ) nextBit = 1 ;
}
// ponieważ był impuls krótki i jestem na początku bitu to musze przesunąc się do połowy bitu
if (( impulseType == IMPULSE_TIME_SHORT )&&(i<12)){
impulseType = getChangeTime();
// ponieważ byłem na początku bitu to spodziewam się impulsu krótkiego.
if (( impulseType == IMPULSE_TIME_ERROR )||( impulseType == IMPULSE_TIME_LONG )) return DECODE_ERROR ;
}
value = value * 2 ;
value = value + nextBit ;
}
_delay_us( LONG_IMPULSE_TIME_MAX );
//
// wynik odczytu zapisywany jest tekże w zmiennych globalnych:
//
command = ( value & 0b0000000000111111 ) ;
address = ( value & 0b0000011111000000 ) / 64 ;
toggle = ( value & 0b0000100000000000 ) / 2048 ;
return value;
}
};
Programowanie potencjometru:
class classDigitalPotFM62429{
public:
static const int8_t MAX_ATTENTUATION = 84 ;
static const int8_t MUTE_ATTENTUATION = 84 ;
void set ( uint8_t attLevel, uint8_t channel, uint8_t both ) {
attLevel = this->MUTE_ATTENTUATION - attLevel ;
if ( both > 1 || channel > 1 ) return ; // są tylko 2 kanały
if ( attLevel > this->MAX_ATTENTUATION ) attLevel = this->MUTE_ATTENTUATION ; // blokada na maksymalne tłumienie.
uint16_t dataToSend = 0 ; // Dane / bity do wysłania
// Przygotowujemy 11 bitów zgodnie ze specyfikacją układu
dataToSend |= channel ; // numer kanału
dataToSend |= ( both << 1 ); // 0 = oba kanały, 1 = każdy kanał osobno
if ( attLevel <= this->MAX_ATTENTUATION ) {
dataToSend |= ( 21 - ( attLevel / 4 ) ) << 2 ; // ATT1
dataToSend |= ( 3 - ( attLevel % 4 ) ) << 7 ; // ATT2
}
dataToSend |= 0b11 << 9; // ostatnie bity = 11
//
// wysyłamy dane
for ( uint8_t i = 0; i <= 10; i++ ) {
_delay_us( 3 );
PORT_VOL_DATA &= ~VOL_DATA ; // DATA = 0
_delay_us( 3 );
PORT_VOL_CLK &= ~VOL_CLK ; // CLK = 0
_delay_us( 3 );
if ( ( ( dataToSend >> i ) & 0x01 ) == 1 ) {
PORT_VOL_DATA |= VOL_DATA ; // DATA = 1
} else {
PORT_VOL_DATA &= ~VOL_DATA ; // DATA = 0
}
_delay_us( 3 );
PORT_VOL_CLK |= VOL_CLK ; // CLK = 1
}
_delay_us( 3 );
PORT_VOL_DATA |= VOL_DATA ; // DATA = 1
_delay_us( 3 );
PORT_VOL_CLK &= ~VOL_CLK ; // CLK = 0
_delay_us( 3 );
return;
}
};