STM32的ADC DMA USART綜合學(xué)習
四個(gè)任務(wù):
本文引用地址:http://dyxdggzs.com/article/201612/325054.htm1.AD以中斷方式(單次)采集一路
2.AD以中斷方式連續采集四路
3.AD以DMA方式采集一路,DMA深度為一級
4.AD以DMA方式采集四路,每路DMA深度為28級,并濾波,說(shuō)明濾波原理。
總結:
第一個(gè)任務(wù):ADC以中斷方式采集一路ADC,通過(guò)配置ADC_InitStructure結構體中的ADC_ScanConvMode,它規定模數轉換工作在掃描模式(多通道)還是單次模式(單通道),
ADC_InitStructure.ADC_ScanConvMode=DISABLE,為單通道單次模式。
ADC_ContinuousConvMode,定轉換是連續還是單次,ADC_ContinuousConvMode=DISABLE
為單次,ADC_NbrOfChangnel規定ADC規則轉換的通道數。ADC_NbrOfChannel=1;//開(kāi)啟1個(gè)通道數。
ADC_RegularChannelConfig(ADC1,ADC_Channel_13, 1,ADC_SampleTime_55Cycles5);設置指定規則組的通道的采樣順序和轉換時(shí)間。這里以為只有一路通道,采用的是PC3引腳,對應的通道數是13通道,采樣順序也就是1,。
ADC_Cmd(ADC1,ENABLE);使能ADC
ADC_ITConfig(ADC1, ADC_IT_EOC,ENABLE);開(kāi)啟ADC轉換結束中斷。
ADC_ResetCalibration(ADC1);//重置校驗寄存器
while(ADC_GetResetCalibrationStatus(ADC1));//等待重置校驗成功
ADC_StartCalibration(ADC1);//開(kāi)始ADC校驗
while(ADC_GetCalibrationStatus(ADC1));//等待ADC校驗好
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//軟件觸發(fā)開(kāi)始轉換
因為ADC有一個(gè)16位的規則組數據寄存器(ADC_DR),采用一路轉換時(shí)可以不用通過(guò)DMA傳輸。這里就沒(méi)有配置DMA。
void ADC_IRQHandler(void)
{
ADCConvertedValue=ADC_GetConversionValue(ADC1);
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
}
當一次轉換結束,DAC產(chǎn)生中斷,在中斷函數里,讀取ADC_DR寄存器中的值,一定清除中斷標志位。
采集出來(lái)的數據是16進(jìn)制數,要經(jīng)過(guò)處理,變成10進(jìn)制數,具體如下:
(value*100/4096)*33,value是從寄存器讀出來(lái)的十六進(jìn)制的數據,經(jīng)過(guò)此變換后就變成10進(jìn)制數,是個(gè)整數,我們通過(guò)串口顯示的時(shí)候要把小樹(shù)部分也要顯示出來(lái)則有:((value*100/4096)*33)/1000,整數部分。
((value*100/4096)*33)%1000/100,((value*100/4096)*33)%100/10),小數部分,
串口配置,我是通過(guò)STM32上的串口1與PC機通訊的,具體配置如下:
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate=9600;波特率9600
USART_InitStructure.USART_WordLength=USART_WordLength_8b;//8位數據位
USART_InitStructure.USART_StopBits=USART_StopBits_1;1個(gè)停止位
USART_InitStructure.USART_Parity=USART_Parity_No;無(wú)奇偶校驗
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStructure);初始化串口配置
USART_Cmd(USART1,ENABLE);使能串口
}
int fputc(int ch,FILE *f)
{
USART_SendData(USART1, (u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)//檢查發(fā)送是否完成
{
}
return ch;
}此函數,是把printf輸出函數定向到USART。
第一個(gè)任務(wù)大概就是這個(gè)過(guò)程,在后面的任務(wù)有相同之處,就不重復敘述了。
第二個(gè)任務(wù):ADC以中斷方式連續采集四路。
首先配置4路模擬輸入,我配置的是PC0、PC1、PC2、PC3四個(gè)IO口,輸入方式為模擬輸入,速度采用2M,它們對應的ADC通道分別是10、11、12、13通道。
在第一個(gè)任務(wù)說(shuō)了,ADC規則轉換多路采樣時(shí),ADC的數據寄存器只有一個(gè)16位寄存器,所以必須采用DMA來(lái)傳輸數據,DMA配置如下:
DMA_InitStructure.DMA_PeripheralBaseAddr=DR_ADDRESS; //DMA對應的外設基地址
DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&Buf; //內存存儲基地址,定義的一個(gè)數組
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC; //DMA轉換模式為SRC模式,由外設搬移到內存
DMA_InitStructure.DMA_BufferSize=4; // DMA緩存大小,4個(gè)(設置DMA在傳輸時(shí)緩沖區的長(cháng)度)
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //接收一次數據后,設備地址禁止后移(設置DMA的外設遞增模式)
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; //關(guān)閉接收一次數據后,目標內存地址后移(設置DMA的內存遞增模式)
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//定義外設數據長(cháng)度
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;
//循環(huán)模式開(kāi)啟,Buf寫(xiě)滿(mǎn)后,自動(dòng)回到初始地址開(kāi)始傳輸
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//優(yōu)先級高
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
ADC配置:
//ADC配置
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//獨立轉換模式
ADC_InitStructure.ADC_ScanConvMode=ENABLE;//開(kāi)啟掃描模式
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//開(kāi)啟連續轉換模式
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//ADC外部開(kāi)關(guān),關(guān)閉狀態(tài)
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//對齊方式,右對齊方式
ADC_InitStructure.ADC_NbrOfChannel=4;//開(kāi)啟通道數,4個(gè)
ADC_Init(ADC1,&ADC_InitStructure);//初始化ADC
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_11,2,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_12,3,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_13,4,ADC_SampleTime_55Cycles5);;
//ADC通道組,第10、11、12、13個(gè)通道,采樣順序分別是1,2,3,4轉換時(shí)間55.5個(gè)周期
ADC_DMACmd(ADC1, ENABLE);//使能ADC1模塊DMA
ADC_Cmd(ADC1, ENABLE);//打開(kāi)ADC1
ADC_ResetCalibration(ADC1);//重置ADC1校準寄存器
while(ADC_GetResetCalibrationStatus(ADC1));//等待ADC1校準重置完成
ADC_StartCalibration(ADC1);//開(kāi)始ADC1校準
while(ADC_GetCalibrationStatus(ADC1));//等待ADC1校準完成
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能ADC1軟件開(kāi)始轉換
中斷是采用DMA中斷,當DMA第一輪傳輸結束時(shí),設一個(gè)標志位,當標志位為1時(shí),表明第一輪轉化和傳輸完成,此時(shí)就可以讀取數組中的數據,經(jīng)過(guò)處理就可以通過(guò)串口顯示出來(lái)。
void DMAChannel1_IRQHandler(void)
{
ADC_DMA_OK=1;
DMA_ClearITPendingBit(DMA1_IT_TC1);
}中斷函數。
第二個(gè)任務(wù)大概就這樣子。
第三個(gè)任務(wù):AD以DMA方式采集一路,DMA深度為一級。
這個(gè)任務(wù)不難,關(guān)鍵要理解到DMA深度,用自己的語(yǔ)言來(lái)理解哈DMA深度吧,當ADC以一路采集時(shí),ADC轉換完成就自動(dòng)把轉換結果通過(guò)DMA傳給目的地址,如果傳輸一次結束DMA就產(chǎn)生中斷的話(huà),DMA的深度就為一級,如果連續傳輸N次,DMA的深度就位N級,當然這個(gè)N是又范圍的,因為受目的地址的內存大小控制和數據寬度,這個(gè)大家應該豆明白的。
這個(gè)任務(wù)在第一個(gè)任務(wù)的基礎上我通過(guò)DMA傳輸,意思是AD配置沒(méi)什么區別。DMA配置和第二個(gè)任務(wù)的區別就是DMA_BufferSize的寬度不同。
#defineDR_ADDRESS(u32)0x4001244cADC的地址
#defineDMA_Count1DMA深度,也就是連續傳輸的次數
#defineADC_Channle1ADC通道
數據處理和串口通訊這里不重復敘述。DMA中斷和任務(wù)二的類(lèi)似。
第四個(gè)任務(wù):AD以DMA方式采集四路,每路DMA深度為128級,并濾波,說(shuō)明濾波原理。
這個(gè)任務(wù)和是個(gè)綜合性任務(wù),只要弄懂前面三個(gè)任務(wù),難點(diǎn)是再如何濾波,開(kāi)始的時(shí)候我也不知道怎么濾波,同事提醒我才知道怎么濾波的,我大概說(shuō)哈我的理解,把四路通道采集的數據分別放到四個(gè)數組中,然后給他來(lái)個(gè)排序,降序,升序都行,把首位兩個(gè)數丟掉,然后加起來(lái)求平均值。但是我這里因為DMA的深度為128級,也就是四個(gè)通道分別采樣了128次,大家都知道,數據越多,求平均值就越準確,所以我就沒(méi)有采用什么排序法了,直接給他們分別求平均值,具體如下:
#defineDR_ADDRESS(u32)0x4001244cADC的地址
#defineDMA_Count128DMA深度,也就是連續傳輸的次數
#defineADC_Channle4ADC通道
for(i=0;i<(ADC_Channle*DMA_Count);i+=4)
{
Value1[j]=Buf[i+0];
Sum1+=Value1[j];
Value2[j]=Buf[i+1];
Sum2+=Value2[j];
Value3[j]=Buf[i+2];
Sum3+=Value3[j];
Value4[j]=Buf[i+3];
Sum4+=Value4[j];
j++;
}
Valu1=Sum1/DMA_Count;
Valu2=Sum2/DMA_Count;
Valu3=Sum3/DMA_Count;
Valu4=Sum4/DMA_Count;
Delay(100000);
printf("rn當前AD_0值:0x%x,電壓值:%d.%d%dVnr",
Valu1,((Valu1*100/4096)*33)/1000,((Valu1*100/4096)*33)%1000/100,((Valu1*100/4096)*33)%100/10);
Delay(100000);
printf("rn當前AD_1值:0x%x,電壓值:%d.%d%dVnr",
Valu2,((Valu2*100/4096)*33)/1000,((Valu2*100/4096)*33)%1000/100,((Valu2*100/4096)*33)%100/10);
Delay(100000);
printf("rn當前AD_2值:0x%x,電壓值:%d.%d%dVnr",
Valu3,((Valu3*100/4096)*33)/1000,((Valu3*100/4096)*33)%1000/100,((Valu3*100/4096)*33)%100/10);
Delay(100000);
printf("rn當前AD_3值:0x%x,電壓值:%d.%d%dVnr",
Valu4,((Valu4*100/4096)*33)/1000,((Valu4*100/4096)*33)%1000/100,((Valu4*100/4096)*33)%100/10);
Delay(100000);
關(guān)于A(yíng)DC配置和DMA配置這里不重復敘述了。
評論