本帖最后由 1223657347 于 2017-11-25 13:46 编辑
2.1固件
固件核心结构如下图
固件设计难点和要点主要有以下几个方面: (1)USB枚举和通信。USB设备在接入主机时,主机通过总线枚举(Bus Enumeration)获取设备描述、设备配置。USB端点(Endpoint)是USB通信的管道,有输入事务(IN Transaction)和输出事务(OUT Transaction)。数据采集设备就通过IN端点向主机传输数据。 (2)定时采样和存储。输入采样是数据采集设备的基本功能,定时采样的间隔即为采样率。采样结果需要缓冲暂存,再通过USB集中发送。 (3)采样控制。数据采集设备的开始、停止采样需要可控,同时可设定的采样率也是必须的。 USB枚举和通信是固件最难的部分,但ST公司提供的STM32Cube USB库可以使这部分的设计变得非常容易。用户只需要对设备描述符(Device Descriptor)、配置描述符(Configuration Descriptor)和接口描述符(Interface Descriptor)修改,USB枚举过程完全由HAL库和STM32CubeUSB库完成。由于数据采集设备不是标准USB设备,因此设备描述符中设备类字段为自定义USB设备;接口描述符中向USB主机报告了所使用的端点及端点配置,本数据采集设备使用批量(Bulk)端点传输数据。 模拟/数字输入定时采样和存储需要STM32的多个外设进行配合,包含了ADC,定时器、DMA(Direct Memory Access,直接内存存取)。定时器溢出事件触发ADC转换,ADC转换完成的结果由DMA进行搬运,该流程中不消耗CPU资源,减弱对CPU搬运数据的依赖。4K点的环形缓冲区使用了片上SRAM(实际占用64Kb),通过修改DMA目标地址(写指针),可以依次放置ADC序列采样结果到缓冲区去。在读指针和写指针的指示下,USB端点读取缓冲区数据不会发生阻塞和覆盖。 数据采集设备的控制采用多级指令的方式,将端点2传输数据解码/编码后得到指令包,指令包分为命令包和响应包。命令包又细分为控制类、改写类、读取类,响应包细分为无数据响应和有数据响应。为了优化采样启动和停止速度,相应的命令包取消了响应机制。USB主机在启动采样之后,还需要对缓冲区进行预读,防止非法的指针访问和批量输入事务阻塞。 下面展示并说明部分核心固件代码:
- static uint8_t DAQ_Itf_DataRxCallBack(uint8_t* pbuff, uint16_t length)
- {
-
- USBD_DAQ_HandleTypedef *hdaq = (USBD_DAQ_HandleTypedef*)hdaq_temp->pClassData;
-
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
-
- /* Recall Functions Here */
- if(daq_cfg.SampleIsEN == DAQ_SAMPLE_ON)
- {
- if(daq_cfg.Mode == DAQ_MODE_CONTI)
- {
- //Out Pack Write Pointer Manage
- hdaq_io.Out_wPointer += length / DAQ_DATA_OUT_PACK_SIZE;
- if(hdaq_io.Out_wPointer >= DAQ_DATA_OUT_DEPTH)
- {
- hdaq_io.Out_wPointer = 0;
- }
- }
- else if(daq_cfg.Mode == DAQ_MODE_BURST)
- {
- hdaq_io.Out_wPointer = 0;
-
- if(*(hdaq_io.Out_Buff + hdaq_io.Out_wPointer * DAQ_DATA_OUT_PACK_SIZE) == DAQ_DATA_OUT_SOH)
- {
- if(daq_cfg.AO_IsEN == DAQ_ENABLE)
- {
- //AO0 Updata
- DAC->DHR12R1 = *(uint16_t*)(hdaq_io.Out_Buff + hdaq_io.Out_wPointer * DAQ_DATA_OUT_PACK_SIZE + 2);
- }
-
- if(daq_cfg.DO_IsEN == DAQ_ENABLE)
- {
- //DO Channel Updata
- DO0_GPIO_Port->ODR = (DO0_GPIO_Port->ODR & 0x00FF) |
- ((*(hdaq_io.Out_Buff + hdaq_io.Out_wPointer * DAQ_DATA_OUT_PACK_SIZE + 1)) << 8);
- }
-
- }
-
- DAQ_Itf_DataTxPack(hdaq_io.In_Buff, DAQ_DATA_IN_PACK_SIZE);
- }
- }
-
- USBD_DAQ_SetDataRxBuffer(hdaq_temp, hdaq_io.Out_Buff + hdaq_io.Out_wPointer * DAQ_DATA_OUT_PACK_SIZE);
- USBD_LL_PrepareReceive(hdaq_temp, DAQ_DATA_EPOUT_ADDR, hdaq->DataRxBuffer, DAQ_DATA_EPOUT_SIZE);
-
- // HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
-
- return USBD_OK;
- }
- static uint8_t DAQ_Itf_CtlRxCallBack(uint8_t* pbuff, uint16_t length)
- {
-
- USBD_DAQ_HandleTypedef *hdaq = (USBD_DAQ_HandleTypedef*)hdaq_temp->pClassData;
- uint8_t ack_rs = DAQ_ACK_FAIL;
-
- /* Recall Functions Here */
- if(*pbuff == length)
- {
- hdaq_ctl.Out_Buff = pbuff;
- DAQ_CTL_PackDeCode(&hdaq_ctl);
-
- if(hdaq_ctl.Out_Pack.bType == DAQ_CMD)
- {
- switch(hdaq_ctl.Out_Pack.data[0])
- {
- case DAQ_CMD_CTL: //*(data) -> level 0 Command
- switch(hdaq_ctl.Out_Pack.data[1])
- {
- case DAQ_CFG: //NID ACK
- switch(hdaq_ctl.Out_Pack.data[2])
- {
- case DAQ_AI:
- daq_cfg.AI_IsEN = hdaq_ctl.Out_Pack.data[3];
- break;
- case DAQ_DI:
- daq_cfg.DI_IsEN = hdaq_ctl.Out_Pack.data[3];
- break;
- case DAQ_AO:
- daq_cfg.AO_IsEN = hdaq_ctl.Out_Pack.data[3];
- break;
- case DAQ_DO:
- daq_cfg.DO_IsEN = hdaq_ctl.Out_Pack.data[3];
- break;
- default:
- goto ACK_NONE;
- }
-
- /* DAQ Parts Manage Callback here */
- DAQ_CMD_PartsEN(&daq_cfg);
-
- /* ACK */
- ack_rs = DAQ_ACK_OK;
- goto ACK_MNG;
-
- case DAQ_MODE: //NID ACK
- /*************DAQ Running Mode************
- * DAQ_MODE_BURST
- * DAQ_MODE_CONTI
- **/
- daq_cfg.Mode = hdaq_ctl.Out_Pack.data[2];
-
- /* DAQ running mode Callback here */
- if((daq_cfg.Mode == DAQ_MODE_BURST) || (daq_cfg.Mode == DAQ_MODE_CONTI))
- {
- ack_rs = DAQ_ACK_OK;
- }
- else
- {
- ack_rs = DAQ_ACK_FAIL;
- }
-
- /* ACK */
- goto ACK_MNG;
-
- case DAQ_SAMPLE: //NO ACK
- daq_cfg.SampleIsEN = hdaq_ctl.Out_Pack.data[2];
-
- /* DAQ Sample Start or Stop Callback here */
- ack_rs = DAQ_CMD_RunStop(&daq_cfg, &hdaq_io);
-
- goto ACK_MNG;
-
- default:
- goto ACK_NONE;
- }
- case DAQ_CMD_ASIGN:
- switch(hdaq_ctl.Out_Pack.data[1])
- {
- case DAQ_AI_CH_CFG:
- /***********AI Channel CFG Msg*************
- * Channelx = hdaq_ctl.Out_Pack.data[2]
- * State = hdaq_ctl.Out_Pack.data[3]
- * Index = hdaq_ctl.Out_Pack.data[4]
- **/
- /* DAQ AI Channel Config Callback here */
- ack_rs = DAQ_CMD_AI_CH_CFG_Callback(&hdaq_ctl, &daq_cfg);
-
- /* ACK */
- goto ACK_MNG;
-
- case DAQ_IO_SR:
- /* DAQ Sample Rate Config Callback here */
- //sr = (hdaq_ctl.Out_Pack.data[4] << 16) | (hdaq_ctl.Out_Pack.data[3] << 8) | (hdaq_ctl.Out_Pack.data[2]);
-
- daq_cfg.SampleRate = (hdaq_ctl.Out_Pack.data[4] << 16) | (hdaq_ctl.Out_Pack.data[3] << 8) | (hdaq_ctl.Out_Pack.data[2]);
-
- /* DAQ SampleRate Setting Callback here */
- ack_rs = DAQ_CMD_SampleRate(&daq_cfg);
- /* ACK */
- goto ACK_MNG;
-
- default:
- goto ACK_NONE;
- }
-
- case DAQ_CMD_FETCH: //NID Data
- switch(hdaq_ctl.Out_Pack.data[1])
- {
- case DAQ_CFG:
- ack_rs = DAQ_CMD_Cfg(&hdaq_ctl, &daq_cfg);
- break;
-
- case DAQ_MODE:
- ack_rs = DAQ_CMD_Mode(&hdaq_ctl, &daq_cfg);
- break;
-
- case DAQ_SAMPLE:
- ack_rs = DAQ_CMD_Sample(&hdaq_ctl, &daq_cfg);
- break;
-
- case DAQ_AI_CH_CFG:
- ack_rs = DAQ_CMD_AI_CH_Cfg(&hdaq_ctl);
- break;
-
- case DAQ_IO_SR:
- ack_rs = DAQ_CMD_IO_SR(&hdaq_ctl, &daq_cfg);
- break;
-
- case DAQ_IN_BUFF:
- ack_rs = DAQ_CMD_IN_Buff(&hdaq_ctl, DAQ_EPIN_State(DAQ_DATA_EPIN_ADDR));
- break;
-
- default:
- goto ACK_NONE;
-
- }
-
- if(ack_rs == DAQ_ACK_OK)
- {
-
- goto ACK_DATA;
- }
- else
- {
- goto ACK_MNG;
- }
-
- default:
- goto ACK_NONE;
- }
- }
- }
- else
- {
- goto ACK_NONE;
- }
-
- ACK_MNG:
- DAQ_CTL_ACK_Result(&hdaq_ctl, ack_rs);
- ACK_DATA:
- DAQ_Itf_CtlTxPack(hdaq_ctl.In_Buff, hdaq_ctl.In_Pack.bLength);
- ACK_NONE:
- USBD_LL_PrepareReceive(hdaq_temp, DAQ_CTL_EPOUT_ADDR, hdaq->CtlRxBuffer, DAQ_CTL_EPOUT_SIZE);
-
- return USBD_OK;
- }
- uint8_t DAQ_Itf_DataTxPack(uint8_t* pbuff, uint16_t length)
- {
- USBD_DAQ_HandleTypedef *hdaq = (USBD_DAQ_HandleTypedef*)hdaq_temp->pClassData;
-
- if((hdaq_temp->pClassData != NULL)||(pbuff != NULL))
- {
- if(hdaq->DataTxState == 0)
- {
- USBD_DAQ_SetDataTxBuffer(hdaq_temp, pbuff, length);
-
- hdaq->DataTxState = 1;
-
- USBD_LL_Transmit(hdaq_temp, DAQ_DATA_EPIN_ADDR, hdaq->DataTxBuffer, hdaq->DataTxLength);
-
- return USBD_OK;
- }
- else
- {
- return USBD_BUSY;
- }
- }
- else
- {
- return USBD_FAIL;
- }
- }
- uint8_t DAQ_Itf_CtlTxPack(uint8_t* pbuff, uint16_t length)
- {
- USBD_DAQ_HandleTypedef *hdaq = (USBD_DAQ_HandleTypedef*)hdaq_temp->pClassData;
-
- if((hdaq_temp->pClassData != NULL)||(pbuff != NULL))
- {
- if(hdaq->CtlTxState == 0)
- {
- USBD_DAQ_SetCtlTxBuffer(hdaq_temp, pbuff, length);
-
- hdaq->CtlTxState = 1;
-
- USBD_LL_Transmit(hdaq_temp, DAQ_CTL_EPIN_ADDR, hdaq->CtlTxBuffer, hdaq->CtlTxLength);
-
- return USBD_OK;
- }
- else
- {
- return USBD_BUSY;
- }
- }
- else
- {
- return USBD_FAIL;
- }
- }
这4个函数对主机命令进行响应,控制4个端点的数据/控制指令
2.2 驱动
驱动这部分实际上没有太多可以发挥的内容,必须按照巨硬的规范来,inf文件部分参考书可看《Windows驱动开发技术详解》—张帆。具体inf文件如下
- ; Ksp_DAQ_v20.inf
- ; Copyright (c) 2010-2016 Pete Batard <pete@akeo.ie> (GNU LGPL)
- [Strings]
- DeviceName = "Ksp DAQ v2.0" ;设备名
- VendorName = "Ksp" ;制造商名
- SourceName = "Ksp DAQ v2.0Install Disk"
- DeviceID = "VID_0308&PID_0200" ;硬件ID
- DeviceGUID = "{44B53307-B39F-43D1-B7F0-69D647B12660}" ;设备接口GUID
- [Version]
- Signature = "$Windows NT$"
- Class = "USBDevice"
- ClassGuid = {88bae032-5a81-49f0-bc3d-a4ff138216d6}
- Provider = %VendorName%
- CatalogFile = Ksp_DAQ_v20.cat
- DriverVer = 04/10/2016, 15.27.20.931
- [ClassInstall32]
- Addreg = WinUSBDeviceClassReg
- [WinUSBDeviceClassReg]
- HKR,,,0,"Universal Serial Bus devices"
- HKR,,Icon,,-20
- [Manufacturer]
- %VendorName% = libusbDevice_WinUSB,NTx86,NTamd64,NTarm
- [libusbDevice_WinUSB.NTx86]
- %DeviceName% = USB_Install, USB\%DeviceID%
- [libusbDevice_WinUSB.NTamd64]
- %DeviceName% = USB_Install, USB\%DeviceID%
- [libusbDevice_WinUSB.NTarm]
- %DeviceName% = USB_Install, USB\%DeviceID%
- [USB_Install]
- Include = winusb.inf
- Needs = WINUSB.NT
- [USB_Install.Services]
- Include = winusb.inf
- AddService = WinUSB,0x00000002,WinUSB_ServiceInstall
- [WinUSB_ServiceInstall]
- DisplayName = "WinUSB - Kernel Driver 03/31/2015 6.1.7600.16385"
- ServiceType = 1
- StartType = 3
- ErrorControl = 1
- ServiceBinary = %12%\WinUSB.sys
- [USB_Install.Wdf]
- KmdfService = WINUSB, WinUsb_Install
- [WinUSB_Install]
- KmdfLibraryVersion = 1.11
- [USB_Install.HW]
- AddReg = AddDeviceInterfaceGUID
- [NoDeviceInterfaceGUID]
- ; Avoids adding a DeviceInterfaceGUID for generic driver
- [AddDeviceInterfaceGUID]
- HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
- [USB_Install.CoInstallers]
- AddReg = CoInstallers_AddReg
- CopyFiles = CoInstallers_CopyFiles
- [CoInstallers_AddReg]
- HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01011.dll,WdfCoInstaller","WinUSBCoInstaller2.dll"
- [CoInstallers_CopyFiles]
- WinUSBCoInstaller2.dll
- WdfCoInstaller01011.dll
- [DestinationDirs]
- CoInstallers_CopyFiles = 11
- [SourceDisksNames]
- 1 = %SourceName%
- [SourceDisksFiles.x86]
- WinUSBCoInstaller2.dll = 1,x86
- WdfCoInstaller01011.dll = 1,x86
- [SourceDisksFiles.amd64]
- WinUSBCoInstaller2.dll = 1,amd64
- WdfCoInstaller01011.dll = 1,amd64
- [SourceDisksFiles.arm]
- WinUSBCoInstaller2.dll = 1,arm
- WdfCoInstaller01011.dll = 1,arm
对于自定义USB设备驱动,目前常见的教程都是在使用LibUSB(1.0版本)等,我们这里使用的是Windows自带的WinUSB,开发者不需要关心内核,详细可阅读WinUSB官网(Website:https://msdn.microsoft.com/en-us/library/windows/hardware/ff540196%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396)。这里给出DAQ的模/数数据读写代码,
- KSP_WinUSB_StatusTypeDef KSP_DAQ_BURST_WR(uint8_t* w_buff, uint8_t* r_buff)
- {
- uint32_t rx_len;
- if (KSP_WinUSB_USBD_BulkWrite(DAQ_DATA_EPOUT_ADDR, w_buff, DAQ_DATA_OUT_PACK_SIZE) != USBD_OK)
- {
- return USBD_FAIL;
- }
- if (KSP_WinUSB_USBD_BulkRead(DAQ_DATA_EPIN_ADDR, r_buff, DAQ_DATA_IN_PACK_SIZE, &rx_len) != USBD_OK)
- {
- return USBD_FAIL;
- }
- return USBD_OK;
- }
- KSP_WinUSB_StatusTypeDef KSP_DAQ_CONTI_W(uint8_t* w_buff, uint32_t w_buff_len)
- {
- return KSP_WinUSB_USBD_BulkWrite(DAQ_DATA_EPOUT_ADDR, w_buff, w_buff_len);
- }
- KSP_WinUSB_StatusTypeDef KSP_DAQ_CONTI_R(uint8_t* r_buff, uint32_t* r_len)
- {
- return KSP_WinUSB_USBD_BulkRead(DAQ_DATA_EPIN_ADDR, r_buff, DAQ_DATA_EPIN_SIZE, r_len);
- }
而其中核心的块读写代码如下
- /**
- * @brief 通过指定端点写入数据
- * @param ep_addr:端点号
- pbuff:待发送的数据缓冲
- txsize:数据缓冲长度
- * @retval 操作结果
- @arg @KSP_WinUSB_StatusTypeDef
- */
- KSP_WinUSB_StatusTypeDef KSP_WinUSB_USBD_BulkWrite(uint8_t ep_addr, uint8_t* pbuff, uint32_t txsize)
- {
- KSP_WinUSB_StatusTypeDef status = USBD_OK;
- uint32_t bytessend;
- if (KSP_WinUSB_USBD_IsOpen() != 1)
- {
- status = USBD_FAIL;
- goto DONE;
- }
- if (WinUsb_WritePipe(h_ksp_winusb.WinusbHandle, ep_addr, pbuff, txsize, (PULONG)&bytessend, 0) == FALSE)
- {
- status = USBD_FAIL;
- }
- DONE:
- return status;
- }
- /**·
- * @brief 通过指定端点读出数据
- * @param ep_addr:端点号
- pbuff:读出数据的缓冲区
- rxsize:接收到的数据长度(按字节计)
- * @retval 操作结果
- @arg @KSP_WinUSB_StatusTypeDef
- */
- KSP_WinUSB_StatusTypeDef KSP_WinUSB_USBD_BulkRead(uint8_t ep_addr, uint8_t* pbuff, uint32_t buflen, uint32_t* rxsize)
- {
- KSP_WinUSB_StatusTypeDef status = USBD_OK;
- if (KSP_WinUSB_USBD_IsOpen() != 1)
- {
- status = USBD_FAIL;
- goto DONE;
- }
- if (WinUsb_ReadPipe(h_ksp_winusb.WinusbHandle, ep_addr, pbuff, buflen, (PULONG)rxsize, 0) == FALSE)
- {
- status = USBD_FAIL;
- }
- DONE:
- return status;
- }
在Visual Studio平台中,inf的编写编译,DAQ设备的读写测试,封装成动态链接库(dll)一气呵成。对外提供的函数接口如下
- LIBRARY Ksp_daq_v21_dll
- EXPORTS
- KSP_DAQ_Open [url=home.php?mod=space&uid=72445]@[/url] 1
- KSP_DAQ_Close @ 2
- KSP_DAQ_CTL_PartsEN @ 3
- KSP_DAQ_CTL_Mode @ 4
- KSP_DAQ_CTL_SampleEN @ 5
- KSP_DAQ_ASIGN_AI_CH_Config @ 6
- KSP_DAQ_ASIGN_SampleRate @ 7
- KSP_DAQ_FETCH_PartsEN @ 8
- KSP_DAQ_FETCH_Mode @ 9
- KSP_DAQ_FETCH_SampleEN @ 10
- KSP_DAQ_FETCH_AI_CH_Config @ 11
- KSP_DAQ_FETCH_SampleRate @ 12
- KSP_DAQ_FETCH_BUFF_State @ 13
- KSP_DAQ_BURST_WR @ 14
- KSP_DAQ_CONTI_W @ 15
- KSP_DAQ_CONTI_R @ 16
2.3 应用软件
对于Windows下设备访问只要把接口写好,其他都能由系统与环境自动完成。MATLAB中如何使用前一节Release的dll文件呢,请看如下测试DAQ设备的m文件
- %%测试DLL文件
- [~,~]=loadlibrary('Ksp_daq_v21_dll','ksp_daq_vxx.h');
- SampleDepth = 400;
- SampleRate = 900000;
- if strcmp(calllib('Ksp_daq_v21_dll','KSP_DAQ_Open'),'USBD_OK') == 1
- disp('设备打开成功')
-
- %设置采样率为100KHz
- calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_SampleRate',SampleRate);
- disp(strcat('当前采样率为',int2str(SampleRate),'KHz'));
-
- %设定采样模式
- calllib('Ksp_daq_v21_dll', 'KSP_DAQ_CTL_Mode', 2);
-
- %预读缓冲区
- IN_BUFF_State = zeros(1, 1, 'uint8');
- rx_len = zeros(1, 1, 'uint32');
- rx_buff = zeros(1, (16*SampleDepth + 512), 'uint8');
-
- tx_buff = uint8(hex2dec({'bb','01','99','09'}))';
-
- calllib('Ksp_daq_v21_dll','KSP_DAQ_FETCH_BUFF_State', IN_BUFF_State);
- if (IN_BUFF_State == 2)
- calllib('Ksp_daq_v21_dll','KSP_DAQ_CONTI_R',rx_buff, rx_len);
- end
- %通道配置
- calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_AI_CH_Config', 0, 2, 8);
- calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_AI_CH_Config', 1, 2, 8);
- calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_AI_CH_Config', 2, 2, 8);
- calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_AI_CH_Config', 3, 2, 8);
- calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_AI_CH_Config', 4, 2, 8);
- calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_AI_CH_Config', 5, 2, 8);
- calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_AI_CH_Config', 6, 2, 8);
-
- calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_AI_CH_Config', 0, 1, 1);
- %calllib('Ksp_daq_v21_dll','KSP_DAQ_ASIGN_AI_CH_Config', 1, 1, 2);
-
- total_len = 0;
-
- %启动采样
- calllib('Ksp_daq_v21_dll','KSP_DAQ_CTL_SampleEN', 1);
-
- calllib('Ksp_daq_v21_dll', 'KSP_DAQ_CONTI_W', tx_buff, 4);
-
- while (total_len<(16*SampleDepth))
- [rs, rx_buff((total_len+1):( total_len+512)), rx_len]=calllib('Ksp_daq_v21_dll','KSP_DAQ_CONTI_R', rx_buff((total_len+1):( total_len+512)), rx_len);
- total_len = total_len + rx_len;
- end
-
- %停止采样
- calllib('Ksp_daq_v21_dll','KSP_DAQ_CTL_SampleEN', 2);
-
- if strcmp(calllib('Ksp_daq_v21_dll','KSP_DAQ_Close'),'USBD_OK') == 1
- disp('设备关闭成功')
- else
- disp('设备关闭失败')
- end
-
- AI0 = [];
- for i=1:1:SampleDepth
- adc_value = (double(rx_buff((i -1 )*16 + 3)) + 256*double(rx_buff((i -1 )*16 + 4)))*2.5/4095;
- AI0(i) = adc_value;
- end
-
- Ts = 1 / SampleRate;
-
- plot([0:Ts:(Ts*(SampleDepth-1))], AI0);
- xlabel('t/s')
- ylabel('AI0/v')
- else
- disp('设备打开失败')
- end
- unloadlibrary('Ksp_daq_v21_dll')
运行成功就能看到模拟通道0输入的电压波形图啦,下图是MATLAB下GUIDE一个简单的测试结果,硬件上DO0接到了DI0。
|