- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.
--- L’équipe FantasPic ---
Modérateur : Jérémy
- paulfjujo
Expert- Messages : 2597
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
Ce post est en parralelle avec la section ASM sur la gestion LCD 4x20 , mais en I2C
il est destiné à faire apparaitre de futurs problemes lié à la complexité progressive d'un programme...
où des effets de bords commencent à se manifester.
debordement de page , de bank ...
.. en plus des erreurs humaines !
Pour l'instant, en asm, l'ecriture en dur à des adresses bien precises et CONNUES donnent ( toujours) de bon resultats.
En C , on fait confiance au compilateur ...
Suite au rajout de cette fonction dansun programme existant ( pourtant succint!) :
Code : Tout sélectionner
// convert int ADC value to a string with 3 decimal => 0.000 to 5.000
char * value_converter(unsigned int adc_value)
{
// declaration d'un pointeur sur char
char *p1; // with this additional pointer , OK sur terminal, OK sur LCD
char T[8]; // local variable table de characteres
// char *p1; // with this additional pointer ,OK sur terminal , BAD sur LCD
long vout ;
unsigned int va;
p1=&T[0]; // initialise la valeur du pointeur
vout= (long)adc_value * 5000 >>10;
value = (unsigned int) vout;
T[0] = va/1000+48; //Add 48 to get the ASCII character
T[1]='.' ;
T[2] = ( va/100)%10+48;
T[3] = (va/10)%10 +48;
T[4] = ( va %10) +48;
T[5]=0;
return p1; // OK .. but BAD with return &T[0]; or return T;
}
... usage
txt=&TEXTE[0];
*(txt)=0;
txt=value_converter(EA0); // return a pointer
strcat(txt," V");
UART1_Write_Text(txt); // OK on terminal
CRLF1();
LCD_putcmd(LCD_LINE4,1); // Bad on LCD if i don't use an additional char pointer inside value_converter(EA0);
LCD_puts(txt);
Delay_1sec();
et ensuite utiliser le pointeur resultant avec l'UART ou le LCD
je constate que le comportement differe suivant l'ordre d'initialisation du pointeur situé dans ma fonction!
j'ai ouvert un post la-dessus sur le forum MikroC.
En C traditionnel on pouvait gerer les Far_pointeurs ..(Turbo C2.00) et les manipuler facilement.
sous mikroC on ne sait pas trop comment c'est géré.
dans l'ASM généré par le compilo
Code : Tout sélectionner
_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0722.c,694 :: char * value_converter(unsigned int adc_value)
char * value_converter(unsigned int adc_value)
{
char * p1; // with this additional pointer , OK sur LCD if declared first
char T[8]; // local variable
long vout ;
unsigned int value;
p1=&T[0];
donne
;_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0722.c,702 :: p1=&T[0];
MOVLW value_converter_T_L0+0
MOVWF value_converter_p1_L0+0
MOVLW hi_addr(value_converter_T_L0+0)
MOVWF value_converter_p1_L0+1
et le retour :
;_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0722.c,711 :: return p1; // OK ;
MOVF value_converter_p1_L0+0, 0
MOVWF R0
MOVF value_converter_p1_L0+1, 0
MOVWF R1
;_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0722.c,712 :: }
L_end_value_converter:
RETURN 0
déja , le Return 0
ne montre pas reellement que la fonction retourne un pointeur !
si ce n'est dans le contenu de R0 et R1 registre virtuels du compilateur
txt = value_converter(EA0);
Cet appel de fonction retourne un pointeur local p1 (avec p1 = T), donc txt va pointer sur le buffer T en sortie de fonction.
La suite du programme utilise donc T et pas TEXTE.
Le problème est que p1 et T ne sont plus valides car locaux, le compilateur réutilisera dès que possible les cases mémoire qu'ils occupaient.
Pourquoi tu ne remplis pas directement le buffer TEXTE dans la fonction.
Ou alors tu fais un strcpy(TEXTE, T) en fin de fonction.
Ou T disparaît et value_converter(EA0, TEXTE);
Le pointeur txt est-il vraiment utile ?
paulfjujo a écrit :Source du message Pour l'instant, en asm, l’écriture en dur à des adresses bien précises et CONNUES donnent ( toujours) de bon resultats.
et ouais, il y a que ça de vrai, car on sait ce qu'on fait...
paulfjujo a écrit :Source du message En C , on fait confiance au compilateur ...
Alors bonne chance....
A+
- paulfjujo
Expert- Messages : 2597
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
satinas a écrit :Le pointeur txt est-il vraiment utile ?
Code : Tout sélectionner
TEXTE=value_converter(EA0); // return a pointer
1016 318 Assigning to non-lvalue '' _18F46k22_Big_LCD_4x20_I2C1_HW_2020_0723.c
D'une façon generale , j'utilise ce pointeur txt pour toute sortie sur ecran terminal ou LCD .
Et je preferre utiliser des pointeurs plutot que des indices de table
Ledit pointeur pouvant etre affecté à n'importe quelle table ..
je pense avoir trouvé le probleme, mais je n'ai pas d'outils
(In Circuit Debugger Tool) pour le mettre en evidence..
l'usage de pointeur est correct
mais il doit y avoir un probleme de STACK Overflow
en decomposant ma routine utilisée dans le main program
LCD_Puts(txt);
Code : Tout sélectionner
void LCD_puts( char *s)
{int i=0;
while((*(s+i) != 0)&& (i<20))
{
LCD_putch(*(s+i));
i++;
}
}
par son contenu detaillé
Code : Tout sélectionner
LCD_putcmd(LCD_LINE4,1);
// LCD_puts(txt); // <------------- AUCUN affichage sur la 4em ligne avec appel de fonction
// OK, si decomposition de la fonction
i=0;
while((*(txt+i) != 0)&& (i<20))
{
LCD_putch(*(txt+i));
i++;
}
je diminue ainsi les appels , donc reduit la position maxi dans la pile ..
Ce debordement de pile ne faisant pas de degat "visuel " tel que reset , difficile à cerner
Nota:
la version passage du pointeur comme argument ne posait pas de probleme , soit avec le pointeur txt, soit
avec directement le pointeur sur table TEXTE
ce qui m'interessait dans mon test , etait l'usage d'un pointeur retourné par une fonction.
retour de fonction pouvant d'ailleurs etre fait sur un unsigned int ou * pointeur
via R0,R1 registres 8 bits dans bank0 utilisé par le compilo
Code : Tout sélectionner
_Value_converter(EA0, TEXTE);
UART1_Write_Text(TEXTE);
CRLF1();
LCD_putcmd(LCD_LINE1,1);
LCD_puts(TEXTE);
Delay_1sec();
TempsX a écrit :et ouais, il y a que ça de vrai, car on sait ce qu'on fait...
j'attends de voir des exemples un peu plus complexe en asm , pour voir si c'est toujours aussi facile ...
voila ce que donne le resultat asm de compilation sur ce petit test
Code : Tout sélectionner
/ TEST
unsigned int Test(void)
{
char * px;
px=&TEXTE[0];
_asm nop ;
_asm nop;
return px ;
}
Code : Tout sélectionner
;_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0723.c,740 :: unsigned int Test(void)
;_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0723.c,743 :: px=&TEXTE[0];
MOVLW _TEXTE+0
MOVWF R2
MOVLW hi_addr(_TEXTE+0)
MOVWF R3
;_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0723.c,744 :: _asm nop ;
NOP
;_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0723.c,745 :: _asm nop;
NOP
;_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0723.c,746 :: return px ;
MOVF R2, 0
MOVWF R0
MOVF R3, 0
MOVWF R1
;_18F46k22_Big_LCD_4x20_I2C1_HW_2020_0723.c,747 :: }
L_end_Test:
RETURN 0
; end of _Test
avec le debugger mikroc
j'ai bien verifier que le pointeur retourné, pointe bien sur le debut de TEXTE
Code : Tout sélectionner
// TEST
char *p1;
.....
txt=&TEXTE[0];
strConstRamCpy(TEXTE,"ABC");
ICI:
p1=Test();
UART1_Write_Text(p1);
CRLF1();
Dans ton premier post tu retournais l'adresse d'un tableau T local à la fonction, et continuais à le remplir par le biais de son adresse, car le C est très permissif. Cela pouvait tomber en marche au bon vouloir des compilations successives.
On peut quand même retourner l'adresse d'une variable locale, mais il faut la déclarer static.
- paulfjujo
Expert- Messages : 2597
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
c'est en effet la BONNE solution !
j'avais plutot l'habitude d'utiliser un passage de pointeur comme argument dans la fonction
ledit pointer étant global et par defaut static , ainsi que l'objet (table) pointée ... no problemo
All globals have static duration. ....
All functions, wherever defined, are objects with static duration.
......Other variables can be given static duration by using the explicit static or extern storage class specifiers.
confusion entre objet et variable , qui DOIT etre specifiée STATIC pour bloquer la reservation de l'espace en RAM
exclusivement à cet usage.
ça me rappelle les allocations memoires avec mem manager, heap reservation ...etc
qui existe aussi avec les PIC mais dont on ne se sert que tres rarement
(utilisé avec un LCD ILI9341)
les 2 versions :
Code : Tout sélectionner
// convert ADC value to a string with 3 decimal => 0.000 to 5.000
char * value_converter(unsigned int adc_value)
{
static char T[8]; // <------ must be a STATIC variable
long vout ;
unsigned int value=0;
vout= (long)adc_value * 5000 >>10;
value = (unsigned int) vout;
T[0] = value/1000+48; //Add 48 to get the ASCII character
T[1]='.' ;
T[2] = ( value/100)%10 +48;
T[3] = (value/10)%10 +48;
T[4] = ( value %10) +48;
T[5]=0;
return T;
}
// .. OK if pointer passed as parameter
void _Value_converter(unsigned int adc_value, char *T)
{
long vout ;
unsigned int value;
vout= (long)adc_value * 5000 >>10;
value = (unsigned int) vout;
T[0] = value/1000+48; //Add 48 to get the ASCII character
T[1]='.' ;
T[2] = ( value/100)%10+48;
T[3] = (value/10)%10 +48;
T[4] = ( value %10) +48;
T[5]=0;
}
Qui est en ligne
Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 43 invités