TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Dancrazy en 26 de Diciembre de 2007, 16:42:10
-
Hola a Todos (y Feliz Navidad)
Voy al grano, he encontrado un problemilla con mi querido Compilador CCS, que no doy con la manera de resolver...
Segun la ayuda, el ccs NO pasa Constantes string como Parametro... Es decir, lo siguiente (por ejemplo) es ilegal en este compilador:
<Includes, defines y otros>
void UsaTexto(char Texto[16],int8 Posicion)
{
<operaciones>
}
void main()
{
<operaciones>
UsaTexto("Una Prueba",1);
<Operaciones>
}
eso es legal en otros compiladores.... y usando punteros.. ( es decir: void UsaTexto(char *Texto,int8 Posicion) )
pero aqui no...
incluso probe esto que encontre en el fondo del baúl
#device PASS_STRINGS=IN_RAM
pero ni aun asi funciona....
hasta el momento me he tenido que contentar con
<Includes, defines y otros>
void UsaTexto(char Texto[16],int8 Posicion)
{
<operaciones>
}
void main()
{
char Mensaje[16];
<operaciones>
strcpy(Mensaje,"un texto");
UsaTexto(Mensaje,1);
alguien sabe si hay algun truco para hacer esto?
alguien sabe por qué los punteros fallan en este caso?
gracias a todos por su atencion y felices fiestas....
PS: ah! uso el CCS PIC C version 4...
-
Hasta lo que yo sé la gente de CCs todavía no a solucionado el tema de pasar un puntero a una constante. Así que por ahora hay que hacerlo de la segunda forma que presentado, copiarlo sobre RAM y pasarle el puntero de tu variable. :?
-
Antes que nada saludos y espero que lo siguiente los ayude a manejar vectores de string en ROM usando el compilador CCS. De acuerdo a ellos (CCS) y cito al propio fabricante:
/*
A more complex example that creates an array of pointers to constant strings:
*/
ROM char *strings[] =
{
"HELLO",
"WORLD",
"CONST",
"STRINGS"
};
/*
Access the above const pointers
*/
ROM char *ptr;
while (i = 0; i < (sizeof(strings) / sizeof(const char *)); i++)
{
ptr = strings;
printf("%s", ptr);
}
que lo pueden leer aquí (http://www.ccsinfo.com/content.php?page=flexconst), es posible guardar vectores de constantes de longitud aleatoria y luego poder leerlas dentro del código. Por supuesto quién lo pueda hacer con la explicación que dan en lo citado merecería un premio.
Lo siguiente tiene la limitación de que solo es aplicable a controladores donde se permita el uso de la función "read_program_memory()".
Basandomé en el código enviado al foro de CCS (ver código (http://www.ccsinfo.com/forum/viewtopic.php?t=33000&highlight=readprogrammemory)) y aunque este no compile (tiene errores menores) y tampoco funcione (asumo que el autor copió un código aún no probado) si dá la punta del ovillo de como el compilador maneja los vectores de constantes. Después de varias horas de pelea pude determinar como los diseñadores de CCS han resuelto el tema de ubicar en la memoria ROM un array con strings de longitudes arbitrarias, es muy ingenioso pero desgraciadamente para nosotros no está bien documentado.
Asumiendo el array ROM char *strings[] =
{
"HELLO",
"WORLD",
"CONST",
"STRINGS"
};
&strings nos dá una valor de 32 bits (para los 18F) que es la posición de la memoria ROM donde comienza el vector "strings" pero al comienzo no está el contenido del vector en sí, si no los offsets de 16 bits que hay que sumarle a &strings para encontrar la dirección exacta donde empieza el miembro del vector que queremos. Por esto la función original que fué publicada en el foro de CCS necesita las siguientes modificaciones para que funcionevoid MsgSend(int32 msgAddress, int language, int align){
int buffer[LCD_TYPE_WIDTH + 1]; //Temp RAM storage
//Actual address of the text in the chosen language:
int32 languageMsgAddress = 0; //si no se hace 0 funciona en el simulador pero no en el micro real
int i, msgLength = 0, startPosition;
//Read the CCS compiled address of our sub-string
//read_program_memory(address + (language * 2), &languageMsgAddress, 2);
read_program_memory(msgAddress + (language * 2), &languageMsgAddress, 2);
//la variable languageMsgAddress ahora tiene el offset del vector
//por lo que hay que sumarle la dirección de memoria original
languageMsgAddress += msgAddress;
//Copy the string into the temporary RAM buffer, for formatting
read_program_memory(languageMsgAddress, buffer, LCD_TYPE_WIDTH);
for (i = 0; i < LCD_TYPE_WIDTH; i++) { //Fills with spaces
bufferLcdFinal[i] = ' ';
}
msgLength = strlen(buffer);
switch (align) { //Picks the correct start position for alignment
case ALIGN_CENTER: startPosition = (LCD_TYPE_WIDTH - msgLength) / 2; break;
case ALIGN_LEFT: startPosition = 0; break;
case ALIGN_RIGHT: startPosition = LCD_TYPE_WIDTH - msgLength; break;
}
//We copy the message into the final buffer at the correct position.
//Note that we use strncpy instead of strcpy to avoid writing
//a terminating 0x00 at the end.
strncpy(bufferLcdFinal + startPosition, buffer, msgLength);
//Here, bufferLcdFinal is ready to be sent to your display device.
} Espero haber sido claro, falta determinar si para los 16F en que la dirección es de 16bits el offset es de 8 bits pero eso se lo dejo para alguno de Uds.
Saludos desde Córdoba, Argentina
Marcelo
-
Seguro que será muy útil tu magnífica explicación Marcelo. Muchas gracias
-
Buenisimo aporte Marcelo !! :-/
felicitaciones !! :lol:
-
Muy buen aporte Marcelo. Voy a probarlo y te cuento. :mrgreen:
-
gracias por el aporte,
aun lo estoy digiriendo, jeje...
tengo una pregunta mas, que no se si sera a proposito del tema...
mi pregunta es basicamente de CCS
el tipo char (un byte) es basicamente distinto a el tipo int8 (1 byte). en todo lo que he programado no habia visto algo asi, y siempre char era igual a cualquier tipo de longitud equivalente.... demonios, esto me plantea un terrible problema, pues a veces lo que almaceno cambia segun como defina....
por ejemplo, me paso esto:
#use rs232(baud=9600,RCV=PIN_C7, XMIT=PIN_C6,Parity=N,Bits=8)
//Variable Global
int8 Enviado[20];
//Procedimiento
void Comando(char Temporal[20])
{
int8 i;
Enviado[0]=0x42;
Enviado[1]=0x00;
Enviado[2]=strlen(Temporal);
Enviado[3]=8F;
strcpy(&Enviado[4],&Temporal[0]);
Enviado[strlen(Temporal)+4]=0xA4;
for(i=0;i<=strlen(Temporal)+5;i++)
putc(Enviado[i]);
}
void main()
{
char Mensaje[18];
strcpy(Mensaje,"BIENVENIDOS");
Comando(Mensaje);
}
si observan bien, lo que hago es que en un arreglo char copio una cadena de caracteres, llamo un procedimiento Comando, en el cual coloco una cabecera, y la cadena, y la envio serialmente... entonces estoy enviando
(en hexadecimal)
--->42 00 11 8F 42 49 45 4E 56 45 4E 49 44 4F 53 A4
B I E N V E N I D O S
a que no adivinan qué recibo?
42 00 11 8F 2A 8D C4 D5 15 4D 08 A0 92 07 55 A4
no le veo el sentido. El "Bienvenidos" se cambio totalmente, pero el resto esta correcto.... y ha pasado en varias formas distintas
alguna idea?
-
Daniel
Más allá de que tu código me parece que derrocha muchos recursos de memoria, te adjunto el código que compilado con el CCS 4.057 y simulado en el MPLAB 7.62 funciona, probalo y fijate.
Saludos
Marcelo
#use rs232(baud=9600,RCV=PIN_C7, XMIT=PIN_C6,Parity=N,Bits=8)
//Variable Global
int8 Enviado[20];
//Procedimiento
void Comando(char Temporal[20]){
int8 i;
Enviado[0]=0x42;
Enviado[1]=0x00;
Enviado[2]=strlen(Temporal);
Enviado[3]=0x8F;
strcpy(&Enviado[4],&Temporal[0]);
Enviado[strlen(Temporal)+4]=0xA4;
//Hasta acá todo bien, ahora yo lo cambiaría de la
//siguiente manera
for(i=0;i<sizeof(Enviado);i++){
putc(Enviado[i]);
if(Enviado[i] == 0xA4) break;
}
//asume que se vá a enviar todo el array, pero cuando
//encuentra el carácter 0xA4 (que vos lo agregas al final
//de la trama) finaliza la acción
//for(i=0;i<=strlen(Temporal)+5;i++)
// putc(Enviado[i]);
}
void main(){
char Mensaje[18];
strcpy(Mensaje,"BIENVENIDOS");
Comando(Mensaje);
}
-
¿Seguro que funciona? en PROTEUS no funciona.
-
bueno, lo probe en el PIC, claro, con algunas cosas mas....
por alguna razon que desconozco, el sizeof() no funciona, solo transcribe 2 bytes (BI)
este es un ejemplo de los tipos de datos que debo enviar, mas adelante (es ciclico) incluso llega a pasar que
--->42 00 11 8F 42 49 45 4E 56 45 4E 49 44 4F 53 A4
B I E N V E N I D O S
recibo
42 00 01 8F A4
se tragó el Bienvenidos
(que maleducado ¿no?) :lol:
el problema es que a veces lo que envio consta de puros bytes y no hay caracteres
pero diablos... int8 no es igual a char a int, que no es igual que BYTE (en otros compiladores) es solo una posicion de memoria de 8 bits.... ¿no? eso es lo que no me cabe en la cabeza....
-
si, es seguro...
es un problema de definicion de variables
porque los caracteres que indico manualmente, (y el numero de parametros que voy a enviar) o los envia completos o no envia ninguno... pero eso indica que el procedimiento funciona. el problema esta en el strcpy()
Repito, ocurre que
-->42 00 0B 2B 80 49 45 4E 56 45 4E 49 44 4F 53 72-->deberia enviar
-->42 00 0B 2B 80 2A 95 C0 DC 15 4C 0C A0 12 07 72--> Envia
|<---correcto----->|<------errado---------------------->| \
y a veces correcto
-->42 00 02 2B 80 EB-->deberia enviar
-->42 00 02 2B 80 EB--> Envia
en ambos casos la ultima cifra es un checksum y esta bien calculada y el numero de caracteres (la tercera cifra esta bien expresada.... el problema es de paso de parametros...
pueden ser dos cosas, o un error mio, o un bug de ccs
-
en ambos casos la ultima cifra es un checksum y esta bien calculada y el numero de caracteres (la tercera cifra esta bien expresada.... el problema es de paso de parametros...
pueden ser dos cosas, o un error mio, o un bug de ccs
Que version del CCS utilizas??
-
Tanto para pocher como para Dancrazy. Sería muy bueno, como lo sugiere MGLSOFT, que pusieran las versiones de las herramientas que están utilizando (compilador, simulador, etc.) y si no verfiquen aquí (http://www.ccsinfo.com/devices.php?page=versioninfo) si la versión del compilador que están usando no es la fuente de los problemas.
Saludos
-
Dancrazy, hasta donde sé, en C no se pasan los strings por copia sino por referencia.
En C++ si se permite pasar por copia. Tal vez allí esté tu problema...
Estas queriendo hacer algo que no solo no está permitido sino que además consume enormes recursos en manejo de stack provocando un muy probable desborde. Como ves, solo te copia los 4 primeros bytes como si de un float de 32 bits se tratase...
Saludos
-
jejeje,
pido disculpas a los tres... claro! cada version del CCS tiene problemas resueltos y quizas algun bug...
fijense, tengo
IDE=4.032
PCB=4.032
PCM=4.032
PCH=4.032
pero tambien puedo conseguir que me presten, si es necesario, una anterior la 3.227 que tienen unos amigos...
bueno, creo que a lo mejor maunix da en el clavo... lo que pasa es que yo me acostumbre a programar puntos de venta en C++ y que tienen cerca de 1MByte de memoria de programa y 1Mbyte o 512 de memoria ram y 64K de flash, y tambien para programas de computadora, y el ambos casos la memoria es "ilimitada" (ojo, lo de ilimitada, es una impresion, que aunque falsa, puede parecer aproximadamente cierta en tales casos, pues es dificil llegar a usarla toda, por muy despilfarrador que se sea) lo que evidentemente, en el PIC no es cierto en absoluto, de hecho, por ello trate de limitar todo el uso a cerca de 100 bytes en los arreglos principales
pense en declarar una estructura, o quiza enumeracion de mensajes para mostrar en pantalla, y luego segun un indice, pasarlos por parametro
-
pense en declarar una estructura, o quiza enumeracion de mensajes para mostrar en pantalla, y luego segun un indice, pasarlos por parametro
Bueno, lo que te comento de C es también para PC. De todas formas en C es simple hacer un arreglo y luego pasarlo por referencia. Es cierto, programar para micros grandes y/o PC puede generar ciertas costumbres que son perjudiciales para un microcontrolador. De la misma forma hacer códigos que ejecuten rápido en un microcontrolador puede llevarte a hacer cosas que en una pc no harías como por ejemplo evitar el uso de variables locales. Las variables locales (si no son estáticas) generan trabajo de stack con la consecuente importante pérdida de velocidad.
Pero para no irnos por las ramas, sii es un string que será fijo, se declara como una constante en rom y la envías también como parámetro por referencia y en la rutina lo procesas hasta encontrar un #0.
En el caso de los vectores debes indicarle cuantos caracteres procesar, algo así como
void mirutina(char * mibuffer, unsigned char count)
Donde count indicará precisamente cuantos datos se procesaran y/o enviarán por la usart , lcd o lo que estés usando. Esto es ya que en un vector está permitido que haya un #0 en cambio en el string es el fin de la cadena, de allí la diferencia.
Saludos
-
tal cual, uno de mis problemas es que, el pic no permite que para lo que tu definiste
void mirutina(char * mibuffer, unsigned char count)
el utilizarlo en algo asi como:
<otros comandos>;
mirutina("Prueba1",sizeof("Prueba 1"));
<otros comandos>;
pues yo deseo generar unos #includes en los cuales, un tercer usuario, los incluya en su main, y con algunas definiciones mas que él tenga que hacer, utilizando funciones y procedimientos que yo generé, realice su propio programa, sin tener que meterse en las profundidades de la comunicacion y otros
es decir, quiero crear "cajas negras" o "built in"s que deje para que un programador solo dé unos parametros y realice todo el resto de cosas... tal como yo hago en los puntos de venta....
¡Que problemita con el stack! debe haber una manera... por ahora hago pruebas con un PIC 16F877A pero se qe en algun momento me tengo que cambiar a uno con mas capacidad, como un 18F4550 o algo asi
Gracias por los excelentes consejos...
saludos!!!
-
Dancrazy la verdad no uso CCS pero en C18 por ejemplo puedes hacer esto
const rom char mystr[] = "hola mundo";
void mifuncion(const rom char *data)
{
// Tu codigo acá
// trabajarás con *data hasta que sea igual a 0
}
Un esquema así no te sirve?
-
ajá
C18, es HI-TECH? si, alguien me presto el HI-TECH V8
(la licencia cuesta caro ¿no? tengo que estar muy seguro para comprarlo :mrgreen:)
es menos automático y quizas algo mas parecido a ANSI C puro, pero no trae los procedimientos getch y putch para RS232 pre-contruidos... hice unos que encontre en una carpeta "\samples\serial\bitbanging" y tuve algunos problemas,
dado la premura que tengo, regrese al CCS que es mas automatico...
pero ahora que me habeis guiado por los caminos de la sabiduria y me indicaron que el problema puede ser el stack, puedo tratar de dilucidar como arreglarlo... tengo el fin de semana
sé que en CCS existe algo como
#device PASS_STRINGS=IN_RAM
#device ANSI
voy a investigar cómo se hace...
y cuando termine este proyecto, voy a hacer (con ayuda de ustedes, gracias!!!) un auto-curso de HI-TECH y de Pic Basic para tener varias visiones de cómo programar un PIC. Te vas a reir de mi, pero no se programarlo en Asembler, lo unico que programé en asembler fue un Intel 8051, y no quede con mas ganas de volverlo a hacer..
si logro sacar algo en claro, les cuento para que no le vaya a pasar a otro....
sospecho que el strcpy() y el memcpy() puede tener algo que ver
veremos
de verdad gracias por todas las ideas...
-
ajá
C18, es HI-TECH? si, alguien me presto el HI-TECH V8
(la licencia cuesta caro ¿no? tengo que estar muy seguro para comprarlo :mrgreen:)
C18 es de microchip (solo para la familia 18F y es gratuito en su versión estudiante).
El de Hi-tech es el PICC. Ya está por la version 9.6x para los 16F.
Cuesta unos 1000 dolares por familia, lo cual lo hace caro pero a mi modo de verlo es bastante mejor que el CCS incluso mejor que el C18 en algunos aspectos.
es menos automático y quizas algo mas parecido a ANSI C puro, pero no trae los procedimientos getch y putch para RS232 pre-contruidos... hice unos que encontre en una carpeta "\samples\serial\bitbanging" y tuve algunos problemas,
Si, es bastante menos automático, lo cual a mi hace que me guste el C18 y el Hitech y "no me guste" el CCS. Pero sobre gustos... :)
y cuando termine este proyecto, voy a hacer (con ayuda de ustedes, gracias!!!) un auto-curso de HI-TECH y de Pic Basic para tener varias visiones de cómo programar un PIC. Te vas a reir de mi, pero no se programarlo en Asembler, lo unico que programé en asembler fue un Intel 8051, y no quede con mas ganas de volverlo a hacer..
Nadie se te va a reír porque no hayas programado en assembly. Es útil saberlo pero no obligación. Lo más importante es que conozcas bien la arquitectura y cómo funciona el pic, el assembly ayuda a conocer bien eso.
si logro sacar algo en claro, les cuento para que no le vaya a pasar a otro....
sospecho que el strcpy() y el memcpy() puede tener algo que ver
Fíjate si tienes alguna función que copie de ROM a RAM, eso te ayudaría a guardar tus strings en rom y luego usarlas en la ram para trabajar con ellas si es necesario
-
ah, C18... ups... no sabia que era de Microchip
bueno, lo voy a buscar a ver
tengo el MPLAB, seguro se integra automaticamente
en cuanto a los gustos, lo entiendo perfectamente, de hecho en otro hilo de este foro, hablabamos de las "Cajas Negras" (y alguien me indico que se llamaban "built in") que son los codigos que hacen todo automaticamente.... y de como pueden jugarle malas pasadas a uno...
voy a seguir explorando esos otros compiladores.... siempre es bueno saber mas de uno.
y Dios!!! si es caro el PICC HI-TECH... pero como tu dices, si te va a resolver los problemas, vale la pena
gracias por todo
-
ah, C18... ups... no sabia que era de Microchip
bueno, lo voy a buscar a ver
tengo el MPLAB, seguro se integra automaticamente
Así es, pero te repito es solo para la familia 18F.
en cuanto a los gustos, lo entiendo perfectamente, de hecho en otro hilo de este foro, hablabamos de las "Cajas Negras" (y alguien me indico que se llamaban "built in") que son los codigos que hacen todo automaticamente.... y de como pueden jugarle malas pasadas a uno...
Seguro que si... no tengas duda de eso.
voy a seguir explorando esos otros compiladores.... siempre es bueno saber mas de uno.
Si quieres alguna alternativa libre tienes el SDCC. http://sdcc.sourceforge.net/
y Dios!!! si es caro el PICC HI-TECH... pero como tu dices, si te va a resolver los problemas, vale la pena
Según varios, es caro pero el mejor. :mrgreen:
-
No se como vas a usar los strings , pero si los diriges a rs23,lcd etc. una forma elegante podria ser asi .
#define string(x) printf(chr,x);
void chr(char ch){
// <procesa un caracter>
}
void main(void){
string("hola amigo");
}
PD: otro ejemplo
#define string( linea , columna , texto) { procesa_posicion( linea , columna ); printf( chr , texto ); }
void procesa_posicion(int8 lin , int8 col){
// <procesa posicion>
}
void chr(char ch){
// <procesa caracter>
}
void main(void){
string( 4 , 0 , "hola amigo" );
}
-
No se supone que desde la version 4.1xx del CCS ya se podria hacer punteros a constantes ??? =/