Exemplos ccs

11

Click here to load reader

description

 

Transcript of Exemplos ccs

Page 1: Exemplos ccs

PROGRAMAS DE EXEMPLOS DO COMPILADOR CCS

1. Exemplos de xestión de portos 1.1. Xestión de portos en C

1.1.a) Xestión a través da memoria RAM

A configuración dos portos correspondentes dos PIC faise a través dos rexistros especiais TRISX, que

determinan os pins dos portos correspondentes que serán utilizados como entradas (1 no bit de

configuración) ou como saídas (0 no bit de configuración). Os valores lense ou sácanse a través dos portos

correspondentes PORTX.

Unha forma de controlar a configuración e os valores recibidos/transmitidos polos portos é definindo

a súa posición de memoria como unha variable da función a través da directiva #BYTE.

Logo podemos escribir no porto ou ler do porto un valor. Tamén podemos manexar independentemente os

bits.PORTX = valor // Saca polo porto X os bits correspondentes a valor

valor = PORTX // Asigna o dato do porto á variable valor

bit_clear (var, bit) // Pon 0 no bit especificado da variable

bit_set (var, bit) // Pon 1 no bit especificado da variable

bit_test (var, bit) // Recolle o valor do bit especificado da variable

swap (var) // Intercambia os 4 bits de maior peso (nibble superior) cos de menor peso (nibble

// inferior)

Exemplo 1: Terminal RB0 como entrada, RB1 como saída. O valor da entrada é reflectido na saída.

Para poder manexar a entrada con un interruptor conectado ou non a terra debemos activar

as resistencias internas de pull-up para obter un nivel alto cando o interruptor estea

desconectado.

Solución 1: Mediante o manexo das direccións de memoria RAM.

#include <16F84A.h> // O PIC empregado

#fuses XT, NOWDT // Fusibles: oscilador cristal (<=4 MHz)

// sen activar can gardián

#use delay(clock=4000000) // Velocidade do reloxo 4 MHz

#BYTE TRISB = 0x86 // Posición na RAM do rexistro de configuración do porto B

#BYTE PORTB = 0x06 // Posición do porto B na RAM

#BYTE OPTION_REG = 0x81 // Posición deste rexistro, para activar pull-up en B

void main () { bit_clear (OPTION_REG,7); // Habilitación do pull-up en B

bit_set (TRISB,0); // Pin 0 de configuración a 1: entrada

bit_clear (TRISB,1); // Pin 1 de configuración a 0: saída

bit_clear (PORTB,1); // Sacamos un 0 polo pin 1 do porto B

while (1) { // Bucle infinito

if (bit_test(PORTB,0) == 1) // Comprobamos se o bit 0 vale 1 (RB0==1??)

Page 2: Exemplos ccs

bit_clear(portb,1); // Se vale 1, sacamos un 0 pola saída (bit 1)

else bit_set(portb,1); // Se vale 0 sacamos un 1 polo bit 1 do porto B

}}

1.1.b) Xestión mediante as directivas do compilador

Solución 2: Mediante as directivas do compilador de C.

O compilador ten funcións especificas para traballar cos portos:

output_X (valor) // Saca un valor binario de 8 bits polo porto X (0-255)

input_X (valor) // Obtén o valor do porto X

set_tris_X (valor) // Configura o rexistro TRISX poñéndolle o valor (0-255)

port_b_pullups (valor) // valor=TRUE habilita pull-ups; valor=FALSE(=0) desabilítao

get_trisX() // Devolve o valor do rexistro TRISX

Ademais podemos manexar independentemente os pins dos portos (definidos mediante parámetros

no ficheiro de encabezamento do chip correspondente) con certas funcións:

output_low(pin) // Pon o pin a 0

output_high(pin) // Pon o pin a 1

output(pin,valor) // Pon o pin ao valor especificado

output_toggle(pin) // Complementa o valor do pin

output_float(pin) // Pin en drenador aberto, saída flotante

input_state(pin) // Le o valor do pin, sen modificar o sentido do terminal

input(pin) // Le o valor do pin e pono como entrada dependendo do tipo #USE *_IO usado

#USE FAST_IO (PORTO)Utilízase o porto correspondente para sacar valores con ouput_x() ou lelos con input_x() pero sen

modificar a configuración do porto. Os rexistros TRIS de configuración deben estar correctamente definidos.

#include <16F84A.h> // O PIC empregado

#fuses XT, NOWDT // Fusibles: oscilador cristal (<=4 MHz)

// sen activar can gardián

#use delay(clock=4000000) // Velocidade do reloxo 4 MHz

#use fast_io (B) // Forma de configurar porto B

void main () { port_b_pullups (TRUE); // Habilitación do pull-up en B

set_tris_B(0x01); // Pin 0=1 (entrada); pin 1=0 (saída)

output_low(PIN_B1); // Sacamos un 0 polo pin 1 do porto B

while (1) { // Bucle infinito

if (input(PIN_B0) == 1) // Comprobamos se o bit 0 vale 1 (RB0==1??)

output_low(PIN_B1); // Se vale 1, sacamos un 0 pola saída (bit 1)

else output_high(PIN_B1); // Se vale 0 sacamos un 1 polo bit 1 do porto B

}}

#USE STANDARD_IO(PORTO)

Page 3: Exemplos ccs

O compilador modifica o TRIS correspondente para asegurarse de que os terminais usados estean

correctamente configurados: saída coa función output_x() e entrada coa función input_x(). É a directiva que

se utiliza por defecto.

#include <16F84A.h> // O PIC empregado

#fuses XT, NOWDT // Fusibles: oscilador cristal (<=4 MHz)

// sen activar can gardián

#use delay(clock=4000000) // Velocidade do reloxo 4 MHz

#use standard_io (B) // Forma de configurar porto B

void main () { port_b_pullups (TRUE); // Habilitación do pull-up en B

// Agora non fai falla configurar o TRISB

output_low(PIN_B1); // Sacamos un 0 polo pin 1 do porto B

while (1) { // Bucle infinito

if (input(PIN_B0) == 1) // Comprobamos se o bit 0 vale 1 (RB0==1??)

output_low(PIN_B1); // Se vale 1, sacamos un 0 pola saída (bit 1)

else output_high(PIN_B1); // Se vale 0 sacamos un 1 polo bit 1 do porto B

}}#USE FIXED_IO(PORTO_OUTPUTS=pin*, ...)

Na directiva só se indican os terminais de saída e o compilador xera o código de configuración

correspondente, independentemente de que as operacións realizadas sexan de entrada ou de saída.

#include <16F84A.h> // O PIC empregado

#fuses XT, NOWDT // Fusibles: oscilador cristal (<=4 MHz)

// sen activar can gardián

#use delay(clock=4000000) // Velocidade do reloxo 4 MHz

#use fixed_io (b_outputs=pin_b1) // Só pin 1 do porto B como saída

void main () { port_b_pullups (TRUE); // Habilitación do pull-up en B

// Agora non fai falla configurar o TRISB

output_low(PIN_B1); // Sacamos un 0 polo pin 1 do porto B

while (1) { // Bucle infinito

if (input(PIN_B0) == 1) // Comprobamos se o bit 0 vale 1 (RB0==1??)

output_low(PIN_B1); // Se vale 1, sacamos un 0 pola saída (bit 1)

else output_high(PIN_B1); // Se vale 0 sacamos un 1 polo bit 1 do porto B

}}

1.1.c) Xestión mediante punteiros

Solución 3: Mediante a utilización de punteiros dirixidos ás posicións de memoria correspondentes.

Os punteiros débense definir como enteiros (int*).

#define TRISA (int*) 0x85

#define PORTA (int*) 0x05

Os rexistros manéxanse co operador de indirección *.

int valor;

Page 4: Exemplos ccs

valor = *portoa;

Os terminais lense e escríbense utilizando operacións lóxicas con bits.

*portoa != 0b0000001; // RA0 = 1 mediante OR (resto dos bits do porto non cambian

*portoa &= 0b11111101; // RA1 = 0 mediante AND (resto dos bits do porto non cambian

bit0 = (*portoa & 0b00000001); // Lemos o bit 0 do portoa

O exemplo quedaría:

#include <16F84A.h> // O PIC empregado

#fuses XT, NOWDT // Fusibles: oscilador cristal (<=4 MHz)

// sen activar can gardián

#use delay(clock=4000000) // Velocidade do reloxo 4 MHz

#define TRISB (int*) 0x86 // Contido de TRISB na dirección 0x86

#define PORTB (int*) 0x06 // Contido de PORTB na dirección 0x06

#define OPTION (int*) 0x81 // Contido de OPTION na dirección 0x81

void main () { *option &= 0b0111111; // Habilitación do pull-up en B poñendo 0 no bit 7 do

// OPTION_REG (variable option)

*trisb = 0x01; // RB0 entrada, RB1 (e o resto) saída

*portb = 0x00; // Sacamos un 0 polo pin 1 do porto B

while (1) { // Bucle infinito

if (*portb & 0x01) // Comprobamos se o bit 0 vale 1 (RB0==1??)

*portb = 0x00; // Se vale 1, sacamos un 0 pola saída (bit 1)

else *portb = 0x02; // Se vale 0 sacamos un 1 polo bit 1 do porto B

}}

1.1.d) Exemplo utilización

Exemplo 2: Realizar un contador de 0 a 99 con dous displays de 7 segmentos de cátodo común. O

díxito das decenas debe estar apagado de 0 a 9.

#include <16f84A.h>#use delay (clock = 4000000)#fuses XT, NOWDT, NOPROTECT, NOPUT#use standard_io (A)#use standard_io (B)

byte CONST display[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};// O valor hexadecimal proporciona os 7 bits para activar os leds e ver os números de 0 a 9

main() {byte ud=0, dec=0;output_b(0);for (;;) {

for (dec=0;dec<10;dec++) { // Bucle externo para decenas

for (ud=0;ud<10;ud++) { // Bucle interno para unidades

output_a (0x02); // Alimentamos cun 0 visualizador de unidades

output_b(display[ud]); // Percorremos as unidades

delay_ms(50); // Parando un pouco en cada unha

if (dec==0) output_a(0x03); // Se non hai decenas non se ve 0

else output_a (0x01); // Se as hai alimentamos o visulizador decenas

Page 5: Exemplos ccs

output_b(display[dec]); // Percorremos as decenas

delay_ms(50); // Parando un pouco en cada una

}}

}}

1.2. Xestión de dispositivos de entrada e saída

1.2.a) LCD

O compilador inclúe ficheiros en C para traballar con visualizadores LCD. Este ficheiro pódese

modificar para adaptalo ás nosas necesidades.NOTA: A MODIFICACIÓN DOS FICHEIROS DO COMPILADOR DEBE REALIZARSE CON CAUTELA, COIDANDO DE FACER COPIA DO FICHEIRO ORIXINAL E

GARDAR CON OUTRO NOME O ARQUIVO MODIFICADO.

Un dos arquivos é lcd.c, no cartafol drivers, e debe incluírse para a compilación no noso ficheiro fonte.

Dentro deste arquivo existen varias funcións definidas que facilitan o manexo do visualizador.

lcd_init ();Configúrao para traballar con 4 bits, dúas liñas e tamaño de 5x8 puntos por caracter, sen visualización do

cursor e con xestión automática do punteiro de direccións. As catro liñas de funcionamento serven para a

xestión e para a escritura e lectura de datos. Débese chamar en primeiro lugar.

lcd_gotoxy (byte x, byte y);Indica a posición de traballo no LCD: (1,1) é a primeira columna da primeira liña e (2,1) é a primeira columna

da segunda liña. O LCD ten 2 liñas e 16 caracteres.

lcd_getc (byte x, byte y);Le o contido da posición (x,y).

lcd_putc (char s);Escribe a variable tipo char na posición correspondente. Permite os seguintes caracteres especiais:

\f limpa o LCD

\n cursor á posición (1,2)

\b o cursor retrocede unha posición

Tamén podemos utilizar unha función semellante a printf () do C para utilizar o LCD.

printf (string) // string é unha cadea ou array de caracteres

printf (cstring, valores ...) // valores é unha lista de variables separadas por comas

printf (fname, cstring, valores ...) // fname é unha función

A función permite a utilización de formato de presentación de variables tipo %nt, onde n é opcional e indica

a cantidade de caracteres e/ou decimais que se representan e t indica o tipo de formato para a variable.NOTA: PARA MAIOR INFORMACIÓN SOBRE AS FUNCIÓNS ESPECÍFICAS DO COMPILADOR PÓDESE CONSULTAR A AXUDA DO MESMO, NO APARTADO BUILT-

IN FUNCTIONS.

Exemplos de utilización:

byte x, y, z;

printf (“Ola”);

printf (“Valor => %2x\n\r”, get_rtcc () );

printf (“%2u %X %4x\n\r”, x, y, z);

printf (LCD_PUTC, “n=%u”, n);

Page 6: Exemplos ccs

O ficheiro está configurado para traballar co porto D, pero non comentar unha das liñas permite utilizar o

porto B. A utilización doutros portos require modificacións máis amplas. A conexión do porto utilizado cos

pins do LCD está tamén indicada no arquivo.

Exemplo 3: Realizar un menú de control mediante dous pulsadores: un permite seleccionar entre os tres

elementos do menú que aparecen no LCD e o outro executa a función asociada a ese

elemento (modificar unha das saídas para acender o LED asociado).

#include <16f84A.h>#fuses XT, NOWDT#use delay (clock=4000000)#include <lcd_b.c> // O ficheiro modificado para traballar co porto B

#use fast_io (A)#use standard_io (B)

enum funciones {med, cal, ini}; // Asigna un valor a cada elemento

// med = 0, cal = 1, ini = 2

void medir (void){set_tris_a (0x03); // Pins 0 e 1 entradas, resto do porto A saídas

output_toggle(pin_A2); // A función asociada a medir é cambiar o estado do pin 2

}

void calibrar (void){set_tris_a (0x03); // Pins 0 e 1 entradas, resto do porto A saídas

output_toggle(pin_A3); // A función asociada a calibrar é cambiar o estado do pin 3

}

void inicializar (void){set_tris_a (0x03);output_toggle(pin_A4); // A función asociada a calibrar é cambiar o estado do pin 4

} /* Coidado, este pin é de saída en drenador aberto e necesita resistencia de pull-up externa para mostrar un nivel alto */

void run_func (int numfunc){

switch (numfunc){ // Segundo o valor de numfunc realizamos a función asociada

case med: // med vale 0, coa orde enum

medir();break;

case cal: // cal vale 1, pola orde enum

calibrar ();break;

case ini:inicializar (); // ini vale 2, pola orde enum

break;}

}

void main () {char item; // Percorremos o menú secuencialmente

char n_menus = 3; // Para volver ao primeiro elemento ao rematalos

Page 7: Exemplos ccs

lcd_init(); // Primeira función para traballar co LCD

while(1) {

if (input(pin_A0 == 1)) { // A cada pulsación no pin A0

item++; // avanzamos un elemento de menú

delay_ms (300); // Retardo para evitar rebotes

lcd_putc ('\f'); // Borramos LCD

}if (item > (n_menus-1)) // Rematamos os elementos do menú?

item = 0; // Se os rematamos volvemos ao principio

switch (item) { // Poñemos no LCD o elemento de menu

case 0:lcd_gotoxy (1,1);printf (lcd_putc, “MEDIR”);lcd_gotoxy (1,1);break;

case 1:printf (lcd_putc, “CALIBRAR”);lcd_gotoxy (1,1);break;

case 2:printf (lcd_putc, “INICIALIZAR”);lcd_gotoxy (1,1);break;

}if (input (pin_A1) == 1) { // Poñendo A1 en alta ...

delay_ms (200); // retardo para evitar rebotes ...

run_func (item); // Executamos a función asociada a ese elemento do menú

}}

}

1.2.b) LCD GRÁFICO

Para o manexo de LCD gráficos o compilador proporciona varios arquivos para utilizalos como

controladores: glcd.c, graphics.c, hdm64gs12.c. Tamén podemos buscar controladores para os

visualizadores en internet.

A maioría dos controladores indican os terminais que se utilizan para o manexo, as conexións

necesarias cos portos do PIC e as funcións que pode manexar: liñas, círculos, rectángulos, ... e os

parámetros necesarios para utilizalas. É conveniente botar unha ollada a estes arquivos, e tamén editalos

para adaptalos ás nosas necesidades.

Para escribir as letras no modo gráfico utilízase unha matriz na que se definen mediante valores

hexadecimais os pixels que se deben acender en cada unha das columnas coas que se definen os

caracteres (no noso caso caracteres de 5x7, cinco columnas de 7 puntos). Podemos modificar estes valores

para cambiar o aspecto dos caracteres ou definir outros novos (por exemplo para poder manexar Ñ, ñ, Á, á

ou outros non incluídos no controlador).

Page 8: Exemplos ccs

O visualizador ten dous terminais de selección CS1 e CS2 , que manexan as dúas metades

verticais en que está dividido. No controlador utilizado debemos cambiar a asignación dos pins que os

manexan para lograr unha correcta visualización.

As funcións definidas nestes controladores son as siguintes:

glcd_init (mode)Acende se mode é ON ou apaga se mode é OFF o LCD. Debe ser a primeira que se chama.

glcd_pixel(x,y,cor)Pode activarse ou desactivarse para que o pixel apareza iluminado ou non (só admite dúas cores).

glcd_fillScreen(cor)Enche o visualizador coa cor seleccionada.

glcd_update()Escribe o contido da RAM no LCD.

glcd_line(x1,y1,x2,y2,cor)Debuxa unha liña entre o primeiro punto e o segundo da cor indicada (ON ou OFF)

glcd_rect(x1,y1,x2,y2,fill,cor)Debuxa un rectángulo dando o vértice superior dereito e o inferior esquerdo, o recheo e a cor.

glcd_bar(x1,y1,x2,y2,ancho,cor)Debuxa unha barra, co ancho especificado en pixels.

glcd_circle(x,y,radio,fill,cor)Debuxa un círculo dando o centro e o radio, recheo ou non e coa cor activada ou non.

glcd_text57(x,y,textptr,tamaño,cor)Comezando no punto indicado, escribe o texto ao que apunta textptr (punteiro). O texto debe rematar co

caracter nulo e pódese escoller o tamaño (número enteiro) e activar ou non a cor.

Exemplo 4: Visualizar nun LCD gráfico o estado das entradas do porto A, mediante un rectángulo

recheo ou non segundo a entrada correspondente sexa 1 ou 0.

#include <18F452.h>#fuses HS,NOWDT,NOPROTECT,NOLVP#use delay(clock=8000000)#include <HDM64GS12.c>#include <graphics.c>#use standard_io(a)

void main() {CHAR A5[ ]="A5";CHAR A4[ ]="A4";CHAR A3[ ]="A3";CHAR A2[ ]="A2";CHAR A1[ ]="A1";CHAR A0[ ]="A0";CHAR IN[ ]="PUERTO A";glcd_init(ON);glcd_text57(33, 30,A5, 1, 1);glcd_text57(49, 30,A4, 1, 1);glcd_text57(65, 30,A3, 1, 1);glcd_text57(81, 30,A2, 1, 1);

Page 9: Exemplos ccs

glcd_text57(97, 30,A1, 1, 1);glcd_text57(113, 30,A0, 1, 1);glcd_text57(30,5,IN, 2, 1);

while(1){if (input_state(PIN_A5)==0) glcd_rect(32,40,46,60,1,1);else glcd_rect(32,40,46,60,1,0);glcd_rect(32,40,46,60,0,1);if (input_state(PIN_A4)==0)glcd_rect(48,40,62,60,1,1);else glcd_rect(48,40,62,60,1,0);glcd_rect(48,40,62,60,0,1);if (input_state(PIN_A3)==0) glcd_rect(64,40,78,60,1,1);else glcd_rect(64,40,78,60,1,0);glcd_rect(64,40,78,60,0,1);if (input_state(PIN_A2)==0) glcd_rect(80,40,94,60,1,1);else glcd_rect(80,40,94,60,1,0); glcd_rect(80,40,94,60,0,1);if (input_state(PIN_A1)==0) glcd_rect(96,40,110,60,1,1);else glcd_rect(96,40,110,60,1,0);glcd_rect(96,40,110,60,0,1);if (input_state(PIN_A0)==0) glcd_rect(112,40,126,60,1,1);else glcd_rect(112,40,126,60,1,0);glcd_rect(112,40,126,60,0,1);delay_ms(400);}

}

Os controladores de LCD utilizados neste exemplo usan os portos B e C para o control e o porto D

para os datos. A simulación é correcta, pero no LCD real debemos cambiar os pins de selección das cúas

metades CS1 e CS2 . Tamén adaptamos o controlador para manexar o visualizador mediante os

portos B e D. Coma sempre, facemos copia dos controladores orixinais antes de modificalos.

1.2.c) TECLADO

O compilador inclúe tamén controladores para manexar teclados, en concreto un teclado matricial de 3x4. O

arquivo kbd.c incorpora as seguintes funcións:

kbd_init()Inicializa o sistema. Debe chamarse antes do uso do teclado.

kbd_getc()Devolve o valor da tecla pulsada. O valor atópao na táboa que ten programada en forma de matriz de 4x3

(catro filas e tres columnas).

O controlador utiliza o porto D para manexar o teclado, pero pódese modificar facilmente para

traballar co porto B. Tamén se poden configurar as conexións de filas e columnas e o patrón de teclas

asignadas. Para o funcionamento correcto o porto utilizado debe ter activado o pull-up para ler un nivel alto

cando non se pulsa ningunha tecla.

As pulsacións das teclas recóllense como caracteres ASCII. Para poder operar con elas como

números debemos restarlle o valor decimal 48 (código ASCII do número 0).

Exemplo 5: Deseñar un sistema que permita abrir unha porta ao introducir o código correcto a través

dun teclado. Indicar mediante unha pantalla LCD a apertura ou non da porta.

No exemplo gardaremos a clave da porta na memoria EEPROM, para poder modificala de forma doada.

#include <16f84A.h> #fuses xt, nowdt, noput, noprotect #use delay (clock = 4000000)

Page 10: Exemplos ccs

#use standard_io(A)

#include <lcd_b.c> #include <kbd_b.c> #include <stdlib.h> #rom 0x2100={'1', '2', '3'} // Posición de inicio da EEPROM e datos gardados

void main() {

char k; // Garda a pulsación

int i; // Percorre os elementos da matriz

char data[3], clave[3]; // Matrices para gardar as pulsacións e a clave

lcd_init(); kbd_init(); port_b_pullups(TRUE); // Pull-up activo no porto que recibe pulsacións do teclado

while (TRUE){ i=0; printf(lcd_putc, "\fPulsar tecla 1\n"); // Indicamos recepción primeiro número

while (i<=2){ // O índice de matriz para o primeiro número é 0

k=kbd_getc(); if (k!=0){ // Recollemos pulsación?

data[i]=k; // Asignamos valor na matriz

i++; // Seguinte índice

printf(lcd_putc, "\fPulsar tecla %u\n", i+1); }

} for (i=0;i<=2;i++)

clave[i]=read_eeprom(i); // Lemos ROM e asignámoslle un elemento da matriz

if ((data[0]==clave[0])&&(data[1]==clave[1])&&(data[2]==clave[2])) { // Comprobamos se o introducido coincide co gardado

printf(lcd_putc, "\fAbrindo porta\n"); output_high(pin_A0); // Se coincide abrimos porta

delay_ms(500); output_low(pin_A0); // Pulso en alta de 0,5 s para excitar o relé

} else printf (lcd_putc, "\fPorta pechada\n");

delay_ms(1000); }

}Neste exemplo tanto o teclado como o visualizador LCD están manexados co porto B, mentres a saída se

toma do pin 0 do porto A.

Exemplo 6: Elaborar un programa que permita sacar por un pin un sinal PWM proporcional ao valor

introducido a través dun teclado. O sinal PWM será utilizado para controlar a velocidade dun

motor, de maneira proporcional ao valor introducido.

Utilizamos unha variable tipo int ou char para definir os tempos en alta e en baixa do sinal, de maneira que

o valor máximo sexa 255. Así, se o ciclo de traballo é 100 %, o valor do tempo en alta será 255 e o do

tempo en baixa será 0. Para indicar cun valor numérico entre 0 e 9 o ciclo de traballo deberiamos facerlle

Page 11: Exemplos ccs

corresponder o 100 % ao valor 9, e por tanto 2559

×N a cada valor N posible. Para non manexar valores

decimais (variables float), que ocupan moito espazo en memoria, utilizaremos en lugar de 2559 o valor

enteiro máis próximo: 28. Ao tempo en baixa corresponderalle o valor 255 - (tempo en alta).