O que acontecerá quando eu usar um número de PIN inválido?


Respostas:


9

O compilador não detectará nenhum erro e o código será compilado e executado. Portanto, para ver o que acontece, precisamos explorar a mágica dos bastidores. Para um resumo, pule para o final.


A segunda linha do seu código é onde a mágica acontecerá e é aí que precisamos nos concentrar.

pinMode(pin, OUTPUT);

A parte pinModerelevante para esta discussão é:

void pinMode(uint8_t pin, uint8_t mode) 
{

    uint8_t bit = digitalPinToBitMask(pin); //The first instance where pin is used
    uint8_t port = digitalPinToPort(pin);

    if (port == NOT_A_PIN) return;

//Do something
}

(A implementação completa pode ser encontrada em fiação_digital.c )

Então, aqui, digitalPinToBitMaskparece estar usando pinpara calcular um bit intermediário. Explorando ainda mais, digitalPinToBitMaské uma macro definida em Arduino.hcuja definição é esta linha única:

#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )

Este forro de aparência estranha faz uma tarefa muito simples. Ele indexa o elemento P th na matriz digital_pin_to_bit_mask_PGMe o retorna. Essa matriz digital_pin_to_bit_mask_PGMé definida no pins_arduino.hmapa de pinos da placa específica que está sendo usada.

const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
    _BV(0), /* 0, port D */
    _BV(1),
    _BV(2),
    _BV(3),
    _BV(4),
    _BV(5),
    _BV(6),
    _BV(7),
...
};

Essa matriz possui 20 elementos no total, então estamos sem sorte. 999 indexará um local de memória na memória flash fora dessa matriz, levando a um comportamento imprevisível. Ou será?

Ainda temos outra linha de defesa contra a anarquia de tempo de execução. É a próxima linha da função pinMode:

uint8_t port = digitalPinToPort(pin);

digitalPinToPortnos leva por um caminho semelhante. É definido como uma macro junto com digitalPinToBitMask. Sua definição é:

#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )

Agora, indexamos o elemento P th , digital_pin_to_port_PGMque é uma matriz definida no mapa de pinos:

const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
    PD, /* 0 */
    PD,
    ....
    PC,
    PC,
};

Essa matriz contém 20 elementos, portanto, 999 está novamente fora de alcance. Novamente, este comando lê e retorna um valor da memória flash cujo valor não podemos ter certeza. Isso levará novamente a um comportamento imprevisível a partir de agora.

Ainda existe uma última linha de defesa. Esse é o ifcheck-in pinModeno valor de retorno de digitalPinToPort:

if (port == NOT_A_PIN) return;

NOT_A_PINé definido como 0 pol Arduino.h. Portanto, se o byte retornado de digitalPinToPortfor zero, pinModefalhará e retornará silenciosamente.

De qualquer forma, pinModenão pode nos salvar da anarquia. 999 está destinado a resultar em desgraça.


TL; DR, o código será executado e o resultado será imprevisível. Provavelmente, nenhum pino será definido OUTPUTe digitalWritefalhará. Se você tiver uma sorte excepcionalmente ruim, um pino aleatório pode ser definido como OUTPUTe digitalWritepode ser definido como HIGH.


É interessante que não haja verificação de limites. O digitalWrite é tão lento e volumoso de qualquer maneira, não seria estranho colocar em tempo de compilação ou em verificações de tempo de execução.
— Cybergibbons

Se todos os pinos do arduino estiverem em um intervalo contíguo, eles não poderiam substituir a porta == não uma verificação de pinos por um pino> verificação BOARD_MAX_PIN, em que o pino máximo da placa é definido em algum arquivo de cabeçalho com base em algum ifdef que detecta a placa?
— EternityForest

Você está esquecendo que o 999 não pode ser representado em um, uint8_tpelo que seria primeiro convertido em 231 pela chamada de código pinMode. O resultado final é o mesmo: pinModee digitalWriteterá um comportamento imprevisível e poderá estragar partes aleatórias da memória se você as chamar com um argumento incorreto.
— David Grayson

3

Nas bibliotecas padrão, existem macros projetadas para converter pinos em portas, que são usadas na montagem. Aqui estão eles para o Uno do Arduino 1.0.5:

#define digitalPinToPCICR(p)    (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0))
#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1))
#define digitalPinToPCMSK(p)    (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0))))
#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14)))

Há mais, mas não vou mostrá-las aqui.

Acredito que seu programa subtraia 14 de 999, o que ainda seria muito grande para o submarino. Ele tentaria apontar para o 985º elemento da digital_pn_to_bit_mask_PGMmatriz, que contém apenas 20 elementos. Provavelmente, isso acabaria atrapalhando o Arduino, apontando para um ponto aleatório no programa.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.