Académique Documents
Professionnel Documents
Culture Documents
PicMana by RedRaven
Inicio . Mapa . Presentacin . Electrnica Bsica . Experimentos . Proyectos . CCS C . C30 . Invitados . Eagle . Conceptos
Datasheets . IC's . USB . Trucos e Ideas . Cajn de Sastre . Recursos . Enlaces . RedPic . Noticias . Histrico . Visitas
Buscar
Bsqueda personalizada
Curso c para
PICS
Curso-taller c
para PIC16f887
Diplomado de
programacin de
pics
www.commtechcomput
Ms CCS C : 1 2 3 4
ndice General:
Template para el uso de la Interrupcin RTCC mediante el TIMER0
La primera y quizs la mas utilizada de las interrupciones, por ejemplo es la
bsica para los Relojes en Tiempo (casi) Real.
Template para el uso de la Interrupcin RDA de la USART
Utilsima para recibir datos desde el PC mientras nuestro micro se dedica a otra
cosa mariposa.
Una aplicacin prctica de RTCC : Cronopic 1.0
Contando segundos y minutos con nuestro PIC y mostrndolos sobre 4 displays
de 7 segmentos multiplexados.
BIN2BCD
para enviar nuestros bytes a los Displays de 7 segmentos.
Flex LCD
una completa librera para manejar un mdulo LCD con la posibilidad de
configurar los pines a usar.
Modificando el ancho de un pulso, generado con RTCC, mediante ordenes
RS-232. O un PWM por Software.
Una librera para rastrear un Teclado matricial 4x4
Serie Tcnicas en C:
Tcnicas en C : ndice
Un punto de entrada a esta nueva serie de artculos.
Tcnicas en C : Midiendo un pulso. 1 Parte
Midiendo en tiempo que un pulso permanece en alto mediante INTEXT.
Nota 1:
Los Micros usados son el 16F628, el 16F876A y el 18F4550 pero puede ser
fcilmente adaptado a otros modelos de PIC. Ocasionalmente se usan tambin
los 18F1320 y 18F2550.
Todos los tiempos estn calculados para cristales de 4 Mhz y 20 Mhz, salvo en
los 18F4550 y 18F2550 en funciones de USB que "corren" a 48 Mhz mediante el
PLL interno.
->
->
->
->
->
->
->
->
512
1.0
2.0
4.0
8.1
16.3
33.3
66.6
El Template que propongo usa un Preescaler de 128 para producir una interrupcin
RTCC cada 33.3 mS y as cada 30 veces que se produce cambio de estado la variable
Flag, o sea 33.3 x 30 = 999 mS.
Exactamente este Template es el utilizado en el experimento WinkIntc en el que
hacemos parpadear un Led cada 0.25 segundos (aproximadamente).
// Numero de interrupciones
// VARIABLES GLOBALES
char C_Ints=0;
ocurridas
char Flag=0;
interrupciones
// Contador de Interrupciones
// Flag que cambia cada NInts
#int_RTCC
desbordamiento
RTCC_isr() {
// Interrupcin por
if(Flag==0){
Flag=1;
}
else{
Flag=0;
}
C_Ints=0;
Ints
}
++C_Ints;
interrupciones
}
// Reinicializo Contador de
// Incremento el nmero de
// Ocurridas
void main(void) {
setup_counters(RTCC_INTERNAL,RTCC_DIV_128);// TIMER0: Clock
Interno, Presescaler 128
setup_timer_1(T1_DISABLED);
// para una RTCC cada
33.3 milisegundos
setup_timer_2(T2_DISABLED,0,1);
// -> 1 Segundo = 30
RTCC
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_RTCC);
Interrupcin RTCC
enable_interrupts(global);
Interrupciones
// Habilito
// Habilito
// si ha cambiado Flag
...
// AQUI HAGO LO QUE DESEE CADA 1 SEGUNDO
k=Flag;
anterior de Flag
}
// Guardo estado
}While(TRUE);
}
Descargar Template RTCC
Haciendo Click sobre la imagen inferior puede verse un momento de la simulacin
realizada con el programa anterior haciendo parpadear un Led conectado a PORTB.0.
(La simulacin est realizada con el PIC Simulator IDE 5.22 de Oshon Soft)
Este Template demuestra cmo recibir cada carcter que llega hacindole eco desde
el programa principal. Si necesitamos recoger muchos caracteres y nuestra rutina
principal es larga y farragosa es interesante recibir mediante RDA los caracteres e irlos
almacenando en un BUFFER ms amplio para ser posteriormente tratados.
void main() {
enable_interrupts(global);
enable_interrupts(int_rda);
printf("\r\n\Listen on RS232 (Int)\r\n");
do {
} while (TRUE);
}
Descargar Template RDA
Para este ejemplo vamos a cambiar de micro y nos mudamos del 16F628 al
16F876A, aunque nuestro programa funcionara exactamente igual en uno que en otro
con solo cambiar el include correspondiente.
No estara de ms que le dieses un vistazo al artculo Los Cristales y El Tiempo
donde discutimos los clculos que despus vamos a utilizar en nuestro Cronopic 1.0.
He intentado comentar suficientemente el cdigo fuente, sin embargo debo explicar
al menos que tcnica he seguido para desarrollarlo. El asunto es como sigue:
Cronopic 1.0 habilita la interrupcin RTCC usando un Cristal de 4 Mhz y con un
Preescaler de 1:256 por lo que se produce un desbordamiento cada 66.6 ms. Con 15
interrupciones de stas tenemos 15 * 66.6 = 999 ms, o aproximadamente un
segundo.
As que lo que vamos a implementar es un contador de segundos que solo se
incrementa cada 15 RTCC's consecutivas. Para esto utilizamos la variable nRTCC que
cuando es igual a la constante RTCCxS permite incrementar la variable segundo, que
es nuestro contador de segundos transcurridos. Si segundo pasa de 59
incrementamos minuto, y si ste sobrepasa el valor de 59 volvemos a comenzar
reinicindolo a 0. Esto dentro de la rutina de tratamiento de la interrupcin RTCC.
En el bucle principal, y eterno, dentro de Main() habilitamos una variable
ksegundo que si no es igual a segundo nos indica que el segundo actual ha
cambiado. Al ocurrir esto disparamos la actualizacin de los valores a sacar por
nuestros 7 segmentos. Para ello llamamos a time2bcd() que es la rutina que va a
formatear segundo y minuto para que puedan ver visualizados. Inmediatamente
hacemos ksegundo igual a segundo para que no volvamos a hacer esto mismo hasta
que no cambie el segundo actual, que volveremos a detectar comparndolo con
ksegundo.
El formateo realizado en time2bcd() consiste en convertir segundo y minuto de
sus actuales valores binarios a BCD que es el que acepta el driver de los displays.
Esta conversin carga con sus nuevos valores las variables D1 y D2 que son los
dgitos Low y Hight en que se convierte segundo y D3 y D4 que son los de minuto.
Dentro del bucle principal de main() se llama constantemente a la rutina
display_reloj() que es la encargada de poner los valores de D1, D2, D3 y D4 en el
driver de los displays.
Y eso esto, o casi todo ya que este Cronopic tiene un error de 1 milisegundo por cada
segundo contado por lo que no debes tener una fe absoluta en l si tu vida depende
de ello. No he querido complicarlo en esta primera versin pero no es difcil
compensar este desfase usando el mtodo que he bautizado como pic-bisisesto y que
lo realizaremos para versiones posteriores de Cronopic.
Cronopic 1.0
#include <16f876a.h> // Selecciona el PIC
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT // Opciones de configuracin
#use delay(clock=4000000) // Velocidad del Cristal : 4 Mhz
#use standard_io(B) // PORTB en estandar IO digital
#use
fixed_io(b_outputs=PIN_B0,PIN_B1,PIN_B2,PIN_B3,PIN_B4,PIN_B5,PIN_B6,PIN_B7)
char const RTCCxS=15; // Nmero de RTCC's para 1 segundo con 4 Mhz /
1:256.
// VARIABLES GLOBALES
int
int
int
int
int
int
int
int
int
nRTCC=0x00;
segundo=0x0;
minuto=0x0;
D1=0x00;
D2=0x00;
D3=0x00;
D4=0x00;
l_digit, h_digit;
i;
//
//
//
//
void testdisplays(void);
void display_reloj(void);
void time2bcd(void);
x BCD
void bin2bcd(int valor);
#int_RTCC
RTCC_isr() {
if(++nRTCC==RTCCxS){
nRTCC=0x00;
if(++segundo>59){
segundo=0;
if(++minuto>59){
minuto=0;
}
}
}
}
void main(void) {
int ksegundo=0x00;
setup_counters(RTCC_INTERNAL,RTCC_DIV_256); // TIMER0: Clock Interno y
Preescaler
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_RTCC);// Habilito Interrupcin RTCC
enable_interrupts(global); // Habilito Interrupciones
display_reloj();
// Muestra constantemente
}While(TRUE);
}
void display_reloj(void){ // Funcin que muestra el contenido del reloj
output_b(D1);
output_high(PIN_B4);
delay_us(30);
output_b(D2);
output_high(PIN_B5);
delay_us(30);
output_b(D3);
output_high(PIN_B6);
delay_us(30);
output_b(D4);
output_high(PIN_B7);
delay_us(30);
}
void time2bcd(void){
bin2bcd(segundo);
D1 = l_digit;
D2 = h_digit;
bin2bcd(minuto);
D3 = l_digit;
D4 = h_digit;
}
void bin2bcd(int valor){ // Funcin que convierte de Binario a BCD
h_digit=0;
if (valor>=10){
do{
valor-=10;
h_digit++;
} while (valor>=10);
}
l_digit=valor;
}
Bin2BCD
Cuando queremos utilizar uno de esos drivers para Displays de 7 segmentos que
solo aceptan datos en BCD se impone una rutina que nos convierta nuestro byte en
tan estrambtico Binary Code Decimal.
Ah os dejo una funcin para realizar la necesaria conversin:
Bin2BCD (1):
int l_digit, h_digit;
h_digit=0;
if (valor>=10){
do{
valor-=10;
h_digit++;
}while (valor>=10);
}
l_digit=valor;
}
Una librera para manejar un LCD con los Pines que deseemos: flex_lcd.c
Aqui os brindo una librera para manejar un LCD con 4 bits de datos, pudiendo
establecer los pines que deseemos para ellos y para los de control E, R/W y RS. Slo
hay que modificar los #defines de los mismos.
Para usarla solo debis incluir el correpondiente #include "flex_lcd.c" en vuestro
programa.
flex_lcd.c
// flex_lcd.c
// Change these pins to fit your own board.
#define
#define
#define
#define
LCD_DB4
LCD_DB5
LCD_DB6
LCD_DB7
PIN_B4
PIN_B5
PIN_B6
PIN_B7
=
=
=
=
input(LCD_DB4);
input(LCD_DB5);
input(LCD_DB6);
input(LCD_DB7);
output_low(LCD_E);
return(retval);
}
#endif
//--------------------------------------// Read a byte from the LCD and return it.
#ifdef USE_LCD_RW
int8 lcd_read_byte(void)
{
int8 low;
int8 high;
output_high(LCD_RW);
delay_cycles(1);
high = lcd_read_nibble();
low = lcd_read_nibble();
return( (high<<4) | low);
}
#endif
//---------------------------------------// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);
#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif
if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);
delay_cycles(1);
#ifdef USE_LCD_RW
output_low(LCD_RW);
delay_cycles(1);
#endif
output_low(LCD_E);
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
//---------------------------void lcd_init(void)
{
int8 i;
output_low(LCD_RS);
#ifdef USE_LCD_RW
output_low(LCD_RW);
#endif
output_low(LCD_E);
delay_ms(15);
for(i=0 ;i < 3; i++)
{
lcd_send_nibble(0x03);
delay_ms(5);
}
lcd_send_nibble(0x02);
for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);
// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 60 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
#ifndef USE_LCD_RW
delay_ms(5);
#endif
}
}
//---------------------------void lcd_gotoxy(int8 x, int8 y)
{
int8 address;
if(y != 1)
address = lcd_line_two;
else
address=0;
address += x-1;
lcd_send_byte(0, 0x80 | address);
}
//----------------------------void lcd_putc(char c)
{
switch(c)
{
case '\f':
lcd_send_byte(0,1);
delay_ms(2);
break;
case '\n':
lcd_gotoxy(1,2);
break;
case '\b':
lcd_send_byte(0,0x10);
break;
default:
lcd_send_byte(1,c);
break;
}
}
//-----------------------------#ifdef USE_LCD_RW
char lcd_getc(int8 x, int8 y)
{
char value;
lcd_gotoxy(x,y);
// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));
output_high(LCD_RS);
value = lcd_read_byte();
output_low(lcd_RS);
return(value);
}
#endif
void lcd_setcursor_vb(short visible, short blink) {
lcd_send_byte(0, 0xC|(visible<<1)|blink);
}
Descargar flex_lcd.c
fcilmente adaptado a cualquier micro PIC, por ejemplo para manejar un Servo.
Fuente pwm_rtcc_232.c
#include <16f876a.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=4000000)
#use standard_io(b)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
int Led=0x00;
int Offseth=0x00;
int Offsetl=0x00;
char Onda='C';
char Keypress=' ';
void eco_offset(void);
#int_rda
void rda_isr() {
Keypress=0x00;
if(kbhit()){
Keypress=getc();
}
}
#int_RTCC
RTCC_isr(){
// RB0
Switch(Led){
Case 0: output_high(PIN_B0);
set_timer0(Offseth);
break;
Case 1: output_low(PIN_B0);
set_timer0(Offsetl);
break;
}
if(++Led>1){
Led=0;
}
}
void main() {
setup_counters(RTCC_INTERNAL,RTCC_DIV_2); // TEST
enable_interrupts(int_rda);
enable_interrupts(global);
enable_interrupts(INT_RTCC);
do {
if(Keypress!=0x00){
switch(Keypress){
// Tipo de Onda
case 'c': Onda='C';
break;
case 'h': Onda='H';
break;
case 'l': Onda='L';
break;
// Incrementando y decrementando periodos
case '+': if(Onda=='C'){ ++Offseth; ++Offsetl; }
if(Onda=='H'){ ++Offseth; }
if(Onda=='L'){ ++Offsetl; }
break;
case '-': if(Onda=='C'){ --Offseth; --Offsetl; }
if(Onda=='H'){ --Offseth; }
if(Onda=='L'){ --Offsetl; }
break;
// Periodos Prefijados
case '1': if(Onda=='C'){ Offseth=0; Offsetl=0; }
if(Onda=='H'){ Offseth=0; }
if(Onda=='L'){ Offsetl=0; }
break;
case '2': if(Onda=='C'){ Offseth=128; Offsetl=128; }
if(Onda=='H'){ Offseth=128; }
if(Onda=='L'){ Offsetl=128; }
break;
case '4': if(Onda=='C'){ Offseth=192; Offsetl=192; }
if(Onda=='H'){ Offseth=192; }
if(Onda=='L'){ Offsetl=192; }
break;
}
eco_offset();
Keypress=0x00;
}
} while (TRUE);
}
void eco_offset(void){
printf("\r\nOnda %c h%u l%u\r\n",Onda,Offseth,Offsetl);
}
Descargar pwm_rtcc_232.c
#if defined(__PCH__)
#if defined use_portb_kbd
#byte kbd = 0xF81 // This puts the entire
#else
#byte kbd = 0xF83 // This puts the entire
#endif
#else
#if defined use_portb_kbd
#byte kbd = 6 // on to port B (at address
#else
#byte kbd = 8 // on to port D (at address
#endif
#endif
#if defined use_portb_kbd
#define set_tris_kbd(x) set_tris_b(x)
structure
structure
6)
8)
#else
#define set_tris_kbd(x) set_tris_d(x)
#endif
COL0
COL1
COL2
COL3
(1
(1
(1
(1
<<
<<
<<
<<
0)
1)
2)
3)
//
//
//
//
PIN_B0
PIN_B1
PIN_B2
PIN_B3
#define
#define
#define
#define
ROW0
ROW1
ROW2
ROW3
(1
(1
(1
(1
<<
<<
<<
<<
4)
5)
6)
7)
//
//
//
//
PIN_B4
PIN_B5
PIN_B6
PIN_B7
kchar=last_key;
last_key='\0';
}
} else {
if((kbd & (ALL_ROWS))!=(ALL_ROWS)) {
if((kbd & ROW0)==0)
row=0;
else if((kbd & ROW1)==0)
row=1;
else if((kbd & ROW2)==0)
row=2;
else if((kbd & ROW3)==0)
row=3;
last_key =KEYS[row][col];
kbd_down = true;
} else {
++col;
if(col==4)
col=0;
}
}
kbd_call_count=0;
}
set_tris_kbd(ALL_PINS);
return(kchar);
}
Descargar kbd_lib.c
#include <16f876a.h>
// Definiciones del PIC 16F876A
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Los Fuses de siempre
#use delay(clock=4000000) // Oscilador a 4 Mhz
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)// RS232 Estndar
// CONSTANTES
/////////////////////////////////////////////////////////////////
int const lenbuff=32; // Longitud de buffer, Ajustar
// a lo que desees (o te sea posible)
// VARIABLES EN RAM
///////////////////////////////////////////////////////////
int xbuff=0x00;
char cbuff[lenbuff];
char rcvchar=0x00;
int1 flagcommand=0;
//
//
//
//
// Declaracin de Funciones
///////////////////////////////////////////////////
void inicbuff(void);
int addcbuff(char c);
void echos(char c);
void procesa_comando(void);
//
//
//
//
Borra buffer
aade carcter recibido al buffer
Eco selectivo sobre RS232
Procesa comando
// INTERRUPCIONES
/////////////////////////////////////////////////////////////
#int_rda
void serial_isr() {
rcvchar=0x00;
if(kbhit()){
rcvchar=getc();
addcbuff(rcvchar);
echos(rcvchar);
}
}
// Desarrollo de Funciones
////////////////////////////////////////////////////
void echos(char c){ // Echo selectivo ---------------------switch(c){
case 0x0D: printf(" [Ent] "); // Si he pulsado la tecla [Intro]
break;
case 0x08: printf(" [Del] "); // Si he pulsado la tecla
[Retroceso]
break;
case 0x1B: printf(" [Esc] "); // Si he pulsado la tecla [Escape]
break;
default:
putc(rcvchar);
// Echo de cualquier otro carcter
}
}
void inicbuff(void){ // Inicia a \0 cbuff ------------------int i;
for(i=0;i<lenbuff;i++){
cbuff[i]=0x00;
}
xbuff=0x00;
}
int addcbuff(char c){ // Aade a cbuff ----------------------switch(c){
case 0x0D:
// Enter -> Habilita Flag para procesar
flagcommand=1;
// Comando en Main
break;
case 0x08:
// Del -> Borra ltimo carcter del Buffer
if(xbuff>0) cbuff[--xbuff]=0x00;
break;
case 0x01B:
// Esc -> Borra el Buffer completamente
inicbuff();
break;
default:
cbuff[xbuff++]=c; // Aade carcter recibido al Buffer
}
}
// Programa Principal
/////////////////////////////////////////////////////////
void main() {
inicbuff(); // Borra buffer al inicio
printf("\r\n\** RS232 Buffered **\r\n\r\n"); // Presenta men
printf("[Enter] Procesa comando\r\n");
printf("[Escape] Borra todo el buffer\r\n");
printf("[Delete] Borra ltimo carcter del buffer\r\n");
printf("[\\w] Comando Escribe\r\n");
printf("[\\r] Comando Lee\r\n");
printf("\r\n");
enable_interrupts(int_rda); // Habilita Interrupcin RDA
enable_interrupts(global); // Habilita interrupciones
do {
if(flagcommand) procesa_comando(); // Si hay comando pendiente
// de procesar ... lo
procesa.
} while (TRUE);
}
// Procesador de Comandos
/////////////////////////////////////////////////////
void procesa_comando(void){
int i;
char arg[lenbuff]; // Argumento de comando (si lo tiene)
flagcommand=0; // Desactivo flag de comando pendiente.
printf("\r\nProcesando ... "); // Monitorizo procesando ...
for(i=0;i<lenbuff;i++){ // Bucle que pone a 0 todos los
arg[i]=0x00; // caracteres en el argumento
}
if(cbuff[0]=='\\'&&cbuff[1]=='r'){ // Comparo inicio del buffer con
comando "\r"
printf("Leyendo ... ");
con comando "\r"
}
if(cbuff[0]=='\\'&&cbuff[1]=='w'){ // Comparo inicio del buffer con
comando "\w"
i=2;
do{ // Extraemos argumento del buffer
arg[i-2]=cbuff[i]; // a partir del 3er byte y hasta \0.
}while(cbuff[++i]!=0x00);
printf("Escribiendo %s ... ",arg);// Aqui lo que deseemos hacer
con comando "\w"
// Monitorizamos el argumento.
}
inicbuff(); // Borro buffer.
printf("Procesado.\r\n\r\n"); // Monitorizo procesado.
}
Descargar rs232_buffered.c
Y por ltimo solo me queda mostrar los resultados sobre mi monitor RS232 en el PC:
www.commtechcomputers.net
Spring-Pin JTAG Connector Plugs Directly to your PCB Zero Component Cost Per Board! www.Tag-Connect.com
*DisplayArt Innovacin En Exhibicin Stands Impactantes Entrega A Tiempo www.displayart.mx
Nota: Esta pgina Web esta repleta de imgenes, textos, logotipos y dems material extrados de los
mas variados medios de los que no soy ni autor ni depositario de los correspondientes derechos de
autor, uso y/o reproduccin. Si Ud. es depositario de dichos derechos y desea que el material
correspondiente sea eliminado de esta Web no dude en ponerse en contacto conmigo mediante e-mail y
ser inmediatamente retirado. Gracias.
Visitas
Totales : 109264 Hoy: 68 Activas: 1 Vistas: 109264
Esta pgina fue modificada el 07-08-2010 22:42:21