1. Este proyecto es muy interesante ya que pone
a prueba dos interrupciones por TIMERS al
mismo tiempo. El proyecto consta de:
Cantidad Componente
6 Display de 7 seg (An)
6
1 PIC18F2550
3 Microinterruptores
4
7 Resis 330R
Antes de empezar a programar debemos de
tener algunos criterios definidos.
¿Cómo hacer prender 6 Display con
circuito integrado?
Si usted es un electrónico, recordara que
existen algunos circuitos especialmente para
realizar dicha acción, como es el 7490 que nos
cuenta los pulsos que son ingresado a el y
después empieza a contar en forma binaria.
ste proyecto es muy interesante ya que pone
a prueba dos interrupciones por TIMERS al
El proyecto consta de:
Componente
Display de 7 seg (An)
2N2222A
PIC18F2550
Microinterruptores
Resis 10K
Resis 330R
Antes de empezar a programar debemos de
tener algunos criterios definidos.
hacer prender 6 Display con un solo
Si usted es un electrónico, recordara que
especialmente para
realizar dicha acción, como es el 7490 que nos
cuenta los pulsos que son ingresado a el y
después empieza a contar en forma binaria.
Circuito esquemático de un 7490
El conteo lo hace de 0 a 9, pero esto
que está listo para visualizarse a un display de 7
segmentos, ya que tiene que pasar por un
decodificador para ahora si usar un display de 7
segmentos.
Un ejemplo sencillo para entender este
funcionamiento lo podemos ver en seguida:
Consta de simplemente de un CI 7490 y un
7447, unas cuantas resistencias de 330 ohms y
un display de 7 seg.
Construiremos un circuito que maneje 6
display de 7 segmentos, para Visualizar
el valor de una lectura de ADC.
Circuito esquemático de un 7490
El conteo lo hace de 0 a 9, pero esto no significa
visualizarse a un display de 7
segmentos, ya que tiene que pasar por un
decodificador para ahora si usar un display de 7
Un ejemplo sencillo para entender este
funcionamiento lo podemos ver en seguida:
Consta de simplemente de un CI 7490 y un
7447, unas cuantas resistencias de 330 ohms y
Construiremos un circuito que maneje 6
display de 7 segmentos, para Visualizar
el valor de una lectura de ADC.
2. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 86
Es una forma muy fácil, pero cuando se trata de
utilizar más de 1 display se vuelve una tarea
muy tediosa, llegando ser no muy complejo
pero demasiado grande para poder
desarrollarlo en poco tiempo, por eso hay
técnicas muy eficientes para ahorrar muchos
circuitos y a la vez hacer más fácil de
desarrollar.
La técnica más usada para usar menos circuitos
y realizar la misma tarea es la Multiplexor, esta
técnica trata de encender cada display en un
periodo de tiempo definido y cada vez que uno
es encendido se da el dato a visualizar y
después apagada para encender el siguiente.
Esta técnica se puede utilizar con lógica TTL
pero la desventaja de usar compuertas,
decodificadores, multiplexores se vuelve un
poco caro, ya que eleva la eficiencia pero a un
costo, que al fin al cabo costara más que hacer
uno tradicional.
Un esquema de ejemplo se puede apreciar
enseguida:
Esquema de dos Display multiplexados
Entonces se llega a una conclusión de que
utilizando lógica TTL es eficiente pero conlleva
un costo.
Entonces para realizar lo misma función y tener
la misma eficiencia pero mucho menor costo,
es utilizar un microcontrolador para que realice
todas las tareas y hasta mas.
Nuestra tarea consiste en usar 6 display de 7
segmentos a la vez, y leer la entrada análoga y
visualizarla en los display.
Se oye una tarea muy tediosa pero los
microcontroladores va ser muy sencillo, ya que
usaremos un PIC18F2550 que es muy eficiente
en todos los aspectos.
Esquema de un contador simple
3. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 87
Para hacer el Multiplexor con un
microcontrolador es muy sencillo,
simplemente usamos un puerto completo para
visualizar el número y otros pines que
depende de cuantos display se quiera visualizar,
en este caso para llevar a cabo el proyecto se
tiene 6 Display, se usaran 6 pines del
microcontrolador para hacer el switcheo.
Cada 3.33mS surgirá una interrupción por
TIMER0 y cambiara de pin llegando hasta el
máximo que son 6, y así será el ciclo de
Multiplexor.
Como hablamos de que cada 3.33mS que
corresponden a cada display de encendido,
entonces si son 6 tendremos una frecuencia
total en cada uno de ellos de:
݂ =
1
݀݅ݎ݁ ∗ ܰ݀݅ݕ݈ܽݏ
݂ =
1
3.33݉ܵ ∗ 6
≅ 50 ݖܪ
Suficiente para desaparecer el parpadeo, para
configurar el TIMER0 se debe de utilizar la
formula:
ܶ0ܴܯ = 65535 −
݁݉݅ݐ ∗ ܱܿݏ
ሺ4 ∗ ݎ݈ܽܿݏ݁ݎሻ
൨
ܶ0ܴܯ = 65535 −
3.33݉ܵ − 8ܯℎݖ
4 ∗ 1
൨
ܶ0ܴܯ = 58875
El valor obtenido se debe de cargar cada vez
que surja la interrupción por timer0.
La configuración del timer0 al inicio del nuestro
programa es el siguiente:
Como el Microcontrolador PIC18F2550 cuenta
tan solo de 3 Puerto completo y uno lo vamos a
usar para Mostrar los números en cada display
correspondiente, y otro para hacer el
Multiplexor.
Pero como los pines que están dedicados al USB
no se puede configurar como salida, entonces
perdemos un par de pines, por eso se adopto
por usar solo tres pines del PUERTO C y tres del
PUERTO A.
Para hacer el corrimiento en tales pines se
usara la siguiente lógica de programación:
Se usa una variable ‘flag’ para hacer el cambio
de puerto, cuando el corrimiento del PUERTO C
termine cambia rápidamente al PUERTO A, al
finalizar empezara otra vez el ciclo.
OpenTimer0(TIMER_INT_ON &//Interrupción activada
T0_16BIT &//valor de 16 bit
T0_SOURCE_INT &//oscilador principal
T0_PS_1_1); //Preescalar de 16
if(flag==0){
LATC<<=1;//Recorre un bit a la Izquierda
if(LATC==0){//A recorrido los tres bit?
flag=1; //Cambia de puerto
LATA=0x02;//Empieza en el puerto A
}
}else{
LATA<<=1;//Recorre un bit a la Izquierda
if(LATA>=16){//Ha llegado al limite
flag=0; //Cambia de Puerto
LATC=0x01;//Inicia otra vez el ciclo
}
}
4. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 88
Ahora bien tenemos 3.33mS de retardo para
poder visualizar el numero en el display
correspondiente, entonces cuando la
interrupción por timer0 termine, regresa al loop
principal, donde colocaremos las
comparaciones de cada pin, para cuando se
cumpla uno de ellos entre al proceso que es
visualizar el numero.
Se usa una variable de tipo array donde
contiene los datos en la memoria ROM, que
corresponde a cada número para mostrar en los
display.
Ahora bien como se desea tener una lectura del
convertidor Análogo-Digital, pero sin
interrumpir el Multiplexor, recuerde que el
microcontrolador hace las tareas línea tras línea
no en forma paralela, si se sabe que estamos
trabajando a una frecuencia 50Hz que para
nosotros es muy rápido, pero a nivel de
procesador es muy lento, ya que podemos
hacer lo que necesitamos en menos de 3.33mS.
Vallamos por pasos debemos de configurar
primero que nada la entrada análoga. Por eso
vamos a usar el PINA0 como una entrada
análoga, 10bit a una tasa de adquisición de 20
Tad, con valor de referencia de la fuente de
alimentación a tierra (+5v, gnd).
Al tener configurado el Convertidor AD,
debemos de configurar el TIMER1 como
temporizador y que surja una interrupción por
desbordamiento cada 100mS, haciendo de que
cada vez que entre a la interrupción por TIMER1
empiece la conversión a análoga-digital, lo
guarde en una
variable de tipo
int al tener
guardado el dato
análogo, se pasa
por un proceso
de conversión de
numero a BCD, esto quiere decir que separara
cada numero para ser guardado en variables,
que solo contenga el numero que debe de
visualizarse en cada display.
Por ejemplo:
Si hemos realizado una
lectura de 1023 que es
el valor máximo de 10-
bit , al pasar por el proceso de conversión de
numero a BCD, tendremos en cuatro variables
de tipo char
M=1
C=0
D=2
U=3
Para hacer este proceso de conversión se usa
una técnica muy sencilla, es hacer una pregunta
antes de entrar al ciclo de restar con relación al
valor tenido.
while(1){
if(LATC==0x01) {LATB=mostrar[0];}//Simplemente Muestra 0
else if(LATC==0x02) {LATB=mostrar[0];}//Simplemente Muestra 0
else if(LATC==0x04) {LATB=mostrar[M];}//Simplemente Muestra Milesimas
else if(LATA==0X02) {LATB=mostrar[C];}//Simplemente Muestra Centecimas
else if(LATA==0X04) {LATB=mostrar[D];}//Simplemente Muestra Decimas
else if(LATA==0X08) {LATB=mostrar[U];}//Simplemente Muestra Unidades
}
const unsigned char
mostrar[10]={0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,
0b10010010,0b10000011,0b11111000,0b00000000,0b00011000};
5. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 89
DATO=ReadADC()
;
DATO>=1000?
DATO>=100?
DATO>=10?
DATO>0?
DATO-=1000;
M++;
DATO-=100;
C++;
DATO-=10;
D++;
U=DATO;
U=DATO;
Regresa
al
programa
si
si
si
si
no
no
no
no
6. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 90
Ahora bien si se desea una interrupción por overflow del TIMER1 se debe de configurar de la siguiente
manera y cargar al timer1 cada vez que surja la interrupción por el valor de:
Cada display debe de tener un transistor para que la corriente no caiga en el pin del microcontrolador y
así hace que el display ilumine un poco más.
Las conexiones de los 7 segmentos se debe de unirse todos y tener un solo
en común, y este será conectado al PUERTO B
del microcontrolador.
Entonces usaremos seis Transistores para
poder manejar los seis display.
En la base del transistor se debe de
conectar una resistencia de 1Kohm
aproximadamente para que limite al
microcontrolador salga más corriente.
Podemos realizar la conexión de todos
los Display y transistores en un solo
Protoboard, dejando el
microcontrolador en otro Protoboard
para poner más adelante mas
circuitería si queremos:
//////////////////////////////////////////////////////////////////////
// Configuración de Timer1 ///
//////////////////////////////////////////////////////////////////////
OpenTimer1(TIMER_INT_ON & //Interrupción Desactivada
T1_16BIT_RW & //valor de 16 bit
T1_SOURCE_INT & //Corriente desde el oscilador principal
T1_PS_1_8 & //Preescalar de 8
T1_OSC1EN_OFF &
T1_SYNC_EXT_OFF &
T1_SOURCE_CCP); //Sincronismo desactivado
/*---------------------Fin de Conf. TIMER1--------------------------*/
WriteTimer1(40535);//Valor para tener una interrupción cada 100ms
7. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 91
Imagen fisica de nuestro Proyecto
Como no tenía un potenciómetro a la mano use una fotoresistencia, para hacer el cambio de Voltaje y
así para poder apreciar el descenso de la lectura por ADC.
Imagen Completa de nuestro Proyecto
Fotoresistencia
8. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 92
Diagrama a Manejar:
Como podemos notar los microcontroladores nos ahorran pero mucho a desarrollar cosas más
complejas a comparación de usar la lógica TTL de los circuito discretos de la seria 74XXXX, aunque para
empezar se recomienda empezar por lo difícil jeje.
Este circuito utiliza un voltaje total de 5 Volts, para usar mas voltaje y regularlo, siempre es
recomendable usar un regulador de voltaje de 7805, ya que puede regular hasta 24 volts a 5 volts
continuo.
9. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 93
El programa es el siguiente:
////////////////////////////////////////////////////////
// USO DE ADC Y DISPLAY 7 SEG ////
//Autor: george.manson.69 ////
//Lugar: Mexico ////
//Compilador: HI TECH PIC18 (LITE MODE) ////
////////////////////////////////////////////////////////
#include<htc.h>
/////////////////////////////////////////////////////////////
//Configuracion para trabajar Con oscilador interno de 8Mhz
__CONFIG(1,INTIO & FCMDIS & IESODIS & PLLDIV5 & PLLPOSTDIV2 & CPUDIV1 & USBOSC);
/////////////////////////////////////////////////////////////
__CONFIG(2,VREGDIS & PWRTEN & BORDIS & WDTDIS & BORV45 & WDTPS32K);
__CONFIG(3,PBDIGITAL & LPT1DIS & MCLREN);
__CONFIG(4,STVRDIS & LVPDIS & ICPORTDIS & DEBUGDIS);
__CONFIG(5,UNPROTECT);
__CONFIG(6,UNPROTECT);
__CONFIG(7,UNPROTECT);
//////////////////////////////
//Frecuencia FOSC 8Mhz
//////////////////////////////
#define _XTAL_FREQ 8000000
/////////////////////////////
//VARIABLES
/////////////////////////////
const unsigned char mostrar[10]={0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,
0b10010010,0b10000011,0b11111000,0b00000000,0b00011000};
unsigned int adc;
unsigned char M,C,D,U;
unsigned char flag=0;
/////////////////////////////////////////////////
//Funcion de interrupcion
//Si no se usa simplemente no hacemos nada...
//Esto sirve para direccionar lo los datos
//en un lugar muy cercano al Inicio de la memoria
//de datos
////////////////////////////////////////////////
static void interrupt
isr(void){
/////////////////////////////////////////////////////////////////////////
// INTERRUPCION POT TIMER0 ///
//CADA 3.33mS habra una interrupcion que hara que corra un bit hacia ///
//la IZQUIERDA para encender el siguiente DISPLAY ///
//Cuando surga la interrupcion por TIMER1 no entrara aqui ///
/////////////////////////////////////////////////////////////////////////
if(TMR0IF && !TMR1IF && TMR0IE){//NO HA SURGIDO INT. POR TIMER0?
if(flag==0){
LATC<<=1; //Recorre un bit a la Izquierda
if(LATC==0){//A recorrido los tres bit?
flag=1; //Cambia de puerto
LATA=0x02;//Empieza en el puerto A
}
}else{
LATA<<=1;//Recorre un bit a la Izquierda
if(LATA>=16){//Ha llegado al limite
flag=0; //Cambia de Puerto
LATC=0x01;//Inicia otra vez el ciclo
}
}
TMR0IF=0;//Reset flag
10. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 94
WriteTimer0(58875);//carga nuevamente el valor
}
/*---------------------Fin de INT. TIMER0---------------------------*/
//////////////////////////////////////////////////////////////////////
// INTERRUPCION POT TIMER1 ///
//Al entrar aqui, inicializa las variables a cero desactiva ///
//Interrupcion por TIMER0 y empieza el convertidor ///
//Cuando tengamos el valor analogo, debemos de sacar las Milesimas ///
//Centecimas, Decimas y Unidades. ///
//Esta interrupcion surgira cada 100mS ///
//////////////////////////////////////////////////////////////////////
if(TMR1IF){
M=C=D=U=0;//Inicializa variables
TMR0IE=0; //Desactiva INT por timer0
ConvertADC();//Empieza la conversion Analoga
while(BusyADC());//Ha terminado?
adc=ReadADC();//Lee el dato
while(adc>=1000){//Es mayor de 1000?
adc-=1000; //Resta 1000
M++; //Incrementa 1
}
while(adc>=100){ //Es mayor de 100?
adc-=100; //Resta 100
C++; //Incrementa 1
}
while(adc>=10){ //Es mayor de 10?
adc-=10; //resta 10
D++; //Incrementa 1
}
if(adc>0){ //Es mayor de 0?
U=adc; //Toma el valor ultimo
}else{
U=0; //Sino,valor a Cero
}
TMR1IF=0; //Reset timer1
TMR0IE=1; //Activa Timer0
WriteTimer1(40535);//Carga el valor nuevamente.
}
/*---------------------Fin de INT. TIMER1---------------------------*/
}
//////////////////////////////
//FUNCION PRINCIPAL
//////////////////////////////
void main(void){
OSCCON=0x70;
NOP();NOP();NOP();NOP();
//////////////////////////////////////////////////////////////////////
// Configuracion de Puertos ///
//////////////////////////////////////////////////////////////////////
TRISB=0x00;//Puerto B como salida
TRISC=0x00;//Puerto C como salida
TRISA=0x01;//Pin A0 como entrada analoga
CMCON=0x07;
/*---------------------Fin de Conf. Puertos-------------------------*/
//////////////////////////////////////////////////////////////////////
// Configuracion de Timer1 ///
//////////////////////////////////////////////////////////////////////
OpenTimer0(TIMER_INT_ON & //Interrupcion activada
T0_16BIT & //valor de 16 bit
T0_SOURCE_INT & //Corriente desde el oscilador principal
T0_PS_1_1); //Preescalar de 16
/*---------------------Fin de Conf. TIMER1--------------------------*/
11. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 95
//////////////////////////////////////////////////////////////////////
// Configuracion de Timer1 ///
//////////////////////////////////////////////////////////////////////
OpenTimer1(TIMER_INT_ON & //Interrupcion Desactivada
T1_16BIT_RW & //valor de 16 bit
T1_SOURCE_INT & //Corriente desde el oscilador principal
T1_PS_1_8 & //Preescalar de 8
T1_OSC1EN_OFF &
T1_SYNC_EXT_OFF &
T1_SOURCE_CCP); //Sincronismo desactivado
/*---------------------Fin de Conf. TIMER1--------------------------*/
//////////////////////////////////////////////////////////////////////
// Configuracion de ADC ///
//////////////////////////////////////////////////////////////////////
OpenADC(ADC_FOSC_RC &//Internal Oscilador Interno
ADC_RIGHT_JUST &//Justificacion a la derecha (10-bit)
ADC_20_TAD, //Tiempo de Adquisicion (TAD)
ADC_CH0 &//CANAL 3 analogo
ADC_INT_OFF &//Interrupcion por ADC APAGDO
ADC_REF_VDD_VSS, //V+ref=VCC,V-ref=GND
ADC_CH0); //AN4=analogo,resto digitales
/*---------------------Fin de Conf. ADC------------------------------*/
INTCON|=0b00100000;//Para activar interrupcion por timer0
WriteTimer0(58875);//Valor para tener una interrupcion cada 3.33 mS
WriteTimer1(40535);//Valor para tener una interrupcion cada 100ms
GIE=1; //INTERRUPCIONES GLOBALES ACTIVADAS
PEIE=1; //ACTIVA INTERURPCIONES POR PERIFERICOS
PORTB=0x00;//Inicializa PUERTO B como apagado
LATC=0x01;
LATA=0x00;
while(1){
if(LATC==0x01) {LATB=mostrar[0];}//Simplemente Muestra 0
else if(LATC==0x02) {LATB=mostrar[0];}//Simplemente Muestra 0
else if(LATC==0x04) {LATB=mostrar[M];}//Simplemente Muestra Milesimas
else if(LATA==0X02) {LATB=mostrar[C];}//Simplemente Muestra Centecimas
else if(LATA==0X04) {LATB=mostrar[D];}//Simplemente Muestra Decimas
else if(LATA==0X08) {LATB=mostrar[U];}//Simplemente Muestra Unidades
}
}
12. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 96
Para seguir con nuestro circuito ya armado, y
no desperdiciar más cables, se propone realizar
un contador de eventos, en este caso se tiene
en lugar de una entrada análoga, una entrada
digital, que cada vez que se detecte un pulso
este empiece a incrementar las variables que se
mostraran en los display.
El programa a manejar es muy parecido del
anterior, ya que solo se modifico, dos cosas.
Una solo se removió la opción del convertidor
análogo digital dejando solo entradas digitales
en el PINA0. Dos se quito la lógica de
programación del convertidor de número a BCD
en la interrupción y se modifico.
Ahora como hemos de realizar un contador con
un push botón, hay que tener en cuenta
algunos aspectos, cada vez que presionamos el
botón puede surgir los rebotes, se le dice
rebotes de corriente, ya que al presionar el
botón, abra picos de voltaje que pueden
producir información de pulsaciones erróneas,
causando que cuente más de lo previsto.
Para la solución de este problema se adopto por
realizar lo siguiente: Crear una variable que
cuente 3 interrupción por timer1 que
corresponden a una temporización de 300mS, al
llegar al máximo de pulsos, pregunta si se ha
presionado el botón, si es así, incrementara la
variable U, cuando dicha variable llega al valor
máximo que es 10, se resetea e incrementa la
siguiente variable que es D y así sucesivamente
hasta llegar a la variable M.
El botón puede ser un pulsador, conectado a
+5v y el otro extremo a una resistencia de 10k
hacia tierra.
Siguiendo con nuestro
circuito armado de 6
display. Para contar
eventos con un botón.
ET
Sin tiempo
Con tiempo
antirepote
13. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 97
Podemos apreciar el diagrama a manejar:
El Programa que contiene el microcontrolador es el siguiente:
////////////////////////////////////////////////////////
// Contador ////
//Autor: george.manson.69 ////
//Lugar: Mexico ////
//Compilador: HI TECH PIC18 (LITE MODE) ////
////////////////////////////////////////////////////////
#include<htc.h>
/////////////////////////////////////////////////////////////
//Configuracion para trabajar Con oscilador interno de 8Mhz
__CONFIG(1,INTIO & FCMDIS & IESODIS & PLLDIV5 & PLLPOSTDIV2 & CPUDIV1 & USBOSC);
/////////////////////////////////////////////////////////////
__CONFIG(2,VREGDIS & PWRTEN & BORDIS & WDTDIS & BORV45 & WDTPS32K);
__CONFIG(3,PBDIGITAL & LPT1DIS & MCLREN);
__CONFIG(4,STVRDIS & LVPDIS & ICPORTDIS & DEBUGDIS);
__CONFIG(5,UNPROTECT);
__CONFIG(6,UNPROTECT);
__CONFIG(7,UNPROTECT);
//////////////////////////////
//Frecuencia FOSC 8Mhz
14. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 98
//////////////////////////////
#define _XTAL_FREQ 8000000
/////////////////////////////
//VARIABLES
/////////////////////////////
const unsigned char mostrar[10]={0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,
0b10010010,0b10000011,0b11111000,0b00000000,0b00011000};
unsigned int adc;
unsigned char M,C,D,U;
unsigned char flag=0;
unsigned char var;
/////////////////////////////////////////////////
//Funcion de interrupcion
//Si no se usa simplemente no hacemos nada...
//Esto sirve para direccionar lo los datos
//en un lugar muy cercano al Inicio de la memoria
//de datos
////////////////////////////////////////////////
static void interrupt
isr(void){
/////////////////////////////////////////////////////////////////////////
// INTERRUPCION POT TIMER0 ///
//CADA 3.33mS habra una interrupcion que hara que corra un bit hacia ///
//la IZQUIERDA para encender el siguiente DISPLAY ///
//Cuando surga la interrupcion por TIMER1 no entrara aqui ///
/////////////////////////////////////////////////////////////////////////
if(TMR0IF && !TMR1IF && TMR0IE){//NO HA SURGIDO INT. POR TIMER0?
if(flag==0){
LATC<<=1; //Recorre un bit a la Izquierda
if(LATC==0){//A recorrido los tres bit?
flag=1; //Cambia de puerto
LATA=0x02;//Empieza en el puerto A
}
}else{
LATA<<=1;//Recorre un bit a la Izquierda
if(LATA>=16){//Ha llegado al limite
flag=0; //Cambia de Puerto
LATC=0x01;//Inicia otra vez el ciclo
}
}
TMR0IF=0;//Reset flag
WriteTimer0(58875);//carga nuevamente el valor
}
/*---------------------Fin de INT. TIMER0---------------------------*/
//////////////////////////////////////////////////////////////////////
// INTERRUPCION POT TIMER1 ///
//Cheka cada 300mS el switch, si esta presionado suma 1 ///
//A la variable que corresponda.
//////////////////////////////////////////////////////////////////////
if(TMR1IF){
TMR0IE=0; //Desactiva INT por timer0
var++;
if(var>3){
var=0;
if(RA0){
U++;
if(U>=10){
U=0;
D++;
if(D>=10){
D=0;
C++;
15. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 99
if(C>=10){
C=0;
M++;
if(M>=10){
M=0;
}
}
}
}
}
}
TMR1IF=0; //Reset timer1
TMR0IE=1; //Activa Timer0
WriteTimer1(41035);//Valor para tener una interrupcion cada 100ms
}
}
/*---------------------Fin de INT. TIMER1---------------------------*/
//////////////////////////////
//FUNCION PRINCIPAL
//////////////////////////////
void main(void){
OSCCON=0x70;
NOP();NOP();NOP();NOP();
//////////////////////////////////////////////////////////////////////
// Configuración de Puertos ///
//////////////////////////////////////////////////////////////////////
TRISB=0x00;//Puerto B como salida
TRISC=0x00;//Puerto C como salida
TRISA=0x01;//Pin A0 como entrada digital
ADCON1=0x0F;
CMCON=0x07;
/*---------------------Fin de Conf. Puertos-------------------------*/
//////////////////////////////////////////////////////////////////////
// Configuración de Timer1 ///
//////////////////////////////////////////////////////////////////////
OpenTimer0(TIMER_INT_ON & //Interrupción activada
T0_16BIT & //valor de 16 bit
T0_SOURCE_INT & //Corriente desde el oscilador principal
T0_PS_1_1); //Preescalar de 16
/*---------------------Fin de Conf. TIMER1--------------------------*/
//////////////////////////////////////////////////////////////////////
// Configuración de Timer1 ///
//////////////////////////////////////////////////////////////////////
OpenTimer1(TIMER_INT_ON & //Interrupción Desactivada
T1_16BIT_RW & //valor de 16 bit
T1_SOURCE_INT & //Corriente desde el oscilador principal
T1_PS_1_8 & //Preescalar de 8
T1_OSC1EN_OFF &
T1_SYNC_EXT_OFF &
T1_SOURCE_CCP); //Sincronismo desactivado
/*---------------------Fin de Conf. TIMER1--------------------------*/
INTCON|=0b00100000;//Para activar interrupción por timer0
WriteTimer0(58875);//Valor para tener una interrupción cada 3.33 mS
WriteTimer1(41035);//Valor para tener una interrupción cada 100ms
GIE=1; //INTERRUPCIONES GLOBALES ACTIVADAS
PEIE=1; //ACTIVA INTERURPCIONES POR PERIFERICOS
PORTB=0x00; //Inicializa PUERTO B como apagado
LATC=0x01;
LATA=0x00;
while(1){
if(LATC==0x01) {LATB=mostrar[0];}//Simplemente Muestra 0
else if(LATC==0x02) {LATB=mostrar[0];}//Simplemente Muestra 0
16. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 100
else if(LATC==0x04) {LATB=mostrar[M];}//Simplemente Muestra Milesimas
else if(LATA==0X02) {LATB=mostrar[C];}//Simplemente Muestra Centecimas
else if(LATA==0X04) {LATB=mostrar[D];}//Simplemente Muestra Decimas
else if(LATA==0X08) {LATB=mostrar[U];}//Simplemente Muestra Unidades
}
}
Algunas imágenes del Contador:
Recuerde siempre alimentar al circuito coin un voltaje de 5 Volts.
Boton
17. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 101
Algunas veces en nuestra vida como
electrónicos, o simplemente como hobbystas,
se nos pasa por la mente realizar un reloj con
display, como podemos realizarlos de distintas
formas como usando lógica TTL, o pasando ya a
usar cosas más avanzadas como los
microcontroladores, pues ¿Porque no
realizarlo?, ya que tenemos el circuito armado
con los 6 display, ahorraremos mucho tiempo
para desarrollarlo, simplemente necesitamos
colocar 3 pulsadores y realizar otra tipo de
lógica de programación en nuestro PIC y hemos
realizado nuestro reloj.
La idea es tener tres pulsadores de cual un
servirá para controlar los demás.
Por ejemplo llamemos a uno como SET, a otro
botón como HORAS, y el último como
MINUTOS, cuando el botón SET no esté
presionado, el microcontrolador no hará caso
los botones de HORAS y MINUTOS, pero si
tenemos lo contrario que el botón SET este
presionado mientras este así, podemos cambiar
o presionar los botones HORAS y MINUTOS.
Teniendo ya establecido las condiciones del los
pulsadores ya podemos empezar a programar,
lo único que cambiaremos de del programa
anterior es algunas variables y solo
cambiaremos la función de interrupción del
TIMER1, ya que la interrupción por TIMER0 es
ya es de ley tenerla. Lo que cambiaremos de la
interrupción del TIMER1 es como se debe de
comportar al presionar un botón, pero a la vez
no interrumpir el proceso de contar los
segundos ya que si hacemos que los pulsadores
corten la sincronía del tiempo, podemos
adelantar o retrasar nuestro reloj.
Como sabemos que la configuración de
interrupción del TIMER1 surge cada 100mS
teniendo que realizar 10 veces dicha
interrupción para tener aproximadamente un
segundo, crearemos una variable que cuente las
interrupciones y al llegar a la decima
interrupción sume a otra variable +1.
Se han creado 6 variables para que cada una de
ellas corresponda a cada display, por ejemplo:
H2 H1 M2 M1 S2 S1
La variable que se le sumara uno cuando las 10
interrupciones pasen, es “S1” ya que esta
variable es la que corresponde al primer display
de Derecha a Izquierda, cuando la variable “S1”
llegue al máximo en este caso a 10, “S1=0” y
suma uno a la siguiente variable “S2” pero esta
Aun siguiendo con nuestro
circuito armado para realizar
un reloj simple.
18. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 102
variable no debe de llegar hasta 10 sino a 6, ya
que debemos de contar solo 60 segundos,
cuando la variable “S2” llegue a 6 se volverá a
cero, y sumara uno a la variable M1, y así
sucesivamente pero si deseamos realizar que
las horas solo cuente hasta 24, se realiza la
siguiente lógica:
Ya tenemos la lógica de cómo realizar la
sumatoria de las variables con respecto al
tiempo, pero aun no tenemos como poner la
lógica de introducir los botones sin afectar el
conteo de segundos y aparte de no afectar con
rebotes al presionar dicho botón.
Bueno para solucionar los rebotes al presionar
cualquier botón, se debe de esperar 300mS
para que entre o compare si se ha presionado el
botón de SET, se usa la comparación:
If((var%3)==1);
Esta comparación hace que cada 300mS entre y
vea que si se ha presionado el botón de SET, ya
que:
1%3 No es múltiplo de tres entrega 0
2%3 No es múltiplo de tres entrega 0
3%3 Es múltiplo de tres entrega 1
4%3 No es múltiplo de tres entrega 0
5%3 No es múltiplo de tres entrega 0
6%3 3 Es múltiplo de tres entrega 1
….
Al entrar a esta comparación ahora veremos si
se ha presionado el botón SET
Ahora si cada vez que pase 300mS se podrá
checar el pulsador SET pero sin afectar el
tiempo de los segundos.
Pero recuerde que los segundos pueden ser
afectados a la acumulación de instrucciones de
nuestro programa porque recuerde que el
lenguaje C esta hecho por macros es decir que
contiene líneas de lenguaje ensamblador pero
todo el conjunto de una sola instrucción está
dirigido simplemente a una línea en C.
Por ejemplo:
TRISB=0x00 ;No se ejecuta en un ciclo maquina
sino lo transformamos a lo que es realmente en
ensamblador y tenemos que:
Bcf STATUS,5
Movlw 0x00
Movwf TRISB
H1++;
if(H1==10 && H2<2){
H1=0;
H2++;
}else if(H1==4 && H2==2){
H2=H1=0;
}
else if((var%3)==1){
if(SET){
if(HORAS){
H1++;
if(H1==10 && H2<2){
H1=0;
H2++;
}else if(H1==4 && H2==2){
H2=H1=0;
}
}
if(MINUTOS){
M1++;
if(M1>=10){
M1=0;
M2++;
if(M2>=6){
M2=0;
}
}
}
}
}
19. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 103
En realidad se ejecuta en tres ciclos maquina, esto lo menciono para que tenga una idea de cómo debe
de optimizar los códigos para que realice lo mismo pero consuma menos tiempo maquina.
Y nuestro proyecto es afectado por los términos anteriores, y podría retrasarse unos segundos cada
cuatro u ocho días, se recomienda realizar una buena lógica de programación para solucionar o hacer
mucho más pequeño el lapso de tiempo perdido.
El circuito a Manejar es el siguiente;
Como vemos no se ha cambiado en absoluto la configuración de los transistores, ni los display solo
hemos puesto 2 pulsadores extras para cambiar la HORA y MINUTOS.
20. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 104
El programa se muestra a continuación:
////////////////////////////////////////////////////////
// Contador ////
//Autor: george.manson.69 ////
//Lugar: Mexico ////
//Compilador: HI TECH PIC18 (LITE MODE) ////
////////////////////////////////////////////////////////
#include<htc.h>
/////////////////////////////////////////////////////////////
//Configuracion para trabajar Con oscilador interno de 8Mhz
__CONFIG(1,INTIO & FCMDIS & IESODIS & PLLDIV5 & PLLPOSTDIV2 & CPUDIV1 & USBOSC);
/////////////////////////////////////////////////////////////
__CONFIG(2,VREGDIS & PWRTEN & BORDIS & WDTDIS & BORV45 & WDTPS32K);
__CONFIG(3,PBDIGITAL & LPT1DIS & MCLREN);
__CONFIG(4,STVRDIS & LVPDIS & ICPORTDIS & DEBUGDIS);
__CONFIG(5,UNPROTECT);
__CONFIG(6,UNPROTECT);
__CONFIG(7,UNPROTECT);
//////////////////////////////
//Frecuencia FOSC 8Mhz
//////////////////////////////
#define _XTAL_FREQ 8000000
//////////////////////////////
//Definiciones Globales
//////////////////////////////
#define SET RA0
#define HORAS RC6
#define MINUTOS RC7
/////////////////////////////
//VARIABLES
/////////////////////////////
const unsigned char mostrar[10]={0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,
0b10010010,0b10000011,0b11111000,0b00000000,0b00011000};
unsigned int adc;
unsigned char H2,H1,M2,M1,S2,S1;
unsigned char flag=0;
unsigned char var;
/////////////////////////////////////////////////
//Funcion de interrupcion
//Si no se usa simplemente no hacemos nada...
//Esto sirve para direccionar lo los datos
//en un lugar muy cercano al Inicio de la memoria
//de datos
////////////////////////////////////////////////
static void interrupt
isr(void){
/////////////////////////////////////////////////////////////////////////
// INTERRUPCION POT TIMER0 ///
//CADA 3.33mS habra una interrupcion que hara que corra un bit hacia ///
//la IZQUIERDA para encender el siguiente DISPLAY ///
//Cuando surga la interrupcion por TIMER1 no entrara aqui ///
/////////////////////////////////////////////////////////////////////////
if(TMR0IF && !TMR1IF && TMR0IE){//NO HA SURGIDO INT. POR TIMER0?
if(flag==0){
LATC<<=1; //Recorre un bit a la Izquierda
if(LATC==0){//A recorrido los tres bit?
flag=1; //Cambia de puerto
LATA=0x02;//Empieza en el puerto A
}
21. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 105
}else{
LATA<<=1;//Recorre un bit a la Izquierda
if(LATA>=16){//Ha llegado al limite
flag=0; //Cambia de Puerto
LATC=0x01;//Inicia otra vez el ciclo
}
}
TMR0IF=0;//Reset flag
WriteTimer0(58875);//carga nuevamente el valor
}
/*---------------------Fin de INT. TIMER0---------------------------*/
//////////////////////////////////////////////////////////////////////
// INTERRUPCION POT TIMER1 ///
//Cheka cada 300mS el switch, si esta presionado suma 1 ///
//A la variable que corresponda.
//////////////////////////////////////////////////////////////////////
if(TMR1IF){
TMR0IE=0; //Desactiva INT por timer0
/*CODIGO PRINCIPAL*/
//Segundos jamas se interrupe//
var++;
if(var>=10){
var=0;
S1++;
if(S1==10){
S1=0;
S2++;
if(S2==6){
S2=0;
M1++;
if(M1==10){
M1=0;
M2++;
if(M2==6){
M2=0;
H1++;
if(H1==10 && H2<2){
H1=0;
H2++;
}else if(H1==4 && H2==2){
H2=H1=0;
}
}
}
}
}
}
else if((var%3)==1){
if(SET){
if(HORAS){
H1++;
if(H1==10 && H2<2){
H1=0;
H2++;
}else if(H1==4 && H2==2){
H2=H1=0;
}
}
if(MINUTOS){
M1++;
if(M1>=10){
M1=0;
22. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 106
M2++;
if(M2>=6){
M2=0;
}
}
}
}
}
/*******************/
TMR1IF=0; //Reset timer1
TMR0IE=1; //Activa Timer0
WriteTimer1(41900);//Valor para tener una interrupcion cada 100ms
}
}
/*---------------------Fin de INT. TIMER1---------------------------*/
//////////////////////////////
//FUNCION PRINCIPAL
//////////////////////////////
void main(void){
OSCCON=0x70;
NOP();NOP();NOP();NOP();
//////////////////////////////////////////////////////////////////////
// Configuracion de Puertos ///
//////////////////////////////////////////////////////////////////////
TRISB=0x00;//Puerto B como salida
TRISC=0xD0;//Puerto C como salida
TRISA=0x01;//Pin A0 como entrada digital
ADCON1=0x0F;
CMCON=0x07;
/*---------------------Fin de Conf. Puertos-------------------------*/
//////////////////////////////////////////////////////////////////////
// Configuracion de Timer1 ///
//////////////////////////////////////////////////////////////////////
OpenTimer0(TIMER_INT_ON & //Interrupcion activada
T0_16BIT & //valor de 16 bit
T0_SOURCE_INT & //Corriente desde el oscilador principal
T0_PS_1_1); //Preescalar de 16
/*---------------------Fin de Conf. TIMER1--------------------------*/
//////////////////////////////////////////////////////////////////////
// Configuracion de Timer1 ///
//////////////////////////////////////////////////////////////////////
OpenTimer1(TIMER_INT_ON & //Interrupcion Desactivada
T1_16BIT_RW & //valor de 16 bit
T1_SOURCE_INT & //Corriente desde el oscilador principal
T1_PS_1_8 & //Preescalar de 8
T1_OSC1EN_OFF &
T1_SYNC_EXT_OFF &
T1_SOURCE_CCP); //Sincronismo desactivado
/*---------------------Fin de Conf. TIMER1--------------------------*/
INTCON|=0b00100000;//Para activar interrupcion por timer0
WriteTimer0(58875);//Valor para tener una interrupcion cada 3.33 mS
WriteTimer1(41900);//Valor para tener una interrupcion cada 100ms
GIE=1; //INTERRUPCIONES GLOBALES ACTIVADAS
PEIE=1; //ACTIVA INTERURPCIONES POR PERIFERICOS
PORTB=0x00;//Inicializa PUERTO B como apagado
LATC=0x01;
LATA=0x00;
while(1){
if(LATC==0x01) {LATB=mostrar[H2];}//Simplemente Muestra 0
else if(LATC==0x02) {LATB=mostrar[H1];}//Simplemente Muestra 0
else if(LATC==0x04) {LATB=mostrar[M2];}//Simplemente Muestra Milesimas
else if(LATA==0X02) {LATB=mostrar[M1];}//Simplemente Muestra Centecimas
23. [PROYECTO #1] 13 de enero de 2011
Usando Display de 7 segmentos Página 107
else if(LATA==0X04) {LATB=mostrar[S2];}//Simplemente Muestra Decimas
else if(LATA==0X08) {LATB=mostrar[S1];}//Simplemente Muestra Unidades
}
}
Algunas fotos del Reloj:
Foto de reloj
SET