Lire un octet de l'UART sur AVR en C - Page 2

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From French to

Threaded View
Re: Lire un octet de l'UART sur AVR en C
Jean-Christophe, le 27/11/2009 a écrit :
Quoted text here. Click to load it

Si mes souvenirs de plus de 25 ans - la MIDI 1.0 n'était pas vieille -
sont exact, il n'y a pas de bit de parité. Il y a un start et un stop
encadrant 8 bits.

J'ai vérifié dans Google, et effectivement et contrairement à ce que je
pensais, en MIDI le MSB est balancé en premier, en rs232 c'est le LSB.
Je ne m'en souvenais pas parce que je codais à l'époque en dur (tempo
logicielles sur un Apple ][) ou avec du 6850. J'imagine que le 6850
permettait de positionner le bit-boutisme ?

Donc changement de processeur (c'est peut-être le plus raisonnable) ou
table de look-up.

--
Pierre Maurette



Re: Lire un octet de l'UART sur AVR en C
Le 27/11/2009 22:41, Pierre Maurette a écrit :
Quoted text here. Click to load it

C'est cela.


Donc ça expliquerait tout ça. Par contre, comment expliquer que les
messages que j'envoie (j'envoie bien 0xC0 pour un Program Change, et pas
0x03) sont bien interprétés par l'appareil MIDI à commander ?

Quoted text here. Click to load it

Au point où j'en suis, je ne peux plus trop changer ça.

Re: Lire un octet de l'UART sur AVR en C
Quoted text here. Click to load it

Je partage, ce n'est pas normal!

--

Alain



Re: Lire un octet de l'UART sur AVR en C
jlp a tapoté du bout de ses petites papattes :

Quoted text here. Click to load it

Le Midi est une liaison série tout à fait orthodoxe. On utilisait
d'ailleurs des Usart standards au début des 80s. Seule la vitesse
(31k250 bauds), assez peu standard, peut géner. La sortie est pilotée
par un collecteur ouvert (l'autre fil va sur une pull-up), l'entrée est
donc un opto-coupleur. Donc bien penser que la polarité est inversée
par rapport à une rs-232, ça peut donner l'illusion - si on regarde au
scope une boucle de test qui compte - que le comptage se fait dans le
mauvais sens.

--
LeLapin



Re: Lire un octet de l'UART sur AVR en C

Quoted text here. Click to load it

Oui mais cela ne rE9%soud pas le cas exposE9% par Difool :
L'inversion de polaritE9% ne ferait que complE9%menter les valeurs
logiques
des bits, mais conserverait leur ordre MSB/LSB dans un octet.
Par exemple, une inversion de polaritE9% de 0x03 donne 0xFC,
tandis-qu'un renversement de l'ordre des bits donne 0xC0.

Re: Lire un octet de l'UART sur AVR en C

snipped-for-privacy@l13g2000yqb.googlegroups.com...
Bonjour,

Je suis en train de concevoir un footcontroller MIDI avec un
AtMega644. Pour cela, j'utilise l'UART du microcontrôleur.
Pour l'envoi des messages MIDI, c'est OK mais pour la lecture, ça se
corse un peu.

Dans un premier temps, j'ai besoin de détecter si un message de
Program Change est reçu sur le canal 0, soit le code 0xC0, mais comme
le bit de poids fort est envoyé en premier, je reçois 0x03 et c'est
donc cette valeur que je dois lire.

Y-a-t-il un moyen de contourner ça simplement ?
J'ai pensé écrire un algo de pile LIFO mais ça me parait un peu lourd
pour ça.
===========
Le c avr   dispose   je crois des fonctions de manipulation de bit  comme
"bit_set()  bit_clear) et bit_test  "
Une petite fonction "basique"  comme celle-ci retournera facilement  l'ordre
des bits

int inverse (int x) {
int y=0;
for(i=0;i<8;i++)  if(bit_test(x,i)bit_set(y,8-i);
return(y);
}



Re: Lire un octet de l'UART sur AVR en C
difool, le 27/11/2009 a écrit :
Quoted text here. Click to load it

C'est étonnant. Êtes-vous certain par exemple ne n'avoir fait qu'une ou
deux manips par hasard erronnées qui vous ont amené à penser à cette
inversion ?
Si votre flux MIDI est standard, et c'est plus que certainement le cas,
alors il y aurait un binz dans l'UART du µ-contrôleur. Il devrait alors
logiquement y avoir un truc, soit hard, une possibilité d'inverser le
décalage, soit soft, une inversion de l'ordre des bits en une
instruction.

Quoted text here. Click to load it

Je ne connais pas Atmel, ni les possibilité de l'AtMega644. Mais sur 8
bits, une table de lookup est souvent une bonne solution. Elle n'occupe
en définitive que 256 octets(*), à diminuer de l'occupation *réelle* du
code généré par votre code d'inversion de l'ordre des bits. Et niveau
vitesse, sécurité et maintenabilité, c'est quand même autre chose.
Bien entendu, vous pouvez vous faire un bout de C ou mieux du langage
de script que vous aimez pour générer le morceau du source qui déclare
la table.

(*) Peut-être 512, en 256 words ?

--
Pierre Maurette



Explication : Lire un octet de l'UART sur AVR en C
difool a écrit :
Quoted text here. Click to load it

* Lisez simplement la norme MIDI : le bit de poids fort est envoyé en
premier, alors qu'en rs232, c'est le bit de poids faible. *

Il est donc normal d'voir des mots inversés.

Le plus simple pour avoir un programme simple et lisible c'est d'inclure
une routine d'inversion des bits dans les fonctions de lecture et
d'écriture assurant ainsi la logique de cohérence entre les octets
"messages" et les octets sur la couche physique.

bien plus simple et plus propre que de faire des #define à tout va!

de plus, au vu de la vitesse de transmission, cette inversion prendra un
temps tout à fait négligeable.

la meilleure méthode consiste à utiliser des décalages sur l'octet lu,
et d'utiliser le bit passé dans le bit Carry pour effectuer un décalage
dans l'autre sens sur l'octet remis dans l'ordre. ça doit tenir en
quelques lignes d'assembleur.

JJ

Re: Explication : Lire un octet de l'UART sur AVR en C

Quoted text here. Click to load it
=============
Cette solution  "d'école" à été abondamment  proposée ..  sans trop
intéresser
apparemment  notre ami ..





Re: Explication : Lire un octet de l'UART sur AVR en C
Le 29/11/2009 08:19, Pierre_Edouard a écrit :
Quoted text here. Click to load it

C'est pas que ça ne m'intéresse pas, c'est que ça me parait lourd à
mettre en place, en terme de temps d'execution.
La solution du #define proposée sur ce fil me parait plus appropriée.

Re: Explication : Lire un octet de l'UART sur AVR en C
GRENON Loïc, le 29/11/2009 a écrit :
Quoted text here. Click to load it

La solution par #define ne résoud qu'un problème. Vous parlez d'un
footcontroler, vous allez sans doute jouer sur la dynamique. Et de
toutes façons autant l'envisager. Comment allez-vous faire par exemple
pour multiplier une vélocité par 0.75 ?
Il vous faut remettre vos codes à la bonne valeur dès l'acquisition.
J'ai vu la mémoire dont vous disposez, une table de 256 octets ne
devrait pas vous embêter trop, d'autant qu'après c'est immédiat.
D'autant que la ~µs que va vous prendre la conversion est constante, ce
qui est toujours un plus en temps réel. Vous définissez ce tableau:

static unsigned char reverse_octets[] = {
        0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
        0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
        0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
        0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
        0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
        0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
        0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
        0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
        0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
        0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
        0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
        0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
        0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
        0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
        0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
        0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
        0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
        0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
        0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
        0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
        0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
        0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
        0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
        0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
        0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
        0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
        0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
        0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
        0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
        0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
        0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
        0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};

et ensuite, si vous aviez un truc genre:

a = USART0;
ou
return USART0;

vous remplacez par:

a = reverse_octets[USART0];
ou
return reverse_octets[USART0];

Notez que la conversion est réflexive. Vous auriez pu l'utiliser en
sortie si vous en aviez eu besoin. Vous pouvez aussi faire
reverse_octets[reverse_octets[i]] pour vérifier la table.

Pour info, la table se fait facilement, par exemple en Python (j'avais
les fonctions dans ma boite à clous, sinon il y a plus simple):


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import sys

################################################################################
def computeNumBits(value, signed=False):
  """Calcule le nombre de bits dans la série 8, 16, 32, 64, 128, 256,
etc.
     nécessaires pour contenir value.
     La représentation envisagée est du binaire naturel ou en
complément à 2.

     arguments:
     - value, un entier
     - signed, booléen, à True si on souhaite une représentation
signée.
       Si value est négatif, signed est "forcé" à True.

     retourne:
     - Le nombre de bits.

  """
  n, max, neg = 8, 256, (value < 0)
  if signed or neg:
    value *= (1, -1)[neg]
    value <<= 1
    value -= neg
  while max <= value:
    n *= 2
    max *= max
  return n

################################################################################
def val2hexc2(value, hexdigits=0, signed=False):
  """Fabrique la chaîne de l'expression hexadécimale de value.
     Formatée sur hexdigits chiffres, ou plus si nécessaire.

     arguments:
     - value, un entier
     - hexdigits, nombre de chiffres souhaités.
     - signed, booléen, à True si on souhaite une représentation
signée.
       Si value est négatif, signed est "forcé" à True.

     retourne:
     - La chaîne de l'expression hexadécimale.

  """
  bits = max(hexdigits * 4, computeNumBits(value, signed))
  abovevalue = 1 << bits
  firststring = hex((abovevalue + value) %
abovevalue).upper().split('X')[-1].rstrip('L').lstrip('0')
  return '0' * ((bits / 4) - len(firststring)) + firststring

################################################################################
def val2binc2(value, bits, signed=False):
  """Fabrique la chaîne de l'expression binaire de value.
     Formattée sur bits chiffres (bits), ou plus si nécessaire.

     arguments:
     - value, un entier
     - bits, nombre de bits souhaités.
     - signed, booléen, à True si on souhaite une représentation
signée.
       Si value est négatif, signed est "forcé" à True.

     retourne:
     - La chaîne de l'expression binaire.

  """
  return ''.join({
         '0':'0000'
        ,'1':'0001'
        ,'2':'0010'
        ,'3':'0011'
        ,'4':'0100'
        ,'5':'0101'
        ,'6':'0110'
        ,'7':'0111'
        ,'8':'1000'
        ,'9':'1001'
        ,'A':'1010'
        ,'B':'1011'
        ,'C':'1100'
        ,'D':'1101'
        ,'E':'1110'
        ,'F':'1111'
        }[c.upper()] for c in val2hexc2(value, bits/4, signed))

################################################################################

################################################################################
def __doIt():

  def uneligne(seq):
    return ', '.join(['0x' + val2hexc2(int(val2binc2(i, 8,
False)[::-1], 2), 2) for i in seq])

  ValsByLine, Indent = 8, 8

  print 'static unsigned char reverse_octets[] = {\n' +  (Indent - 1) *
' ',
  print (',\n' + Indent * ' ').join([uneligne(range(_,_ + ValsByLine))
for _ in range(0,256,ValsByLine)])
  print '};'
  sys.exit(0)


if __name__ == '__main__':
  __doIt()

--
Pierre Maurette



Re: Explication : Lire un octet de l'UART sur AVR en C
Quoted text here. Click to load it

Essaye de comparer le temps d'execution du decalage d'un octet d'un bit ( au
pire quelques microsecondes et encore je pense que je suis largement
pessimiste), avec le temps d'envoi d'un octet en RS232, meme 115Kbauds!
Cela reviendrait ( reste aprouver) a travailler plus vite, mais attendre
plus longtemps!

--

Alain



Re: Explication : Lire un octet de l'UART sur AVR en C

4b126aeb$0$18395$ snipped-for-privacy@news.free.fr...
Quoted text here. Click to load it
ce que tu ne vois pas, c'est que pour du midi, il faut reagir le plus vite
possible, et le µp n'aura pas qu'inverser des octets a faire.
comme dit pierre, s'il y a du calcul a faire sur les données, il faut passer
par une table de conversion. ca revient a ecrire OctetReel =
table[OctetRecu], a la reception, et a l'emission c'est pareil
OctetAEnvoyer= table[OctetReel].

s'il n'y a pas de calcul a faire, un simple define suffit (de toute facon il
faudra le faire, a mois de coder comme un cochon)
l'envoi en serie, c'est une ecriture a une adresse, apres c'est l'uart qui
se debrouille, et le µp peut faire son traitement.

pourquoi vouloir perdre du temps a effectuer des calculs pour inverser des
bits ?



Re: Explication : Lire un octet de l'UART sur AVR en C

4b123e3e$0$947$ snipped-for-privacy@news.orange.fr...
Quoted text here. Click to load it
========
La  solution  d'utiliser le préprocesseur  est bien  évidemment   légère et
serait  préférable  s'il ne faut retourner  que  deux ou trois mots choisis
.
Mais pour en retourner 255, une fonction en "C" , ( celle-là "ridiculement
petite"  dans un
programme de  plusieurs milliers peut-etre de lignes  ...) peut
difficilement etre qualifiée de lourdeur,  c'est le principe même de travail
que l'on
demande à un  processeur, micro ou non.
Pour le plaisir on peu même bâtir cette fonction en ASM , ( bien qu'un
compilateur très modeste est capable de faire aussi bien,)    qui pourra
etre rangée  dans   l' include <perso.h>  et oubliée .
Enfin  pour trancher il te suffit de tester les méthodes retenues (
certainement plus rapide que de discuter ;-)  )




Re: Explication : Lire un octet de l'UART sur AVR en C

4b12cacf$0$1009$ snipped-for-privacy@news.orange.fr...
Quoted text here. Click to load it

bhen oui, et apres, si l'on demande d'ecrire le code, on verra bien qu'il y
aura des define

Quoted text here. Click to load it

si, utiliser une fonction, qui est lourde, au lieu d'utiliser une table
d'indirection, est idiot, ca ne presente aucun interet

Quoted text here. Click to load it


c'est simple, indirection,3 cycles , peut etre moins sur certains micros

inversion de bits, 32 cycles ( a la louche)

quand a faire de l"asm .....



Re: Explication : Lire un octet de l'UART sur AVR en C
Le 29/11/2009 01:53, jj a écrit :
Quoted text here. Click to load it

J'ai lu la norme MIDI puisque je dis justement ça dans mon message
initial ...
Ce que je n'ai pas lu, c'est la norme RS232.


Mais sinon, comment vous expliquez que ça fonctionne  « normalement »
dans le sens de l'émission ?

Re: Explication : Lire un octet de l'UART sur AVR en C
GRENON Loïc a écrit :
Quoted text here. Click to load it

Je n'ai pas d'explication, si ce n'est que cela ne me parait pas normal!

as-tu essayé de lire les octets que tu envoies afin de t'assurer de
cette différence ?

a moins que l'UART dispose d'une fonction d'inversion de sens de
transmission?

sinon, le plus simple à mon avis est d'assurer la logique entre la
couche physique et la couche logique en croisant les mots

une routine du genre :

(je l'ai écrit dans une syntaxe du genre PIC, je ne connais pas l'avr,
ce n'est que pour décrire le principe)

movlw 8
movwf compteur
boucle:
clrc
ror octet_uart
rol octet_lu
defsz compteur
goto boucle

JJ

Site Timeline