From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

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 725 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 702 Visites