Problème math et programmation

C'est le lieu des discussions diverses et variées, mais toujours en rapport avec le thème général du forum et dans l'esprit de celui-ci. Contient des rubriques électroniques.

Modérateurs : Papy.G, fneck, Carl

Avatar de l’utilisateur
gleike
Messages : 1341
Inscription : 16 oct. 2014 11:12
Localisation : Ludres (54710) Meurthe & Moselle

Problème math et programmation

Message par gleike »

Bonjour,

J'ai un petit problème de programmation que je n'arrive pas à résoudre,
j'ai un petit SBC programmable en basic avec un convertisseur ADC qui me donne une valeur entre 0 et 255
suivant la position d'un potentiomètre,

le microcontrôleur à un port avec 8 LEDS, si j'envoie la valeur lue du potar sur le port,
j'ai son affichage en binaire sur les LEDS,

je voudrais avoir une seule LED qui s'allume et se déplace en fonction de la valeur lue du potar,

autrement dit convertir proportionnellement les valeurs de 0 à 255 en valeur 0,1,2,4,8,16,32,64,128
de façon élégante en basic en évitant de faire trop de tests.
Avez-vous une solution ?
Je sèche dessus depuis 2 jours :evil:

Merci.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Problème math et programmation

Message par __sam__ »

Tu te fais une table precalculée qui associé pour chacune des entrées possibles la sortie associée par la formule 2^arrondi_vers_le_bas(input/32).

Si ton sbc a assez de puissance et que tu veux économiser la ram tu peux faire la formule en asm avec des décalages: 1<<(input>>5). Soit tu prends l’entrée, tu la décale à droite 5 fois (c’est une division par 32) ça te donne le nombre de fois à décaler 1 à gauche (c’est une puissance de 2).

Bon le hic c’est que tu ne sors pas 0. Pour cela il faut faire un truc genre x=2^((input+1)/32)-1, et tabuler y=x&-x (le "et logique bit à bit" entre x et son opposé: cela ne garde que le bit de poids fort de x) pour toutes les inputs de 0 à 255. Ça doit se faire en basic sans soucis. Si tu tabules uniquement x, tu auras une barre de leds et pas juste le pixel du haut. Ça peut être bien aussi.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: Problème math et programmation

Message par hlide »

Tu as 8 LED et tu veux en allumer un seul qui indique une progression logarithmique binaire de ton potard ? je présume que ta sortie est un octet sur la même adresse I/O (chaque bit de cet octet encode une LED)

En pseudo language C :

Code : Tout sélectionner

unsigned char E = IN(kADC); // notre valeur analogique
unsigned char S = 0; // notre valeur de sortie initialement à 0
unsigned char M = 128; // le masque de sortie le plus grand initialement
for (char I = 0; I < 8; ++I)
{
	if (E >= M)
	{
		S = M;
		break; // un bit de positionné puis on sort de la boucle !
 	}	
	M = M / 2;
}
OUT(kLED, S); // on n'allume que la led au poids le plus significatif ou aucune si l'entrée est 0 
J'ai fait en sorte de ne pas utiliser des opérateurs & (AND octet) et >> (décalage de bits) pour être transposable en BASIC.

Le coup du tableau à 256 éléments est effectivement une façon très rapide d'obtenir la valeur de sortie (car d'ordre O(1) !) pour peu que l'on ait suffisamment de place en mémoire et se taper un code d'initialisation pour ce tableau.

EDIT:
en BASIC, l'algo pourrait être quelque chose du genre :

Code : Tout sélectionner

10 E = IN(IO_ADC) : S = 0 : M = 128
20 FOR I = 1 TO 8 : IF E >= M THEN S = M ELSE M = M / 2 : NEXT ' J'espère que NEXT ne s'exécute qu'après le ELSE... 
30 OUT IO_LEDS, S
…
Dernière modification par hlide le 30 juil. 2022 21:41, modifié 1 fois.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Problème math et programmation

Message par __sam__ »

Non c’est pas du log, mais de l’exponentielle plutôt (input linéaire et sortie en puissance de 2).

M’enfin le principe est là. La difficulté étant de mapper régulièrement 256 valeurs sur 9 valeurs (0, 1, 2, 4, 8, 16, 32, 64, 128 ca fait 9 valeurs).

En principe les basic savent faire du "et bit à bit", donc "x AND -x" doit bel et bien retourner le bit de poids fort de x, même en basic.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
remy
Messages : 1
Inscription : 18 juil. 2022 12:45

Re: Problème math et programmation

Message par remy »

moi je ferai comme __Sam__ avec 2^(int(val/8)) ou quelque chose d'approchant pour tenir compte des limites inférieures et supérieures.
Avatar de l’utilisateur
gleike
Messages : 1341
Inscription : 16 oct. 2014 11:12
Localisation : Ludres (54710) Meurthe & Moselle

Re: Problème math et programmation

Message par gleike »

Merci pour vos réponses, je vais faire des essais.
Avatar de l’utilisateur
gleike
Messages : 1341
Inscription : 16 oct. 2014 11:12
Localisation : Ludres (54710) Meurthe & Moselle

Re: Problème math et programmation

Message par gleike »

Voilà le résultat de mes essais, ça fonctionne très bien comme ça, merci de m'avoir mis sur la bonne piste.
conversion.jpg
conversion.jpg (37.69 Kio) Consulté 1725 fois
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: Problème math et programmation

Message par hlide »

Bon ok la demande ne correspondait pas du tout à ce que je croyais.

Mois j'avais compris un log2 :
* 0 < adc < 2 => Led 0 allumé pour indiquer niveau 1
* 2 < adc < 4 => Led 1 allumé pour indiquer niveau 2
* 4 < adc < 8 => Led 2 allumé pour indiquer niveau 3
* 8 < adc < 16 => Led 3 allumé pour indiquer niveau 4
* 16 < adc < 32 => Led 4 allumé pour indiquer niveau 5
* 32< adc < 64 => Led 5 allumé pour indiquer niveau 6
* 64 < adc < 128 => Led 6 allumé pour indiquer niveau 7
* 128 < adc => Led 7 allumé pour indiquer niveau 8

Alors qu'en fait, vous vouliez faire juste un démultiplexeur 3->8 avec les 3 bits les plus significatifs de adc.
Avatar de l’utilisateur
gleike
Messages : 1341
Inscription : 16 oct. 2014 11:12
Localisation : Ludres (54710) Meurthe & Moselle

Re: Problème math et programmation

Message par gleike »

Oui, en fait, ma demande était plus simple et je cherchais à éviter d'utiliser un tableau
en trouvant une formule pouvant faire directement la conversion ADC>>PORT.
Avatar de l’utilisateur
pascalien
Messages : 964
Inscription : 21 janv. 2019 23:40
Localisation : 93200 ST DENIS
Contact :

Re: Problème math et programmation

Message par pascalien »

Est ce que la fonction mathématique compliquée à trouver pourrait être une régle de trois?

led=pot/255*8

en trichant un peu 256 ca se fait avec un decalage.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Problème math et programmation

Message par __sam__ »

Ça n’aurait pas allumé les leds comme voulu. Les valeurs de 0 à 7 envoyés allument plusieurs leds en même temps (avec 3 leds au max, pour la valeur 7). Or il fallait n’allumer qu’au plus une des 8 leds.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Bernouilli92
Messages : 1254
Inscription : 24 déc. 2021 09:46
Localisation : Région parisienne

Re: Problème math et programmation

Message par Bernouilli92 »

D'après ce que je comprends, il faut allumer une led. Cette led a un numéro entre 0 et 8 et représente les valeurs 0 à 128 en puissances de 2.
Il suffit de faire n=INT(LOG(V)/LOG(2))
Cela ne fonctionne pas pour 0, d'où le programme suivant
IF v=0 THEN n=1 ELSE n=1+INT(LOG(V)/LOG(2))

Si on dispose pas de la fonction LOG, il suffit de parcourir les bits du nombre en question, du bit le plus fort au bit le plus faible et de s'arrêter dès qu'on trouve un 1. On obtient alors la position de la led mais en ordre inverse (8 à 1 pour bit 7 à 0). Si aucun bit n'est à 1 alors on sort 0.

Édit : après avoir relu le poste initial, voici ma solution :
IF v=0 THEN n=0 ELSE n=2**INT(LOG(v)/LOG(2))
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Problème math et programmation

Message par __sam__ »

D'après ce que je comprends, il faut allumer une led. Cette led a un numéro entre 0 et 8 et représente les valeurs 0 à 128 en puissances de 2.
Non pas exactement. Gleike dit clairement qu’il veut convertir les valeurs de 0 à 255 proportionnellement dans l’ensemble de 9 valeurs v(0), v(1), ..., v(8) (bref des v(i)),
autrement dit convertir proportionnellement les valeurs de 0 à 255 en valeur 0,1,2,4,8,16,32,64,128
de façon élégante en basic en évitant de faire trop de tests.
A partir de là on a résolu le problème: il faut que

Code : Tout sélectionner

         i=input*8/255 (arrondir â l’entier le plus proche)
C’est bien du proportionnel (règle de trois).

Ah oui j’ai oublié de dire ce que sont les v(0)..v(8). En fait ce sont ce qu’on veut pour la sortie. Ça peut être des trucs arbitraires: 8,1, 9, 17, ... défini par un tableau de valeurs dependant du hard. Le problème s’arrêté alors la. On utilise le tableau et c’est tout.

Bon il se trouve qu’ici on a de la chance car on peut aussi exprimer les v(i) par une puissance de 2 : v(i)=arrondi_vers_le_bas(2 puissance (i-1)), donc pas besoin de tableau intermédiaire, mais juste enchaîner du calcul sur des réels à faire en basic:

Code : Tout sélectionner

i = input*8/255.0 : rem On ignore l’arrondi au plus proche ici, c’est pas grave.
o = INT(2^(i-1))   : rem calcul du v(i)
zéro test. Juste des maths. Et surtout pas de LOG() sur l’entrée. On ne teste pas son ordre de grandeur (combien il faut de bits pour la représenter), mais sa valeur.

Note: On peut évidemment combiner les deux étapes de calcul en une seule, mais je crois que ça complexifie inutilement les choses en perdant ceux qui n’aiment pas trop les équations et leur sens caché. J’espère avoir été plus didactique que ma 1ère réponse ce coup ci.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Bernouilli92
Messages : 1254
Inscription : 24 déc. 2021 09:46
Localisation : Région parisienne

Re: Problème math et programmation

Message par Bernouilli92 »

Je crois qu'il y a une incompréhension sur le terme "proportionnellement" que j'ai mal compris à cause de cela :
"j'ai son affichage en binaire sur les LEDS,
je voudrais avoir une seule LED qui s'allume et se déplace en fonction de la valeur lue du potar,"
J'en ai conclu qu'il suffisait de supprimer les diodes supplémentaires qui s'affichent.

Maintenant si le déplacement de la diode est proportionnel à la valeur entre 0 et 255, alors il faut effectivement une règle de 3.
Mais j'écrirais cela plutôt comme cela :

i=int(((input+1)*9)/257)
o=int(2**(i-1))

Voici le résultat pour les valeurs de 0 à 255 :

Code : Tout sélectionner

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 
00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100
00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 
00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 
00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000
01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 
10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000

Et si on veut la variante où il y a toujours une diode allumée :
i=int(((input+1)*8)/257)
o=int(2**i)

Voici les valeurs obtenue pour input de 0 à 255 :

Code : Tout sélectionner

00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010 00000010
00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100 00000100
00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000 00001000
00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000 00010000
00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000
01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000 01000000
10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 10000000 
Avatar de l’utilisateur
gleike
Messages : 1341
Inscription : 16 oct. 2014 11:12
Localisation : Ludres (54710) Meurthe & Moselle

Re: Problème math et programmation

Message par gleike »

J'ai testé les différentes méthodes proposées, et celle qui fonctionne le mieux et celle-ci :
Bernouilli92 a écrit : 01 août 2022 12:13 i=int(((input+1)*9)/257)
o=int(2**(i-1))
Je ne l'aurais pas trouvé tous seul :roll:

À part que mon potar a pleins de mauvais contacts et provoque des sauts dans l'affichage, mais bon, il a au moins 50 ans.

Merci à tous pour votre implication 8)
Répondre