基于stm32f103zet6的DMA學(xué)習(xí)
stm32內(nèi)部集成的ADC介紹
一、參考電壓的范圍為
/*2.4V≦ V ≦3.6V
所以它的輸入模擬電壓范圍0 <= V <=V*/
二、需要測(cè)量負(fù)電壓或測(cè)量的電壓信號(hào)超出范圍時(shí),要先經(jīng)過(guò)運(yùn)算電路進(jìn)行平移或利用電阻分壓。
三、我采用的是51單片機(jī)上面的10k的電阻來(lái)模擬輸入
四、規(guī)則通道和注入通道
/*所謂規(guī)則,那么就是按常理出牌的,我們可以稱(chēng)之為正常的通道,那么與之對(duì)應(yīng)的是注入通道,就是
在規(guī)則通道正在轉(zhuǎn)換的時(shí)候是可以被注入通道打斷,轉(zhuǎn)而去執(zhí)行注入通道轉(zhuǎn)換的,當(dāng)注入通道轉(zhuǎn)換完
成之后,才繼續(xù)去進(jìn)行規(guī)則通道里面的轉(zhuǎn)換,TM32ADC的規(guī)則通道組最多包含16 個(gè)轉(zhuǎn)換,而注入通道
組最多包含 4 個(gè)通道*/
五、初始化ADC這是必須的,比東有一個(gè)結(jié)構(gòu)體來(lái)初始化這個(gè)ADC
1、首先確定從哪里輸入我們的模擬量呢?
這里涉及到ADC通道的知識(shí),每個(gè)ADC通道都對(duì)應(yīng)著一個(gè)GPIO引腳端口
PC0對(duì)應(yīng)的默認(rèn)復(fù)用功能是ADC1、ADC2、ADC3的通道10
所以最開(kāi)始應(yīng)該配置GPIO,現(xiàn)在可以來(lái)做個(gè)猜測(cè)
2、配置GPIO
GPIO_Mode = GPIO_Mode_AIN
GPIO_Pin = GPIO_Pin_10
GPIO_Speed = GPIO_Speed_50MHz
以上就是模擬輸入
六、然后是配置ADC,也就是初始化ADC了,
找到這樣一個(gè)結(jié)構(gòu)體
ADC_InitTypeDef
結(jié)構(gòu)體成員有{
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ù)用來(lái)配置是否開(kāi)啟循環(huán)采集ENABLE or DISABLE
2、ADC_DataAlign明顯意思是數(shù)據(jù)對(duì)齊,它的取值有
#define ADC_DataAlign_Left ((uint32_t)0x00000800)
#define ADC_DataAlign_Right ((uint32_t)0x00000000)
#define IS_ADC_DATA_ALIGN(ALIGN)
左對(duì)齊,右對(duì)齊。。
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ā)方式很豐富,當(dāng)然 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ī)則組的概念,有些單詞不是很熟悉,沒(méi)關(guān)系那就先這樣吧!用到了再來(lái)
5、ADC_NbrOfChannel采樣通道?
明顯一般采用的是是16個(gè)規(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,字面意思不是很懂,看手冊(cè)
Specifies whether the conversion is performed in Scan (multichannels) or Single (one channel)
mode. This parameter can be set to ENABLE or DISABLE
意思是當(dāng)有多個(gè)通道的時(shí)候,使用掃描的方式,反之只有單個(gè)通道的是那么就是選擇單通道了
那么取值就是ENABLE or DISABLE
至此結(jié)構(gòu)成員分析完畢,下面來(lái)猜測(cè)一下,應(yīng)該怎樣賦值,聲明:?jiǎn)瓮ǖ啦杉?,右?duì)齊(方便存數(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
下面來(lái)對(duì)照下,原始代碼看看:
/* 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);
顯然錯(cuò)誤還是比較多的,沒(méi)關(guān)系,慢慢分析
1、因?yàn)槭且粋€(gè)通道沒(méi)必要掃描,所以第2個(gè)錯(cuò)了
2、通道數(shù)目理解錯(cuò)誤。我以為那是指定的哪個(gè)通道,原來(lái)是number of channel
3、好的最后就是少了一個(gè)庫(kù)函數(shù)的調(diào)用,這確實(shí)是缺乏這種意識(shí)呀!
七、既然是使用DMA來(lái)傳送數(shù)據(jù),那么下一步就開(kāi)始初始化DMA吧!DMA的知識(shí)暫時(shí)不分析,那個(gè)得單獨(dú)出來(lái)
我還是先來(lái)了解下DMA的變成思想吧!
1、STM32就是這樣完美,每個(gè)模塊都能有個(gè)結(jié)構(gòu)體來(lái)組織它的一些參數(shù)配置,我甚至覺(jué)得它和uboot一樣討人喜歡
這只是我的愚見(jiàn),也是這樣一個(gè)結(jié)構(gòu)體 DMA_InitTypeDef DMA_InitStructure;
跟著手冊(cè)來(lái)吧
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
從存儲(chǔ)器到外設(shè)或者從外設(shè)到存儲(chǔ)器
5、DMA_M2M 這個(gè)可以猜測(cè)到,DMA的作用出了上面一個(gè)還有M to M的沒(méi)有提及那么
#define DMA_M2M_Disable ((uint32_t)0x00000000)
#define DMA_M2M_Enable ((uint32_t)0x00004000)
可以這樣設(shè)置了
6、DMA_MemoryBaseAddr、DMA_PeripheralBaseAddr
這兩個(gè)可以一起看了,字面意思很清楚了,外設(shè)地址和存儲(chǔ)器(變量)地址,這個(gè)得看你的地址了
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
地址增加?理解嚴(yán)重錯(cuò)誤,那么就是地址遞增的意思吧,那就是可以連續(xù)采集多個(gè)通道咯?繼續(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)先級(jí)這個(gè)就好理解了,不就是控制優(yōu)先權(quán)么看解釋以及取值
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個(gè)優(yōu)先級(jí)
至此,分析完畢,嘗試性猜測(cè)
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 = 一個(gè)地址單元的變量單字節(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);
貌似有點(diǎn)不妙的感覺(jué)
1、MA_InitStructure.DMA_DIR這個(gè)明顯是作為數(shù)據(jù)源
2、DMA_MemoryDataSize_Byte和DMA_PeripheralDataSize_HalfWord有什么區(qū)別
百度里面我沒(méi)有找到,先這樣,等做完實(shí)驗(yàn)再驗(yàn)證
八、結(jié)構(gòu)體成員初始化完畢之后,還有很多工作要做
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));//復(fù)位校準(zhǔn)
/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));//校準(zhǔn)
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//軟件觸發(fā),這時(shí)候真正開(kāi)始轉(zhuǎn)換
硬件測(cè)試后,結(jié)果正確的!