04-03-2017 07:43 AM
Hello everyone,
I am trying to use python with nicaiu.dll to do some measurements with myDAQ,
I found a instruction from NI, http://www.ni.com/white-paper/8911/en/, I tried the example calling_daq_dll.py, it works very well with python 2.7, but something wrong with python 3.5,
by adding a channel to the task with the command:
dll = windll.LoadLibrary("nicaiu.dll")
dll.DAQmxCreateAIVoltageChan(taskHandle, physicalChannel, channelName, terminalConfig, minVal, maxVal, units, customScaleName)
it always shows the error: DAQmxErrorInvalidDeviceID, -200220
Does anyone have a idea? Is it a compatible problem with python 3 ?
Thanks.
Zhiwen
Solved! Go to Solution.
04-03-2017 08:37 AM
Instead of writing your own C API Python wrappers, you may want to look at the nidaqmx Python package.
04-03-2017 08:43 AM
Thanks for your replay, with the package it works well, I just wonder, why it doesn't work with original dll calls.
04-03-2017 08:52 AM
Did you update the physicalChannel variable? The example sets it to "dev1/ai0". On most PCI/USB NI DAQ devices the default name is "Devn", but with NI myDAQs the default name is "myDAQn". You'd probably need to change that to "myDAQ1/ai0".
04-03-2017 09:03 AM
Yes, I changed it to "myDAQ1/ai0", but it doesn't work.
The same code works well under python2 (except grammar difference for print).
04-03-2017 09:24 AM
Hmm, I'm not sure then. My python-fu is not strong, and I don't understand why that particular call would have different behavior between python2 and python3. (Perhaps some slight change happened to the way that ctypes marshals parameters?)
04-03-2017 09:34 AM
Anyway, thanks for your replies.
04-04-2017 10:06 AM
05-23-2017 09:05 AM
As you already found out you have to pass the name as a bytes object. Here a little bit more explanation why:
The signature of the function you called is:
int32 __CFUNC DAQmxCreateAIVoltageChan (TaskHandle taskHandle, const char physicalChannel[], const char nameToAssignToChannel[], int32 terminalConfig, float64 minVal, float64 maxVal, int32 units, const char customScaleName[]);
so it expects a `const char *` for the physicalChannel parameter, which in ctypes is represented as a `c_char_p` object.
Between Python 2 and Python 3, the corresponding "native" python type for `c_thar_p` changed:
- In Python 2.7 `c_char_p` was equivalent to the python `string` object which has 8bit characters in Py2.7.
- In Python 3 `c_char_p` is equivalent to the python `bytes` object. The `string` type is equivalent to `c_wchar_p` (note the `w` which means it is a 16bit character pointer).
When you write in python a string `"blablabla"` (without any prefixes) it will have the `string` type by default. So when you wrote the string in Py2.7 it automatically already had the right type (8bit characters). But in Python 3 the default string has 16bit characters, so you either have to explicitly produce a bytes object (by adding the prefix `b` to the string) or you have to convert the `string` to a bytes object (e.g. `myBlaBla.encode()`)
See also the tables for Python 2.7 and Python 3:
https://docs.python.org/2.7/library/ctypes.html#fundamental-data-types
https://docs.python.org/3/library/ctypes.html#fundamental-data-types