Este apunte público tratará muchos conceptos y haré referencias a información extra para mantenerlo corto. Comenzaré con la razón por la que necesité hacer este programa. Requería construir un pulso para caracterizar un sistema (identificación de sistemas) a partir de su la respuesta. Un impulso o Delta de Dirac es una distribución que tiene la peculiaridad de tener un espectro que abarca todas las frecuencias. En teoría, si queremos saber cual será la respuesta de un sistema a todas las frecuencias entonces debemos aplicar como entrada una señal impulsiva. En la práctica hay algunos problemas. Es imposible construir un impulso ideal y a demás los sistemas físicos como los sensores están siempre limitados a una banda de frecuencias. Peor aún, al digitalizar la señal de un sensor analógico se restringe a un más el ancho de banda útil. Es por eso que en algunos casos en mejor utilizar una función Sinc (o seno cardinal) como entrada de caracterización ya que permite definir bastante bien el ancho de banda de trabajo. En mi caso particular, necesito una señal Sinc con un periodo de lóbulo principal de 1/(3.8kHz) o 263.16 us y con los bordes suavizados por una gaussiana. El periodo del lóbulo principal se mide entre sus cruces por 0. Su gráfica en el tiempo y su espectro se muestra a continuación:
Se puede notar que he establecido mi ancho de banda de trabajo de 0 a 3.8kHz. Ahora lo que procede es escribir un programa en un microcontrolador que me de un PWM que codifique mi señal Sinc. Por restricciones de espacio, mi aplicación requiere de un microcontrolador muy pequeño por lo que elegí el PIC16F15313 que tiene solo 8 pines. Justo los que requería. En México pueden comprarlos en AG Electrónica. El circuito usado es el siguiente:miércoles, 3 de marzo de 2021
Conversión Digital-Analógica por PWM filtrado en PIC16F15313
lunes, 15 de febrero de 2021
Módulo RTCC en PIC24
En la entrada anterior comentaba que necesitaba una interrupción con reloj secundario para verificar que mi configuración de cristal era correcta. Lo que en realidad quería hacer es de lo que quiero hablar en esta entrada. He combinado la librería de consola serial de Chan con una librería terminé de escribir a partir de los programas de ejemplo de la página de Microchip. Es una aplicación sencilla en la que se puede leer y escribir el valor del RTCC vía puerto serial. Los detalles los pueden encontrar en este repositorio de Github. No olviden ponerme una estrella.
jueves, 11 de febrero de 2021
Interrupción por TMR1 con reloj secundario (SOSC) en PIC24
martes, 11 de agosto de 2020
Chan's FatFs en PIC24: Librería para lectura/escritura en memorias SD
FatFs es un módulo de sistema de archivos FAT32/16 para microcontroladores. Está escrito en ANSI C y es altamente portable entre una gran variedad de dispositivos. Si bien su documentación es muy detallada, al ser muy genérica es fácil perderse a la hora de hacer una implementación en un microcontrolador en particular. En esta entrada trataré de explicar lo mejor posible como portarla a la familia PIC24. Lo primero que hay que entender es como están estructurados sus 5 archivos:
Los únicos archivos del módulo que hay que editar son diskio.c y ffconf.h. La portabilidad radica en terminar de escribir las siguientes funciones de comunicación SPI:- BYTE xchg_spi (BYTE dat)
- void xmit_spi_multi (const BYTE* buff, UINT cnt)
- void rcvr_spi_multi (BYTE* buff, UINT cnt )
- void FCKL_SLOW(void)
- void FCKL_FAST(void)
definir los macros:
- CS_LOW()
- CS_HIGH()
- MMC_CD
- MMC_WP
y crear una rutina de interrupción por timer de 1 KHz que incrementa una variable de conteo de tiempo: volatile UINT Timer. Esta interrupción sirve para el manejo de timeouts. En los archivos del ejemplo podrán encontrar comentarios detallados sobre el funcionamiento de estas funciones. Pondré un enlace al final.
Para simplificar esta primer versión del programa de ejemplo he desactivado la opción de reloj de tiempo real modificando la linea 237 de ffconf.h: FF_FS_NORTC = 1. Cuando está opción esta desactivada se requiere crear una función adicional que maneje el tiempo del sistema de archivos (lo haremos en otra entrada usando el módulo RTC del PIC24FJXXGB002).
En esta entrada ya he explicado como configurar el reloj de sistema y en esta otra como configurar el modulo SPI y el Periferial Pin Select.
Configuración de SCK
La primer cosa que hay hacer es estar seguros de que se pueda elegir entre dos frecuencias diferentes para el reloj del módulo SPI. Una baja que se encuentre entre 100 y 400 KHz y una alta que se la de operación (hay limites para esta frecuencia que explicaré más adelante). En la página 23 del documento Section 23. Serial Peripheral Interface encontramos la siguiente información:
Los módulos de la familia PIC24 tienen dos prescalers. En este ejemplo lo que haré será dejar fijo el prescaler primario a 16:1 y alternar con el secundario entre 8:1 para el reloj con FCLK_SLOW() para tener 125 KHz y 2:1 con FCLK_FAST() para tener 500 KHz. Para verificar experimentalmente que la frecuencia sea correcta pueden usar el modo de disparo único de un osciloscopio (aquí hay un tutorial para configurar ese modo). Buena parte de las fallas con la implementación de la librería FatFs tienen que ver con una frecuencia baja incorrecta.
Conexión con el modulo SD
La segunda falla de implementación más común tiene que ver con la conexión física con los módulos SD. He visto en varios foros, y también me pasó, que los dispositivos de 3.3 V fallan con algunos módulos microSD de este tipo pero que funcionan perfectamente cuando construyen sus propios circuitos de conexión a la memoria SD. En mi caso sólo me ha funcionado cn PIC24 con un módulo SD de tamaño estándar (como este) y con jumper flotando conectado a SCK. Desde PIC18 a 5V no he tenido problemas.
La tercer falla más común es con la frecuencia máxima. Comentan en los foros que algunos módulos prefabricados no están optimizados para trabajar a máxima frecuencia de SDK. Sus circuitos tienen un pasa-bajas que solo permite frecuencias de entre 1-2 MHz. Si están desarrollando una aplicación comercial es mejor que integren su propio circuito de conexión con un socket microSD.
Edit: ¡Alcance hacerla funcionar hasta la frecuencia máxima de SCK para el GB002 que es de 8MHz!
Otro detalle más. El simulador Proteus solo funciona con memorias virtuales en formato FAT16 en algunas instalaciones. Al menos a mi sólo me he funcionado así. En físico no he tenido problemas con FAT32.
Nivel de optimización
Esta librería ocupa bastante espacio. Un microcontrolador de 32K de memoria de programa es apenas suficiente (pero funciona). Idealmente deberían usar de al menos 64K. Si llega a marcar un error al compilar pueden intentar subir el nivel de optimización del compilador a 2 de la siguiente forma:
![]() |
| Click para agrandar |
Código principal
Si todo lo anterior está en orden el siguiente ejemplo de escritura debe funcionar sin problemas con este circuito (el código es para GB002, el circuito en Proteus tiene un GA002 pero el conexionado es el mismo):
sábado, 27 de junio de 2020
Consola serial en PIC en XC16
- void xputs (const char* str) : análoga a la función puts()
- void xprintf (const char* fmt, ...) : análoga a la función printf()
- int xgets (char* buff, int len) : similar a la función gets()
xputs() permite escribir una cadena simple. como un "Bienvenidos al programa". xprintf() nos permite dar formato a la cadena, como ("Temperatura %d",temp), como lo haríamos en un C en una PC. xgets() es muy útil y la que la dará mucha presentación a un programa para microcontrolador. Es en esencia muy distinta a su contraparte gets(). Lo que hace xgets es ir capturando en tiempo real lo que se vaya recibiendo el microcontrolador del puerto serial hasta que se presiona ENTER. La misma función va enviado simultáneamente cada carácter a Tx como espejo (aunque esta opción puede desactivarse en los macros del header). ¡Permite incluso borrar caracteres!
La librería no puede funcionar por si sola. Es necesario asociarla a funciones de escritura y lectura bajo nivel. Lo que sigue ahora es crear un programa que contenga las rutinas para enviar y recibir un byte por puerto serial con la siguiente forma:
//-- Poner byte en el registro Rx
unsigned char uart_getc(void);
//-- Poner byte en el registro Tx
void uart_putc(unsigned char d);
Esta parte del programa siempre será dependiente del dispositivo y compilador. Estas dos rutinas pueden tener cualquier nombre siempre y cuando se asocien en el código principal de la siguiente manera:
//-- Unir UART con funciones de consola
xdev_in(uart_getc);
xdev_out(uart_putc);
La implementación de las funciones de comunicación serial también están basadas en la implementación de Chan pero las he reescrito de una forma más clara y comentadas lo mejor que pude. Esta implementación utiliza dos colas (registros FIFO), una de envío y otra de recepción. Esto es muy útil porque permite aprovechar las interrupciones de la UART para no perder bytes. Las referencias a páginas son para la data del GB004 pero es la misma información.
Aislamiento
Si están utilizando baterías para alimentar al PIC o van a estar realizando depuración es una buena práctica utilizar opto-acopladores. Esto también permite utilizar módulos de conversión USB-Serial que no tengan salida de 3.3v:
Programa completo:
domingo, 5 de abril de 2020
Comunicación SPI para PIC24FJXXGA004 en XC16
El circuito simulado en Proteus es el siguiente:
![]() |
| (Click para agrandar) |
miércoles, 11 de marzo de 2020
Blinking-led en PIC24FJXXGB002 en XC16
Primero, veamos la conexión física. Esta serie de microcontroladores trabajan a 3.3v lo que los hace más susceptibles al ruido si no se hace un buen conexionado. Es estrictamente necesario colocar capacitores de 0.1 uF entre cada par de pines Vdd-Vss como se muestra en la Figura 2-1 de la datasheet (yo estaré usando en este ejemplo un PIC24FJ32GB002):
Si no se colocan estos capacitores el PIC tendrá un comportamiento errático debido al ruido. Usaré en este ejemplo un cristal de 8MHz con capacitores de 22pF. Una vez conectado el circuito podemos avanzar a la configuración del oscilador. Configuraremos el oscilador externo con PLL activado con la frecuencia de reloj FOSC máxima de 32 MHz (recordemos que FCY = FOSC/2). He marcado el camino que nos interesa sobre el diagrama de la Figura 8-1 de la página 107:
Si estamos usando un cristal de 8 MHz ¿Qué modo es el adecuado? Eso lo ponemos encontrar en la tabla 8-3 de la pag. 114, el cual dice que es XTPLL. En la misma tabla se indica que el divisor del PLL requerido es 2. Ahora solo necesitamos saber que bits de configuración necesitamos modificar. En la tabla 8-1 de la página 108 podemos ver que son POSCMD y FNOSC. Para encontrar los macros necesarios podemos ir a Compiler Help en el dashboard de MPLAB X:
Abrirá un archivo HTML donde debemos buscar Configuration Settings Reference. De ahí podrán copiar los pragmas requeridos. Ahora solo falta un ajuste más pero se hará escribiendo en un registro. Lo que falta es asegurarnos que FOSC tenga un frecuencia de 32 MHz. Para esto debemos revisar el registro CLKDIV (pág. 111) dónde podremos ver que el valor de división del último postcaler es de 0. Ahora tenemos toda la información necesaria para escribir nuestro programa:
jueves, 16 de enero de 2020
Escribir datos en sistema FAT32 con un PIC18F4550
Deben agregar el archivo __Lib_FAT32.h de cabecera a header files de su proyecto o solo copiándolo en el directorio donde se encuentre su archivo fuente .c.
Teniendo todo instalado, deben conectar el modulo SD al PIC de la siguiente manera:
- MISO ------ SDI (RB0)
- MOSI ------ SDO (RC7)
- SCK -------- SCK (RB1)
- CS----------- RC2
Para el manejo de múltiples archivos y directorios recomiendo revisar el ejemplo que viene en la documentación de la librería.
martes, 19 de marzo de 2019
CIAA
lunes, 18 de marzo de 2019
LCD en MPLAB X / XC8
martes, 12 de marzo de 2019
Máquina de Estados Finitos en C [PIC18F45K50]
En una gran cantidad de problemas a resolver mediante un sistema embebido es necesario llevar a cabo un proceso estrictamente secuencial. En estos casos es muy útil y elegante estructurar nuestros programas como una máquina de estados. Quizá muchos de ustedes estén tentados a usar una estructura case para elegir un segmento de código cuando se cumple una condición. Si el numero de estados es pequeño, quizá se una opción fácil. Desafortunadamente el uso de case's es muy ineficiente cuando la máquina de estados y su tabla de transiciones es muy compleja. La implementación que se mostrará en esta entrada parecerá un tanto rebuscada pero tiene la ventaja de tener buen despeño a la hora de escalarla a numero grande de estados.
El diagrama de estados de la FSM de este ejemplo es el siguiente:
![]() |
| Diagrama hecho en LaTeX con TIKz |
Movámonos al programa. Primero, debemos definir un tipo enumerado para codificar nuestro conjunto de estados:
//-- Definición de tipo de estados
typedef enum {
Estado_0, // Estado inicial
Estado_1,
Estado_2,
Estado_3,
Estado_4,
No_de_Edos
} ESTADOS;
Creamos con esto una variable enumerada global que usaremos para almacenar el estado actual de la máquina:
//-- Variable global de estado
ESTADOS Estado_Actual = Estado_0;
El siguiente paso es definir una estructura que nos permitirá construir un objeto para nuestra FSM:
//-- Estructura de Maquina de Estados (FSM))
typedef struct {
ESTADOS Estado; // Estado miembro del conjunto enumerado ESTADOS
void (*func)(int); // Acciones asociadas al estado
} FSM;
Con lo anterior podemos ahora crear una instancia que sera nuestra FSM:
//-- Prototipos de funciones de estado
void Codigo_EDO_0(int);
void Codigo_EDO_1(int);
void Codigo_EDO_2(int);
void Codigo_EDO_3(int);
void Codigo_EDO_4(int);
//-- Creación de la estructura global de la FSM
FSM Maquina_de_Estados[] = {
{Estado_0,Codigo_EDO_0},
{Estado_1,Codigo_EDO_1},
{Estado_2,Codigo_EDO_2},
{Estado_3,Codigo_EDO_3},
{Estado_4,Codigo_EDO_4},
};
Es importante que los prototipos de las funciones asociadas a cada estado aparezcan antes de la creación de la estructura (estas funciones serán definidas más adelante en el código). El segmento de código principal queda reducido elegantemente de la siguiente manera:
void main(void) {
int sw = 0;
setup();
//-- FSM ---
while(1){
sw = PORTBbits.RB0;
(*Maquina_de_Estados[Estado_Actual].func)(sw);
}
return;
}
Código completo:
Circuito utilizado:
viernes, 22 de febrero de 2019
Iniciando con el PIC18F45K50 / 25K50 en XC8
1. Configuración del reloj
El esquema de reloj es distinto al de su antecesor [pag. 29]. Usando un cristal de 16 MHz, este es el camino que debe estar habitado para conseguir los 48 MHz:
![]() |
| Click para agrandar |
#pragma config PLLSEL = PLL3X
#pragma config CFGPLLEN = OFF // ver Tabla 3-3
#pragma config CPUDIV = NOCLKDIV
#pragma config FOSC = HSM
#pragma config PCLKEN = ON
Los pines RB0 y RD0 son usados por el módulo ADC por lo que deben desactivarse para ellos. En el caso del puerto B, esto puede hacerse al generar la cabecera de fuses con la linea:
#pragma config PBADEN = OFF
Para el caso de RDO deberá hacerse en el código principal escribiendo en el registro ANSELD [la tabla con todos los registros de función especial está en la página 84 de la datasheet] :
3 Código completo en C
Como regla general siempre se debe leer en puerto y escribir en latch:
jueves, 13 de septiembre de 2018
Librerías de periféricos en MPLAB X v5+ / XC8
Pueden leer aquí un tutorial de modificacion de los pines para el LCD.
miércoles, 12 de septiembre de 2018
Instalar MPLAB X en Debian 9 (64 bits)
$ sudo dpkg --add-architecture i386
Luego instalar librerias de compatibilidad para i386:
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install libc6:i386 libx11-6:i386 libxext6:i386 libstdc++6:i386 libexpat1:i386
Finalmente se ejecuta el instalador descargado de aquí:
$ sudo ./MPLABX-v5.05-linux-installer.sh
Si la instalación se realiza correctamente podemos iniciar MPLAB X buscándolo en las aplicaciones:
NOTA: Deben tener ya instalado Java Runtime Enviroment en su sistema. Aquí hay una guía de instalación en español.
viernes, 4 de diciembre de 2015
Implementación de un controlador PID discreto en un PIC18F2550
Para controlar esta planta utilizaremos el siguiente controlador discreto a partir de la transformación backward Euler:
Dónde:
Obteniendo transformada inversa, la salida de control descrita como ecuación de diferencias nos queda:
Estos coeficientes pueden encontrarse manualmente siguiendo el procedimiento descrito aquí, o ejecutando éste programa de Matlab: [PID_Proteus.m]. Teniendo estos valores podemos realizar una verificación de la ecuación en Simulink:
Algo muy importante que se debe notar es que en esta simulación se está considerando la limitación física de la saturación de la salida del controlador real. Sin esta limitación la respuesta del controlador sería más rápida y con un sobreimpulso mucho menor. Sabiendo ahora que nuestra ecuación de diferencias es correcta podemos proceder a escribir el programa en el PIC en lenguaje C con el compilador MikroC. El programa completo se adjuntará más adelante. La función de control principal queda descrita como:
void pid(void) // Función para el controlador
{
e2=e1; e1=e0; u2=u1; u1=u0; // update de variables
y = ADC_Read(0); // Lectura analógica por AN0
yd = (double) y; // Conversión a double
vin = (yd/1023*5);
y = ADC_Read(1); // Lectura analógica por AN1
yd = (double) y; // Conversión a double
reff = (yd/1023*5);
e0 = reff - vin; // Error
u0 = ke0*e0 + ke1*e1 + ke2*e2 - ku1*u1 - ku2*u2; // Ecuación de diferencias
salida = (int) floor(((u0+5)/10)*1023);
if (salida > 1023) salida = 1023; // Saturación de DAC
if (salida <= 0) salida = 0;
DAC_Output(salida); // Enviar dato
}
Es muy importante que ésta función sea ejecutada dentro de una rutina de interrupción de manera que se tenga control del tiempo de muestreo Ts en exactamente 0.01 segundos para que el controlador funcione correctamente. Para la salida analógica del controlador se esta utilizando un DAC LTC1660 [2][3]. Compilando el programa y simulando en Proteus:
Nota: El relay en la simulación lo único que hace es evitar que la salida bipolar del DAC envíe un voltaje de saturación negativo al inicio [ver este programa].
jueves, 27 de marzo de 2014
Comunicación SPI PIC2550 con DAC LTC1660 (MikroC)
// DAC module connections
sbit Chip_Select at RB5_bit;
sbit Chip_Select_Direction at TRISB5_bit;
// End DAC module connections
double t,valor;
void InitMain() {
Chip_Select = 1; // Libera DAC
Chip_Select_Direction = 0; // Pin CS# como salida
SPI1_Init(); // Inicializa modulo SPI
}
void DAC_Output(unsigned int valueDAC) {
char temp;
Chip_Select = 0; // Selecciona chip
//High Byte
temp = (valueDAC >> 6) & 0x0F; // Corrimiento
temp |= 0xF0; // Cargar dato al canal A
SPI1_Write(temp); // Envía parte alta del byte
//Low Byte
temp = valueDAC<< 2;
SPI1_Write(temp); // Envía parte baja del byte
Chip_Select = 1; // Libera chip
}
void main() {
int i = 0;
ADCON1 |= 0x0F; // Desactiva entradas analógicas
CMCON |= 7; // Desactiva comparadores
// Puerto B como salidas
TRISB = 0x00;
PORTB = 0X00;
//
InitMain(); // Secuencia de inicialización
while(1){
for (i=0; i < 80; i++){ // función de prueba
t = t + 0.078;
valor = (unsigned int) floor(512*sin(t)+512);
DAC_Output(valor); // Enviar dato
if (t > 2*3.14) t = 0;
}
}
}
* * *
Para que la salida de la DAC sea bipolar, es decir que tenga un rango de -5 a +5 V, se debe implementar el siguiente circuito:
lunes, 3 de febrero de 2014
Función promedio para lectura analógica desde PIC (MikroC)
unsigned int promediolectura(void){
int i =0;
unsigned int a = 0;
for (i=0; i <16;i++){a+ = ADC_Read(0);}
a = a >>4;
return a;
}
miércoles, 18 de septiembre de 2013
Interrupciones externas con PIC18f4550 en MikroC
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;
}
}
viernes, 20 de julio de 2012
Lectura analógica de un LM35 en PIC18F4550 (MikroC)
unsigned int in = 0;
void main() {
ADCON1 |= 0x00; // AN 0-12 como entradas analógicas
CMCON |= 7; // Comparadores desactivados
TRISA = 0xFF; // PORTA como entrada
TRISC = 0; // PORTC como salida
TRISB = 0; // PORTB como salida
do {
in = ADC_Read(0); // Lectura analógica por AN0
PORTB = in; // 8 bits a PORTB
PORTC = in >> 8; // los 2 bits mas significantes a RC1 y RC0
} while(1);
}
martes, 20 de septiembre de 2011
Control PWM + LCD con PIC18F4550 en MikroC
// Rodolfo E. Escobar U.
// Facultad de Ciencias de la Electrónica, BUAP
// LCD module connections
sbit LCD_RS at LATB4_bit;
sbit LCD_EN at LATB5_bit;
sbit LCD_D4 at LATB0_bit;
sbit LCD_D5 at LATB1_bit;
sbit LCD_D6 at LATB2_bit;
sbit LCD_D7 at LATB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections
int velocity = 0;
int duty = 0;
char txt[6] = "0";
void main() {
ADCON1 |= 0x0F;
CMCON |= 7;
PORTC = 0; // sets port c to all 0
TRISC = 0; //configures port c as output port
PWM1_Init (5000); // sets pwm frequency to 5000Hz
PWM1_Start(); // starts pwm1 peripheral
Lcd_Init(); // Inicializa LCD
Lcd_Cmd(_Lcd_CLEAR); // Limpiar display
Lcd_Cmd(_Lcd_CURSOR_OFF); // Desactivar cursor
while(1)
{
wordToStr(velocity, txt);
Lcd_Out(1,4,"Velocidad");
Lcd_Out(2,7,Ltrim(txt));
Lcd_Out(2,10,"%");
if (PORTA.F0 == 1){ // Incremento de PWM
Lcd_Out(2,7," ");
velocity = velocity + 20;
duty = duty + 51;
if (duty >= 255) duty = 255;
if (velocity >= 100) velocity = 100;
}
if (PORTA.F1 == 1){ // Decremento de PWM
Lcd_Out(2,7," ");
velocity = velocity - 20;
duty = duty - 51;
if (duty <= 0) duty = 0;
if (velocity <= 0) velocity = 0;
}
if (PORTA.F2 == 1){ // Detener
duty = 0;
velocity = 0;
Lcd_Out(2,7," ");
}
PWM1_Set_Duty(duty); // Establece ciclo de trabajo
Delay_ms(10); // 10 msec delay
}
}































