O que acontece quando escrevemos 0 para um GPIO
Pergunta
Eu quero saber o que acontece quando nós escrevemos "0" para um GPIO (a intenção real é para puxar para baixo a saída).
Eu não tenho certeza se o controlador de puxa para baixo o GPIO pin e liga-se internamente para a terra ou ele simplesmente desliga o pino internamente e faz com que ele desconectado do periférico (LED) conectado a ele a partir do micro controlador.
A tarefa real para mim é:
Eu tenho que enviar a um 8 bits de dados a partir de 4 pinos gpio(Ex PORTA4-7).Então, para fazer isso eu tenho que escrever o maior bits(D4-D7) então (D0-D3).
Minha abordagem é:
% Writing the higher bits first
PORTA=PORTA|(DATA & 0xF0);
%Writing the lower bits
PORTA=PORTA|((DATA & 0x0F)<<4);
A principal dúvida é "Será que este pedaço de código perturbar os restantes GPIO (PORTA0-3)".Porque eu estou conectando-los para 4 ADC entradas.
Solução
A melhor maneira de entender como GPIO são acoplados é apenas de visitar a folha de dados.TI as plataformas msp430 da folha de dados são um excelente exemplo.
A Entrada/Saída secções têm muito explícita ilustrações sobre como o GPIO registra interagir com o IO Almofadas de si.Aqui é a Porta P1.0-P. 17 (a partir da página 80 de Folha de dados acima).
Saídas
O básico vantagem aqui é que:
- Escrever um '0' para P1OUT.x (e.g bit0 é P1OUT.0) unidade de saída baixa, se a IO pad estiver no modo output.
Aqui é uma simples versão reduzida do que:
Entradas
Da mesma forma, aqui está uma inspeção de utilizar o e / s bloco de 'entrada' modo de
O básico vantagem aqui é que a escrita para P1OUT.x aqui não tem nenhum efeito sobre a saída;o buffer de saída é tri-afirmou!
Perigos
Se o seu programa de ações de uma única porta GPIO-registrar entre várias tarefas, você deve garantir o acesso a este cadastro é thread-safe.Para sistemas embarcados geralmente, isso significa apenas 'certifique-se de ISRs não vai estragar as coisas".Considere -
//... (from main thread)
P1OUT = P1OUT | 0x02;
//... (from some ISR)
P1OUT = P1OUT | 0x01;
isso geralmente se traduz da seguinte desmontagem
//... (from main thread)
mov P1OUT, %some_reg
operate on %some_reg
mov %some_reg, P1OUT
//... (from some ISR)
mov P1OUT, %some_reg
operate on %some_reg
mov %some_reg, P1OUT
//and then the time series looks like (P1OUT = 0 initially)
[0]: mov P1OUT, %some_reg_main_thread (%reg_m = 0)
[1]: or 0x02, %some_reg_main_thread (%reg_m = 2)
[2]: ISR fires!
[3]: mov P1OUT, %some_reg_isr_thread (%reg_i = 0)
[4]: or 0x01, %some_reg_isr_thread (%reg_i = 1)
[5]: mov %some_reg_isr_thread, P1OUT (P1OUT = 1)
[6]: ISR exits
[7]: mov %some_reg_main_thread, P1OUT (P1OUT = 2)
(end result: P1OUT=2, but should be 3 (0x01 | 0x02))
Também, IO Almofadas não são tão simples como parecem, e você deve sempre visitar a folha de dados para compreender o quão ruim/delicado/confuso/etc é.
Por exemplo, na TI exemplo acima, os seguintes perigos de aplicar à sua pergunta original:
(enquanto P1DIR.x = 0)
P1REN.x + P1OUT.x
- se P1REN.x é '1', e você alternar P1OUT.x, que alterna a resistência pullup e fora também
Claro, IO pad topologias são MCU específicas.Eu recomendo a revisão IO-Pad topologia em sua folha de dados antes de avançar no seu projeto.Ele deve ser o seu melhor amigo.
Código De Práticas
Considere usar o |=, &= e ^= operadores quando você pode, por exemplo:
P1OUT |= (1<<2)+(1<<3) //assert pin2 & pin3 high
e quando não for possível, considere a utilização de refeições de estruturas, ou unidade-testado encapsulamento de rotinas:
struct myporta {
uint b3_0 : 4; //use unsigned int-type
uint b4 : 1;
uint b5_10 : 6;
uint b25_b11 : 15;
uint b26 : 1;
uint b31_27 : 5;
} __attribute__ ((packed)); //gcc syntax
...
//write to my LED
myporta *porta = &PORTA; //if you w
porta->b26 = 1; //turn the led on
nada é pior do que gpio clobbering um do outro!
Outras dicas
O MCU vai dirigir ativamente o pino de baixo, você pode pensar nele como o pino de aterramento, mais informações aqui.
PORTA=PORTA|(DATA & 0xF0);
Isto não irá afetar a 4 pinos inferiores, mas ainda não é o correto.Se a PORTA já está alta e dados contém zeros, você não vai dirigir os pinos de baixo.Você deseja mascarar as partes relevantes de DADOS e você deseja preservar a parte da PORTA que você não está mudando:
PORTA = (PORTA & 0x0F) | (DATA & 0xF0);
e, em seguida, da mesma forma para a configuração de 4 lsb:
PORTA = (PORTA & 0xF0) | (DATA & 0x0F);
Sim, escrever para PORTA vai perturbar todos os bits, mesmo se alguns deles são designados entradas com DDRA.
Você precisará certificar-se de que você não está escrevendo para o maior bits enquanto estiver a tomar ADC leituras de bits inferiores.
Mesmo algo como
% Writing the higher bits first
PORTA=PORTA|(DATA & 0xF0);
%Writing the lower bits
PORTA=PORTA|((DATA & 0x0F)<<4);
não vai funcionar.A leitura da PORTA do lado direito da atribuição que vai ter algum valor para os seus alfinetes, 0 ou 1, mesmo se a tensão está em algum lugar no meio.Que valor terá, então, ser escrito para o mesmo pin, dirigindo-alta ou baixa momentaneamente.