0

Je dois lire la valeur d'entrée d'une source externe qui est une balance utilisant le processeur STM32F107. Cette balance est externe à la carte qui contient le processeur et communique avec elle via PA4.comment réparer les oscillations de l'entrée analogique lues par STM32F107

Voici ma première tentative de lecture de l'entrée de la balance.

J'utilise cette fonction pour configurer l'ADC:

void ADC_Configuration(void) { 

    ADC_InitTypeDef ADC_InitStructure; 
    /* PCLK2 is the APB2 clock */ 
    /* ADCCLK = PCLK2/6 = 72/6 = 12MHz*/ 
    RCC_ADCCLKConfig(RCC_PCLK2_Div6); 
    /* Enable ADC1 clock so that we can talk to it */ 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 
    /* Put everything back to power-on defaults */ 
    ADC_DeInit(ADC1); 

    /* ADC1 Configuration ------------------------------------------------------*/ 
    /* ADC1 and ADC2 operate independently */ 
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 
    /* Disable the scan conversion so we do one at a time */ 
    ADC_InitStructure.ADC_ScanConvMode = DISABLE; 
    /* Don't do contimuous conversions - do them on demand */ 
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; 
    /* Start conversin by software, not an external trigger */ 
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 
    /* Conversions are 12 bit - put them in the lower 12 bits of the result */ 
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 
    /* Say how many channels would be used by the sequencer */ 
    ADC_InitStructure.ADC_NbrOfChannel = 1; 

    /* Now do the setup */ 
    ADC_Init(ADC1, &ADC_InitStructure); 
    /* Enable ADC1 */ 
    ADC_Cmd(ADC1, ENABLE); 
    /* Enable ADC1 reset calibaration register */ 
    ADC_ResetCalibration(ADC1); 
    /* Check the end of ADC1 reset calibration register */ 
    while(ADC_GetResetCalibrationStatus(ADC1)); 
    /* Start ADC1 calibaration */ 
    ADC_StartCalibration(ADC1); 
    /* Check the end of ADC1 calibration */ 
    while(ADC_GetCalibrationStatus(ADC1)); 
} 

J'utilise cette fonction pour obtenir l'entrée:

u16 readADC1(u8 channel) { 

    ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_1Cycles5); 

    // Start the conversion 
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); 
    // Wait until conversion completion 
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); 
    // Get the conversion value 

    return ADC_GetConversionValue(ADC1); 
} 

Le problème est que dans les mesures N du même poids, je obtenir N résultats différents. Par exemple, le poids est de 70kg et la sortie du readADC1 (ADC_Channel_4) est 715,760,748,711,759 etc.

Qu'est-ce que je fais mal?

Modifier. J'ai ajouté cette fonction (qui simule un filtre lp) pour stabiliser l'entrée et cela fonctionne bien. Le problème est de savoir comment convertir la valeur renvoyée par cette fonction en kilogrammes. L'utilisation d'un coefficient de coût (déterminé en mesurant un objet connu) donne une erreur de croissance proportionnelle au poids croissant de l'intrant. Tout suggère d'avoir une meilleure conversion?

double fix_oscillations(){ 
    int i; 
    double LPOUT=0,LPACC=0; 
    int K = 5000; 

    for(i=0;i<5000;i++){ 
     LPACC = LPACC + readADC1(ADC_Channel_4) - LPOUT; 
     LPOUT = LPACC/K; 
    } 
    return LPOUT; 
} 
+0

Il est temps d'ajouter du moyennage/filtrage ... –

+0

Si vous voulez que les gens lisent votre code, une convention de retrait commune et cohérente et un peu d'espace vertical seraient utiles. – Clifford

Répondre

2

Il est possible que l'entrée soit intrinsèquement bruyante ou que du bruit soit introduit par un autre équipement. Il est intéressant d'observer le signal avec un oscilloscope pour déterminer le type d'interférence ou de bruit sur le signal, car cela peut affecter la meilleure solution.

Si possible, vous devez éliminer toute source d'interférence externe, puis un signal analogique externe doit être appliqué, idéalement par un filtre passe-bas avec une fréquence de coupure égale ou inférieure à la moitié de la fréquence d'échantillonnage prévue. Vous êtes alors en mesure d'appliquer le filtrage dans le domaine numérique si nécessaire. Pour les signaux statiques (niveaux de tension), une moyenne de bloc simple suffira, pour des signaux de déplacement plus rapides, une moyenne mobile (filtre boxcar) serait meilleure. Pour les signaux complexes dont vous avez besoin d'extraire certaines fréquences, des filtres plus complexes sont nécessaires, mais ce n'est probablement pas le cas dans ce cas.

+0

J'ai ajouté de nouvelles informations à la question. Pouvez-vous jeter un coup d'oeil? Merci pour votre aide. –

+1

AKA 'mettre un plus grand condensateur à travers l'entrée' :) –

1

Modifier. J'ai ajouté cette fonction (qui simule un filtre lp) pour stabiliser l'entrée et cela fonctionne bien. Le problème est de savoir comment convertir la valeur renvoyée par cette fonction en kilogrammes. L'utilisation d'un coefficient de coût (déterminé en mesurant un objet connu) donne une erreur de croissance proportionnelle au poids croissant de l'intrant. Tout suggère d'avoir une meilleure conversion?

Cela valait probablement la peine de poster une question distincte car elle n'est pas clairement liée au titre de la question. Si votre sortie est non linéaire, vous pouvez utiliser plusieurs points d'étalonnage avec interpolation linéaire entre les points, mais il est probable que la courbe puisse être caractérisée par une équation. Prendre un certain nombre de mesures sur la gamme d'intérêt, puis tracer ces points dans un outil de feuille de calcul comme Excel ou OpenOffice.org Calc. Les outils de cartographie comprennent un tracé de «ligne de tendance» de divers types, et peuvent afficher l'équation de la courbe. Sélectionnez le type de courbe le plus simple avec un ajustement adéquat. Si vous avez besoin d'un polynôme avec plus de deux termes, assurez-vous d'afficher les termes d'équation avec des décimales suffisantes, car ceux-ci peuvent être critiques. Vous pouvez tester pour voir si vous avez assez de précision en utilisant l'équation pour générer une courbe et voir à quel point il répond à la ligne de tendance.Tracer l'équation est probablement une bonne idée pour n'importe quelle courbe comme test pour une précision suffisante. Lorsque vous écrivez le code, assurez-vous d'utiliser un type de données avec une précision suffisante.

Une note sur la ligne:

LPOUT = LPACC/K; 

en prenant vous effectivement augmenté de 5000 échantillons votre résolution ADC d'environ 12 bits (au détriment du temps de l'échantillon), mais en divisant par K, vous avez perdu cette précision inutile, et c'est aussi une division tronquée. Il vaudrait mieux utiliser la somme indivise directement dans la conversion en Kg. Je réalise que diviser fait apparaître la valeur "stable" mais c'est sur le rapport signal/bruit que sur l'amplitude du bruit absolu. La conversion en Kg et l'affichage à la précision requise dans le monde réel auront le même effet de "stabilisation" du résultat mais avec une erreur cumulative plus faible.

+0

Mais si je ne divise pas par K, je ne peux pas éliminer l'erreur. En ne considérant que la somme des moyens, continuez l'erreur. Droite? –

+0

@BoonTobias: Non. Comme je l'ai dit, il s'agit du rapport S/N. Dites que la valeur réelle était 4.5 mais vous avez des échantillons entiers 4,5,3,6, la somme est 18 - erreur zéro (4,5 * 4 = 18), si vous divisez-entier par 4 le résultat est 4 pas 4,5, alors maintenant votre erreur est de 0.5. Les unités ADC sont arbitraires et ne sont pas liées à la valeur réelle du monde. En prenant par exemple un ADC 8 bits avec une plage de 0 à 255, et en additionnant 4 échantillons, la plage est maintenant comprise entre 0 et 1023 - en réalité un ADC 12 bits avec un meilleur rapport S/B. Convertissez directement cette valeur de résolution supérieure en unités réelles. – Clifford

+0

Ma division est entre un double LPOUT et un entier K. Donc je suppose que je ne perds pas la précision. –

1

Avez-vous vu les notes de l'application STM32 pour améliorer la précision de l'ADC? Il existe également une note d'application pour augmenter la résolution, ainsi que quelques autres.

Vous devriez jeter un coup d'œil à ce lien here. Effectuez une recherche de page dans la zone de défilement pour "ADC".

Les notes d'application de STMicro sont souvent utiles, car ils préfèrent sortir leurs produits plus tôt que tard, puis ajouter la documentation/support après-mots.

0

Vous trouverez peut-être cette façon utile de la moyenne:

float FilteredValue; 
#define TIME_CONSTANT 100 
FilteredValue += ((float)ADCreading - FilteredValue)/TIME_CONSTANT; 

Cela représente un vrai filtre passe-bas avec une constante de temps de TIME_CONSTANT x fréquence d'échantillonnage. S'il y a un changement d'étape dans ADCreading, FilteredValue changera progressivement à la nouvelle valeur. En théorie, il ne l'atteindra jamais, puisqu'il implémente un filtre exponentiel inverse. Plus la valeur de TIME_CONSTANT est grande, meilleure est la réjection du bruit, mais plus il faudra de temps pour se stabiliser.