Vous êtes sur la page 1sur 25

El Rincn del CCS C -1 Parte

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

El Rincn del CCS C -1 Parte

El lenguaje C es el que uso por


defecto para el 90% de mis
programas. Aqu os muestro
algunos ejemplos de cmo hacer
cosas con este idioma. Todos
ejemplos que se muestran en esta
seccin se han realizado usando el
PCW PICC de CCS (Veriones 3.242
a 4.096 segn depende)

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

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

Lista para usar (y configurable).


Procesador de comandos va RS232 (con Buffer de recepcin)
Para dar rdenes con mas enjundia a nuestro PIC
Controlando un SERVO con el PIC desde nuestro PC
O todo lo que siempre quiso saber sobre los Servomotores y nunca se atrevi a
preguntar
Strings Demo o como se pueden manejar las cadenas en nuestro PIC
No te voy a explicar que sn los punteros o los arrays pero puedes verlos
funcionar.
RROS v 2.0 La EEPROM interna puesta a nuestro servicio
Escribiendo o recuperando datos de la EEPROM interna desde nuestro PC va
RS232.
Funciones de Date y Time para PIC
Coleccin de funciones para manejar Aos, meses, semanas, das, horas,
minutos y segundos.
Leer y Escribir en la EEPROM interna del PIC variables int 16 bits (2 bytes)
Para cuando nuestra variable es mayor que el byte
Lib_Int_EEPROM Funciones especiales para Leer y Escribir la EEPROM
interna del PIC
Para cuando queremos utilizar otras variables distintas al Int8.
Rutina de conversin de Nmeros Arbigos a Nmeros romanos
Para que nuestro PIC hable en Latn Clsico.
Manejando un Array de bits I y Manejando un Array de bits II (simulado
en CCS C que no lo implementa)
Para que nuestro PIC no desperdicie memoria.
Teclado Matricial 4x4 con Driver Analgico
Una tcnica para ahorrar pines del pic.
Controlando 8 Servos con una sola interrupcin.
Una tcnica para conseguir estabilidad y potencia.
Teora y Praxis de la Comunicaciones TTL
Hablando con el PIC hasta por los codos.

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.

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

Tcnicas en C : Midiendo un pulso. 2 Parte


Midiendo en tiempo que un pulso permanece en alto mediante INTCCP en modo
Capture.
Tcnicas en C : Midiendo un pulso. 3 Parte
Midiendo en tiempo que un pulso permanece en alto mediante INTRB.
Tcnicas en C : Midiendo un pulso. 4 Parte
Midiendo el pulso completo. Periodo y Frecuencia.
Tcnicas en C : Generando un pulso. 1 Parte
Generando una onda cuadrada simtrica de 2 Khz mediante INTRTCC.
Tcnicas en C : Generando un pulso. 2 Parte
Generando una onda cuadrada simtrica de 2 Khz mediante INTCCP en modo
Compare.
Tcnicas en C : Librera de Funciones "tiles"
Un artculo muy til sobre funciones tiles y su implementacin en CCS C.

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.

Template para el uso de la Interrupcin RTCC mediante el TIMER0


La interrupcin RTCC se produce cada vez que el contador TIMER0 pasa de FFh a
00h.
El TIMER0 hace un cmputo completo de 00h a FFh cada 512 S, sin embargo este
tiempo puede ser cambiado mediante un preescaler o sea un divisor, ajustable. Los
tiempos generados para cada configuracin son (Ver Nota 1):
:2
:4
:8
:16
:32
:64
:128
:256

->
->
->
->
->
->
->
->

512
1.0
2.0
4.0
8.1
16.3
33.3
66.6

S al mnimo preescaler posible.


mS
mS
mS
mS
mS
mS
mS al mximo preescaler posible.

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

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).

Template para el uso de la Interrupcin RTCC mediante el TIMER0


#include <16f628.h>
// Selecciona el PIC
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT // Opciones de configuracin
#use delay(clock=4000000)
// Velocidad del Cristal : 4
Mhz
byte const NInts=30;
para 1 Segundo

// 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(C_Ints > NInts){


ints para 1 Seg.

// Si las ints ocurridas >

if(Flag==0){
Flag=1;
}
else{
Flag=0;
}
C_Ints=0;
Ints
}
++C_Ints;
interrupciones
}

// del TIMER0 RTCC

// 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);

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

setup_vref(FALSE);
enable_interrupts(INT_RTCC);
Interrupcin RTCC
enable_interrupts(global);
Interrupciones

// Habilito
// Habilito

do{ // Bucle infinito


if(Flag==K){}
else
{

// 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)

Template para el uso de la Interrupcin RDA de la USART


La interrupcin RDA se produce cada vez que en la USART hay disponible un
carcter para ser ledo.
El buffer de recepcin de la USART del PIC 16F628 dispone de solo 2 bytes por lo
que es importantsimo el descargarlo tal como se van recibiendo los caracteres, de
esta forma evitamos el que se vean tristemente perdidos en el limbo serie.

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

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.

Template para el uso de la Interrupcin RDA de la USART


#include <16f628.h> // Selecciona el PIC
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Opciones de
configuracin
#use delay(clock=4000000) // Velocidad del Cristal : 4 Mhz
#use standard_io(b)
#use rs232(baud=9600, xmit=PIN_B2, rcv=PIN_B1) // Definicin del
RS232
char Keypress=' ';
#int_rda
void serial_isr() {
Keypress=0x00;
if(kbhit()){
Keypress=getc();
if(Keypress!=0x00){
putchar(keypress);
keypress=0x00;
}
}
}

void main() {
enable_interrupts(global);
enable_interrupts(int_rda);
printf("\r\n\Listen on RS232 (Int)\r\n");
do {

} while (TRUE);
}
Descargar Template RDA

Una aplicacin prctica de RTCC : Cronopic 1.0


Este artculo nos presenta un mtodo razonable para implementar un cronmetro en
nuestro PIC. Hacemos uso en l del Template para el uso de la Interrupcin RTCC
mediante el TIMER0 descrito ms arriba as como del Hardware descrito en Hardware
de Experimentos : 4 x 7 Segmentos.

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

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.

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

// 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;

//
//
//
//

Contador de interrupciones RTCC completas


Segundos del Reloj
Minutos del Reloj
Contenido de los Displays

// Resultado de la conversin bin2bcd


// index general

void testdisplays(void);
void display_reloj(void);
void time2bcd(void);
x BCD
void bin2bcd(int valor);

// Funcin que testea los displays


// Funcin que muestra el contenido del reloj
// Funcin que convierte minutos y segundos a 4

#int_RTCC
RTCC_isr() {

// Interrupcin por desbordamiento


// del TIMER0 RTCC

// Funcin que convierte de Binario a BCD

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

do{ // Bucle infinito


if(segundo!=ksegundo){
time2bcd();
ksegundo=segundo;
}

// si cambia el segundo actualizo las


// variables con lo que hay que mostrar

display_reloj();

// Muestra constantemente

}While(TRUE);

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

}
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);

// Muestro 1er carcter de segundo

// Muestro 2do carcter de segundo

// Muestro 1er carcter de minuto

// Muestro 2do carcter de minuto

}
void time2bcd(void){
bin2bcd(segundo);
D1 = l_digit;
D2 = h_digit;
bin2bcd(minuto);
D3 = l_digit;
D4 = h_digit;

// Funcin convierte minutos y segundos a 4 x BCD


// Paso de binario a BCD el segundo y actualizo
// contenido a mostrar
// Paso de binario a BCD el minuto y actualizo
// contenido a mostrar

}
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:

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

Bin2BCD (1):
int l_digit, h_digit;

// resultado de la conversion bin2bcd

void bin2bcd(int valor){


BCD

// Funcion que convierte de Binario a

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

#define LCD_RS PIN_C0


#define LCD_RW PIN_C1
#define LCD_E PIN_C2
// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.
#define USE_LCD_RW 1
//========================================

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines


#define lcd_line_two 0x40 // LCD RAM address for the 2nd line

int8 const LCD_INIT_STRING[4] =


{
0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};

//------------------------------------void lcd_send_nibble(int8 nibble)


{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
output_bit(LCD_DB4, !!(nibble & 1));
output_bit(LCD_DB5, !!(nibble & 2));
output_bit(LCD_DB6, !!(nibble & 4));
output_bit(LCD_DB7, !!(nibble & 8));
delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
}
//----------------------------------// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine. For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.
#ifdef USE_LCD_RW
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3
retval = 0;
output_high(LCD_E);
delay_cycles(1);
retval_0
retval_1
retval_2
retval_3

=
=
=
=

input(LCD_DB4);
input(LCD_DB5);
input(LCD_DB6);
input(LCD_DB7);

output_low(LCD_E);
return(retval);
}

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

#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

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

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;

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

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

Modificando el ancho de un pulso, generado con RTCC, mediante ordenes


RS232:
Este ejemplo nos muestra cmo podemos realizar el ultra famoso led parpadeando,
pero realizado con la interrupcin RTCC del Timer0, y recibiendo ordenes va RS232
para poder modificar el ancho del pulso, o la separacin entre dos pulsos sucesivos.

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

Conceptos, ideas y tcnicas utilizadas:


- Cada vez que salta la interrupcin RTCC cambiamos de LOW a HIGH, de HIGH a
LOW, el pin RB0. Para ello utilizamos la variable Led que nos indica cual fue el ltimo
cambio para poder hacer el complementario.
- Cada vez que realizamos dicho cambio de LOW a HIGH, o de HIGH a LOW,
cargamos el contador del Timer0 con un valor variable que podemos ajustar
externamente: OffsetL para el semiperiodo LOW y OffsetH para el semiperiodo HIGH
(Si OffsetL y OffsetH son igual a cero, como es el caso cuando acabamos de resetear
el micro, tenemos una onda cuyo periodo es exactamente igual a 2 * RTCC: Una
RTCC completa conde ponemos RB0 en HIGH y otra RTCC completa en la que
ponemos RB0 en LOW)
- Recibimos distintas ordenes desde el RS232 con las cuales modificamos los valores
de OffsetH y OffsetL.
- Cualquier valor mayor que 0 en OffsetH o en OffsetL hace que al producirse la
correspondiente interrupcin RTCC, que como sabis salta al pasar el Timer0 de FFh a
00h, se carge el Timer0 con dicho valor: Por lo que la siguiente interrupcin ser mas
corta, y de forma directamente proporcional al valor cargado, ya que en vez de tener
que esperar a que Timer0 recorra todo su contador de 00h a FFh lo va ha hacer
solamente desde OffsetH, u OffsetL, hasta FFh.
* Cuanto mayor sea OffsetH menos tiempo va a estar RB0 en HIGH.
* Cuanto mayor sea OffsetL menos tiempo va a estar RB0 en LOW
- Si OffsetH y OffsetL tienen el mismo valor la onda producida tendr iguales ambos
semiperiodos, con valores distintos ser por ende distintos ambos y por ello nos
variar la frecuencia. Para mantener la frecuencia constante, o el periodo constante,
debemos ampliar o disminuir complementariamente ambos Offset. Lo que se
incremente uno de ellos debemos disminuir el otro, o viceversa.
- Hemos incluido una variable Onda con la que podemos ordenarle a qu parte de
nuestro pulso va a afectar la siguiente orden: "C" (de cuadrada para ambos
semiperiodos) "H" para el semiperiodo Alto y "L" para el semiperiodo Bajo.
Este ejemplito es bsicamente un PWM realizado por Software que puede ser

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

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);

printf("\r\n\PWM (RTCC) OS\r\n");


Onda='C';
Offseth=0x00;
Offsetl=0x00;

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

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

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

Una librera para rastrear un Teclado matricial 4x4


Aqu tenis una librera que permite leer un teclado matricial de 16 teclas (4 filas x
4 columnas). Solo tenis que incluir con #include esta librera en vuestro programa
principal y llamar a la funcin kbd_getc() donde lo necesitis.
Nota: Esta librera esta derivada de la original incluida en \drivers del CCS PIC C. En
cursiva marco los cambios que he realizado para adaptarla a mi hardware particular.
kbd_lib.c
///////////////////////////////////////////////////////////////////////////
//// kbd_lib.c by Redraven ////
//// ////
//// Derived from kbdd.c ////
//// Generic keypad scan driver ////
//// ////
//// kbd_init() Must be called before any other function. ////
//// ////
//// c = kbd_getc(c) Will return a key value if pressed or /0 if not ////
//// This function should be called frequently so as ////
//// not to miss a key press. ////
//// ////
///////////////////////////////////////////////////////////////////////////
//// (C) Copyright 1996,1997 Custom Computer Services ////
//// This source code may only be used by licensed users of the CCS C ////
//// compiler. This source code may only be distributed to other ////
//// licensed users of the CCS C compiler. No other use, reproduction ////
//// or distribution is permitted without written permission. ////
//// Derivative programs created using this software in object code ////
//// form are not restricted in any way. ////
////////////////////////////////////////////////////////////////////////////
////////////////// The following defines the keypad layout on port D
// Un-comment the following define to use port B
#define use_portb_kbd TRUE
// Make sure the port used has pull-up resistors (or the LCD) on
// the column pins

#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)

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

structure
structure

6)
8)

El Rincn del CCS C -1 Parte

#else
#define set_tris_kbd(x) set_tris_d(x)
#endif

//Keypad connection: (for example column 0 is B0)


#define
#define
#define
#define

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

#define ALL_ROWS (ROW0|ROW1|ROW2|ROW3)


#define ALL_PINS (ALL_ROWS|COL0|COL1|COL2|COL3)
// Keypad layout:
char const KEYS[4][4] = {{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}};
#define KBD_DEBOUNCE_FACTOR 33 // Set this number to apx n/333 where
// n is the number of times you expect
// to call kbd_getc each second
void kbd_init() {
}
char kbd_getc( ) {
static byte kbd_call_count;
static short int kbd_down;
static char last_key;
static byte col;
byte kchar;
byte row;
kchar='\0';
if(++kbd_call_count>KBD_DEBOUNCE_FACTOR) {
switch (col) {
case 0 : set_tris_kbd(ALL_PINS&~COL0);
kbd=~COL0&ALL_PINS;
break;
case 1 : set_tris_kbd(ALL_PINS&~COL1);
kbd=~COL1&ALL_PINS;
break;
case 2 : set_tris_kbd(ALL_PINS&~COL2);
kbd=~COL2&ALL_PINS;
break;
case 3 : set_tris_kbd(ALL_PINS&~COL3);
kbd=~COL3&ALL_PINS;
break;
}
if(kbd_down) {
if((kbd & (ALL_ROWS))==(ALL_ROWS)) {
kbd_down=false;

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

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

Procesador de comandos va RS232 (con Buffer de recepcin)


Hasta ahora, en nuestros trabajos anteriores, utilizbamos comandos enviados
va RS232 consistentes en un nico carcter, con el que hacamos ejecutar
alguna de las funciones que nuestro programa implementaba. Este mtodo es de
muy corto alcance por dos motivos fundamentales: Primero porque eran
ejecutados inmediatamente tan pronto eran recibidos y segundo porque no
podamos enviarle datos (una cadena de caracteres) para ser procesados.
En este nuevo artculo vamos a solucionar exactamente eso. He imaginado un
programa que admite dos comandos de alto nivel: uno de lectura "\r" sin
argumentos y otro de escritura "\w" que va seguido de un argumento tan largo
como necesitemos.
Para manejar el envo de ambos comandos as como el/los argumentos
necesarios he implementado lo bsico para manejar el buffer en el PIC, a base
de teclas nicas, cada una con su funcin: [INTRO] 0x0D para indicar que
hemos terminado de escribir el comando, [RETROCESO] 0x08 para borrar el
ltimo carcter enviado y [ESCAPE] 0x1B para borrar todo el contenido actual
del buffer. (Como podis imaginar este mini-programa puede complicarse hasta
el infinito y solo tenis que aadir comandos a vuestra entera discrecin).
El programa va entonces recibiendo caracteres, uno tras otro, y guardndolos
en el Buffer. Si recibe el comando [INTRO] habilita un flag para que se procese
el comando, y tras ser procesado borra el buffer y vuelve a empezar. Las otras
dos teclas de [RETROCESO] y [ESCAPE] las usamos para editar el contenido

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

del buffer antes de enviarle la orden de procesado.


He intentado comentar profusamente el programa para que sea
meridianamente claro su funcionamiento y hacer as innecesarias mas
explicaciones:
command_232_buffered.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;

//
//
//
//

ndice: siguiente char en cbuff


Buffer
ltimo carcter recibido
Flag para indicar comando disponible

// 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);
}

// Interrupcin recepcin serie USART


//
//
//
//
//

Inicializo carcter recibido


Si hay algo pendiente de recibir ...
lo descargo y ...
lo aado al buffer y ...
hago eco (si procede).

}
// 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

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

[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;

// Bucle que pone a 0 todos los


// caracteres en el buffer
// Inicializo el ndice de siguiente
// carcter

}
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.

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

} 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"

// Aqui lo que deseemos hacer

}
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:

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

Curso c para PICS Curso-taller c para PIC16f887 Diplomado de programacin de pics

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

DmSoft WAMP Escribir Unreal

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

El Rincn del CCS C -1 Parte

http://picmania.garcia-cuervo.net/picc.php[09/01/2012 01:40:30 p.m.]

Vous aimerez peut-être aussi