使用模拟发现2调试不同的电机控制器

模拟发现debugg 2是一个有用的工具ing projects or designs that use a variety of signal types and can be used with the WaveForms SDK to write automated or custom tests. The following example is a replication of a motor controller tester application used by a customer working in consumer electronics. In this particular application multiple motors were used in a system where their functionality directly impacted the safety of the user, so extensive testing was necessary.

As an example of what was done the following guide presents how to create a C/C++ project for the Analog Discovery 2 using WaveForms SDK and how to use it to debug an H-Bridge DC motor controller and a stepper motor controller, both used in an automatic baby swing design.


Prerequisites

Hardware
Software

笔记:WaveForms can be installed by following theWaveForms Getting Started Guide. By installing WaveForms, WaveForms SDK will be installed, which is needed later in this guide.


Preparation

在e following, an existing Arduino motor controller project will be tested and debugged. The project consists of a brushed DC and a stepper motor, with the proper drivers, two potentiometers and a latching hall-effect sensor, all controlled by an Arduino microcontroller. One potentiometer sets the speed of the DC motor and the other sets the position of the stepper (like in theAccelStepper-比例控制example). The Hall-effect sensor changes the DC motor's direction on every rising/falling edge. The simplified design of the device, the schematic and the Arduino code can be downloaded fromhere.

创建此电动机控制器项目超出了本指南的范围,此处涵盖的测试概念可以用于各种项目。为了尝试此示例,您可以将模拟发现2连接到任何简单的电机驾驶应用程序,或者使用下面讨论的代码段进行一些修改调试您自己的项目。


Hardware Setup

在e project we want to debug as an example, an H-Bridge DC motor driver and a stepper driver are controlled by an Arduino UNO, according to the input of two potentiometers. One potentiometer sets the speed of the DC motor, while the other sets the position of the stepper. A Hall-effect sensor sends an interrupt signal to the MCU after every half-turn of the DC motor, and the direction of rotation is changed.

In order to test the system first the potentiometer values should be measured, then both motors should be tested by sending digital control signals to the drivers, while the MCU is disabled, then, after enabling the MCU again, it's output signals should be recorded.

为了读取电位计上的电压,将使用两个模拟输入通道。为了控制电动机驱动程序并读取MCU输出信号,将使用数字I/O线。右图的图像显示了如何将所有这些连接起来的示例。

笔记:任何数字I/O线都可以连接到MCU/驱动程序的任何引脚,只需记下连接,因为必须在代码后面定义它们。

笔记:接线图仅显示模拟发现2与其他设备之间的连接。


Creating the Project

When the C/C++ project is created, copy thedwf.libfile from the WaveForms installation library,WaveFormsSDK\lib\x86subfolder and thedwf.hfile from the WaveForms installation library,WaveFormsSDK\incsubfolder to your project directory. Include thedwf.hheader file in your source file, and link thedwf.liblibrary into the project. Following this, you can use the functions from the WaveForms SDK.


控制不同仪器的功能

在e following, the functions used for controlling the instruments in this example are discussed. For details about other available functions in the WaveForms SDK, check theWaveForms SDK Reference Manual.

Connecting and Disconnecting the Analog Discovery 2

To be able to use the Analog Discovery 2, it must be connected. To safely connect the device, the program should check if there is an Analog Discovery 2 connected to the PC. If yes, it also should check, whether there are any devices, which are available (unused by other programs). If an available device is detected, it should be opened, so its device handle (hdwf) can be passed to the other functions.

//initialization function for AD2boolinit_AD2(HDWF*HDWF,char*error){// detect if AD2 is connected or notintnr_of_connected_dev;FDwfEnum(devidDiscovery2,&nr_of_connected_dev);如果(nr_of_connected_dev==0){strcpy(错误,“错误:模拟发现2未连接”);error[strlen(“错误:模拟发现2未连接”)]=0;返回false;}// detect if AD2 is used by other program or not (select the unused one if there are more devices)intUNUSED_DEV_INDEX=-1;for(inti=0;i<nr_of_connected_dev;i++){intdevice_is_used;FDwfEnumDeviceIsOpened(i,&device_is_used);如果(!device_is_used){UNUSED_DEV_INDEX=i;//save free device index休息;}}如果(UNUSED_DEV_INDEX==-1){strcpy(错误,"Error: all connected Analog Discovery 2s are in use");error[strlen("Error: all connected Analog Discovery 2s are in use")]=0;返回false;}// connect to the unused AD2如果(!FDwfDeviceOpen(Unused_dev_index,hdwf)){strcpy(错误,"Error: can't connect to Analog Discovery 2");error[strlen("Error: can't connect to Analog Discovery 2")]=0;返回false;}返回真的;}

When the program finishes using the Analog Discovery 2, it must disconnect it, not to prevent other software from using it. Before disconnecting, all used instruments should be reset to their default state with the respective重置function.

//重置每个二手仪器和关闭设备空白close_AD2(HDWF*hdwf){fdwfdigitalioreset(*hdwf);//重置数字I/OFDWFANALOGINRESET(*hdwf);//reset analog inFDwfDigitalOutReset(*hdwf);//reset digital outfdwfdigitalinreset(*hdwf);//重置数字FDwfDeviceClose(*hdwf);//close device返回;}
Static I/O

To control the state of the Analog Discovery 2's digital I/O pins, thefdwfdigitalio功能将被使用。The function should be similar to thedigitalWrite()function on Arduino: it receives the number of the pin and a logic state, and sets the received state on the given digital I/O line.

The first step is, to get the pins, which are set as output, and the states set on these pins. The function should not modify the state of the other pins, only the given one. In the next step, a mask is applied to the variable containing the pins used as a digital output, as well as on the variable containing the states of the output pins. The new values are sent back to the Analog Discovery 2.

//write a value on a specific digital i/o pin空白digital_write(HDWF*HDWF,int别针,intvalue){// get current state未签名intprevious_mask, previous_value;fdwfdigitalioOutputEnableGet(*HDWF,&previous_mask);//get current pin setupfdwfdigitalioInputStatus(*HDWF,&以前的_value);//获取当前的PIN状态/ /设置新的面具未签名intpower=1;//power = 2^pinfor(inti=0;i<别针;i++){power*=2;}previous_mask|=power;//set new state如果(value!=0){以前的_value|=power;}else{以前的_value&=~power;}//output new valuesfdwfdigitaliooutputenableset(*HDWF,previous_mask);//set pin setupfdwfdigitalioOutputSet(*HDWF,以前的_value);//set pin state返回;}
Voltmeter

To read voltages with the Analog Discovery 2, theFDwfAnalogIn功能将被使用。The function should be similar to theanalogRead()function on Arduino, with some modifications: the function receives the used oscilloscope channel and, optionally, the number of samples to average.

Firstly, the channel, the range, and the offset are set, then triggering is disabled, then samples are acquired and averaged, if necessary.

//在给定的模拟通道上读取电压floatanalog_read(HDWF*HDWF,intchannel,intaverage){//配置示波器channel-   -;//channels start from 0FDwfAnalogInChannelEnableSet(*HDWF,channel,真的);//启用频道fdwfanaloginchannelrangeset(*HDWF,channel,-6);// -6至6伏的射程fdwfanaloginchanneloffsetet(*HDWF,channel,0);//offset is 0VFDWFANALOGINCONFIGURE(*HDWF,false,false);//没有自动触发器等待(2000);//wait 2 seconds//平均样本floatsum=0;for(inti=0;i<average;i++){FDwfAnalogInStatus(*HDWF,false,无效的);//wait for acquisitiondoubletemporal_voltage;FDwfAnalogInStatusSample(*HDWF,channel,&temporal_voltage);//sample acquisitionsum+=temporal_voltage;等待(100);}sum/=average;//calculate average返回sum;}
逻辑分析仪

To acquire digital data with the Analog Discovery 2, thefdwfdigitalin功能将被使用。该函数应能够在矩阵中保存定义的样本数,每个列代表数字输入线。如果是这种情况,该功能还应该能够发出数据的损失或损坏。

As a start, the Static I/O, the Logic Analyzer, and the Pattern Generator instruments should be reset to their default state. Following this, the acquisition sample rate and the output data format should be set. When using Analog Discovery 2, the recommended data format is 16 bits per word, as the device has 16 digital I/O lines.

The acquisition should be triggered by a rising or falling edge on any pin, but it also should have a timeout, to record cases when there are no changes in the signal (can be useful when debugging).

启动仪器后,将数据连续记录在缓冲区中。在循环中,如果有任何损坏或丢失的数据单词,则将此缓冲区连续保存到输出数组中,同时还将其检查。如果达到所需的样品计数,则将退出循环。

Finally, the recorded data is formatted and the possible errors retuned.

//record digital signalsintdigital_read(HDWF*HDWF,bool**Digital_data,未签名int*buffer_size){//重置数字strumentsfdwfdigitalioreset(*hdwf);//重置数字I/OFDwfDigitalOutReset(*hdwf);//reset digital outfdwfdigitalinreset(*hdwf);//重置数字//create array for results未签名short*unformatted_data=(未签名short*)malloc(*buffer_size*sizeof(未签名short));//set up the instrumentfdwfdigitalinAcquisitionModeSet(*HDWF,acqmodeRecord);//record modedoubleinternal_frequency;fdwfdigitalinInternalClockInfo(*HDWF,&internal_frequency);//get clock speedfdwfdigitalinDividerSet(*HDWF,internal_frequency/100000);//sample rate: 100kHzfdwfdigitalinSampleFormatSet(*HDWF,16);// 16位的数据格式//设置扳机fdwfdigitalinTriggerPositionSet(*HDWF,*buffer_size);//nr of aquisitions after the instrument is triggeredfdwfdigitalinTriggerSourceSet(*HDWF,trigsrcDetectorDigitalIn);//trigger source: digital inputsFDWFDigitalIntriggerAutotimeOutSet(*HDWF,10.0);//触发超时:10sfdwfdigitalinTriggerSet(*HDWF,0,0,0xFFFF,0xFFFF);//triggered if any pin changes (rising/falling edge)//start the aquisitionfdwfdigitalinConfigure(*HDWF,false,真的);//wait for trigger/auto aquisitionintcurrent_sample_count=0, current_available_sample_count, current_lost_sample_count, current_corrupt_sample_count;boolLost_flag=false,rustal_flag=false;Sts Sts;尽管(current_sample_count<*buffer_size){fdwfdigitalinstatus(*HDWF,1,&sts);//检查仪器状态//skip this iteration, if recording hasn't started yet如果(current_sample_count==0&&(sts==DwfStateConfig||sts==DwfStatePrefill||sts==dwfstatearmed)){continue;}//检查缓冲区状态fdwfdigitalinstatusRecord(*HDWF,&current_available_sample_count,&current_lost_sample_count,&current_corrupt_sample_count);//count lost samplescurrent_sample_count+=current_lost_sample_count;//check FIFO overflow如果(current_lost_sample_count!=0){Lost_flag=真的;}如果(current_corrupt_sample_count!=0){corrupt_flag=真的;}//check data availability如果(current_available_sample_count==0){continue;//如果没有可用数据,请跳过此迭代}//如果有更多数据可用,则缓冲区大小,请限制如果(current_sample_count+current_available_sample_count>*buffer_size){current_available_sample_count=*buffer_size-current_sample_count;}//获取样品fdwfdigitalinstatusData(*HDWF,&unformatted_data[current_sample_count],2*current_available_sample_count);//count saved samplescurrent_sample_count+=current_available_sample_count;}//stop the aquisitionfdwfdigitalinConfigure(*HDWF,false,false);//format datafor(inti=0;i<*buffer_size;i++){digital_data[0][i]=unformatted_data[i]&0x0001;digital_data[1][i]=unformatted_data[i]&0x0002;digital_data[2][i]=unformatted_data[i]&0x0004;digital_data[3][i]=unformatted_data[i]&0x0008;digital_data[4][i]=unformatted_data[i]&0x0010;digital_data[5][i]=unformatted_data[i]&0x0020;digital_data[6][i]=unformatted_data[i]&0x0040;digital_data[7][i]=unformatted_data[i]&0x0080;digital_data[8][i]=unformatted_data[i]&0x0100;digital_data[9][i]=unformatted_data[i]&0x0200;digital_data[10][i]=unformatted_data[i]&0x0400;digital_data[11][i]=unformatted_data[i]&0x0800;digital_data[12][i]=unformatted_data[i]&0x1000;digital_data[13][i]=unformatted_data[i]&0x2000;digital_data[14][i]=unformatted_data[i]&0x4000;digital_data[15][i]=unformatted_data[i]&0x8000;}//信号错误如果(Lost_flag){返回1;}如果(corrupt_flag){返回2;}返回0;}
模式生成器

To generate a PWM signal with a given duty cycle, theFDwfDigitalOut功能将被使用。First, the frequency of the pattern generator on the selected digital I/O line should be enabled, then the signal frequency should be set. The duty cycle is given as high time and low time.

以下代码片段在数字I/O线CH上初始化一个PWM信号,并逐渐将其占空比从0%增加到100%,每50ms后增加1%,然后停止信号。

//set up the pwm signalFDwfDigitalOutEnableSet(*HDWF,CH,真的);//enable channelFDwfDigitalOutTypeSet(*HDWF,CH,0);//set type to previous_valuedoubleinternal_clock_frequency;FDwfDigitalOutInternalClockInfo(*HDWF,&internal_clock_frequency);//get clock frequency未签名intrange_min,range_max;FDwfDigitalOutCounterInfo(*HDWF,CH,&range_min,&range_max);//get counter rangeintfrequency=1000;//1KHz pwm frequency未签名intdivider=Ceil(internal_clock_frequency/frequency/range_max);FDwfDigitalOutDividerSet(*HDWF,CH,Divider);//设置PWM频率未签名int脉冲=round(internal_clock_frequency/frequency/divider);//varying the speed of the motorfor(inti=0;i<100;i++){未签名int最大限度=脉冲*i/100;未签名intmin=脉冲-最大限度;FDwfDigitalOutCounterSet(*HDWF,CH, min, max);//set duty cyclefdwfdigitaloutconfigure(*HDWF,真的);//start the instrument等待(50);}//stop the motorFDwfDigitalOutEnableSet(*HDWF,CH,false);

The Complete Program

The complete source code can be downloaded from here:ad2_motor_debugger_v2.zip. It contains the dwf.h header file, the dwf.lib library, the AD2_motor_debugger.h header, which contains the functions for different operations, the main.cpp source file, which is a wrapper, defines the structure of the project and two scripts, one in Python and one in MATLAB, for displaying the recorded data.

在项目开始时,应定义连接。通过在代码开头定义这些,如果调试器的接线到MCU或向电动机驱动程序进行更改,则更容易修改它们。电机驱动程序的默认状态启用引脚和使用的库也在此处定义。

//define connections//数字I/O#define MCU_RESET 0#define DC_AIN1 1#define DC_AIN2 2#define DC_STBY 3#define DC_PWMA 4#define step_en 5#define STEP_MS1 6#define STEP_MS2 7#define STEP_DIR 8#define STEP_STEP 9#define HALL 10//类似物#define POT_SPEED 1#define POT_POS 2//define defaults#define DC_ON HIGH //state of the stby pin when the motor is on#define step_on低//步进时的EN PIN状态//define constants#定义TEST_ANALOG_INPUT_AVERAGE 10 / /我多少asurements should be averaged#define TEST_STEPS 1024 //how many steps to do with the stepper motor#define OUTPUT_CSV_HEADERS false //save headers to the output csv file or not/*-------------------------------------------------------------------------*///include headers needed for input/output#include #include #include #include //include the DWF header and the custom header for this project#include“ dwf.h”#include“ ad2_motor_debugger.h”

在e main function, the first step is to connect the Analog Discovery 2. If it can't be connected, the program must be finished, as the rest of the functions can't be called. The function init_AD2() is discussed under the控制不同仪器的功能heading, in the Connecting and Disconnecting the Analog Discovery 2 drop-down.

//main functionint主要的(intargc,char**argv){HDWF HDWF;//variable for instrument handlecharerror[512];//variable for error messages// initialize the Analog Discovery 2如果(!init_AD2(&HDWF,error)){printf("%s\nPress any key to exit...", error);_getch();返回0;}printf("Analog Discovery 2 is connected\n");等待(2000);//wait 2 seconds

To test the motor drivers, the microcontroller must be turned off by setting it's RESET pin to low. After that, the voltages on the potentiometers can be read, and the digital_write() and PWM generation functions can be used to test both motors with varying speeds, in both directions. Details about the used functions can be found under the控制不同仪器的功能heading, in the Voltmeter, Static I/O and Pattern Generator drop-downs.

//main functionprintf("\nReading controls and testing motors:\n");// turn the microcontroller off to read/test peripheralsprintf("\tThe MCU is turned off\n");digital_write(&HDWF,MCU_RESET, LOW);//读voltages on potentiometersprintf("\tMeasuring voltages on potentiometers:\n");floatvoltage_speed=analog_read(&hdwf,pot_speed,test_analog_input_average);printf("\t\tVoltage on the potentiometer controlling the speed: %2.2fV\n",voltage_speed);float电压_position=analog_read(&HDWF,POT_POS, TEST_ANALOG_INPUT_AVERAGE);printf("\t\tVoltage on the potentiometer controlling the position: %2.2fV\n",电压_position);//testing the DC motorprintf("\t测试直流电动机\n\t\tClockwise direction...\n");drive_DC(&HDWF,DC_AIN1, DC_AIN2, DC_STBY, DC_ON, DC_PWMA,1);printf("\t\tCounter-clockwise direction...\n");drive_DC(&HDWF,DC_AIN1, DC_AIN2, DC_STBY, DC_ON, DC_PWMA,0);//testing the stepperprintf("\tTesting the stepper motor\n\t\tClockwise direction...\n");drive_STEP(&HDWF,STEP_MS1, STEP_MS2, STEP_EN, STEP_ON, STEP_DIR, STEP_STEP,1, TEST_STEPS);printf("\t\tCounter-clockwise direction...\n");drive_STEP(&HDWF,STEP_MS1, STEP_MS2, STEP_EN, STEP_ON, STEP_DIR, STEP_STEP,0, TEST_STEPS);

要记录来自MCU的信号,必须通过将重置PIN设置为逻辑高。此后,必须指定要记录的样本数(data_size),并且必须在记录数据之前创建具有适当大小(Digital_data)的矩阵。收购后,应检查数据丢失/损坏,然后将记录保存在文件中。有关digital_read()函数的详细信息可以在控制不同仪器的功能heading, in the Logic Analyzer drop-down.

printf("\nReading the output signals of the MCU:\n");//打开微控制器以读取/测试其信号printf("\tMCU已打开\n");digital_write(&HDWF,MCU_RESET, HIGH);//记录来自MCU和Hall效果传感器的所有信号printf("\t录制数字信号\n");//allocate space for the data未签名intdata_size=1000000;//specify the number of samplesbool**digital_data;//buffer for datadigital_data=(bool**)malloc(16*sizeof(bool*));for(inti=0;i<16;i++){digital_data[i]=(bool*)malloc(data_size*sizeof(bool));}intread_state=digital_read(&HDWF,Digital_data,&data_size);//读//检查数据丢失/损坏如果(read_state==1){printf("\t\tData was lost due to FIFO overflow\n");}如果(read_state==2){printf("\t\t数据由于FIFO溢出而损坏\n");}//save data in a file如果(!save_data(Digital_data,data_size, error, OUTPUT_CSV_HEADERS)){printf("%s\nPress any key to exit...", error);_getch();返回0;}printf("\tThe recorded data was saved\n");

When the program is finished, the Analog Discovery 2 must be closed, to make it available to other software. Details about the close_AD2() function can be found under the控制不同仪器的功能heading, in the Connecting and Disconnecting the Analog Discovery 2 drop-down.

// close opened deviceprintf("\nClosing the connected device");close_AD2(&hdwf);返回0;

The results of the test are displayed in the console window along with messages about the current operation.

Data Visualization - Optional

Data exported in a file can be visualized by running the plotting.m MATLAB script or the plotting.py Python program, or you can write your own program to plot the data.


最后笔记

For more guides and example projects for your Analog Discovery 2, please visit itsResource Center.

For more information about how to use WaveForms SDK, please visit theWaveForms SDK Reference Manual.

For technical support, please visit theDigilent Forums.