Discussions au sujet des autres produits NI

annuler
Affichage des résultats de 
Rechercher plutôt 
Vouliez-vous dire : 

synchroniser 2 tâches analogiques en C

Bonjour,

Je cherche à configurer des cartes NI et à les utiliser en C ; j'ai besoin de les synchroniser ; ça semble facile mais je patauge un peu...

Ma configuration :
- un chassis cDAQ-9178
- une carte NI 9265 (Analog Output Current) avec une sortie utilisée : je dois appliquer un courant
- une carte NI 9220 (Analog Input Voltage) avec deux entrées utilisées : une qui me donne un "trigger" et l'autre sur laquelle je dois lire une tension

Le Courant appliqué a une influence sur le Voltage lu, et c'est ça que je cherche à mesurer.
Je veux donc utiliser une horloge commune aux deux cartes pour appliquer le Courant (front montant) puis lire la Tension (front descendant). Toutes les secondes, j'ai un "top départ" : je dois lire 800 échantillons toutes les miliseconde.

Je veux donc :
- attendre le Trigger
- 800 fois (800 ms)
    - appliquer une valeur de Output Current
    - lire la tension conséquente
- récupérer les données
- attendre le TOP suivant (environ 200 ms plus tard) et recommencer


Je n'arrive pas à gérer l'horloge commune et le Trigger.
Pourriez-vous regarder mon code -et les commentaires qui posent des questions- et me donner un coup de main ?
Merci ++ !

 

TaskHandle  taskOutput = 0;
TaskHandle  taskInput = 0;
char    trigName[256];
char timebaseSrc[256];
char        errBuff[2048] = { '\0' };

float64     waveform[800];
for (int i = 0; i < 800; i++) waveform[i] = 0.01 * i / 800;

/*********************************************/
// Sortie : on prépare l'envoi du Courant
/*********************************************/
DAQmxErrChk(DAQmxCreateTask("Courant sortie", &taskOutput));
DAQmxErrChk(DAQmxCreateAOCurrentChan(taskOutput, "/cDAQ1Mod2/ao1", "Intensite", 0.0, 0.02, DAQmx_Val_Amps, NULL));
DAQmxErrChk(DAQmxCfgSampClkTiming(taskOutput, "", 1000., DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, 800));

// la fonction suivante pose problème. Je veux dire "il y aura des triggers successifs". Est-ce nécessaire ?
//	DAQmxErrChk(DAQmxSetStartTrigRetriggerable(taskOutput, 1));

DAQmxErrChk(DAQmxWriteAnalogF64(taskOutput, 800, 0, 10.0, DAQmx_Val_GroupByChannel, waveform, NULL, NULL));

/*********************************************/
// Entrée : deux canaux
/*********************************************/
DAQmxErrChk(DAQmxCreateTask("Tensions en entrée", &taskInput));
DAQmxErrChk(DAQmxCreateAIVoltageChan(taskInput, "/cDAQ1Mod1/ai0", "Tension_à_lire", DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL));

// les deux lignes suivantes pourraient définir la Tension qui va me servir de Trigger. Quelle ligne utiliser ? Et ça ne marche pas...
// j'ai essayé, pendant un temps, de faire cette lecture de trigger dans une Task différente, mais ça n'a pas mieux fonctionné.
//	DAQmxErrChk(DAQmxCreateAIVoltageChan(taskInput, "/cDAQ1Mod1/ai1", "Tension_TRIGGER", DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL));
DAQmxErrChk(DAQmxCfgDigEdgeStartTrig(taskInput, "/cDAQ1Mod1/ai1", DAQmx_Val_Rising));

// la fonction suivante pose problème. Je veux dire "il y aura des triggers successifs". Est-ce nécessaire ?
//	DAQmxErrChk(DAQmxSetStartTrigRetriggerable(taskInput, 1));


DAQmxErrChk(DAQmxCfgSampClkTiming(taskInput, "", 1.0 * 1000, DAQmx_Val_Falling, DAQmx_Val_FiniteSamps, 800));


/*********************************************/
// TRIGGER pour lancer le top départ : j'essaye de le récupérer d'une carte pour l'appliquer à l'autre.
/*********************************************/

DAQmxErrChk(GetTerminalNameWithDevPrefix(taskInput, "ai/StartTrigger", trigName));

// cette ligne est censée aligner les Triggers des cartes pour déclancher au même moment les écritures et lectures
DAQmxErrChk(DAQmxCfgDigEdgeStartTrig(taskOutput, "cDAQ1/ai/StartTrigger", DAQmx_Val_Rising));
	
// je cherche ici à répliquer l'horlge de Input sur Output. Est-ce nécessaire ? Ca ne marche pas...
DAQmxErrChk(DAQmxSetSampClkTimebaseSrc(taskOutput, "cDAQ1/ai/SampleClockTimebase"));

	
// J'ai aussi essayé de jouer avec l'export de signal. Sans succès.
//DAQmxErrChk(DAQmxExportSignal(taskInput, DAQmx_Val_StartTrigger, "ao/StartTrigger"));


// récupérer les données est facile. Je ne la détaille pas.
DAQmxErrChk(DAQmxRegisterEveryNSamplesEvent(taskInput, DAQmx_Val_Acquired_Into_Buffer, 800, 0, EveryFiniteCallback, NULL));
DAQmxErrChk(DAQmxRegisterDoneEvent(taskOutput, 0, DoneCallback, NULL));

 

 

0 Compliments
Message 1 sur 2
2 850 Visites

La nuit porte conseil ; la lecture de documentations "autour" du sujet aussi... Je me réponds (si ça peut être utile à quelqu'un...)

En gros, si j'ai bien compris, les triggers et les horloges peuvent être pris sur le chassis, auquel cas ils sont communs aux cartes !

TaskHandle  taskOutput = 0;
TaskHandle  taskInput = 0;

float64     waveform[800];
for (int i = 0; i < 800; i++) waveform[i] = 0.01 * i / 800;

/*********************************************/
// Sortie : on prépare l'envoi du Courant
/*********************************************/
DAQmxErrChk(DAQmxCreateTask("Courant sortie", &taskOutput));
DAQmxErrChk(DAQmxCreateAOCurrentChan(taskOutput, "/cDAQ1Mod2/ao1", "Intensite", 0.0, 0.02, DAQmx_Val_Amps, NULL));

///// Ici, on met une horloge à 80 MHz du chassis
DAQmxErrChk(DAQmxCfgSampClkTiming(taskOutput, "/cDAQ1/80MhzTimebase", 1000., DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, 800));


DAQmxErrChk(DAQmxWriteAnalogF64(taskOutput, 800, 0, 10.0, DAQmx_Val_GroupByChannel, waveform, NULL, NULL));

/*********************************************/
// Entrée : un seul canal
/*********************************************/
DAQmxErrChk(DAQmxCreateTask("Tensions en entrée", &taskInput));
DAQmxErrChk(DAQmxCreateAIVoltageChan(taskInput, "/cDAQ1Mod1/ai0", "Tension_à_lire", DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL));

///// Même horloge que précédemment
DAQmxErrChk(DAQmxCfgSampClkTiming(taskInput, "/cDAQ1/80MhzTimebase", 1.0 * 1000, DAQmx_Val_Falling, DAQmx_Val_FiniteSamps, 800));

/*********************************************/
// TRIGGER pour lancer le top départ : le prendre sur le chassis
/*********************************************/
DAQmxErrChk(DAQmxCfgDigEdgeStartTrig(taskOutput, "/cDAQ1/PFI0", DAQmx_Val_Rising));
DAQmxErrChk(DAQmxCfgDigEdgeStartTrig(taskInput, "/cDAQ1/PFI0", DAQmx_Val_Rising));


// récupérer les données est facile. Je ne la détaille pas.
DAQmxErrChk(DAQmxRegisterEveryNSamplesEvent(taskInput, DAQmx_Val_Acquired_Into_Buffer, 800, 0, EveryFiniteCallback, NULL));
DAQmxErrChk(DAQmxRegisterDoneEvent(taskOutput, 0, DoneCallback, NULL));

 

0 Compliments
Message 2 sur 2
2 827 Visites