ATMega8 - PUERTO C - Problema de salida digital

Lo que estoy tratando de hacer es configurar el pin PC0 del PUERTO C como salida para encender un LED. El código que estoy usando para eso es:

//SET PORT C
//PC0 = RELAY STATUS LED - O/P
//PC1 = RELAY CTL LINE - O/P
//PC2 = PUSH BUTTON - I/P
//PC3 = SPARE - O/P

DDRC |= _BV(PC0) | _BV(PC1) | _BV(PC3) & _BV(PC2);

//SET PC0 = HIGH

PORTC |= _BV(PC0);

Pero lo anterior no está funcionando. He comprobado mis conexiones y no puedo entender por qué no funciona. Debería ser algo bastante simple.

La única razón por la que creo que podría afectarlo es que también tengo un ISP conectado al AVR ⇒ PC6 que está utilizando como línea de reinicio.

¿Alguna idea de por qué lo anterior no funcionará?

Respuestas (2)

Tu problema:

Su configuración de DDR es incorrecta: ha escrito

DDRC |= _BV(PC0) | _BV(PC1) | _BV(PC3) & _BV(PC2);

pero tu quieres

DDRC |= _BV(PC0) | _BV(PC1) | _BV(PC3)
DDRC &= ~_BV(PC2);

¿Dices que quieres más detalles porque simplemente emulaste otras asignaciones de DDRC y realmente no entiendes lo que escribiste? Bien, aquí va:

Cómo configurar registros con operadores bit a bit en el AVR.

Desglosemos las _BV()definiciones de macro y PCx por un momento. _BV(x)es 1 << xsimplemente Si escribe _BV(5), la macro evaluará el número 0b 0001 0000. PCx es simplemente una macro definida en el valor de x, por lo que _BV(PC5)se evaluará como _BV(5). Probablemente estés esperando que suceda algo como lo siguiente:

   0b 0000 0001  // PC0
|  0b 0000 0010  // PC1
|  0b 0000 1000  // PC3
&  0b 0000 0100  // Misconception: AND does not cause this to output a zero at the set bit
|= ------------
   0b 0000 1011

Sin embargo, no está borrando PC2 correctamente. Estás aplicando un AND binario al final. AND tiene una precedencia más alta que OR en C, por lo que su operación es en realidad

DDRC |= _BV(PC0) | _BV(PC1) | ( _BV(PC3) & _BV(PC2) );

PC3 es 0b 0000 1000 y PC2 es 0b 0000 0100, por lo que la sección entre paréntesis se evalúa como cero. En realidad, esto es una suerte para PC2, pero desafortunado para PC3, que permanece claro cuando lo querías configurar. Para aclarar un poco, sí usa &, pero necesita tomar el complemento del número usando el ~operador. En las siguientes ecuaciones, he usado ?bits que no queremos cambiar:

   0b ???? ???1  // Set PC0
|  0b ???? ??10  // Set PC1 
|  0b ???? 1?00  // Set PC3
|= ------------
   0b ???? 1?11

   0b ???? 1?11
&  0b 1111 1011  // Clear PC2
&= ------------
   0b ???? 1011

En código, estas ecuaciones son:

DDRC |= _BV(PC0) | _BV(PC1) | _BV(PC3)
DDRC &= ~_BV(PC2);

como se muestra arriba. Puede hacer esto en dos pasos como lo hice yo, o aplicar el valor anterior de DDRC con una máscara de bits:

DDRC = (DDRC & 0xF0) | ( ( _BV(PC0) | _BV(PC1) | _BV(PC3) ) & ~_BV(PC2) );

0xF0, o 0b 1111 0000, cuando se hace AND con el valor anterior de DDRC, devuelve 0b ???? 0000, al que podemos hacer OR con nuestros cuatro bits inferiores. Creo que el método de dos pasos es más claro: sus entradas y salidas están en líneas diferentes (tenga en cuenta que puede agregar entradas adicionales con, por ejemplo, DDRC &= ~_BV(PC2) & ~_BV(PC4)). A veces, incluso lo dividiré en más líneas:

DDRC |= _BV(PC0)   // RELAY STATUS LED - O/P
DDRC |= _BV(PC1)   // RELAY CTL LINE - O/P
DDRC &= ~_BV(PC2)  // PUSH BUTTON - I/P
DDRC |= _BV(PC3)   // SPARE - O/P

Ese, para mí, es el mecanismo más claro posible y el más fácil de entender para los futuros lectores. También es el más detallado, pero ¿a quién le importa? El compilador optimizará los tres mecanismos con el mismo código.

gracias por señalar eso y la explicación detallada ... ¡muy apreciado! sin embargo, eso tampoco lo solucionó. Lo recodifiqué de la forma más sencilla posible, DDRC = 0b00000001; PORTC |= _BV(PC0);pero el LED sigue apagado. Revisé dos veces mis conexiones, así que ese no es el problema. También probé otro ATMEGA8 solo para estar seguro. mismo resultado
nvm... funciona ahora... resulta que tenía líneas en mi código encima de esta que se refería a la biblioteca LCD de Peter Fleury que podría estar interfiriendo con ella... cuando elimino el comentario de esas líneas, todo funciona como se esperaba. ¡ahora vamos a descubrir cómo esas líneas están interfiriendo con PORTC!

¿Qué microcontrolador estás usando? ¿Es Atmega32 o 16 o cualquier otro?, luego verifique su Hoja de datos, ya sea que tengan interfaz JTAG o no. Si tienen JTAG, es posible que no pueda usar PortC Pocos pines ya que JTAG está habilitado de forma predeterminada de fábrica.

Para esto, debe deshabilitar JTAG de Fusibles, deshabilitando el bit de fusible JTAGEN

o

escribiendo esto en su inicialización o inicio de su código

MCUCSR|= (1<<JTD);