基于stm32f103zet6的DMA學習
stm32內(nèi)部集成的ADC介紹
一、參考電壓的范圍為
/*2.4V≦ V ≦3.6V
所以它的輸入模擬電壓范圍0 <= V <=V*/
二、需要測量負電壓或測量的電壓信號超出范圍時,要先經(jīng)過運算電路進行平移或利用電阻分壓。
三、我采用的是51單片機上面的10k的電阻來模擬輸入
四、規(guī)則通道和注入通道
/*所謂規(guī)則,那么就是按常理出牌的,我們可以稱之為正常的通道,那么與之對應的是注入通道,就是
在規(guī)則通道正在轉(zhuǎn)換的時候是可以被注入通道打斷,轉(zhuǎn)而去執(zhí)行注入通道轉(zhuǎn)換的,當注入通道轉(zhuǎn)換完
成之后,才繼續(xù)去進行規(guī)則通道里面的轉(zhuǎn)換,TM32ADC的規(guī)則通道組最多包含16 個轉(zhuǎn)換,而注入通道
組最多包含 4 個通道*/
五、初始化ADC這是必須的,比東有一個結構體來初始化這個ADC
1、首先確定從哪里輸入我們的模擬量呢?
這里涉及到ADC通道的知識,每個ADC通道都對應著一個GPIO引腳端口
PC0對應的默認復用功能是ADC1、ADC2、ADC3的通道10
所以最開始應該配置GPIO,現(xiàn)在可以來做個猜測
2、配置GPIO
GPIO_Mode = GPIO_Mode_AIN
GPIO_Pin = GPIO_Pin_10
GPIO_Speed = GPIO_Speed_50MHz
以上就是模擬輸入
六、然后是配置ADC,也就是初始化ADC了,
找到這樣一個結構體
ADC_InitTypeDef
結構體成員有{
FunctionalState ADC_ContinuousConvMode
uint32_t ADC_DataAlign
uint32_t ADC_ExternalTrigConv
uint32_t ADC_Mode
uint8_t ADC_NbrOfChannel
FunctionalState ADC_ScanConvMode
}
1、ADC_ContinuousConvMode的取值有
Specifies whether the conversion is performed in Continuous or Single mode.
This parameter can be set to ENABLE or DISABLE
此參數(shù)用來配置是否開啟循環(huán)采集ENABLE or DISABLE
2、ADC_DataAlign明顯意思是數(shù)據(jù)對齊,它的取值有
#define ADC_DataAlign_Left ((uint32_t)0x00000800)
#define ADC_DataAlign_Right ((uint32_t)0x00000000)
#define IS_ADC_DATA_ALIGN(ALIGN)
左對齊,右對齊。。
3、ADC_ExternalTrigConv外部中斷觸發(fā)方式?它的取值有
#define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO ((uint32_t)0x000C0000)
#define ADC_ExternalTrigConv_None ((uint32_t)0x000E0000)
#define ADC_ExternalTrigConv_T1_CC1 ((uint32_t)0x00000000)
#define ADC_ExternalTrigConv_T1_CC2 ((uint32_t)0x00020000)
#define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x00040000)
#define ADC_ExternalTrigConv_T2_CC2 ((uint32_t)0x00060000)
#define ADC_ExternalTrigConv_T2_CC3 ((uint32_t)0x00020000)
#define ADC_ExternalTrigConv_T3_CC1 ((uint32_t)0x00000000)
#define ADC_ExternalTrigConv_T3_TRGO ((uint32_t)0x00080000)
#define ADC_ExternalTrigConv_T4_CC4 ((uint32_t)0x000A0000)
#define ADC_ExternalTrigConv_T5_CC1 ((uint32_t)0x000A0000)
#define ADC_ExternalTrigConv_T5_CC3 ((uint32_t)0x000C0000)
#define ADC_ExternalTrigConv_T8_CC1 ((uint32_t)0x00060000)
#define ADC_ExternalTrigConv_T8_TRGO ((uint32_t)0x00080000)
觸發(fā)方式很豐富,當然 ADC_ExternalTrigConv_None這就表示不采用外部中斷方式觸發(fā)(那么軟件觸發(fā))
4、ADC_Mode ADC的模式?
Configures the ADC to operate in independent or dual mode.
This parameter can be a value of ADC_mode
它的取值有
#define ADC_Mode_AlterTrig ((uint32_t)0x00090000)
#define ADC_Mode_FastInterl ((uint32_t)0x00070000)
#define ADC_Mode_Independent ((uint32_t)0x00000000)
#define ADC_Mode_InjecSimult ((uint32_t)0x00050000)
#define ADC_Mode_InjecSimult_FastInterl ((uint32_t)0x00030000)
#define ADC_Mode_InjecSimult_SlowInterl ((uint32_t)0x00040000)
#define ADC_Mode_RegInjecSimult ((uint32_t)0x00010000)
#define ADC_Mode_RegSimult ((uint32_t)0x00060000)
#define ADC_Mode_RegSimult_AlterTrig ((uint32_t)0x00020000)
#define ADC_Mode_SlowInterl ((uint32_t)0x00080000)
貌似是有注入組、和規(guī)則組的概念,有些單詞不是很熟悉,沒關系那就先這樣吧!用到了再來
5、ADC_NbrOfChannel采樣通道?
明顯一般采用的是是16個規(guī)則通道,那取值就是1--16
Specifies the number of ADC channels that will be converted using the sequencer for regular
channel group.This parameter must range from 1 to 16
6、ADC_ScanConvMode,字面意思不是很懂,看手冊
Specifies whether the conversion is performed in Scan (multichannels) or Single (one channel)
mode. This parameter can be set to ENABLE or DISABLE
意思是當有多個通道的時候,使用掃描的方式,反之只有單個通道的是那么就是選擇單通道了
那么取值就是ENABLE or DISABLE
至此結構成員分析完畢,下面來猜測一下,應該怎樣賦值,聲明:單通道采集,右對齊(方便存數(shù)據(jù))
軟件觸發(fā),通道采用10(使用PC0)
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None
ADC_InitStructure.ADC_Mode= ADC_Mode_Independent
ADC_InitStructure.ADC_NbrOfChannel = 11
ADC_InitStructure.ADC_ScanConvMode = DISABLE
下面來對照下,原始代碼看看:
/* ADC1 configuration */
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
顯然錯誤還是比較多的,沒關系,慢慢分析
1、因為是一個通道沒必要掃描,所以第2個錯了
2、通道數(shù)目理解錯誤。我以為那是指定的哪個通道,原來是number of channel
3、好的最后就是少了一個庫函數(shù)的調(diào)用,這確實是缺乏這種意識呀!
七、既然是使用DMA來傳送數(shù)據(jù),那么下一步就開始初始化DMA吧!DMA的知識暫時不分析,那個得單獨出來
我還是先來了解下DMA的變成思想吧!
1、STM32就是這樣完美,每個模塊都能有個結構體來組織它的一些參數(shù)配置,我甚至覺得它和uboot一樣討人喜歡
這只是我的愚見,也是這樣一個結構體 DMA_InitTypeDef DMA_InitStructure;
跟著手冊來吧
2、DMA_InitTypeDef{
uint32_t DMA_BufferSize
uint32_t DMA_DIR
uint32_t DMA_M2M
uint32_t DMA_MemoryBaseAddr
uint32_t DMA_MemoryDataSize
uint32_t DMA_MemoryInc
uint32_t DMA_Mode
uint32_t DMA_PeripheralBaseAddr
uint32_t DMA_PeripheralDataSize
uint32_t DMA_PeripheralInc
uint32_t DMA_Priority
}
3、DMA_BufferSize,明顯就是數(shù)據(jù)的大小,看她是怎么描述的
Specifies the buffer size, in data unit, of the specified Channel. The data unit is equal to
the configuration set in DMA_PeripheralDataSize or DMA_MemoryDataSize members depending in
the transfer direction
可以得出DMA_PeripheralDataSize = DMA_MemoryDataSize = DMA_BufferSize
取值可以是
#define DMA_MemoryDataSize_Byte ((uint32_t)0x00000000)
#define DMA_MemoryDataSize_HalfWord ((uint32_t)0x00000400)
#define DMA_MemoryDataSize_Word ((uint32_t)0x00000800)
4、DMA_DIR字面意思不怎么明朗方向?看解釋
Specifies if the peripheral is the source or destination. This parameter can be a value of
DMA_data_transfer_direction
數(shù)據(jù)源和目的源
取值
#define DMA_DIR_PeripheralDST ((uint32_t)0x00000010)
#define DMA_DIR_PeripheralSRC ((uint32_t)0x00000000
從存儲器到外設或者從外設到存儲器
5、DMA_M2M 這個可以猜測到,DMA的作用出了上面一個還有M to M的沒有提及那么
#define DMA_M2M_Disable ((uint32_t)0x00000000)
#define DMA_M2M_Enable ((uint32_t)0x00004000)
可以這樣設置了
6、DMA_MemoryBaseAddr、DMA_PeripheralBaseAddr
這兩個可以一起看了,字面意思很清楚了,外設地址和存儲器(變量)地址,這個得看你的地址了
7、DMA_MemoryInc、DMA_PeripheralInc看變量名不是很了解,中斷觸發(fā)么?看解釋
Specifies whether the memory address register is incremented(adj.增加的) or not.
This parameter can be a value of DMA_memory_incremented_mode
地址增加?理解嚴重錯誤,那么就是地址遞增的意思吧,那就是可以連續(xù)采集多個通道咯?繼續(xù)分析
8、DMA_Mode:DMA的模式,他有什么模式呢?看解釋
Specifies the operation mode of the DMAy Channelx.
This parameter can be a value of DMA_circular_normal_mode
還有一句:The circular buffer mode cannot be used if the memory-to-memory
data transfer is configured on the selected Channel
取值有
#define DMA_Mode_Circular ((uint32_t)0x00000020)
#define DMA_Mode_Normal ((uint32_t)0x00000000)
正常和循環(huán)模式,難道是輪采?先這樣繼續(xù)
9、DMA_Priority優(yōu)先級這個就好理解了,不就是控制優(yōu)先權么看解釋以及取值
Specifies the software priority for the DMAy Channelx. This parameter can be
a value of DMA_priority_level
取值
#define DMA_Priority_High ((uint32_t)0x00002000)
#define DMA_Priority_Low ((uint32_t)0x00000000)
#define DMA_Priority_Medium ((uint32_t)0x00001000)
#define DMA_Priority_VeryHigh ((uint32_t)0x00003000
很明朗4個優(yōu)先級
至此,分析完畢,嘗試性猜測
1、DMA_InitStructure.DMA_BufferSize= 1
2、DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST
3、DMA_InitStructure.DMA_M2M = DMA_M2M_Disable
4、DMA_InitStructure.DMA_MemoryBaseAddr = 一個地址單元的變量單字節(jié) 可以使char型的
5、DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte
6、DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable 不需要地址增量
7、DMA_InitStructure.DMA_Mode = DMA_Mode_Circular 不停的采
8、DMA_InitStructure.DMA_PeripheralBaseAddr = 串口的地址?
9、DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte
10、DMA_InitStructure.MA_PeripheralInc = DMA_PeripheralInc_Disable 同樣的
11、DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh 給最高的
查看源代碼
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
貌似有點不妙的感覺
1、MA_InitStructure.DMA_DIR這個明顯是作為數(shù)據(jù)源
2、DMA_MemoryDataSize_Byte和DMA_PeripheralDataSize_HalfWord有什么區(qū)別
百度里面我沒有找到,先這樣,等做完實驗再驗證
八、結構體成員初始化完畢之后,還有很多工作要做
1、 /* ADC1 regular channel11 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
配置規(guī)則通道11
2、 /* Enable DMA channel1 */
DMA_Cmd(DMA1_Channe10, ENABLE);
使能DMA通道
3、 /* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
使能ADC1的DMA控制器
4、 /* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
使能ADC1
5、 /* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));//復位校準
/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));//校準
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//軟件觸發(fā),這時候真正開始轉(zhuǎn)換
硬件測試后,結果正確的!