Upload
segundos
View
1.066
Download
4
Embed Size (px)
Citation preview
Tutorial de CCS
Sintaxis de programa
Estructura general: rs232_buffer.c
Un programa se escribe con los siguientes cuatro elementos:
- Comentarios
- Directivas del pre-procesador ( #BYTE, #FUSES, etc.)
- Definciones de datos
- Definiciones de funciones
Todo programa en C debe tener una función principal (main) que es el punto de partida de la ejecución del progama.
Comentarios: rs232_buffer.c
Los comentarios pueden ir en cualquier parte del programa.
Los caracteres entre /* y */ se ignoran al igual que los escritos después de // hasta que finalice la línea.
Múltiples archivos en un proyecto : rs232_buffer.c
Cuando hay muchos archivos en un proyecto, todos pueden ser incluidos utilizando #INCLUDE en el archivo main o en los sub-archivos mediante el linker incluido en el compilador. Por ejemplo, si tenemos los archivos main.c, x.c, x.h, y.c, y.h y z.h en un proyecto:
main.c
x.c
y.c
z.c
#include <dispositivo>
#include <x.h>
#include <y.h>
#include <z.h>
#include <x.c>
#include <y.c>
#include <z.c>
En este ejemplo hay 8 archivos y una unidad de compilación. Main.c es el único archivo compilado.
Ejemplo:
Aquí tenemos un ejemplo de programa utilizando CCS C para leer unas muestras de un conversor analógico-digital a través de RS-232:
#include <16F876A.h> // directiva del pre-procesador que selecciona el PIC 16F876
#fuses XT,NOWDT,NOPROTECT,NOLVP // directiva del pre-procesador que define los fusibles del PIC
#use delay(clock=4000000) //directiva del pre-procesador que define la velocidad del reloj
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // directiva del pre-procesador que incluye las librerías de RS-232
void main() { // función main
int i, valor, min, max; // declaración de variables locales
printf("Muestreando:"); // la función printf está incluida en la librería RS232
setup_adc_ports( ALL_ANALOG ); // Seteo los pines del puerto A como análogicos
setup_adc( ADC_CLOCK_INTERNAL ); // 2-6 us
set_adc_channel( 0 ); // selecciono canal 0
do { // do/while
min=255; // expresión
max=0;
for(i=0; i<=30; ++i) { // for
delay_ms(100); // espero 100 ms
valor = read_adc(); // esta función lee el valor digital del conversor analógico-digital
if(valor<min) // if
min=valor;
if(valor>max) // if
max=valor;
}
printf("\n\rMin: %2X Max: %2X\n\r",min,max);
} while (TRUE);
}
Directivas
Las directivas/sentencias a tratar son: if, while, do, do-while, for, switch, return y goto.
IF: rs232_buffer.c
if-else: La directiva if-else se utiliza para realizar decisiones. La sintaxis es:
if (condición 1)
instrucciones 1;
else
instruciones 2;
Se evalua la condición 1, si es verdadera se ejecutan las instrucciones 1, si es falsa se ejecutan las instrucciones 2.
else-if: La directiva else-if se utiliza para realizar múltiples decisiones. La sintaxis es:
if (condición 1)
instrucciones 1;
else if (condción 2)
instruciones 2;
......
else
instrucciones n;
Se evaluan las condiciones en orden, si alguna es verdadera se ejecutan las instrucciones correspondientes, si todas son falsas se ejecutan las instrucciones n.
Ejemplo:
if (y==5)
y=1;
else
y=y+1;
WHILE:
While se utiliza como una sentencia de bucle.
La sintaxis es:
while (condición)
instrucciones
Las instrucciones son ejecutadas mientras la condición es verdadera. Si la condición es falsa la ejecución del programa continúa después de las instrucciones.
Ejemplo:
while (i<10)
i++
DO:
La sintaxis es:
do
instrucciones
while (condición)
Ejemplo:
do
i++
while (i<10)
DO-WHILE: se diferencia de los bucles for y while en que la condición se testea al final. Por lo tanto las instrucciones se ejecutan al menos una vez.
La sintaxis es:
do
instrucciones
while (condición)
Ejemplo:
do
i++
while (i<10)
FOR: también es una directiva para realizar bucles .
La sintaxis es:
for (expresión 1;expresión 2; expresión 3)
instrucciones
expresión 1: inicialización
expresión 2: condición
expresión 1: re-inicialización
Cualquiera puede ser omitida.
Ejemplo:
for (i=0; i<10; i++)
printf ( " \ r \ n " , i )
SWITCH: se utiliza para seleccionar una opción entre varias disponibles.
La sintaxis es:
switch (expresión) {
case constante1: instrucciones
break;
........
default: instrucciones
break;
}
Cada caso(case) comienza donde hay un case y finaliza donde hay un break. Si no escribimos un break el programa sigue con el siguiente case.
Ejemplo:
int numero;
switch( numero ) {
case 1: printf( "Es un 1\n" );
break;
case 2: printf( "Es un 2\n" );
break;
default: printf( "No es ni 1, ni 2\n" );
}
RETURN: permite una salida inmediata de un bucle, switch o función y siempre devuelve un valor.
La sintaxis es:
return (expresión);
Ejemplo:
return (1) ;
GOTO: realiza un salto incondicional a una etiqueta (label).
La sintaxis es:
goto etiqueta;
Ejemplo:
goto BUCLE ;
Expresiones
OPERADORES:
+ Suma
+= Suma y asignación , x += y, es lo mismo que x = x+y
&= And y asignación , x &= y, es lo mismo que x = x&y
& Operador de dirección
& And
^= And exclusivo y asignación , x ^= y, es lo mismo que x = x^y
^ And exclusivo
l= And inclusivo y asignación , x l= y, es lo mismo que x = xly
l And inclusivo
?: Operador de expresión condicional
- - Decremento
/= División y asignación, x /= y, es lo mismo que x = x/y
/ División
== Igualdad
> Mayor que
>= Mayor e igual que
++ Incremento
* Operador de indirección
!= Inigualdad
<<= Shift a la izquierda y asignación, x <<= y, es lo mismo que x = x<<y
< Menor que
<< Shift a la izquierda
<= Menor e igual que
&& AND lógico
! Negación logica
ll OR lógico
%= Módulo y asignación x %= y, es lo mismo que x = x%y
% Módulo
*= Multiplicación y asignación, x *= y, es lo mismo que x = x*y
* Multiplicación
~ Complemento a 1
>>= Shift a la derecha , x >>= y, es lo mismo que x = x>>y
>> Shift a la derecha
-> Operador de puntero a estructura
-= Resta y asignación
- Resta
sizeofDetermina el tamaño en bytes de un operando
PRECEDENCIA DE OPERADORES:
En precedencia descendente
(expr)
!expr ~expr ++expr expr++ - - expr - -
expr
(type)expr *expr &value sizeof(type)
expr*expr expr/expr expr%expr
expr+expr expr-expr
expr<<expr expr>>expr
expr<expr expr<=expr expr>expr expr>=expr
expr==expr expr!=expr
expr&expr
expr^expr
expr | expr
expr&& expr
expr || expr
expr ? expr: expr
lvalue = expr lvalue+=expr lvalue-=expr
lvalue*=expr lvalue/=expr lvalue%=expr
lvalue>>=expr lvalue<<=expr lvalue&=expr
lvalue^=expr lvalue|=expr expr, expr
(Los operadores en la misma línea tienen la misma precedencia)
Definciones de datos
TIPOS BÁSICOS :
Rango
Tipo Tamaño Sin signo
Con signo
Dígitos
int1 1 bit 0 to 1
N/A
1/2
int8 8 bits 0 to 255
-128 to 127
2-3
int16 16 bits 0 to 65535
-32768 to 32767
4-5
int32 32 bits 0 to 4294967295
-2147483648 to 2147483647
9-10
float32
32 bits -1.5 x 1045 to 3.4 x 1038 7-8
Tipos en C Tipo por defecto
short int1
char unsigned int8
int int8
long int16
long long int32
float float32
Calificadores de tipos
static
La variable es global e inicializada a 0.
Solamente accesible desde esta unidad de compilación.
extern
Variable externa utilizada con múltiples unidades de compilación.
unsigned
El dato siempre es positivo. Es el tipo de datos por defecto.
signed
El dato puede ser positivo o negativo.
const
El dato es de solo lectura
DECLARACIONES:
Una declaración especifica un calificador y un especifcador de tipo y es seguido por una lista de una o más variables de ese tipo.
Ejemplo:
int a,b,c,d;
mibit e,f;
mibyte g[3][2];
char *h;
colores j;
static int i;
extern long j;
UTILIZANDO LA MEMORIA DE PROGRAMA PARA DATOS:
Dato constante:
El calificador CONST inserta las variables en la memoria de programa. Si se utiliza la palabra CONST antes de un identificador, este es tratado coo una consante. Las constantes se inicializan y no pueden ser modificadas en tiempo de ejecucuón.
El calificador ROM inserta datos en la memoria de programa (3 bytes por instrucción). La dirección utilizada para ROM no es física.
La sintaxis es: const type id [ cexpr ] = { valor }
Ejemplo:
Insertar datos en ROM: const int TABLA [ 10 ] = { 0,1,....,9 }
Insertar una cadena(string) en ROM: const char cstring [ 6 ] = { "HOLA" }
Crear punteros a constantes:
const char *cpac ;
cpac =string ;
La directiva #ORG puede ser utilizada para insertar constantes en un segmento de dirección especifico:
Ejemplo: la constante ID estará en la dirección 1C00
#ORG 0x1C00 , 0x1C0F
const char ID [10]={ "123456789" };
DIRECTIVA #ROM:
Otro método es utlizar #ROM para asignar datos a la memria de programa.
Lasintaxis es: #ROM direccion= {dato, dato, ....., dato}
Ejemplo: Ubicar 1,2,3,4 en la ROM comenzando en la dirección 0x1000
#ROM 0x1000 = { 1,2,3,4 }
Ubicar un string:
#ROM 0x1000 = { "Hola" }
Este método se utiliza únicamente para inicializar la memoria de programa.
FUNCIONES:
write_program_eeprom(dirección , dato);
read_program_memory (dirección, datoptr, n)
Lee n bytes de la memoria de programa y los guarda en datoptr
DEFINICIÓN DE FUNCIONES:
El formato de definición de una función es el siguiente:
[calificador] id ( [ especficador de tipo id ] ) ] { [ sentencias ] }
Los calificadores para una función son:
- void
- especificador de tipo
- #separate
- #inline
- #int_..
Ejemplo:
void lcd_putc ( char c ) {
...
}
lcd_putc ("Hola.");
Directivas del pre-procesador
Algunas directivas incluidas en CCS son:
#BYTE: #BYTE id=x // id es un identificador válido de C y x es una variable o una constante
Ejemplo:
#byte status = 3
#byte b_port = 6
#CASE: hace que el compilador sea sensible a mayusculas. Por defecto no lo es.
Ejemplo:
#case
int ESTADO;
void funcion() {
int estado;
...
ESTADO = estado; // copia la variable local estado a la variable global ESTADO
}
#DEFINE:
La sintaxis es:
#define id texto
#define id(x,y...) texto
id es un identificador del pre-procesador , texto es cualquier texto, x,y,.. son identificadores locales del pre-procesador.
Se utiliza para reemplazar una cadena (id) por el texto desde ese punto del progama en adelante.
Ejemplo:
#define BITS 3
a=a+BITS; // es lo mismo que a=a+3;
#FUSES: #fuses opciones
Las opciones dependen del dispositio utilizado. Algunas opciones comunes son:
· LP, XT, HS, RC
· WDT, NOWDT
· PROTECT, NOPROTECT
· PUT, NOPUT (Power Up Timer)
· BROWNOUT, NOBROWNOUT
Ejemplo: #fuses XT,NOWDT
#IF expresión:
La sintaxis es:
#if expresión
código
#elif expresión // opcional
código
#else // opcional
código
#endif
expresión es una expresión(condición) con constantes, operadores e/o identificadores del pre-procesador.
Ejemplo:
#if VALOR_MAX > 255
long valor;
#else
int valor;
#endif
#INCLUDE:
La sintaxis es:
#include <nombre_del_archivo>
o
#include "nombre_del_archivo "
donde nombre_del_archivo es un archivo válido incluido en la PC.
Ejemplos:
#include <16F876.H>
#include <C:\misdocumentos\pic\ejemplo.C>
#INT_XXX: las interrupciones más utilizadas son
#INT_AD Conversión análogica-digital finalizada
#INT_CCPn Captura o comparación en unidad n(n:1 a 5)
#INT_EEPROM Escritura finalizada
#INT_EXT Interrupción externa EJEMPLO
#INT_I2C Interrupción en bus I2C
#INT_RDA Dato recibido en RS232 disponible
#INT_RTCC Timer 0 (RTCC) overflow
#INT_TIMER0 Timer 0 (RTCC) overflow
#INT_TIMERn Timer n overflow (n:2 a 5)
#INT_USB actividad USB
Estas directivas especifcan que la siguiente función es de interrupción . El compilador generará un código para saltar a la función cuando se detecta la interrupción. Se genera un código para guardar y volver al estado en que estaba la máquina antes de la interrupción.
Ejemplo:
#int_ad
manejo_adc() {
adc_activo=FALSE;
}
#USE DELAY: #use_delay (clock=velocidad) donde velocidad es una constante 1-100000000 (1 a 100MHz). Le dice al compilador la velocidad del procesador y habilita la utilización de las funciones delay_ms() y delay_us().
Ejemplo: #use delay (clock=4000000) o #use delay (clock=4M)
#USE FAST_IO: #use fast_io(puerto) donde puerto es A, B, C, D, E, F, G, H, I, J o todos. Afecta a como el compilador generará código para las instrucciones de entrada y salida. El método rápido hará que el compilador trabaje con la entrada/salida sin programar los registros de dirección. La operación por defecto del compilador es la opuesta a este comando.
Ejemplo:
#use fast_io(A)
void main() {
output_low(PIN_B0);
output_low(PIN_B1);
....
}
#USE FIXED_IO: #use fixed_io (port_outputs=pin, pin?) donde port es A-G, pin es uno de los pines definidos es dispositivo.h. Afecta a como el compilador generará código para las instrucciones de entrada y salida. El método fijo hace que el compilador genere código para hacer que cada pin sea de entrada o salida cada vez que se utilice.
Ejemplo: #use fixed_io(a_outputs=PIN_A2, PIN_A3)
#USE I2C:
El bus serie I2C fue creado por Philips.
Velocidad standard: 100 Kbits/s
Velocidad en modo rápido: 400 Kbits/s
Velocidad máxima: 3.4 Mbits/s
Comunica microcontroladores y sus periféricos.
Utiliza dos hilos para transmitir información. Uno para los datos (SDA) y otro para el reloj o clock (SCL). Un tercer hilo de masa (GND) suele ser necesario.
Ejemplo de bus:
SDA y SCL so drenador abierto, por lo tanto son necesarias resistencias de pull-up.
Los dispositivos conectados al bus pueden ser MAESTRO o ESCLAVO y poseen una única dirección. El maestro inicia el intercambio de datos y es el que genera la señal de clock (SCL).
El bus está libre cuando SCL y SDA están en alto.
El MAESTRO envía una señal de START y envía un byte al esclavo:
A7-A1: 7 bits (corresponden a la dirección del esclavo).
A0=0 LECTURA (recibe información del esclavo).
A0=1 ESCRITURA (envía información al esclavo).
Cada esclavo compara la dirección enviada por el maestro con su propia dirección. El esclavo seleccionado envía un bit de ACK y entonces el maestro puede comenzar la comunicación. El maestro envía la dirección del registro del esclavo que quiere leer(A0=0) o escribir(A0=1). El esclavo envía otro bit de ACK. El maestro comienza a leer o escribir bytes (8 bits). Cada byte debe ser reconocido por un bit de ACK ya sea del maestro o del esclavo.
A pesar de que el maestro controla la señal de clock, un esclavo de baja velocidad puede forzar el clock a nivel lógico bajo. Entonces el maestro espera, en este momento no envía/recibe datos.
Cuando finaliza la comunicación, el maestro envía una condición de STOP y el bus queda libre.
I2C en CCS
Sintaxis: #use i2c(opciones)
donde las opciones van separadas por coma (,) y algunas pueden ser:
MASTER modo Master
MULTI_MASTER modo Multi-Master
SLAVE Modo Esclavo
SCL=pin Especifica el pin SCL
SDA=pin Especifica el pin SDA
ADDRESS=nn Especifica la dirección del esclavo
RESTART_WDT Reinicia el WDT mientras espera en I2C_READ
FORCE_HW Utiliza funciones I2C de hardware.
FORCE_SW Utiliza funciones I2C de software.
Para ver las demás opciones referirse a la ayuda de CCS.
Ejemplo: #use i2c(master, sda=PIN_B0, scl=PIN_B1)
Funciones:
i2c_start : genera una condición de START. Después del START, el reloj se mantiene a nivel lógico bajo hasta que se llame a la función i2c_write(). Si se produce un nuevo i2c_start() en la misma función antes que se produzca un i2c_stop(), se genera un reinicio.
Sintaxis: i2c_start();
Ejemplo:
i2c_start();
i2c_write(0xa0); // Dirección del dispositivo
i2c_write(address); // Envía el dato al dispositivo
i2c_start(); // Reinicio
i2c_write(0xa1); // Cambia dirección del dispositivo
data=i2c_read(0); // Lee del esclavo
i2c_stop();
i2c_read : lee un byte a través de la interfase I2C. En modo MASTER esta función generará el CLOCK y en modo ESCLAVO esperará por el CLOCK.
Sintaxis:
data = i2c_read();
data=i2c_read(ack);
ack -Opcional (por defecto 1).
0 indica no ACK.
1 indica ACK.
Devuelve: int - 8 bits
Ejemplo:
i2c_start();
i2c_write(0xa1);
data1=i2c_read();
data2=i2c_read();
i2c_stop();
i2c_write : envía un byte a través de la interfase I2C. En modo MASTER esta función generará el CLOCK con los fatos y en modo ESCLAVO esperará por el CLOCK del master.
Sintaxis:
i2c_write (data)
data es un entero (INT) de 8 bits
Devuelve: el bit de ACK
Ejemplo:
long comando;
...
i2c_start();
i2c_write(0xa0); // dirección del dispositivo
i2c_write(comando); // byte bajo de comando
i2c_write(comando>>8); // byte alto de comando
i2c_stop();
i2c_stop : envía una condición de STOP en modo MASTER.
Sintaxis:
i2c_stop ()
Ejemplo:
i2c_start();
i2c_write(0xa0); // Dirección del dispositivo
i2c_write(5); // Comando del dispositivo
i2c_write(12); // Dato del dispositivo
i2c_stop(); // Condición de STOP
#USE RS232: #use rs232 (opciones) donde opciones van separadas por comas y algunas pueden ser
BAUD=x x: velocidad en baudios
XMIT=pin Pin de transmisión
RCV=pin Pin de recepción
RESTART_WDT Hace que GETC() borre el WDT mientras espera por un caracter.
PARITY=X donde x es N, E, o O.
BITS =X donde x es 5-9
STOP=X Setea el número de bits de parada (por defecto es 1).
Ejemplo: #use rs232(baud=9600, xmit=PIN_A2, rcv=PIN_A3)
#USE STANDARD_IO: #use standard_io (port) donde port es A-J o todos. Afecta a como el compilador generará código para las instrucciones de entrada y salida. Es el método por defecto.
Ejemplo: #use standard_io(A)
Interrupciones
Las siguientes funciones permiten el manejo de interrupciones en los microcontroladores. Con estas funciones, las interrupciones pueden ser habilitadas, deshabilitadas y borradas.
Funciones relevantes:
disable_interrupts(): deshabilita la interupción especificada
enable_interrupts(): habilita la interupción especificada
ext_int_edge(): habilta una interrupción externa por flanco, el cual puede ser de subida o bajada (L_TO_H o H_TO_L)
clear_interrupt(): borra la bandera(flag) de interrupción. Puede ser utilizada si una isr(interrupt service routine) global es utilizada o para prevenir que una interrupción sea servida.
Ejemplo: #int_timer0 void timer0interrupt() // #int_timer asocia la siguiente funión con la rutina
// de servicio de interrupción que será llamada enable_interrupts(TIMER0); // habilita la interrupción TIMER0 disable_interrtups(TIMER0);// deshabilita la interrupción TIMER0clear_interrupt(TIMER0); // borra el flag de la interrupción TMER0
EJEMPLO
Descripción:
Este dispositivo tiene un registro de desplazamiento de 8 bits (entrada serial / salida paralela) que alimenta un registro de almacenamiento de 8 bits del tipo D. El registro de almacenamiento posee 8 salidas (3 estados). Relojes (clocks) independientes se utilizan para ambos registros (almacenamiento y desplazamiento) El registro de desplazamiento tiene un pin para cascada.
Diagrama de pines :
Tabla de verdad :
Descripción de pines :
Pin: 1, 2, 3, 4, 5, 6, 7, 15 Símbolo: Qa a Qh Función:Salidas de datos
Pin: 9 Símbolo: QH’ Función: Salida de dato serial
Pin: 10 Símbolo: SCLR negado Función: entrada de borrado del registro de desplazamiento
Pin: 11 Símbolo: SCK Función: entrada de reloj del registro de desplazamiento
Pin: 13 Símbolo: OE negado Función: Entrada de habilitación de salida (Output Enable)
Pin: 14 Símbolo: DS Función: entrada de dato serial
Pin: 12 Símbolo: RCK Función: entrada de reloj de registro de almacenamiento
Pin: 8 Símbolo:GND Función: Tierra( Ground 0V )
Pin: 16 Símbolo: Vcc Función: alimentación
Ejemplo: Turnero. Al presionar un pulsador(interrupción en RB0) se incrementa en una cuenta el display de 7 segmentos. Cuando el turnero está en 9 y se pulsa se inicializa a cero.
Diagrama en Proteus:
Representación de los dígitos 0-9:
Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7
0 1 1 1 1 1 1 0 0
1 0 1 1 0 0 0 0 0
2 1 1 0 1 1 0 1 0
3 1 1 1 1 0 0 1 0
4 0 1 1 0 0 1 1 0
5 1 0 1 1 0 1 1 0
6 1 0 1 1 1 1 1 0
7 1 1 1 0 0 0 0 0
8 1 1 1 1 1 1 1 0
9 1 1 1 1 0 1 1 0
Programa en CCS :
//www.asysc.com.ar * www.asysc.com.ar * www.asysc.com.ar// 25/OCT/2010// PIC16F6876A + 74HC595 + Display 7 segmentos// Simulador : Proteus 7.5 SP3// Compilador: CCS version 4.068// Descripción: - al presionar un pulsador se incrementa en una cuenta el // display de 7 segmentos. Cuando el turnero está en 9 y se pulsa se inicializa// a cero.//www.asysc.com.ar * www.asysc.com.ar * www.asysc.com.ar #include <16F876A.h>#FUSES NOWDT //No Watch Dog Timer#FUSES XT //Crystal/Resonator#FUSES NOPROTECT //Code not protected from reading#FUSES NOBROWNOUT //No brownout reset#FUSES PUT //Power Up Timer#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for // I/O#use delay(clock=4000000) //Reloj: 4 MHz#use fast_io(ALL)#define DATA PIN_A1#define CLOCK PIN_A0#define STROBE PIN_A2int8 TABLA[10]={0b11111100,0b01100000,0b11011010,0b11110010,0b01100110,0b10110110,0b10111110,0b11100000,0b11111110,0b11110110};int mascara[8]={0b00000001,0b00000010,0b00000100,0b00001000,0b00010000,0b00100000,0b01000000,0b10000000};int i=0;void AumentarCuenta(void);
#INT_EXTvoid RB0_isr(){AumentarCuenta();}void main(){set_tris_a(0x00); // todas salidasset_tris_b(0x01); // RB0 entrada, las demás salidasport_b_pullups(TRUE);enable_interrupts(int_ext);ext_int_edge(H_TO_L);enable_interrupts(GLOBAL);while(1){};}void AumentarCuenta(void){int j,i;for(j=0;j<8;j++){if((TABLA[i]&mascara[j])==0){output_low(DATA);}
else{output_high(DATA);}output_high(CLOCK);output_low(CLOCK);}output_high(STROBE); //efectivizar valores enviados enoutput_low(STROBE); //las salidas de los registrosi=i+1;if(i==10){i=0;}}