TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: RaDoN en 28 de Abril de 2005, 07:51:00
-
Buenas al foro, estoi empezando con C pero me cuesta batante viniendo de ASM por que pienso a nivel hardware del PIC y no logro aislarme de el en C

Perdonen si me hago pesado estos días pero el comienzo siempre es duro, y antes de desmoralizarme espero vuestra colaboracion
El programa es bien sencillo pero no me anda
Las luces del coche fantastico con led´s en el puerto D. Ave donde meti la pata:
//***********************************************
//* Primer programa por Daniel G - RaDoN *
//* en CCS. Knigh Rider´s leds *
//***********************************************
#include "16F877.h"
#use delay (clock=4000000)
#use fast_io(D)
#byte port_d = 8
#ORG 0x1F00,0x1FFF {} //for the 8k 16F876/7
main()
{
int i;
set_tris_d(0x00);
port_d = 0x01;
while(true)
{
for(i=0;i==8;++i)
{
delay_ms(500);
port_d = port_d * 2;
}
for(i=0;i==8;++i)
{
delay_ms(500);
port_d = port_d / 2;
}
}
}
-
No he podido probarlo, pero a priori veo un par de cosas en tu programa que me chirrían un poco:
1- declaras PORT_D=0x01, pero esa no es la dirección de memoria que ocupa PORTD en el 16F877, es la 0x08
2- creo que los bucles tal y como los has definido se ejecutarán 9 veces, ya que se cuenta desde el 0 hasta el 8. Yo en tu lugar pondría for (i=0; i<8;i++)
Ya me contarás, paisano
-
Prueba así:
for(i=0;i<=6;++i)
{
delay_ms(500);
port_d = port_d * 2;
}
for(i=0;i<=6;++i)
{
delay_ms(500);
port_d = port_d / 2;
Un saludo
-
Escrito originalmente por nocturno66
1- declaras PORT_D=0x01, pero esa no es la dirección de memoria que ocupa PORTD en el 16F877, es la 0x08
No, arriba hago un #byte port_d = 8, que declara el puerto D con el registro 0x08 (PORTD del 877). El port_d = 0x01 enciende el led de rd0. Es como aprendio ha hacerlo (lo que visto por los ejemplos), si hay otra manera de hacerlo, agradeceria que me lo comentaras.
Y tb me gustaria saber la diferencia de cuando se usan parentesis y la asignación "=" :
set_tris_d(0x00)
port_d = 0x01 ---> si aquí pongo port_d(0x01) no funciona.
Gracias por las resupuestas y tb a pocher
-
Ejem, ejem ¿has probado lo que te he dicho?
-
Es verdad, se me fue la olla con lo del PORT_D.
Hazle caso al gran Pocher y prueba eso. Además, sus bucles sólo dan 7 vueltas, que son los desplazamientos que necesitas para llevar la luz de un extremo al otro.
-
Escrito originalmente por pocher
Ejem, ejem ¿has probado lo que te he dicho?
Si gracias pocher, tb lo he probado con un while hasta que port_D = 128 rotando a la izquierda y while(port_d= 0) rotando a la derecha y tb va.
Al final me va gustar C xD
-
Yo tengo una duda a la hora de configurar los puertos y es cuándo usar:
#use fast_io(...)
#byte port_a = ...
No sé cómo se usan porque he visto programas que las llevan otros que no; si es para configurar el puerto como entrada, como salida; si se ponen antes o después...
¿Me podeis indicar que tendría que poner para configurar en condiciones el puerto A con todo entradas y los puertos B y C como salida para un 16F870?
Gracias.
-
Ninguna de las dos directivas te hace falta para definir un puerto como entrada o salida.
Los puertos se suelen configurar en el main así: set_tris_A (0xFF) ---> todo entradas
set_tris_A (0x00) ---> todo salidas ... idem para otros puertos.
Un saludo
-
El compilador de CCS habilita los TRIS correctos antes de cada entrada o salida de información por el puerto, si es necesario y siempre en función de tu programa. Con el uso de fast_io prohibes al compilador que haga esa función para acelerar la gestión de los puertos, aunque recaerá en el programador la tarea de configurar correctamente los TRIS.
Definir un puerto con un nombre, como haces con #byte port_a=5; te permitirá utilizar el puerto tanto a nivel de entrada como de salida como si de una variable se tratase. Por ejemplo, PORT_A=0xFF, te pondría todas las salidas a nivel alto.
Si no defines los puertos así, en CCS hay instrucciones para manejarlos como output_a o input_a. Supongo que es cuestión de gustos, aunque a mí particularmente me gusta más definir los puertos y usarlos como variables, porque los comandos OUTPUT_x e INPUT_x son particulares de CCS y cuando cambias de compilador te vuelves loco...
-
Ajá ... gracias pocher y nocturno. Estoi contigo de eso para habituarse para poder compilar con cualquiera, pero le veo en contra que tienes que ponerte a definir todas las variables y es un poco coñazo. Anque tb te puedes hacer un ".h" con todo ya.
-
Muchas gracias, aprendido queda.
Estoy haciendo un programilla que no me acaba de funcionar y ya le doy vueltas a todo.
Lo que hace no tener ni idea. 
Una cosilla, lo de los fuses como que no valen para mucho ¿no? ¿Hay algunos imprescindibles o se puede programar sin tenerlo en cuenta?
-
Mirad, para configurar el puerto A como entrada copio el texto en ensamblador que viene en el manual. pero al compilar em dice que no están declaradas las variables STATUS, RP0, etc.
No lo entiendo, si lo estoy haciendo en ensamblador.
¿Qué tengo que declarar?
#asm
BCF STATUS, RP0
BCF STATUS, RP1
CLRF PORTA
BSF STATUS, RP0
MOVLW 0x06
MOVWF ADCON1
MOVLW 0XFF
MOVWF TRISA
#endasm
-
¿Y no te gusta así?: set_tris_a(0xFF) ... ¿que le pasa? ¿porque recurrir a asm para eso?
-
En C para usar los nombres de los registros los tienes que definir previamente con #byte PORTA = 0x05 etc, de lo contrario no los reconoce.
Es dificil al principio dejar el ensamblador y coger el C, pero te aconsejo que intentes dejar de pensar en ensamblador y lo hagas con instrucciones C, para lo cual lo primero que debes de agenciarte es el manual del compilador. La prueba y gran ventaja del C, la tienes en el ejemplo que has puesto, compara el número de instrucciones de ensamblador con la única instrucción que te recomienda Radon.
Un saludo
-
El caso era que como había que meter...
BCF STATUS, RP0
BCF STATUS, RP1
CLRF PORTA
BSF STATUS, RP0
MOVLW 0x06
MOVWF ADCON1
...antes del trisa, puse tal cual lo que venía en el manual.
Al final he puesto...
#byte adcon1=0x9F
adcon1=0x06;
set_tris_a(0xFF);
¿Es lo mismo que lo que está arriba en ensamblador?
-
El adcon1=6, no es necesario meterlo, ya toma las entradas como digitales por omisión.
Un saludo
-
Gracias. Ya que estamos, si no os importa, os copio el programa en cuestión que no hago funcionar y no sé por qué.
El reloj es un cristal externo de 20Mhz (¿con uno menor iría mejor?) así que al programar le digo que el oscilador es XT, y también habilito el wathdogtimer, aunque no sé si es necesario.
El programa lo unico que hace es esperar a que se pulsen uno de los tres pulsadores y en función del que ha sido pulsado incrementa o decremente la salida.
#include <16F870.h>
#use delay(clock=20000000)
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#byte port_b=0x06
#byte port_c=0x07
void main()
{
typedef short bit;
bit e0, e1, e2;
int nivel, estado;
int const tension[6]={0x20,0x30,0x3F,0x4B,0x55,0x6D};
set_tris_a(0xFF);
set_tris_b(0x00);
set_tris_c(0x00);
nivel=0x00;
estado=0x20;
e0=input(PIN_A0);
e1=input(PIN_A1);
e2=input(PIN_A2);
port_b=estado;
port_c=estado;
while(TRUE)
{
restart_wdt();
if(e0!=input(PIN_A0))
{
nivel++;
if (nivel==6) { nivel=0; }
estado=tension[nivel];
port_b=estado;
port_c=estado;
e0=input(PIN_A0);
}
if(e1!=input(PIN_A1))
{
estado++;
port_b=estado;
port_c=estado;
e1=input(PIN_A1);
}
if(e2!=input(PIN_A2))
{
estado--;
port_b=estado;
port_c=estado;
e2=input(PIN_A2);
}
}
}
-
Sin entrar a valorar a fondo tu programa, en el que hay cosas que no acabo de entender, te diré un par de cosas que podrías ir probando:
1.- el fuse XT es para cristales de 4MHz. Si quieres poner un cristal de 20MHz el fuse adecuado es HS. Cuidado porque hay micros que admiten un cristal de 20MHz y otros que no; tendrás que estar seguro que tu micro lo aguanta.
2.- Veo que no has incorporado en tu programa ningún mecanismo antirrebotes, por lo que sólo acercar el dedo a un pulsador hará que se incremente o decremente a toda leche la variable estado.
-
Mil Gracias.
Estáis en lo cierto. He bajado el reloj a 10Mhz y añadido #fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
Ahora va pero peta al tocar el interruptor. Metí un retraso de 100 milisegundos al inicio del "if"para evitar el rebote pero parece que eso no funciona.
Otra cosa que he notado, a la primera fue, luego quité la alimentación ,la volví a poner pero noiba, esperé un tiempo, lo conecté y lo hizo bien, pero al quitarle alimentación otra vez y volver a probar siguió sin ir.
¿Tiene algún buffer o algo que se queda en memoria o tengo que deshabilitar algo para que se finalice en condiciones al quitar la alimentación?
Voy a ver si encuentro algo anti
-
Prueba a aumentar ese retraso, por ejemplo a 250 ms. Es una burrada, pero te permitirá confirmar si funciona bien o no.
Lo que cuentas de los reinicios no es normal. ¿Seguro que ese micro está preparado para correr a 10MHz?
-
Hecho, al final uso el programa que pongo a continuación.
Va bien pero peta al tocar los interruptores.
Es decir el primer valor le saca bien y entra en el bucle infinito pero si toco una entrada con el interruptor todo se va por el agujero.
El delay de 250 tampoco me lo soluciona.
¿Pongo más delay o se debe a otra cosa?
Gracias.
#include <16F870.h>
#use delay(clock=10000000)
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#byte port_b=0x06
#byte port_c=0x07
void main()
{
typedef short bit;
bit e0, e1;
int nivel;
int const tension[6]={0x6F,0x55,0x4A,0x3E,0x30,0x20};
set_tris_a(0xFF);
set_tris_b(0x00);
set_tris_c(0x00);
nivel=0x00;
e0=input(PIN_A0);
e1=input(PIN_A1);
port_c=tension[nivel];
port_b=nivel+1;
while(TRUE)
{
if((e0!=input(PIN_A0)) && (nivel<5))
{
delay_ms(250);
nivel++;
port_c=tension[nivel];
port_b=nivel+1;
e0=input(PIN_A0);
}
if((e1!=input(PIN_A1)) && (nivel>0))
{
delay_ms(250);
nivel--;
port_c=tension[nivel];
port_b=nivel+1;
e1=input(PIN_A1);
}
}
}
-
A ver, define "se va por el agujero"
, vamos, describe el error
Y otra cosa. El delay_ms tiene sentido una vez que hayas procesado lo que quieres que haga el programa al pulsar el botón; si lo pones al comienzo como ahora, y es un retardo importante, notarás cierto retraso en la ejecución de tu programa.
Otra cosa. ¿Necesitas que las rutinas se ejecuten cuando pulsas y también cuando levantas el dedo?. Si es así, está correcto, pero si sólo quieres ejecutarlas cuando pulses el botón, deberías poner:
input(PIN_A0) // para lógica positiva del interruptor
o
!input(PIN_A0) // para lógica inversa del interruptor
y olvidarte de las variables temporales e0 y e1.
Sigue probando y nos cuentas, ¿vale?
-
Me refería a que es tocar un interruptor y aquello dejar de funcionar, poner todas las salidas a cero.
Las entradas son interruptores y por eso he puesto que afecten al programa siempre que cambien de posicion.
Voy a ver si cambiando el delay y poniendo más.
Es que ayer no sé que pasó con la fuente que se me quemó el pic
-
Pon por aquí el esquema de tu circuito.
-
Lo describo, que no domino el proteus.
2: RA0/AN0
3: RA1/AN1
En estas dos patas están los interruptores conectados a masa y a 5V con una resistencia de 10k de por medio.
9: OSC1/CLK1
10: OSC2/CLK0
Aquí pongo el reloj de 10MHz y en cada pata un condensador de 22pF a masa.
11-18: PORTC
Estas salidas van conectadas a las entradas del convertidor digital-analógico DAC08.
21-28: PORTB
No he puesto nada pero en un futuro espero poner un led de 8"s.
8, 19: Vss
Conectada a tierra.
20: Vdd
Conectada a +5V
Esta tarde probaré un programa sin entradas, simplemente que entre y se pase haciendo un "for" de arriba para abajo recorriendo el string con un delay de por medio.
Gracias por el interés.
-
¿Y no tienes conectada una resistencia entre Vdd y el Pin 1 (MCLR)?, pues lo raro es que te funcione hasta que pulsas un interruptor.
Ponla, anda, verás como todo sale funcionando.
-
Por cierto, acabo de entrar en tu perfil y veo que mientes. O mientes con la edad o mientes con la foto


-
Muchas Gracias. Me hubiese vuelto loco sin tu ayuda.
Te debo mucho. Voy a investigar sobre esa resistencia.
¿Te molo?