TODOPIC

Lenguajes de programación para PC => C, C#, C++ => Mensaje iniciado por: yesvari85 en 27 de Octubre de 2015, 00:14:21

Título: Cronometro por interrupciones PIC 16F887 en PIC C
Publicado por: yesvari85 en 27 de Octubre de 2015, 00:14:21
Buenas noches compañeros estoy tratando de escribir un programa para hacer un cronometro con display de 7 segmentos en el PIC 16F887 pero no he podido lograrlo, esto es lo que llevo, me podrían dar una ayuda?. Muchas gracias.

#include <16F887.h>
#fuses NOWDT, NOMCLR, INTRC_IO
#use delay(clock=4Mhz)
#byte portb=0x06 // En el puerto B iran conectados los displays de 7 segmentos
#byte trisb=0x86
#byte portc=0x07 // En el puerto C ira conectado el reset
#byte trisc=0x87
#byte porte=0x09 // En el puerto E iran conectados los transistores
#byte trise=0x89

int contador; //REGISTRO AUXILIAR--> 2000*0.0005 = 1 SEGUNDO.


/* FORMULA PARA CALCULAR LA PRECARGA DEL TIMER0
Temporización = 4*Tcm*Precaler*ValorRealTMR0
T = 4*Tcm*Prescaler(256-Carga timer0)
Tcm = 4/fosc. Periodo del ciclo de maquina
Prescaler = 4
fosc = 4Mhz --> Tcm = 1/4000000
Ejemplo si tiempo de interrupción = 500 mSeg.= 0.0005 seg
0.0005 = (4*1*4*(256-X))/4000000
X=131
*/

byte const display[10]={0x80,0XF2,0X48,0X60,0X32,0X24,0x04,0x70,0x00,0x3 0}; // Tabla displays catodo comun

int segundos=0;
int minutos=0;
int unidad=0; // El display que mostrará las unidades comenzara en cero
int decena=0; // El display que mostrará las decenas comenzara en cero
int centena=0; // El display que mostrará las centenas comenzara en cero

void visualizar(){
portb=display[unidad];
bit_clear(porte,0);
bit_set(porte,1);
bit_set(porte,2);
delay_ms(5);
portb=0xff;

portb=display[decena];
bit_set(porte,0);
bit_clear(porte,1);
bit_set(porte,2);
delay_ms(5);
portb=0xff;

portb=display[centena];
bit_set(porte,0);
bit_set(porte,1);
bit_clear(porte,2);
delay_ms(5);
portb=0xff;

}
void HEX_BCD(contador){
unidad=contador%10;
decena=(contador%100)/10;
}

#INT_TIMER0
void timer0()
{
set_timer0(get_timer0());
contador++;
if(contador==244){
contador = 00;
}
}

#INT_EXT
void tiempo(){
minutos=0;
Segundos=0;
}

void main()
{
trisb=0b00000000; // congifuracion de los puertos
trisc=0b11111111;
trise=0b00000000;
HEX_BCD(contador);
visualizar();
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_EXT);
ext_int_edge(H_TO_L);
//setup_timer_0(RTCC_INTERNAL | RTCC_DIV_4);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_8);
set_timer0(00);

WHILE (TRUE)
{


}
}
Título: Re:Cronometro por interrupciones PIC 16F887 en PIC C
Publicado por: KILLERJC en 27 de Octubre de 2015, 01:12:23
Creo que existen una cuantas cosas mal, y hay varias para mejorar.

Tu programa comienza seteando los tris, Ejecuta la subrutina HEX_BCD, las cuales unicamente actualiza 2 variables de las 3 que mostras ( solo unidad y decena ), centena no la tocas.
Mostrars en tus displays, activas interrupciones y....... y.......... no haces mas nada. queda en el while y solo quedarian las interrupciones a ejecutar.

Mirando las interrupciones veo un problema ahi tambien. Asi que empezamos por nombrar los problemas

Main:
- Quita el HEX_BCD y visualizar y ponerlo dentro del while del main.
Esto te va a permitir que cuando no este en la interrupcion se la pase mostrando el dato. Es decir haciendo la multiplexacion y esas cosas.

- set_timer0(00) no es 0, es 131, lo calculaste al comienzo del programa.

- Primero configura todo, y al final activa las interrupciones, no activar las interrupciones y luego configurar las cosas.

Interrupcion Timer:

Código: [Seleccionar]
#INT_TIMER0
void timer0()
{
set_timer0(get_timer0());
contador++;
if(contador==244){
contador = 00;
}
}

2 errores,  set_timer0() deberia tener el valor 131, y no get_timer0(), si vos te pones a pensar ahi entra cuando se produce el overflow es decir de 255 (0xFF) a 0 (0x00) con lo que hiciste tomaria el 0 que posee el timer y lo pondria en 0 ... No tiene logica. lo que vos intentas es que dure otros 500us , entonces le tenes que poner el 131.
 Luego tenes contador... vos te tenes que dar cuenta que eso es lo que se muestra en los displays, esto esta entrando cada 0.5ms ( 500us ) e incrementandolo, tu codigo para mostrarlo, cada display apaga y prende cada 5ms, todo eso se resume en que no vas a ver NADA. Te hago un ejemplo de lo que sucederia con HEX_CBD y visualizar en el while del main:

Contador = 0
Se ejecuta HEX_BCD... actualiza centena,decena y unidades
Ejecuta visualizar, 5ms del primer display y contador ya estaria en 10, pero vos seguis mostrando 000
Segundo display otros 5ms, contador en 20 vos mostras 000
Tercer display, contador en 30 vos mostras 000
Comienza el while de nuevo!
Esta ves contador esta en 30! asi que mostrarias 030.

Si te diste cuenta estarias mostrando:
000
030
060
090
120

Y todo esto si es que lo ves. ya que se haria cada 15ms, es decir los 3 display se actualizarian 66 veces en 1 segundo, no creo que puedas distinguir eso.

Pienso que el timer 0 te puede servir para tu cronometro, pero por ahora deberias utilizar el Timer1 asi aunque sea poder ver que aumenta el numero, luego achicas los tiempos, por que es de 16 bits y que permite hacer con 4Mhz demoras de hasta 0.5s, sino me equivoco con preescaler 1/8 , si cargas 3036 en el timer tenes una interrupcion cada 0.5s, si haces eso y corregis tu codigo:

Código: [Seleccionar]
void timer1()
{
   set_timer1(3036);
   contador++;
   if(contador>=244) contador = 0;
}


Código: [Seleccionar]
WHILE (TRUE)
{
    HEX_BCD(contador);
    visualizar();
}

Código: [Seleccionar]
void HEX_BCD(contador){
   unidad=contador%10;
   decena = contador /10;
   centena = decena /10;
   decena = decena % 10;
}

Declarar a contador como

volatile int contador;

Y estaria listo como para ver en displays un valor que se incremente cada medio segundo, una ultima cosa, hay varios pines que son analogicos, no se como se maneja CCS con eso y como tenes que indicarle para que se pongan digitales, asi que eso puede ser otro problema. o uso CCS, por lo cual solo puedo decirte algunas cosas. Como:

Si usas TRIS, en el cual tenes una funcion llamada set_tris_x() donde x es el puerto, asi no tenes que definir a tris al comienzo, deberias usar #use fast_io, sino el compilador agrega instrucciones de mas. Igual para setear todo el puerto tenes output_x(0x00); donde x es el puerto, para encender o apagar un bit con output_high(PIN_E0); o output_low(PIN_E2);
Es lo poco que se de CCS

Y una mejora seria usar el modulo CCP en modo compare. El cual te va a exigir el Timer 1, especialmente si usas un cristal de 32768 en el timer 1 asi llevar un poco mas exacto la hora.
Te dejo un link para calcular los tiempos del timer:
http://eng-serve.com/pic/pic_timer.html

Mas simple que estar pensando en los ciclos :P