搜索
bottom↓
回复: 179

我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

  [复制链接]

出0入0汤圆

发表于 2009-3-9 13:46:23 | 显示全部楼层 |阅读模式
今天是3月9号,再过3个月就要大学毕业了,最近工作找得郁闷。干脆躲回实验室,总结下我的毕业设计,算是把自己的大学画个句号吧。

1 概述
毕业设计的题目是“基于STM32的简易示波器设备驱动的研究”,就是利用STM32的AD采集波形数据,然后通过它内置的USB2.0把数据传到PC上面显示出来。框图如下。

(原文件名:框图.JPG)

   题目一共是两个人做,我和我搭档耗子。他做信号处理,采集部分。我做USB在PC下的驱动开发,以及上位机界面的显示。USB固件那部分我们是一起完成的。
  这个课题从08年10月开始,到12月圣诞前夕基本完成。最后基本实现了波形的显示,实测最大可以测量的频率是200KHZ,
效果图如下:

30KHZ ,1V正弦波 (原文件名:效果图1.JPG)


100KHZ ,1V正弦波 (原文件名:效果图2.JPG)

方波的图形好像不是很漂亮会有上升沿老是有尖刺,还需要作软件做处理。没截出来,

  最后能出数据离不开很多前辈的经验。有些地方是借鉴了他们的东西。现在先列出来。
第一个是21IC上面alien2006原帖地址。他也是做了一个简易示波器,但是用的是以太网传输。采集部分我很多借鉴了他的方案。
第二个是电脑圈圈,他对USB的理解令我钦佩。我能搞出驱动,他提供的源码包非常重要,有些代码也是直接在他的基础上修改的。

2 整体方案
  先说下一次完整的采集,比如外面进来的波形是正弦波,波形电压有正负,STM32单片机的AD只能采集0~3.6V的电压,所以要对信号进行处理。也就是需要一个模拟前端电路,把电压抬上去。接着就是采集了,STM32的AD可以用外设进行触发,这里用定时器进行触发。每过一个单位时间AD开启一次,采集一个点,这样采集的频率只要调整这个单位时间也就是定时器就可以控制了。采集了一桢数据,比如200个点。DMA中断被触发,开启USB,把数据发送到上位机,然后显示出来。
  整个过程大体就是这样了,还有一个很重要的环节补充下。熟悉示波器的人都知道示波器有个触发概念。像刚才这样显示的话,比如前一帧数据是波峰开始显示,后一帧是波谷开始。这样显示出来的波形就是乱的,于是为了解决这个问题,就需要做触发,也就是保证每次采集的起始电位相同。我们的采用的是用外中断的形式,外面波形数据先不采集,先让它通过一个比较器,比如比较器的基准电压是1V,也就是每次都和1V比较,低于1V输出低电平,高于1V输出高电平。当数据电压大于1V的时候,比较器输出高电平,高电平接到单片机外中断口,这样外中断就被触发。然后开始采集,这样就能保证每帧数据的起始点都相同。
  这个方案是大体方案,后来做了下修改。就是让AD一直在采集。外中断触发了后开启的是DMA,AD一直开着,只是控制DMA什么时候去取。从哪里开始取,取多少个点。下位机部分不再详说,贴下主要的程序,大侠们随便看看,多多指教。
定时器设置代码如下:
/*******************************************************************************
* Function Name  : TIM_Configuration
* Description    : Configure the TIM2.
*******************************************************************************/
void TIM2_Configuration(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  
  TIM_DeInit(TIM2); //TIM2初始化
   
  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 18; //设置了下一个更新事件装入活动的自动重装载寄存器周期的值
  TIM_TimeBaseStructure.TIM_Prescaler = 0; //设置了用来作为TIMx时钟频率除数的预分频值
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //设置了时钟分割
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //选择了计数器模式向上计数

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx

  /* Prescaler configuration */
//  TIM_PrescalerConfig(TIM2, 1, TIM_PSCReloadMode_Update); //设置TIMx重载次数 预分频值在更新事件装入

  /* TIM_OCMode_Toggle Mode configuration: Channel2 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;         
  TIM_OCInitStructure.TIM_Channel = TIM_Channel_2;         
  TIM_OCInitStructure.TIM_Pulse = 9;  
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;  //TIM输出比较极性低
   
  TIM_OCInit(TIM2, &TIM_OCInitStructure);
  
  TIM_ARRPreloadConfig(TIM2, ENABLE); //使能或者失能TIMx在ARR上的自动装载寄存器
  
  /* TIM2 enable counter */
  TIM_Cmd(TIM2, ENABLE); //使能TIMx外设
}
AD以及DMA设置代码:
/*******************************************************************************
* Function Name  : ADC_Configuration
* Description    : Configure the ADC1.
*******************************************************************************/
void ADC_Configuration(void)
{
  /* DMA channel1 configuration ----------------------------------------------*/
  DMA_DeInit(DMA_Channel1); //复位DMA_Channel1
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //外围设备地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_Data[0]; //memory 地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外围设备做为源
  DMA_InitStructure.DMA_BufferSize = 1024;  //数据单元尺寸
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外围地址是否自动增长 disable不增长
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //memory 是否自动增长
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外围设备寄存器尺寸16位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  //memory尺寸16位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //DMA 循环模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;  //DMA 通道优先级
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //memory- to-memory转换
  DMA_Init(DMA_Channel1, &DMA_InitStructure);  //初始化DMA通道1

  /* DMA IT enable */
  DMA_ITConfig(DMA_Channel1, DMA_IT_TC, ENABLE); //使能DMA传输完成中断

  /* ADC1 configuration ------------------------------------------------------*/                                                     
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  //ADC 工作模式 ADC1 ADC2 单独工作   
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;  //多通道扫描模式
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //是否启用连续转换模式
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;  //触发方式
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;   //数据右对齐
  ADC_InitStructure.ADC_NbrOfChannel = 1;  //ADC规则转换通道数量
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel10 configuration */ //配置转换规则
  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_1Cycles5);
  
  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);

  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);

  /* Enable ADC1 reset calibaration register */
  ADC_ResetCalibration(ADC1);  //复位ADC1 校准
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位完成

  /* Start ADC1 calibaration */
  ADC_StartCalibration(ADC1);  //开始ADC1 校准转换
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));  //等待转换完成
  
  ADC_ExternalTrigConvCmd( ADC1, ENABLE); //使能或者失能ADCx的经外部触发启动转换功能
}

DMA中断服务程序:
/*******************************************************************************
* Function Name  : DMAChannel1_IRQHandler
* Description    : This function handles DMA Stream 1 interrupt request.
*******************************************************************************/
void DMAChannel1_IRQHandler(void)
{
  DMA_Cmd(DMA_Channel1, DISABLE);  //关闭DMA通道1
  for(count=64;count<1024;count++)  //AD数据转换处理
  {
    AD_Data[count]=(ADC_Data[count]*330)/4096;
  }
  flag_usb = 1;  //usb标志位置1,使能usb发送
  DMA_ClearITPendingBit(DMA_IT_TC1);
}

  下面就开始说我做的部分,USB部分。一共有3个地方,
(1)USB固件程序的开发
(2)Windows XP下USB设备驱动的开发
(3)对应的PC上的应用程序开发。
下面来详细论述。

3  USB固件程序的开发
  这部分主要设计USB的协议。一共花了两个星期时间,是我们做的最开心的两个星期。因为是两个人一起来研究,导师崔也经常跑过来讨论。最后测出来的传输速度是700-800K,依据USB2.0全速理论最大速度12Mbps,除以八大概是1M多,基本把速度都开发出来了。期间参考了ouravr里面的一个叫极速狂飙的帖子,也成功开启了双缓冲。
  固件程序主要是根据万利板子提供的4个USB程序中的那个USB转串程序修改的,主要是修改两个文件。第一个是usb_desc.c,这个文件里面配置了全部的描述符。这些描述符在USB2.0协议里面都有严格的定义,跟着配置就好了。
const u8 Virtual_Com_Port_DeviceDescriptor[] =
  {
    0x12,   /* bLength */
    USB_DEVICE_DESCRIPTOR_TYPE,     /* bDescriptorType */
    0x00,
    0x02,   /* bcdUSB = 2.00 USB2.0版本*/
    0xFF,   /* bDeviceClass:  USB分配的设备类*/
    0xFF,   /* bDeviceSubClass 子类*/
    0x00,   /* bDeviceProtocol */
    0x40,   /* bMaxPacketSize0 端点0最大包大小*/
    0x44,
    0x44,   /* idVendor = 0x4444 高位在后*/
    0x33,
    0x33,   /* idProduct = 0x3333 */
    0x00,
    0x02,   /* bcdDevice = 2.00 */
    1,              /* Index of string descriptor describing manufacturer */
    2,              /* Index of string descriptor describing product */
    3,              /* Index of string descriptor describing the device's serial number */
    0x01    /* bNumConfigurations */
  };

const u8 Virtual_Com_Port_ConfigDescriptor[] =
  {
    /*Configuation Descriptor配置描述符*/
    0x09,   /* bLength: Configuation Descriptor size */
    USB_CONFIGURATION_DESCRIPTOR_TYPE,      /* bDescriptorType: Configuration */
    VIRTUAL_COM_PORT_SIZ_CONFIG_DESC,       /* wTotalLength:no of returned bytes */
    0x00,
    0x01,   /* bNumInterfaces: 1 interface 此配置所支持的接口数量*/
    0x01,   /* bConfigurationValue: Configuration value */
    0x00,   /* iConfiguration: Index of string descriptor describing the configuration */
    0xC0,   /* bmAttributes: self powered 自供电*/
    0x00,   /* MaxPower 0 mA 设备从总线提取的电流*/
    /* 9 */
         
    /*Data class Interface Descriptor接口描述符*/
    0x09,   /* bLength: Endpoint Descriptor size */
    USB_INTERFACE_DESCRIPTOR_TYPE,  /* bDescriptorType: */
    0x00,   /* bInterfaceNumber: Number of Interface 该接口编号0为基*/
    0x00,   /* bAlternateSetting: Alternate setting */
    0x02,   /* bNumEndpoints: 该使用的端点数*/
    0xFF,   /* bInterfaceClass:  接口类型*/
    0xFF,   /* bInterfaceSubClass: 子类 */
    0x00,   /* bInterfaceProtocol: 接口遵循的协议*/
    0x00,   /* iInterface: 描述该接口字符串索引*/
    /* 18 */
   
    /*Endpoint 3 Descriptor*/
    0x07,   /* bLength: Endpoint Descriptor size */
    USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
    0x03,   /* bEndpointAddress: (OUT3) */
    0x02,   /* bmAttributes: Bulk */
    0x02,   
    0x00,   /* PacketSize: */
    0x00,   /* bInterval: ignore for Bulk transfer */
   
    /*Endpoint 1 Descriptor*/
    0x07,   /* bLength: Endpoint Descriptor size */
    USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
    0x81,   /* bEndpointAddress: (IN1) */
    0x02,   /* bmAttributes: Bulk */            
    0x40,   
    0x00,   /* wMaxPacketSize:批量传输最大包 64byte*/
    0x00    /* bInterval */
    /* 25 */  
  };

/* USB String Descriptors */
const u8 Virtual_Com_Port_StringLangID[VIRTUAL_COM_PORT_SIZ_STRING_LANGID] =
  {
    VIRTUAL_COM_PORT_SIZ_STRING_LANGID,
    USB_STRING_DESCRIPTOR_TYPE,
    0x09,
    0x04 /* LangID = 0x0409: U.S. English */
  };

const u8 Virtual_Com_Port_StringVendor[VIRTUAL_COM_PORT_SIZ_STRING_VENDOR] =
  {
    VIRTUAL_COM_PORT_SIZ_STRING_VENDOR,     /* Size of Vendor string */
    USB_STRING_DESCRIPTOR_TYPE,             /* bDescriptorType*/
    /* Manufacturer: "STMicroelectronics" */
    'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0,
    'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0,
    'c', 0, 's', 0
  };

const u8 Virtual_Com_Port_StringProduct[VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT] =
  {
    VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT,          /* bLength */
    USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
    /* Product name: "Num send test" */
    'N', 0, 'u', 0, 'm', 0, ' ', 0, 's', 0, 'e', 0, 'n', 0, 'd', 0,
    ' ', 0, 't', 0, 'e', 0, 's', 0, 't', 0, ' ', 0
  };

const u8 Virtual_Com_Port_StringSerial[VIRTUAL_COM_PORT_SIZ_STRING_SERIAL] =
  {
    VIRTUAL_COM_PORT_SIZ_STRING_SERIAL,           /* bLength */
    USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
    'D', 0, 'e', 0, 'm', 0, 'o', 0, ' ', 0, '1', 0, '.', 0, '0', 0,
    '0', 0, '0', 0
  }
有些字符没有修改还是原来DEMO的,大家将就着看看。
还有就是Usb_prop.c 里面这个函数
/*******************************************************************************
* Function Name  : Virtual_Com_Port_Reset
* Description    : Virtual_Com_Port Mouse reset routine
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void Virtual_Com_Port_Reset(void)  //USBIP复位过程,当宏单元收到RESET信号时调用,
{                                  //用户程序在此过程中设置端点
  /* Set Virtual_Com_Port DEVICE as not configured */
  pInformation->Current_Configuration = 0;

  /* Set Virtual_Com_Port DEVICE with the default Interface*/
  pInformation->Current_Interface = 0;
  SetBTABLE(BTABLE_ADDRESS);

  /* Initialize Endpoint 0 */
  SetEPType(ENDP0, EP_CONTROL);
  SetEPTxStatus(ENDP0, EP_TX_STALL);
  SetEPRxAddr(ENDP0, ENDP0_RXADDR);
  SetEPTxAddr(ENDP0, ENDP0_TXADDR);
  Clear_Status_Out(ENDP0);
  SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
  SetEPRxValid(ENDP0);

  /* Initialize Endpoint 1 */
  SetEPType(ENDP1, EP_BULK);  //设置端点1传输模式批量传输
  SetEPTxAddr(ENDP1, ENDP1_TXADDR);  //缓冲区基地址(IN 发)
  SetEPTxCount(ENDP1, 64);  //配置Tx缓冲计数器
  SetEPTxStatus(ENDP1, EP_TX_VALID);  //设置端点发送有效
  SetEPRxStatus(ENDP1, EP_RX_DIS);  //设置端点接收关闭
  
  /* Initialize Endpoint 3 */
  SetEPType(ENDP3, EP_BULK);  //设置端点3传输模式批量传输
  SetEPRxAddr(ENDP3, ENDP3_RXADDR);  //缓冲区基地址(OUT 收)
  SetEPRxCount(ENDP3, 2); //配置Rx缓冲计数器
  SetEPRxStatus(ENDP3, EP_RX_VALID);  //设置端点接收有效
  SetEPTxStatus(ENDP3, EP_TX_DIS);  //端点关闭发送

  /* Set this device to response on default address */
  SetDeviceAddress(0);
}要配置下。就是你开启的那些端点了。

4  Windows XP下USB设备驱动的开发
  这部分是最麻烦的,至少对我来说是这样的,好像已经到了计算机专业范畴,而我对这些非常不熟悉。学习期间第一个方案用的是LABVIEW,它附带一个工具叫VISA,可以直接配置成USB驱动,然后再在LABVIEW里面直接调用,很方便。在研究LABVIEW的时候发现里面有很多DEMO,而且对中文的支持非常好,很多文档都是官方直接出中文文档。(好像半导体大额们对中国这块市场都越来越重视了,前几天看到AVR大部分的文档也都是直接官方翻译的中文文档。)学习了软件里面附带的入门教程,大概也能编一些简单的程序了,调试USB的时候发现里面有几个USB的demo,配合VISA生成的驱动居然直接接收到了下面传上来的数据,这对我们来说无异于是一次莫大的鼓励。后来导师推荐我试试另一种方法,就是用Driverstudio+VC来开发驱动和编写界面。为了学习一下USB的驱动开发,于是在第三个星期的时候开始windows下驱动的开发。老实说吃了很多苦头,到现在虽然功能基本实现了,但是对于这一块我还是只知道皮毛。DS里面的那些类和函数也没怎么搞透,驱动能开发出来主要还是借鉴了DS附带的example 里面的USB BULK 程序。
下面大概讲下我遇到过的问题给后来人一点借鉴:

(1)是安装顺序的问题,因为DriverStudio要嵌入到VC中,以后的代码要用DDK来编写所以三个软件要很好的兼容才可以。
第一步:安装Microsoft Visual C++6.0;
第二步:安装Microsoft Windows XP DDK;
第三步:安装DriverStudio 3.2驱动程序开发工具包。
  VC6.0最好安装英文版的,可以减少不知名的错误。安装完成后DS3.2会嵌入到VC中,在上面多一个标题:
  DriverStudio选项卡下面第三项DDK Build setting要设置成C:\WINDDK\2600(如果DDK安装在C盘),然后要编译DriverStudio安装目录下DriverStudio\DriverWorks\source\VdwLibs.dsw,以得到vdw_wdm.lib这个库文件。编译的时候会出现错误,因为用VC打开vdwlibs.dsw工程文件后,有两个工程,要先将VdwLibs工程设为当前Active Project,然后在工具栏上单击右键选择“组建”,在弹出的编译工具栏中配置一下编译平台的设置:选择Win32 WDM Checked平台(因为我们用的XP),然后编译就应该可以了。

(2)是利用向导生成驱动程序框架
  DS有个DriverWizard可以生成驱动程序的大体框架。
第一步:选择开发环境VC6.0,命名。
第二步:选择WDM Driver不用修改。
第三步:选择WDM Function Driver
第四步:选择USB并设置好PID 和 VID 要与固件里面的设置相同
第五步:设置端点,以及缓冲区。也要和固件里面相对应。
  接下午几步可以根据自己来设置,也可以默认。完成后会生成一个工程目录,里面包含了两个工程,一个是驱动,是我们需要的。另一个是测试程序,好像没有用。当你编译驱动的时候,会提示有错误,这是因为DS里面的一个BUG,选择project-setting,左边两个工程选驱动那个,点右边LINK选项卡,删除Object/library module 项的ntstrsafe.lib。再编译就能通过了。
(3)接下去就是对刚才生成的框架进行研究,添加一些代码以使驱动完整。
  首先来了解下生成的框架。
(1)DriverEntry()该例程是当系统检测到与驱动程序支持的设备时被调用的。
(2)AddDevice()  该例程为系统添加一个设备。
(3)Unload()          该例程为系统卸载设备。
  以上几个例程都存在于XXXXDriver.cpp是设备的基本操作可以直接使用生成的代码,不用修改。
  在另一个文件XXXXDevice.cpp中包含了具体应用函数,比如read和write,但是这个文件也存在这一个BUG,在开头部分有m_Pipe1_in.Initialize(m_Lower, 0x81, 64);        和m_Pipe2_out.Initialize(m_Lower, 3, 64);本次定义了两个端点,一个是叫m_Pipe1_in,0x81表示这个管道的属性是入(in),缓冲区是64.下面一个是m_Pipe2_out表示是出(out),缓冲区是64.向导生成的代码里面漏掉了“0x”这两个字符。
  关键部分代码的添加
  上位机应用程序,主要是通过两种方式来控制驱动,一个是DeviceIoControl()函数,另一个是ReadFile()函数和WriteFile()函数。本次使用的是后者。只要在Read(KIrp I),和Write(KIrp I)里面添加相应的代码就可以。这方面可以参考DS3.2附带的example里面的那个usbbulk例程。
  首先简述一下完成一次驱动调用所要做的具体工作。应用程序想对USB设备进行I/O操作,它需调用Windows API函数比如readfile(),I/O管理器将此请求构造成一个合适的I/O请求包(IRP)并把它传递给USB设备驱动程序。USB设备驱动程序接收到这个IRP后,根据IPR中包含的具体操作代码构造相应USB请求块(URB),并把它放到一个新的IRP中,然后传递给USB底层驱动程序(中间层或总线驱动程序)。USB底层驱动程序根据IRP中所含的URB执行相应的操作,并把操作的结果返回给USB设备驱动程序。USB设备驱动程序接收到此返回的IRP后,将操作结果通过IRP返还给I/O管理器,最后I/O管理器将此IRP操作结果传回给应用程序,至此应用程序对设备的一次I/O操作完成。当上位机调用的ReadFile()的时候,USB设备驱动程序要根据IPR中包含的具体操作代码构造相应USB请求块(URB),这个URB的生成就在这里实现,比如例程里面的
    PURB pUrb = m_Pipe1_in.BuildBulkTransfer(
                                                        Mem,                  // Where is data coming from?
                                                        dwTotalSize,  // How much data to read?
                                                        TRUE,         // direction (TRUE = IN)
                                                        NULL              // Link to next URB
                                                        );
  主要是通过这个函数来实现。函数实现了之后会有不同的返回值,然后打印出不同的信息。这些信息可以在DS调试工具Monitor中看到。

5  驱动开发的过程大概就是这样了。下面是应用程序的开发。主要两步,先打开设备,然后读写数据。
(1)打开设备
  Windows下面有很多针对驱动调用的API函数,要调用一个USB设备首先就要打开这个设备,其对应的API函数为CreateFile,在本次驱动中DS自动生成了一个OpenByInterface.c文件,在该文件里面对这个CreateFile函数进行了封装,其参数如下
HANDLE OpenByInterface(
                GUID* pClassGuid,        // points to the GUID that identifies the interface class
                DWORD instance,                // specifies which instance of the enumerated devices to open
                PDWORD pError                // address of variable to receive error status
                )
所以在主程序中只要调用OpenByInterface函数就可以了。本次中具体实现的代码如下:
        if(g_hUsbDevice==INVALID_HANDLE_VALUE)
        {
                g_hUsbDevice=OpenByInterface(
                        &g_UsbGuid,        // points to the GUID that identifies the interface class
                        0,                // specifies which instance of the enumerated devices to open
                        &Error                // address of variable to receive error status
                        );
                if(g_hUsbDevice==INVALID_HANDLE_VALUE)
                {
                        MessageBox("打开设备失败!",NULL,MB_OK | MB_ICONHAND);
                }
                else
                {
                        MessageBox("打开设备成功!",NULL,MB_OK | MB_ICONASTERISK);               
                }
        }
其中GUID* pClassGuid是对应的设备的GUID,具体定义如下:
GUID g_UsbGuid=GUID_DEVINTERFACE_USB;//打开设备的GUID
其中GUID_DEVINTERFACE_USB是在DS生成的Intrface.h文件中定义的,
#define GUID_DEVINTERFACE_USB \
{ 0x6C8CFFA6, 0xCAB8, 0x45B1, { 0xAA, 0xEE, 0x1E, 0xF4, 0xDF, 0x79, 0xF8, 0xDF } }
这个ID保证了每个USB驱动的唯一性,调用紊乱的情况的出现。OpenByInterface这个函数有一个返回值,通过的改变可以确认设备是否打开成功,然后通过MessageBox函数跳出不同的反馈信息。
(2)读写数据
  Windows中读取数据的API函数有两种,一种是DeviceIoControl,一种是ReadFile、WriteFile函数。前者一个函数可以读也可以写,后者把读写分开来,这次使用的是后者。
  ReadFile的具体实现如下:
ReadFile(
                                g_hUsbDevice,        //我们的设备HANDLE hFile
                                DataBuffer,//输入缓冲,无lpBuffer
                64,                        //输出字节数nNumberOfBytesToRead,
                &BytesReturned,        //实际读取到的字节数lpNumberOfBytesRead,
                NULL
                    )
  g_hUsbDevice是对应我们的设备,DataBuffer是我们定义的数组,读取到的数据就存在这个数组中,64是一次读取的字节数,BytesReturned是实际读取到的字节数,最后一个可以默认为NULL。如果成功读取到了数据,数组DataBuffer中的数据就会更新,然后可以做任意处理。
  写数据基本和读取数据类似。

  至此基本完成了驱动的开发。主要是论述下我学习的整个过程,因为在学习的过程中,最大的苦恼是有时不知道应该朝哪里努力。套用圈圈的一句话:真希望能来个大仙来指指路。涉及到的内容相对本科毕设还是比较多的。很多地方都没吃透。
  第一次发帖,先在word上编辑好的,格式可能会有错误。  帖子里有些内容是我从论文里直接复制过来的。东西是去年做的,没有及时做总结,很多地方都忘掉了。可能会有很多错误,大家指正。
  留下我的联系方式:E-MAIL:fmj118@gmail.com   QQ :110053142 大家有啥新发现不要忘了我啊。最近在想开始学习UCOS如果有做过这块的同学,现在正在搞USB。能交换学习就更好了。
  刚刚发现论坛里面有这个帖子
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=1843081&bbs_page_no=1&search_mode=1&search_text=usb&bbs_id=3020
也是包括了固件,驱动,上位机写的比我详细很多,一起学习下。

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2009-3-9 13:48:59 | 显示全部楼层
不错的大学生活。

出0入0汤圆

发表于 2009-3-9 13:56:54 | 显示全部楼层
相当实在的毕设~~~~~相对目前的大学气候,

出0入0汤圆

发表于 2009-3-9 13:58:34 | 显示全部楼层
mark,楼主本科毕业就能做出这么厉害的东西啊,我读完大学还不知道有STM32,甚至AVR也是来这个坛子才知道的
那个时候好象有上不完的课考不完的试,从来没关注其他的东西,就这样我还算是比较好的学生了

出0入0汤圆

发表于 2009-3-9 14:00:45 | 显示全部楼层
我的毕设也是我实实在在自己在公司做出来的,虽然说相对有些简单

出0入0汤圆

发表于 2009-3-9 14:55:59 | 显示全部楼层
支持楼主

出0入0汤圆

发表于 2009-3-9 15:10:43 | 显示全部楼层
很不错的学生,继续努力!

出0入0汤圆

发表于 2009-3-9 15:56:58 | 显示全部楼层
好样的,赞一个.

出0入0汤圆

发表于 2009-3-9 16:38:31 | 显示全部楼层
实际上PC端写驱动最好的方式是用 WinDriver. 不再需要DDK了.DS+VC6 方式已经过时了. DS和SoftIce 的公司已经不再升级这个软件了.
=======
楼主这样的学生已经很好了,不知道楼主是哪里人,对到南京工作感不感兴趣,对工作岗位有什么要求.

出0入0汤圆

发表于 2009-3-9 16:59:56 | 显示全部楼层
非常实用的资料,对入门者有很大帮助.

出0入0汤圆

发表于 2009-3-9 17:20:51 | 显示全部楼层
这样的同学要鼓励!不是说工作不好找吗?看看楼上的楼上已经开始要人了!

出0入0汤圆

发表于 2009-3-9 17:48:44 | 显示全部楼层
做的很实在。

出0入0汤圆

发表于 2009-3-9 18:54:15 | 显示全部楼层
很不错

出0入0汤圆

发表于 2009-3-9 19:43:46 | 显示全部楼层
我也正在做这个,赞LZ!

出0入4汤圆

发表于 2009-3-9 20:07:31 | 显示全部楼层
很不多,顶一个

出0入50汤圆

发表于 2009-3-9 20:42:18 | 显示全部楼层
楼主是属于——————万绿丛中一点——————红!
赞一个!

出0入0汤圆

发表于 2009-3-9 20:42:35 | 显示全部楼层
很好的毕业设计,楼主试试LABVIEW写上位机程序,界面应该会更好。

出0入0汤圆

 楼主| 发表于 2009-3-10 10:10:10 | 显示全部楼层
回复8楼
说的不错,DS已经不更新了。学的时候特别郁闷。因为资料比较少,好像市面上只有一本武安河的书。现在已经绝版,我只买到本别人自己印的。有时间研究下windriver。
另外我是杭州的,南京还是比较喜欢的。能否把要求以及公司网站发我?我的邮件fmj118@gmail.com

回复16楼  
用LABVIEW是挺漂亮的,我也在这上面花了一个多星期。最大的感觉就是对中文的支持非常好。附带的帮助文档都是官方翻译的中文文档。还有很多DEMO。不过这次主要也是多学点东西,用LABVIEW的话基本不用做多少了。

出0入0汤圆

发表于 2009-3-10 10:16:58 | 显示全部楼层
学习了。

出0入0汤圆

发表于 2009-3-10 22:03:59 | 显示全部楼层
呵呵,好东西

出0入0汤圆

发表于 2009-3-10 22:36:34 | 显示全部楼层
mark,本科做成这样很厉害了,楼主哪个学校的

出0入0汤圆

发表于 2009-3-11 21:25:06 | 显示全部楼层
问一下,为什么速度要12M/8

出0入0汤圆

 楼主| 发表于 2009-3-12 13:43:41 | 显示全部楼层
12M是bps,比特每秒。测试的时候用的是B/s,字节每秒。1 B/s=8 bps(b/s)。以前也搞不清楚,家里2M的ADSL宽带为什么下载速度只有200K/S,那个2M应该也是bps吧。

出0入0汤圆

发表于 2009-3-12 14:44:28 | 显示全部楼层
小伙子干得不错

出0入0汤圆

发表于 2009-3-12 19:23:04 | 显示全部楼层
做的真不赖!学电子的现在工作难找吗?

你的这个USB的传输数据速度有多少啊

出0入0汤圆

发表于 2009-3-12 20:46:37 | 显示全部楼层
楼上的楼上图像不错,很帅,好眼熟!!

出0入0汤圆

发表于 2009-3-16 14:17:02 | 显示全部楼层
不错的年青人,有前途。

出0入0汤圆

发表于 2009-3-16 14:36:39 | 显示全部楼层
强悍的设计。

我的毕业设计上礼拜才发下题目来。
我学机械的。拿了个单片机的题目做毕业设计。

出0入0汤圆

发表于 2009-3-17 00:29:28 | 显示全部楼层
Mark 顶

出0入0汤圆

发表于 2009-3-17 20:15:34 | 显示全部楼层
顶,收藏先

出0入0汤圆

发表于 2009-3-17 21:00:47 | 显示全部楼层
一直想做但没时间做的好东西,先做个记号,呵呵

出0入0汤圆

发表于 2009-3-18 16:17:08 | 显示全部楼层
ding

出0入0汤圆

发表于 2009-3-19 06:55:08 | 显示全部楼层
楼主厉害

出0入0汤圆

发表于 2009-3-21 09:25:21 | 显示全部楼层
佩服的五体投地,赞扬一个,一直在找USB上位机的编写指导,AT91S7x和STM32的USB这下可以好好玩玩上位机了,
谢谢楼主

出0入0汤圆

发表于 2009-3-25 17:28:26 | 显示全部楼层
mark

出0入4汤圆

发表于 2009-3-25 17:33:36 | 显示全部楼层
楼主很有前途,要招人就找楼主一样的人

出0入0汤圆

发表于 2009-3-25 18:48:40 | 显示全部楼层
赞!!!!!

出0入0汤圆

发表于 2009-4-8 09:16:39 | 显示全部楼层
不错不错~!杭电的师弟门~~前途无量啊~~

出0入21汤圆

发表于 2009-4-10 23:34:18 | 显示全部楼层
努力中……

出0入0汤圆

发表于 2009-4-30 10:54:39 | 显示全部楼层
有这样的经验,好多公司会抢着要的!!

出0入0汤圆

发表于 2009-4-30 12:32:06 | 显示全部楼层
强呵呵!

出0入0汤圆

发表于 2009-4-30 12:52:19 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-6-25 12:51:24 | 显示全部楼层
牛啊

出0入0汤圆

发表于 2009-6-25 12:56:26 | 显示全部楼层
牛啊

出0入0汤圆

发表于 2009-6-25 13:01:29 | 显示全部楼层
牛啊

出0入0汤圆

发表于 2009-6-25 13:06:31 | 显示全部楼层
牛啊

出0入0汤圆

发表于 2009-6-25 13:11:33 | 显示全部楼层
牛啊

出0入0汤圆

发表于 2009-6-26 10:29:07 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-6-30 09:59:14 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-7-11 11:15:59 | 显示全部楼层
恩,挺牛的丫!!!

出0入0汤圆

发表于 2009-7-11 11:23:41 | 显示全部楼层
赞一个~~

出10入95汤圆

发表于 2009-7-11 18:53:08 | 显示全部楼层
厉害!有钱途!

出0入0汤圆

发表于 2009-7-11 20:16:02 | 显示全部楼层
强悍

出0入0汤圆

发表于 2009-7-11 21:37:41 | 显示全部楼层
mark,学习价值

出0入0汤圆

发表于 2009-7-31 23:57:59 | 显示全部楼层
着实挺猛~~~~~~~~~顶

出0入0汤圆

发表于 2009-8-1 00:08:02 | 显示全部楼层
强!有时间再来细看

出0入0汤圆

发表于 2009-8-3 09:47:11 | 显示全部楼层
厉害!!!

出0入0汤圆

发表于 2009-9-26 20:10:49 | 显示全部楼层
不错的!!!

出0入0汤圆

发表于 2009-9-26 20:21:40 | 显示全部楼层
MARK!

出0入0汤圆

发表于 2009-9-27 19:09:18 | 显示全部楼层
不顶不好意思

出0入0汤圆

发表于 2009-10-2 13:28:51 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-10-21 17:00:38 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-11-4 19:14:30 | 显示全部楼层
牛啊
相当充实的一个大学生活~!

出0入0汤圆

发表于 2009-11-4 19:16:36 | 显示全部楼层
不错 牛人

出0入0汤圆

发表于 2009-11-9 16:35:51 | 显示全部楼层
两个人用了2个多月做出这么一个东西,硬件上简单,软件功能也很单一,规模不大;界面粗糙.楼主如果想做这行的话,还得继续努力.

出0入0汤圆

发表于 2009-12-3 23:25:00 | 显示全部楼层
楼上的口气倒不小.


顶楼主,如果连你们都找不到工作,那真没天理了

出0入0汤圆

发表于 2009-12-4 00:22:47 | 显示全部楼层
我觉得非常不错地说,学习

出0入0汤圆

发表于 2010-1-11 01:10:11 | 显示全部楼层
鄙视一下删除源代码的楼猪

出0入0汤圆

发表于 2010-1-28 11:07:14 | 显示全部楼层
不错的代码,我也是刚刚入门STM32。谢谢楼主

出0入0汤圆

发表于 2010-1-29 17:36:05 | 显示全部楼层
问LZ一个问题:ADC采样是需要等时间间隔的, 这期间最好没有中断打断ADC的采样, 而DMA和USB都有可能在任何时候产生中断,LZ是如何处理的?

出0入0汤圆

发表于 2010-1-29 17:51:17 | 显示全部楼层
记下啦~

出0入0汤圆

发表于 2010-1-29 19:06:42 | 显示全部楼层
好东西啊

出0入0汤圆

发表于 2010-1-30 11:25:12 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-2-3 23:49:23 | 显示全部楼层
mark一下。

出0入0汤圆

发表于 2010-2-14 17:27:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-3 17:48:51 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-3 18:19:51 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-3 20:35:56 | 显示全部楼层
好帖收藏

出0入0汤圆

发表于 2010-5-24 19:01:33 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-28 08:44:45 | 显示全部楼层
mark!厉害!

出0入14汤圆

发表于 2010-5-28 19:16:14 | 显示全部楼层
支持一下

出0入0汤圆

发表于 2010-5-28 19:35:46 | 显示全部楼层
23楼……

出0入0汤圆

发表于 2010-5-28 20:28:30 | 显示全部楼层
记号~~

出0入0汤圆

发表于 2010-5-29 16:43:37 | 显示全部楼层
好东东!学习了!

出0入0汤圆

发表于 2010-6-30 00:14:02 | 显示全部楼层
Mark 顶

出0入0汤圆

发表于 2010-7-20 09:02:24 | 显示全部楼层
好东西。

出0入0汤圆

发表于 2010-7-20 09:15:33 | 显示全部楼层
标记啦

出0入0汤圆

发表于 2010-7-20 09:20:30 | 显示全部楼层
标记啦

出0入0汤圆

发表于 2010-7-20 22:58:53 | 显示全部楼层
学习了啊!

出0入0汤圆

发表于 2010-7-20 23:14:06 | 显示全部楼层
标记啦

出0入0汤圆

发表于 2010-7-21 00:38:23 | 显示全部楼层
mark4

出0入0汤圆

发表于 2010-7-21 09:19:25 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-7-21 09:43:18 | 显示全部楼层
回复【23楼】hujintao
小伙子干得不错
-----------------------------------------------------------------------

老虎老碰厂了

出0入0汤圆

发表于 2010-7-21 16:14:01 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-8-5 00:29:13 | 显示全部楼层
不错 。。 不过搞这行累啊。。

出0入0汤圆

发表于 2010-9-24 08:02:04 | 显示全部楼层
very good....

出0入0汤圆

发表于 2010-9-24 08:09:40 | 显示全部楼层
very good   good

出0入0汤圆

发表于 2010-12-2 09:19:49 | 显示全部楼层
厉害

出0入0汤圆

发表于 2010-12-2 21:19:44 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-12-3 10:21:46 | 显示全部楼层
mark
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-24 19:03

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表