viernes, 27 de septiembre de 2013
Revolución
Hace poco edité un cartel facebuquero con el título "Libros recomendados para entender cómo hacer una revolución". La corta lista de 3 libros la tomé del video Revolution: An Instruction Manual: "From Dictatoship to Democracy" de Gene Sharp, una guía corta sobre procedimientos de resistencia civil que puede leerse en una sola tarde , "The Crawl" y "The Psychology of Revolution" de Gustave Le Bon. Publiqué el cartel en una página de divulgación científica que mantengo junto con los enlaces las ediciones digitales en español de los 3 libros. Más por curiosidad de experimento social que de "sed revolucionaria" envíe un enlace al cartel con un breve texto a todas las páginas de "revos" que puede encontrar. Sólo una se interesó por la publicación y dio un share que se perdió entre memes de EPN. Más de uno me ha mirado con desaprobación al oírme decir que los adolescentes y adultos jóvenes de este país no quieren realmente un país mejor sino que disfrutan la catarsis del desprecio al símbolo opresor.
miércoles, 18 de septiembre de 2013
Interrupciones externas con PIC18f4550 en MikroC
[Update: El 4550 ya es un poco viejo. ¿No quieres echarle un ojo al 45K50?]
La mayoría de los tutoriales que hay en internet sobre interrupciones en microcontroladores parecen decirnos todo lo que ya sabemos excepto lo que realmente necesitamos. Por esta razón no vamos a tratar aquí las generalidades del proceso. El mejor consejo que puede darse para ser un buen programador de microcontroladores es confiar en la hoja de especificaciones del dispositivo más que en cualquier tutorial. Muchos de los proyectos disponibles en la web son un horrible copy & paste de segmentos de códigos que le funcionaron al programador en otros casos y le fue más sencillo adaptarlos a nuevos propósitos. Muchos de estos programas están repletos de lineas innecesarias y algoritmos innecesariamente complejos que sólo asustan a los que apenas se aventuran en el mundo de los microcontroladores. Si realmente se entiende el funcionamiento, limitaciones y ventajas del PIC en cuestión, la programación simplemente "fluirá" de las manos. Si uno se acostumbra a usar la hoja de especificaciones se podrá adaptar cualquier buen tutorial a un PIC diferente al utilizado en el tutorial. Comencemos...
Registros
Un microcontrolador es, en un sentido estricto, una computadora y hará lo que le ordenes. Los registros nos sirven para configurar la funcionalidad del dispositivo; lo que queremos que se habilite o deshabilite y como queremos que se comporte. Así mismo nos permite saber las cosas se ejecutaron como se ordenaron por medio de banderas (flags). Para el 18F4550 tenemos tres registros de control de interrupciones: INTCON, INTCON2 e INTCON3. Para más detalles pueden revisar la data. Aquí entraremos directo a un ejemplo sencillo:
Ejemplo Encender un LED con un flanco de bajada y apagarlo con un flanco de subida en INT0
Esto, por supuesto, podemos hacerlo sin utilizar interrupciones, pero el punto aquí es visualizar el funcionamiento de estas. Bien entendido, puede utilizarse este ejemplo para hacer cosas más interesantes como un frecuenciometro, medidor de rpm's o cualquier cosa por la que hayan llegado aquí.
Primero, definamos que es lo queremos hacer.
1. Queremos que haya una bandera que se active cuando INT0 se interrupa en flanco de subida.
2. Queremos que la misma bandera se limpie y se vuelva a activar pero con un flanco de bajada.
3. Finalmente queremos utilizar este proceso para hacer algo útil.
Bien, primero entonces debemos modificar los registros correspondientes. Necesitamos una línea que habilite la interrupcion externa por INT0
INTCON.INT0IE = 1; // Interrupción externa INT0 habilitada
...otra línea que habilite todas la interrupciones de manera que nuestro vector de interrupción se ejecute continuamente
INTCON.GIE = 1; // Habilita todas las interrupciones
...y otra que habilite (inicialmente) el disparo de la bandera por flanco de subida
INTCON2.INTEDG0 = 1; // INT0 en flanco de subida
Esta última linea modifica un bit del registro INTCON2. Como las 2 primeras lineas modifican bits del mismo registro, podríamos reducirlas a una sola linea igualando todo el registro al valor del byte deseado. Pero para fines didácticos lo dejaremos así. Bien, lo que sucederá hasta este punto en el programa será que cuando haya un cambio de bajo a alto en RB0 (INT0) la bandera INT0IF, que está en el registro INCON, cambiará a uno y se quedará en ese estado hasta que resetee vía software.
Rutina de interrupción
void interrupt(){
-Instrucciones-
}
Al leer esta rutina, el compilador sabrá que deberá escribir esas lineas de código en el espacio de memoria llamado vector de interrupción. Puesto que se habilitó el bit GIE del registro INCON, no será necesario llamar a "interrupt" desde "main" como normalmente se haría en lenguaje C. Para este ejemplo requerimos que nuestra rutina de interrupción envíe un '1' a RD0 después de detectar un flanco de subida y un '0' al detectar un flanco de bajada. Para esto necesitamos una variable que llamaremos flagFlanco y otra LED que contendrá el estado del puerto. El código completo nos queda:
int LED = 0;
bit flagFlanco; // Las variables de este tipo no pueden
// inicializarse (0 por default)
void interrupt(){
if(INTCON.INT0IF == 1){
flagFlanco = ~flagFlanco;
INTCON.INT0IF = 0; // Limpiar bandera de INT0
}
if( flagFlanco == 1 ){
LED = 1;
INTCON2.INTEDG0 = 0; //INT0 en flanco de bajada
}
else {
LED = 0;
INTCON2.INTEDG0 = 1; // INT0 en flanco de subida
}
}
void main() {
ADCON1 |= 0x0F;
CMCON |= 7;
INTCON.INT0IE = 1; // Interrupción externa INT0 habilitada
INTCON.GIE = 1; // Habilita todas las interrupciones
INTCON2.INTEDG0 = 1; // INT0 en flanco de subida
TRISD = 0x00; // Puerto D como salidas
//TMR0 activado, prescaler 1:2
T0CON = 0b10000000;
while(1) {
PORTD.F0 = LED;
}
}
La mayoría de los tutoriales que hay en internet sobre interrupciones en microcontroladores parecen decirnos todo lo que ya sabemos excepto lo que realmente necesitamos. Por esta razón no vamos a tratar aquí las generalidades del proceso. El mejor consejo que puede darse para ser un buen programador de microcontroladores es confiar en la hoja de especificaciones del dispositivo más que en cualquier tutorial. Muchos de los proyectos disponibles en la web son un horrible copy & paste de segmentos de códigos que le funcionaron al programador en otros casos y le fue más sencillo adaptarlos a nuevos propósitos. Muchos de estos programas están repletos de lineas innecesarias y algoritmos innecesariamente complejos que sólo asustan a los que apenas se aventuran en el mundo de los microcontroladores. Si realmente se entiende el funcionamiento, limitaciones y ventajas del PIC en cuestión, la programación simplemente "fluirá" de las manos. Si uno se acostumbra a usar la hoja de especificaciones se podrá adaptar cualquier buen tutorial a un PIC diferente al utilizado en el tutorial. Comencemos...
Registros
Un microcontrolador es, en un sentido estricto, una computadora y hará lo que le ordenes. Los registros nos sirven para configurar la funcionalidad del dispositivo; lo que queremos que se habilite o deshabilite y como queremos que se comporte. Así mismo nos permite saber las cosas se ejecutaron como se ordenaron por medio de banderas (flags). Para el 18F4550 tenemos tres registros de control de interrupciones: INTCON, INTCON2 e INTCON3. Para más detalles pueden revisar la data. Aquí entraremos directo a un ejemplo sencillo:
Ejemplo Encender un LED con un flanco de bajada y apagarlo con un flanco de subida en INT0
Esto, por supuesto, podemos hacerlo sin utilizar interrupciones, pero el punto aquí es visualizar el funcionamiento de estas. Bien entendido, puede utilizarse este ejemplo para hacer cosas más interesantes como un frecuenciometro, medidor de rpm's o cualquier cosa por la que hayan llegado aquí.
Primero, definamos que es lo queremos hacer.
1. Queremos que haya una bandera que se active cuando INT0 se interrupa en flanco de subida.
2. Queremos que la misma bandera se limpie y se vuelva a activar pero con un flanco de bajada.
3. Finalmente queremos utilizar este proceso para hacer algo útil.
Bien, primero entonces debemos modificar los registros correspondientes. Necesitamos una línea que habilite la interrupcion externa por INT0
INTCON.INT0IE = 1; // Interrupción externa INT0 habilitada
...otra línea que habilite todas la interrupciones de manera que nuestro vector de interrupción se ejecute continuamente
INTCON.GIE = 1; // Habilita todas las interrupciones
...y otra que habilite (inicialmente) el disparo de la bandera por flanco de subida
INTCON2.INTEDG0 = 1; // INT0 en flanco de subida
Esta última linea modifica un bit del registro INTCON2. Como las 2 primeras lineas modifican bits del mismo registro, podríamos reducirlas a una sola linea igualando todo el registro al valor del byte deseado. Pero para fines didácticos lo dejaremos así. Bien, lo que sucederá hasta este punto en el programa será que cuando haya un cambio de bajo a alto en RB0 (INT0) la bandera INT0IF, que está en el registro INCON, cambiará a uno y se quedará en ese estado hasta que resetee vía software.
Rutina de interrupción
void interrupt(){
-Instrucciones-
}
Al leer esta rutina, el compilador sabrá que deberá escribir esas lineas de código en el espacio de memoria llamado vector de interrupción. Puesto que se habilitó el bit GIE del registro INCON, no será necesario llamar a "interrupt" desde "main" como normalmente se haría en lenguaje C. Para este ejemplo requerimos que nuestra rutina de interrupción envíe un '1' a RD0 después de detectar un flanco de subida y un '0' al detectar un flanco de bajada. Para esto necesitamos una variable que llamaremos flagFlanco y otra LED que contendrá el estado del puerto. El código completo nos queda:
int LED = 0;
bit flagFlanco; // Las variables de este tipo no pueden
// inicializarse (0 por default)
void interrupt(){
if(INTCON.INT0IF == 1){
flagFlanco = ~flagFlanco;
INTCON.INT0IF = 0; // Limpiar bandera de INT0
}
if( flagFlanco == 1 ){
LED = 1;
INTCON2.INTEDG0 = 0; //INT0 en flanco de bajada
}
else {
LED = 0;
INTCON2.INTEDG0 = 1; // INT0 en flanco de subida
}
}
void main() {
ADCON1 |= 0x0F;
CMCON |= 7;
INTCON.INT0IE = 1; // Interrupción externa INT0 habilitada
INTCON.GIE = 1; // Habilita todas las interrupciones
INTCON2.INTEDG0 = 1; // INT0 en flanco de subida
TRISD = 0x00; // Puerto D como salidas
//TMR0 activado, prescaler 1:2
T0CON = 0b10000000;
while(1) {
PORTD.F0 = LED;
}
}
domingo, 8 de septiembre de 2013
Suscribirse a:
Entradas (Atom)