免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
stm32多通道ADC波形采集

stm32多通道ADC波形采集

(2012-04-18 12:50:05)
標(biāo)簽:

雜談


int main(void)
{
#ifdef DEBUG
debug();
#endif



RCC_Configuration();



NVIC_Configuration();



GPIO_Configuration();


LcdShow_Init();



DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;//外設(shè)地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_RCVTab;//內(nèi)存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//dma傳輸方向單向
DMA_InitStructure.DMA_BufferSize = 160;//設(shè)置DMA在傳輸時緩沖區(qū)的長度 word
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//設(shè)置DMA的外設(shè)遞增模式,一個外設(shè)
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//設(shè)置DMA的內(nèi)存遞增模式,
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外設(shè)數(shù)據(jù)字長
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//內(nèi)存數(shù)據(jù)字長
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//設(shè)置DMA的傳輸模式:連續(xù)不斷的循環(huán)模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//設(shè)置DMA的優(yōu)先級別
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//設(shè)置DMA的2個memory中的變量互相訪問
DMA_Init(DMA1_Channel1, &DMA_InitStructure);


DMA_Cmd(DMA1_Channel1, ENABLE);



ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//獨(dú)立工作模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE;//掃描方式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//連續(xù)轉(zhuǎn)換
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//外部觸發(fā)禁止
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//數(shù)據(jù)右對齊
ADC_InitStructure.ADC_NbrOfChannel = 8;//用于轉(zhuǎn)換的通道數(shù)
ADC_Init(ADC1, &ADC_InitStructure);



ADC_RegularChannelConfig(ADC1, ADC_Channel_8 , 1, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_9 , 2, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 3, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 4, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 5, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 6, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 7, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 8, ADC_SampleTime_239Cycles5);



ADC_DMACmd(ADC1, ENABLE);


ADC_Cmd(ADC1, ENABLE);



ADC_ResetCalibration(ADC1);

while(ADC_GetResetCalibrationStatus(ADC1));



ADC_StartCalibration(ADC1);

while(ADC_GetCalibrationStatus(ADC1));


ADC_SoftwareStartConvCmd(ADC1, ENABLE);

while(1)
{
vu16 value1 = 0;
vu16 value2 = 0;
vu16 value3 = 0;
vu16 value4 = 0;
vu16 value5 = 0;
vu16 value6 = 0;
vu16 value7 = 0;
vu16 value8 = 0;
value1 = average(ADC_RCVTab,0);
value2 = average(ADC_RCVTab,1);
value3 = average(ADC_RCVTab,2);
value4 = average(ADC_RCVTab,3);
value5 = average(ADC_RCVTab,4);
value6 = average(ADC_RCVTab,5);
value7 = average(ADC_RCVTab,6);
value8 = average(ADC_RCVTab,7);

u8 num1 = value3 % 10;
u8 num2 = (value3 / 10) % 10;
u8 num3= (value3 / 100) % 10;
u8 num4 = value3 / 1000;
if (num1 > 9)
display[3] = num1 + (65 - 10);
else
display[3] = num1 + (48-0);


if (num2 > 9)
display[2] = num2 +(65 - 10);
else
display[2] = num2 + (48 - 0);


if (num3>9)
display[1]=num3+(65-10);
else
display[1]=num3+(48-0);


if (num4>9)
display[0]=num4+(65-10);
else
display[0]=num4+(48-0);


write_string(display);
delay();
}
}

u16 average(vu16 ADCDataTab[], u16 nChannel) { u16 averagevalue=0, maxvalue=0, minvalue=0xFFFF, i; for (i=0;i<20;i++) { averagevalue+=*(ADCDataTab+nChannel+i*8); if(*(ADCDataTab+nChannel+i*8)>maxvalue) maxvalue=*(ADCDataTab+nChannel+i*8); if(*(ADCDataTab+nChannel+i*8)


方波的圖形好像不是很漂亮?xí)猩仙乩鲜怯屑獯?,還需要作軟件做處理。沒截出來,
最后能出數(shù)據(jù)離不開很多前輩的經(jīng)驗。有些地方是借鑒了他們的東西。現(xiàn)在先列出來。
第一個是 21IC 上面 alien2006 原帖地址。他也是做了一個簡易示波器,但是用的是以太網(wǎng)傳輸。采集部分我很多借鑒了他的方案。

第二個是電腦圈圈,他對 USB 的理解令我欽佩。我能搞出驅(qū)動,他提供的源碼包非常重要,有些代碼也是直接在他的基礎(chǔ)上修改的。

2 整體方案
先說下一次完整的采集,比如外面進(jìn)來的波形是正弦波,波形電壓有正負(fù), STM32 單片機(jī)的 AD 只能采集 0~3.6V 的電壓,所以要對信號進(jìn)行處理。也就是需要一個模擬前端電路,把電壓抬上去。接著就是采集了, STM32 AD 可以用外設(shè)進(jìn)行觸發(fā),這里用定時器進(jìn)行觸發(fā)。每過一個單位時間 AD 開啟一次,采集一個點(diǎn),這樣采集的頻率只要調(diào)整這個單位時間也就是定時器就可以控制了。采集了一楨數(shù)據(jù),比如 200 個點(diǎn)。 DMA 中斷被觸發(fā),開啟 USB ,把數(shù)據(jù)發(fā)送到上位機(jī),然后顯示出來。
整個過程大體就是這樣了,還有一個很重要的環(huán)節(jié)補(bǔ)充下。熟悉示波器的人都知道示波器有個觸發(fā)概念。像剛才這樣顯示的話,比如前一幀數(shù)據(jù)是波峰開始顯示,后一幀是波谷開始。這樣顯示出來的波形就是亂的,于是為了解決這個問題,就需要做觸發(fā),也就是保證每次采集的起始電位相同。我們的采用的是用外中斷的形式,外面波形數(shù)據(jù)先不采集,先讓它通過一個比較器,比如比較器的基準(zhǔn)電壓是 1V ,也就是每次都和 1V 比較,低于 1V 輸出低電平,高于 1V 輸出高電平。當(dāng)數(shù)據(jù)電壓大于 1V 的時候,比較器輸出高電平,高電平接到單片機(jī)外中斷口,這樣外中斷就被觸發(fā)。然后開始采集,這樣就能保證每幀數(shù)據(jù)的起始點(diǎn)都相同。
這個方案是大體方案,后來做了下修改。就是讓 AD 一直在采集。外中斷觸發(fā)了后開啟的是 DMA AD 一直開著,只是控制 DMA 什么時候去取。從哪里開始取,取多少個點(diǎn)。下位機(jī)部分不再詳說,貼下主要的程序,大俠們隨便看看,多多指教。
定時器設(shè)置代碼如下:

void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;

TIM_DeInit(TIM2); //TIM2初始化


TIM_TimeBaseStructure.TIM_Period = 18; //設(shè)置了下一個更新事件裝入活動的自動重裝載寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler = 0; //設(shè)置了用來作為 TIMx 時鐘頻率除數(shù)的預(yù)分頻值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置了時鐘分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //選擇了計數(shù)器模式向上計數(shù)

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根據(jù) TIM_TimeBaseInitStruct 中指定的參數(shù)初始化 TIMx


// TIM_PrescalerConfig(TIM2, 1, TIM_PSCReloadMode_Update); //設(shè)置 TIMx 重載次數(shù) 預(yù)分頻值在更新事件裝入


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 上的自動裝載寄存器


TIM_Cmd(TIM2, ENABLE); //使能 TIMx 外設(shè)
}
AD以及 DMA 設(shè)置代碼:

void ADC_Configuration(void)
{

DMA_DeInit(DMA_Channel1); //復(fù)位 DMA_Channel1
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //外圍設(shè)備地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_Data[0]; //memory 地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外圍設(shè)備做為源
DMA_InitStructure.DMA_BufferSize = 1024; //數(shù)據(jù)單元尺寸
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外圍地址是否自動增長 disable 不增長
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //memory 是否自動增長
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外圍設(shè)備寄存器尺寸 16
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //memory尺寸 16
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA 循環(huán)模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA 通道優(yōu)先級
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //memory- to-memory轉(zhuǎn)換
DMA_Init(DMA_Channel1, &DMA_InitStructure); //初始化 DMA 通道 1


DMA_ITConfig(DMA_Channel1, DMA_IT_TC, ENABLE); //使能 DMA 傳輸完成中斷


ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC 工作模式 ADC1 ADC2 單獨(dú)工作
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //多通道掃描模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //是否啟用連續(xù)轉(zhuǎn)換模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //觸發(fā)方式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //數(shù)據(jù)右對齊
ADC_InitStructure.ADC_NbrOfChannel = 1; //ADC規(guī)則轉(zhuǎn)換通道數(shù)量
ADC_Init(ADC1, &ADC_InitStructure);

//配置轉(zhuǎn)換規(guī)則
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_1Cycles5);


ADC_DMACmd(ADC1, ENABLE);


ADC_Cmd(ADC1, ENABLE);


ADC_ResetCalibration(ADC1); //復(fù)位 ADC1 校準(zhǔn)

while(ADC_GetResetCalibrationStatus(ADC1)); //等待復(fù)位完成


ADC_StartCalibration(ADC1); //開始 ADC1 校準(zhǔn)轉(zhuǎn)換

while(ADC_GetCalibrationStatus(ADC1)); //等待轉(zhuǎn)換完成

ADC_ExternalTrigConvCmd( ADC1, ENABLE); //使能或者失能 ADCx 的經(jīng)外部觸發(fā)啟動轉(zhuǎn)換功能
}

DMA中斷服務(wù)程序:

void DMAChannel1_IRQHandler(void)
{
DMA_Cmd(DMA_Channel1, DISABLE); //關(guān)閉 DMA 通道 1
for(count=64;count<1024;count++) //AD數(shù)據(jù)轉(zhuǎn)換處理
{
AD_Data[count]=(ADC_Data[count]*330)/4096;
}
flag_usb = 1; //usb標(biāo)志位置 1 ,使能 usb 發(fā)送
DMA_ClearITPendingBit(DMA_IT_TC1);
}

下面就開始說我做的部分, USB 部分。一共有 3 個地方,
1 USB 固件程序的開發(fā)
2 Windows XP USB 設(shè)備驅(qū)動的開發(fā)
3 )對應(yīng)的 PC 上的應(yīng)用程序開發(fā)。
下面來詳細(xì)論述。

3 USB固件程序的開發(fā)
這部分主要設(shè)計 USB 的協(xié)議。一共花了兩個星期時間,是我們做的最開心的兩個星期。因為是兩個人一起來研究,導(dǎo)師崔也經(jīng)常跑過來討論。最后測出來的傳輸速度是 700-800K ,依據(jù) USB2.0 全速理論最大速度 12Mbps ,除以八大概是 1M 多,基本把速度都開發(fā)出來了。期間參考了 ouravr 里面的一個叫極速狂飆的帖子,也成功開啟了雙緩沖。
固件程序主要是根據(jù)萬利板子提供的 4 USB 程序中的那個 USB 轉(zhuǎn)串程序修改的,主要是修改兩個文件。第一個是 usb_desc.c ,這個文件里面配置了全部的描述符。這些描述符在 USB2.0 協(xié)議里面都有嚴(yán)格的定義,跟著配置就好了。
const u8 Virtual_Com_Port_DeviceDescriptor[] =
{
0x12,
USB_DEVICE_DESCRIPTOR_TYPE,
0x00,
0x02,

0xFF,
0xFF,
0x00,
0x40,
0x44,
0x44,
0x33,
0x33,
0x00,
0x02,
1,
2,
3,
0x01
};

const u8 Virtual_Com_Port_ConfigDescriptor[] =
{

0x09,
USB_CONFIGURATION_DESCRIPTOR_TYPE,
VIRTUAL_COM_PORT_SIZ_CONFIG_DESC,
0x00,
0x01,
0x01,
0x00,
0xC0,
0x00,



0x09,
USB_INTERFACE_DESCRIPTOR_TYPE,
0x00,
0x00,
0x02,
0xFF,
0xFF,
0x00,
0x00,



0x07,
USB_ENDPOINT_DESCRIPTOR_TYPE,
0x03,
0x02,
0x02,
0x00,
0x00,


0x07,
USB_ENDPOINT_DESCRIPTOR_TYPE,
0x81,
0x02,
0x40,
0x00,
0x00

};


const u8 Virtual_Com_Port_StringLangID[VIRTUAL_COM_PORT_SIZ_STRING_LANGID] =
{
VIRTUAL_COM_PORT_SIZ_STRING_LANGID,
USB_STRING_DESCRIPTOR_TYPE,
0x09,
0x04
};

const u8 Virtual_Com_Port_StringVendor[VIRTUAL_COM_PORT_SIZ_STRING_VENDOR] =
{
VIRTUAL_COM_PORT_SIZ_STRING_VENDOR,
USB_STRING_DESCRIPTOR_TYPE,

'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,
USB_STRING_DESCRIPTOR_TYPE,

'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,
USB_STRING_DESCRIPTOR_TYPE,
'D', 0, 'e', 0, 'm', 0, 'o', 0, ' ', 0, '1', 0, '.', 0, '0', 0,
'0', 0, '0', 0
}
有些字符沒有修改還是原來DEMO 的,大家將就著看看。
還有就是Usb_prop.c 里面這個函數(shù)

void Virtual_Com_Port_Reset(void) //USBIP復(fù)位過程,當(dāng)宏單元收到 RESET 信號時調(diào)用,
{ //用戶程序在此過程中設(shè)置端點(diǎn)

pInformation->Current_Configuration = 0;


pInformation->Current_Interface = 0;
SetBTABLE(BTABLE_ADDRESS);


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);


SetEPType(ENDP1, EP_BULK); //設(shè)置端點(diǎn) 1 傳輸模式批量傳輸
SetEPTxAddr(ENDP1, ENDP1_TXADDR); //緩沖區(qū)基地址 (IN 發(fā) )
SetEPTxCount(ENDP1, 64); //配置 Tx 緩沖計數(shù)器
SetEPTxStatus(ENDP1, EP_TX_VALID); //設(shè)置端點(diǎn)發(fā)送有效
SetEPRxStatus(ENDP1, EP_RX_DIS); //設(shè)置端點(diǎn)接收關(guān)閉


SetEPType(ENDP3, EP_BULK); //設(shè)置端點(diǎn) 3 傳輸模式批量傳輸
SetEPRxAddr(ENDP3, ENDP3_RXADDR); //緩沖區(qū)基地址 (OUT )
SetEPRxCount(ENDP3, 2); //配置 Rx 緩沖計數(shù)器
SetEPRxStatus(ENDP3, EP_RX_VALID); //設(shè)置端點(diǎn)接收有效
SetEPTxStatus(ENDP3, EP_TX_DIS); //端點(diǎn)關(guān)閉發(fā)送


SetDeviceAddress(0);
}要配置下。就是你開啟的那些端點(diǎn)了。

4 Windows XP USB 設(shè)備驅(qū)動的開發(fā)
這部分是最麻煩的,至少對我來說是這樣的,好像已經(jīng)到了計算機(jī)專業(yè)范疇,而我對這些非常不熟悉。學(xué)習(xí)期間第一個方案用的是 LABVIEW ,它附帶一個工具叫 VISA ,可以直接配置成 USB 驅(qū)動,然后再在 LABVIEW 里面直接調(diào)用,很方便。在研究 LABVIEW 的時候發(fā)現(xiàn)里面有很多 DEMO ,而且對中文的支持非常好,很多文檔都是官方直接出中文文檔。(好像半導(dǎo)體大額們對中國這塊市場都越來越重視了,前幾天看到 AVR 大部分的文檔也都是直接官方翻譯的中文文檔。)學(xué)習(xí)了軟件里面附帶的入門教程,大概也能編一些簡單的程序了,調(diào)試 USB 的時候發(fā)現(xiàn)里面有幾個 USB demo ,配合 VISA 生成的驅(qū)動居然直接接收到了下面?zhèn)魃蟻淼臄?shù)據(jù),這對我們來說無異于是一次莫大的鼓勵。后來導(dǎo)師推薦我試試另一種方法,就是用 Driverstudio+VC 來開發(fā)驅(qū)動和編寫界面。為了學(xué)習(xí)一下 USB 的驅(qū)動開發(fā),于是在第三個星期的時候開始 windows 下驅(qū)動的開發(fā)。老實說吃了很多苦頭,到現(xiàn)在雖然功能基本實現(xiàn)了,但是對于這一塊我還是只知道皮毛。 DS 里面的那些類和函數(shù)也沒怎么搞透,驅(qū)動能開發(fā)出來主要還是借鑒了 DS 附帶的 example 里面的 USB BULK 程序。
下面大概講下我遇到過的問題給后來人一點(diǎn)借鑒:

1 )是安裝順序的問題,因為 DriverStudio 要嵌入到 VC 中,以后的代碼要用 DDK 來編寫所以三個軟件要很好的兼容才可以。
第一步:安裝Microsoft Visual C++6.0 ;
第二步:安裝Microsoft Windows XP DDK ;
第三步:安裝DriverStudio 3.2 驅(qū)動程序開發(fā)工具包。
VC6.0最好安裝英文版的,可以減少不知名的錯誤。安裝完成后 DS3.2 會嵌入到 VC 中,在上面多一個標(biāo)題:
DriverStudio選項卡下面第三項 DDK Build setting 要設(shè)置成 C:\WINDDK\2600 (如果 DDK 安裝在 C 盤),然后要編譯 DriverStudio 安裝目錄下 DriverStudio\DriverWorks\source\VdwLibs.dsw ,以得到 vdw_wdm.lib 這個庫文件。編譯的時候會出現(xiàn)錯誤,因為用 VC 打開 vdwlibs.dsw 工程文件后,有兩個工程,要先將 VdwLibs 工程設(shè)為當(dāng)前 Active Project ,然后在工具欄上單擊右鍵選擇 組建 ,在彈出的編譯工具欄中配置一下編譯平臺的設(shè)置:選擇 Win32 WDM Checked 平臺(因為我們用的 XP ),然后編譯就應(yīng)該可以了。

2 )是利用向?qū)沈?qū)動程序框架
DS有個 DriverWizard 可以生成驅(qū)動程序的大體框架。
第一步:選擇開發(fā)環(huán)境VC6.0 ,命名。
第二步:選擇WDM Driver 不用修改。
第三步:選擇WDM Function Driver
第四步:選擇USB 并設(shè)置好 PID VID 要與固件里面的設(shè)置相同
第五步:設(shè)置端點(diǎn),以及緩沖區(qū)。也要和固件里面相對應(yīng)。
接下午幾步可以根據(jù)自己來設(shè)置,也可以默認(rèn)。完成后會生成一個工程目錄,里面包含了兩個工程,一個是驅(qū)動,是我們需要的。另一個是測試程序,好像沒有用。當(dāng)你編譯驅(qū)動的時候,會提示有錯誤,這是因為 DS 里面的一個 BUG ,選擇 project-setting ,左邊兩個工程選驅(qū)動那個,點(diǎn)右邊 LINK 選項卡,刪除 Object/library module 項的 ntstrsafe.lib 。再編譯就能通過了。
3 )接下去就是對剛才生成的框架進(jìn)行研究,添加一些代碼以使驅(qū)動完整。
首先來了解下生成的框架。
DriverEntry()該例程是當(dāng)系統(tǒng)檢測到與驅(qū)動程序支持的設(shè)備時被調(diào)用的。
AddDevice() 該例程為系統(tǒng)添加一個設(shè)備。
Unload() 該例程為系統(tǒng)卸載設(shè)備。
以上幾個例程都存在于 XXXXDriver.cpp 是設(shè)備的基本操作可以直接使用生成的代碼,不用修改。
在另一個文件 XXXXDevice.cpp 中包含了具體應(yīng)用函數(shù),比如 read write ,但是這個文件也存在這一個 BUG ,在開頭部分有 m_Pipe1_in.Initialize(m_Lower, 0x81, 64); m_Pipe2_out.Initialize(m_Lower, 3, 64); 本次定義了兩個端點(diǎn),一個是叫 m_Pipe1_in 0x81 表示這個管道的屬性是入( in ),緩沖區(qū)是 64. 下面一個是 m_Pipe2_out 表示是出( out ),緩沖區(qū)是 64. 向?qū)傻拇a里面漏掉了 “0x” 這兩個字符。
關(guān)鍵部分代碼的添加
上位機(jī)應(yīng)用程序,主要是通過兩種方式來控制驅(qū)動,一個是 DeviceIoControl ()函數(shù),另一個是 ReadFile ()函數(shù)和 WriteFile ()函數(shù)。本次使用的是后者。只要在 Read(KIrp I) ,和 Write(KIrp I) 里面添加相應(yīng)的代碼就可以。這方面可以參考 DS3.2 附帶的 example 里面的那個 usbbulk 例程。
首先簡述一下完成一次驅(qū)動調(diào)用所要做的具體工作。應(yīng)用程序想對 USB 設(shè)備進(jìn)行 I/O 操作,它需調(diào)用 Windows API 函數(shù)比如 readfile (), I/O 管理器將此請求構(gòu)造成一個合適的 I/O 請求包( IRP )并把它傳遞給 USB 設(shè)備驅(qū)動程序。 USB 設(shè)備驅(qū)動程序接收到這個 IRP 后,根據(jù) IPR 中包含的具體操作代碼構(gòu)造相應(yīng) USB 請求塊( URB ),并把它放到一個新的 IRP 中,然后傳遞給 USB 底層驅(qū)動程序(中間層或總線驅(qū)動程序)。 USB 底層驅(qū)動程序根據(jù) IRP 中所含的 URB 執(zhí)行相應(yīng)的操作,并把操作的結(jié)果返回給 USB 設(shè)備驅(qū)動程序。 USB 設(shè)備驅(qū)動程序接收到此返回的 IRP 后,將操作結(jié)果通過 IRP 返還給 I/O 管理器,最后 I/O 管理器將此 IRP 操作結(jié)果傳回給應(yīng)用程序,至此應(yīng)用程序?qū)υO(shè)備的一次 I/O 操作完成。當(dāng)上位機(jī)調(diào)用的 ReadFile ()的時候, USB 設(shè)備驅(qū)動程序要根據(jù) IPR 中包含的具體操作代碼構(gòu)造相應(yīng) USB 請求塊( URB ),這個 URB 的生成就在這里實現(xiàn),比如例程里面的
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
);
主要是通過這個函數(shù)來實現(xiàn)。函數(shù)實現(xiàn)了之后會有不同的返回值,然后打印出不同的信息。這些信息可以在 DS 調(diào)試工具 Monitor 中看到。

5 驅(qū)動開發(fā)的過程大概就是這樣了。下面是應(yīng)用程序的開發(fā)。主要兩步,先打開設(shè)備,然后讀寫數(shù)據(jù)。
1 )打開設(shè)備
Windows下面有很多針對驅(qū)動調(diào)用的 API 函數(shù),要調(diào)用一個 USB 設(shè)備首先就要打開這個設(shè)備,其對應(yīng)的 API 函數(shù)為 CreateFile ,在本次驅(qū)動中 DS 自動生成了一個 OpenByInterface.c 文件,在該文件里面對這個 CreateFile 函數(shù)進(jìn)行了封裝,其參數(shù)如下
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
)
所以在主程序中只要調(diào)用OpenByInterface 函數(shù)就可以了。本次中具體實現(xiàn)的代碼如下:
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("打開設(shè)備失敗 !",NULL,MB_OK | MB_ICONHAND);
}
else
{
MessageBox("打開設(shè)備成功 !",NULL,MB_OK | MB_ICONASTERISK);
}
}
其中GUID* pClassGuid 是對應(yīng)的設(shè)備的 GUID ,具體定義如下:
GUID g_UsbGuid=GUID_DEVINTERFACE_USB;//打開設(shè)備的 GUID
其中GUID_DEVINTERFACE_USB 是在 DS 生成的 Intrface.h 文件中定義的,
#define GUID_DEVINTERFACE_USB \
{ 0x6C8CFFA6, 0xCAB8, 0x45B1, { 0xAA, 0xEE, 0x1E, 0xF4, 0xDF, 0x79, 0xF8, 0xDF } }
這個ID 保證了每個 USB 驅(qū)動的唯一性,調(diào)用紊亂的情況的出現(xiàn)。 OpenByInterface 這個函數(shù)有一個返回值,通過的改變可以確認(rèn)設(shè)備是否打開成功,然后通過 MessageBox 函數(shù)跳出不同的反饋信息。
2 )讀寫數(shù)據(jù)
Windows中讀取數(shù)據(jù)的 API 函數(shù)有兩種,一種是 DeviceIoControl ,一種是 ReadFile WriteFile 函數(shù)。前者一個函數(shù)可以讀也可以寫,后者把讀寫分開來,這次使用的是后者。
ReadFile的具體實現(xiàn)如下:
ReadFile(
g_hUsbDevice, //我們的設(shè)備 HANDLE hFile
DataBuffer,//輸入緩沖,無 lpBuffer
64, //輸出字節(jié)數(shù) nNumberOfBytesToRead,
&BytesReturned, //實際讀取到的字節(jié)數(shù) lpNumberOfBytesRead,
NULL
)
g_hUsbDevice是對應(yīng)我們的設(shè)備, DataBuffer 是我們定義的數(shù)組,讀取到的數(shù)據(jù)就存在這個數(shù)組中, 64 是一次讀取的字節(jié)數(shù), BytesReturned 是實際讀取到的字節(jié)數(shù),最后一個可以默認(rèn)為 NULL 。如果成功讀取到了數(shù)據(jù),數(shù)組 DataBuffer 中的數(shù)據(jù)就會更新,然后可以做任意處理。
寫數(shù)據(jù)基本和讀取數(shù)據(jù)類似。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
用STM32的高速AD和USB2.0做簡易示波器 (轉(zhuǎn)載自網(wǎng)絡(luò)) 格式調(diào)整過
用STM32內(nèi)置的高速ADC實現(xiàn)簡易示波器 - 『STM32』 - 『 ARM論壇 』 -...
Cortex-m3啟動代碼分析筆記
STM32F1系列之常用外設(shè)說明
USB的“JoyStickMouse”工作過程詳細(xì)分析 (一)
U盤實現(xiàn)流程跟蹤分析01
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服