廣州做營(yíng)銷(xiāo)型網(wǎng)站/網(wǎng)絡(luò)營(yíng)銷(xiāo)師證書(shū)含金量
基于stm32f103系列
基于《零死角玩轉(zhuǎn) STM32F103—指南者》
ADC簡(jiǎn)介
stm32f103上的ADC
數(shù)量
:3
精度
:12bit(4096)
通道
:ADC1,ADC2均有16個(gè)通道,ADC3有8個(gè)
功能
:
??轉(zhuǎn)換結(jié)束、注入轉(zhuǎn)換結(jié)束和發(fā)生模擬看門(mén)狗事件時(shí)產(chǎn)生中斷。
??單次和連續(xù)轉(zhuǎn)換模式
??從通道0到通道n的自動(dòng)掃描模式
??自校準(zhǔn)
??帶內(nèi)嵌數(shù)據(jù)一致性的數(shù)據(jù)對(duì)齊
??采樣間隔可以按通道分別編程
??規(guī)則轉(zhuǎn)換和注入轉(zhuǎn)換均有外部觸發(fā)選項(xiàng)
??間斷模式
??雙重模式(帶2個(gè)或以上ADC的器件)
輸入電壓范圍
輸入通道
根據(jù)手冊(cè)選擇輸入通道
轉(zhuǎn)換順序
規(guī)則序列
規(guī)則序列 從小到大依次轉(zhuǎn)換
配置SQR3、SQR2、SQR1寄存器。按順序從SQR3中的SQ1,SQ2到SQR1中的SQ16
注入序列
注入序列 依據(jù)通道數(shù)目,從大到小或者從小到大
??注入序列寄存器 JSQR 只有一個(gè),最多支持 4 個(gè)通道。具體多少個(gè)由 JSQR 的 JL[2:0]決定。如果 JL的 值小于 4 的話,則 JSQR 跟 SQR決定轉(zhuǎn)換順序的設(shè)置不一樣,第一次轉(zhuǎn)換的不是 JSQR1[4:0],而是 JCQRx[4:0] ,x = (4-JL),跟 SQR 剛好相反。如果 JL=00(1 個(gè)轉(zhuǎn)換),那么轉(zhuǎn)換的順序是從 JSQR4[4:0]開(kāi)始,而不是從 JSQR1[4:0]開(kāi)始,這個(gè)要注意,編程的時(shí)候不要搞錯(cuò)。當(dāng) JL 等于 4 時(shí),跟 SQR 一樣。
觸發(fā)源
1.CR寄存器中的CONbit位使能,開(kāi)始轉(zhuǎn)換
2.觸發(fā)啟動(dòng):
????內(nèi)部定時(shí)器觸發(fā)和外部 IO 觸發(fā)
觸發(fā)源有很多,具體選擇哪一種觸發(fā)源,由 ADC 控制寄存器 2:ADC_CR2 的EXTSEL[2:0]和 JEXTSEL[2:0]位來(lái)控制。EXTSEL[2:0]用于選擇規(guī)則通道的觸發(fā)源,JEXTSEL[2:0]用于選擇注入通道的觸發(fā)源。選定好觸發(fā)源之后,觸發(fā)源是否要激活,則由ADC 控制寄存器 2:ADC_CR2 的 EXTTRIG 和 JEXTTRIG 這兩位來(lái)激活。其中 ADC3 的規(guī)則轉(zhuǎn)換和注入轉(zhuǎn)換的觸發(fā)源與 ADC1/2 的有所不同。
EXTSEL[2:0]和JEXTSEL2:0]控制位允許應(yīng)用程序選擇8個(gè)可能的事件中的某一個(gè),可以觸發(fā)規(guī)則和注入組的采樣。
轉(zhuǎn)換時(shí)間
ADC 時(shí)鐘
ADC 輸入時(shí)鐘 ADC_CLK 由 PCLK2 經(jīng)過(guò)分頻產(chǎn)生,最大是 14M,分頻因子由 RCC 時(shí)鐘配置寄存器 RCC_CFGR 的位 15:14 ADCPRE[1:0]設(shè)置,可以是 2/4/6/8 分頻,注意這里沒(méi)有 1 分頻。一般我們?cè)O(shè)置 PCLK2=HCLK=72M。
采樣時(shí)間
ADC 使用若干個(gè) ADC_CLK 周期對(duì)輸入的電壓進(jìn)行采樣,采樣的周期數(shù)可通過(guò) ADC 采樣時(shí)間寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位設(shè)置,ADC_SMPR2 控制的是通道 0~9,ADC_SMPR1 控制的是通道 10~17。每個(gè)通道可以分別用不同的時(shí)間采樣。其中采樣周期最小是 1.5 個(gè),即如果我們要達(dá)到最快的采樣,那么應(yīng)該設(shè)置采樣周期為 1.5 個(gè)周期,這里說(shuō)的周期就是 1/ADC_CLK。
ADC 的轉(zhuǎn)換時(shí)間跟 ADC 的輸入時(shí)鐘和采樣時(shí)間有關(guān),公式為:Tconv = 采樣時(shí)間 + 12.5 個(gè)周期。當(dāng) ADCLK = 14MHZ (最高),采樣時(shí)間設(shè)置為 1.5 周期(最快),那么總的轉(zhuǎn)換時(shí)間(最短)Tconv = 1.5 周期 + 12.5 周期 = 14 周期 = 1us。
一般我們?cè)O(shè)置 PCLK2=72M,經(jīng)過(guò) ADC 預(yù)分頻器能分頻到最大的時(shí)鐘只能是 12M,采樣周期設(shè)置為 1.5 個(gè)周期,算出最短的轉(zhuǎn)換時(shí)間為 1.17us,這個(gè)才是最常用的。
數(shù)據(jù)寄存器 ADC->DR
ADC 轉(zhuǎn)換后的數(shù)據(jù)根據(jù)轉(zhuǎn)換組的不同,規(guī)則組的數(shù)據(jù)放在 ADC_DR寄存器,注入組的數(shù)據(jù)放在 JDRx。
規(guī)則數(shù)據(jù)寄存器 ADC_DR寄存器
ADC 規(guī)則組數(shù)據(jù)寄存器 ADC_DR 只有一個(gè),是一個(gè) 32 位的寄存器,低 16 位在單 ADC時(shí)使用,高 16 位是在 ADC1 中雙模式下保存 ADC2 轉(zhuǎn)換的規(guī)則數(shù)據(jù),雙模式就是 ADC1 和ADC2 同時(shí)使用。
規(guī)則通道可以有 16 個(gè)這么多,可規(guī)則數(shù)據(jù)寄存器只有一個(gè),如果使用多通道轉(zhuǎn)換,那轉(zhuǎn)換的數(shù)據(jù)就全部都擠在了 DR 里面,前一個(gè)時(shí)間點(diǎn)轉(zhuǎn)換的通道數(shù)據(jù),就會(huì)被下一個(gè)時(shí)間點(diǎn)的另外一個(gè)通道轉(zhuǎn)換的數(shù)據(jù)覆蓋掉,所以當(dāng)通道轉(zhuǎn)換完成后就應(yīng)該把數(shù)據(jù)取走,或者開(kāi)啟 DMA 模式,把數(shù)據(jù)傳輸?shù)絻?nèi)存里面,不然就會(huì)造成數(shù)據(jù)的覆蓋。最常用的做法就是開(kāi)啟 DMA 傳輸。
注入數(shù)據(jù)寄存器 JDRx寄存器
ADC 注入組最多有 4 個(gè)通道,剛好注入數(shù)據(jù)寄存器也有 4 個(gè),每個(gè)通道對(duì)應(yīng)著自己的寄存器,不會(huì)跟規(guī)則寄存器那樣產(chǎn)生數(shù)據(jù)覆蓋的問(wèn)題。ADC_JDRx 是 32 位的,低 16 位有效,高 16 位保留,數(shù)據(jù)同樣分為左對(duì)齊和右對(duì)齊,具體是以哪一種方式存放,由ADC_CR2 的 11 位 ALIGN 設(shè)置。
中斷
轉(zhuǎn)換結(jié)束中斷
數(shù)據(jù)轉(zhuǎn)換結(jié)束后,可以產(chǎn)生中斷,中斷分為三種:規(guī)則通道轉(zhuǎn)換結(jié)束中斷,注入轉(zhuǎn)換通道轉(zhuǎn)換結(jié)束中斷,模擬看門(mén)狗中斷。
模擬看門(mén)狗中斷
當(dāng)被 ADC 轉(zhuǎn)換的模擬電壓低于低閾值或者高于高閾值時(shí),就會(huì)產(chǎn)生中斷,前提是我們開(kāi)啟了模擬看門(mén)狗中斷,其中低閾值和高閾值由 ADC_LTR 和 ADC_HTR 設(shè)置。例如我們?cè)O(shè)置高閾值是 2.5V,那么模擬電壓超過(guò) 2.5V的時(shí)候,就會(huì)產(chǎn)生模擬看門(mén)狗中斷,反之低閾值也一樣。
DMA請(qǐng)求
規(guī)則和注入通道轉(zhuǎn)換結(jié)束后,除了產(chǎn)生中斷外,還可以產(chǎn)生 DMA 請(qǐng)求,把轉(zhuǎn)換好的數(shù)據(jù)直接存儲(chǔ)在內(nèi)存里面。要注意的是只有 ADC1 和 ADC3 可以產(chǎn)生 DMA 請(qǐng)求。
編程要點(diǎn)
獨(dú)立單通道
ADC GPIO 初始化
static void ADCx_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2,ENABLE)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模擬輸入GPIO_Init(GPIOC, &GPIO_InitStructure);}
ADC 工作模式配置
// ADC 編號(hào)選擇
// 可以是 ADC1/2,如果使用 ADC3,中斷相關(guān)的要改成 ADC3 的
#define ADC_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADCx ADC2
#define ADC_CLK RCC_APB2Periph_ADC2// ADC GPIO 宏定義
// 注意:用作 ADC 采集的 IO 必須沒(méi)有復(fù)用,否則采集電壓會(huì)有影響
#define ADC_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_PIN GPIO_Pin_1
// ADC 通道宏定義
#define ADC_CHANNEL ADC_Channel_11// ADC 中斷相關(guān)宏定義
#define ADC_IRQ ADC1_2_IRQn
#define ADC_IRQHandler ADC1_2_IRQHandlerstatic void ADCx_Mode_Config(void)
{ADC_InitTypeDef ADC_InitStructure;// 打開(kāi) ADC 時(shí)鐘ADC_APBxClock_FUN ( ADC_CLK, ENABLE );// ADC 模式配置// 只使用一個(gè) ADC,屬于獨(dú)立模式ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;// 禁止掃描模式,多通道才要,單通道不需要ADC_InitStructure.ADC_ScanConvMode = DISABLE ;// 連續(xù)轉(zhuǎn)換模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;// 不用外部觸發(fā)轉(zhuǎn)換,軟件開(kāi)啟即可ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;// 轉(zhuǎn)換結(jié)果右對(duì)齊ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;// 轉(zhuǎn)換通道 1 個(gè)ADC_InitStructure.ADC_NbrOfChannel = 1;// 初始化 ADCADC_Init(ADCx, &ADC_InitStructure);// 配置 ADC 時(shí)鐘N狿 CLK2 的 8 分頻,即 9MHzRCC_ADCCLKConfig(RCC_PCLK2_Div8);// 配置 ADC 通道轉(zhuǎn)換順序?yàn)?1,第一個(gè)轉(zhuǎn)換,采樣時(shí)間為 55.5 個(gè)時(shí)鐘周期ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1,ADC_SampleTime_55Cycles5);// ADC 轉(zhuǎn)換結(jié)束產(chǎn)生中斷,在中斷服務(wù)程序中讀取轉(zhuǎn)換值ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);// 開(kāi)啟 ADC ,并開(kāi)始轉(zhuǎn)換ADC_Cmd(ADCx, ENABLE);// 初始化 ADC 校準(zhǔn)寄存器ADC_ResetCalibration(ADCx);// 等待校準(zhǔn)寄存器初始化完成while (ADC_GetResetCalibrationStatus(ADCx));// ADC 開(kāi)始校準(zhǔn)ADC_StartCalibration(ADCx);// 等待校準(zhǔn)完成while (ADC_GetCalibrationStatus(ADCx));// 由于沒(méi)有采用外部觸發(fā),所以使用軟件觸發(fā) ADC 轉(zhuǎn)換ADC_SoftwareStartConvCmd(ADCx, ENABLE);}
ADC 中斷配置
NVIC配置
static void ADC_NVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}
開(kāi)啟ADC中斷
// ADC 轉(zhuǎn)換結(jié)束產(chǎn)生中斷,在中斷服務(wù)程序中讀取轉(zhuǎn)換值ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);
ADC中斷服務(wù)函數(shù)
1.ADC1和ADC2共有一個(gè)中斷服務(wù)函數(shù)
2.中斷服務(wù)函數(shù)中讀取ADC狀態(tài)寄存器SR的相應(yīng)位置
void ADC_IRQHandler(void)
{if (ADC_GetITStatus(ADCx,ADC_IT_EOC)==SET) {// 讀取 ADC 的轉(zhuǎn)換值ADC_ConvertedValue = ADC_GetConversionValue(ADCx);}ADC_ClearITPendingBit(ADCx,ADC_IT_EOC);
}
獨(dú)立模式多通道采集
- 初始化 ADC GPIO;
- 初始化 ADC 工作參數(shù);
- 配置 DMA 工作參數(shù);
- 讀取 ADC 采集的數(shù)據(jù);
GPIO配置
static void ADCx_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 打開(kāi) ADC IO 端口時(shí)鐘ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE );// 配置 ADC IO 引腳模式GPIO_InitStructure.GPIO_Pin = ADC_PIN1|ADC_PIN2|ADC_PIN3|ADC_PIN4|ADC_PIN5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;// 初始化 ADC IOGPIO_Init(ADC_PORT, &GPIO_InitStructure);}
ADC以及DMA模式配置
static void ADCx_Mode_Config(void)
{DMA_InitTypeDef DMA_InitStructure;ADC_InitTypeDef ADC_InitStructure;// 打開(kāi) DMA 時(shí)鐘RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// 打開(kāi) ADC 時(shí)鐘ADC_APBxClock_FUN ( ADC_CLK, ENABLE );/* ------------------DMA 模式配置---------------- */// 復(fù)位 DMA 控制器DMA_DeInit(ADC_DMA_CHANNEL);// 配置 DMA 初始化結(jié)構(gòu)體// 外設(shè)基址為:ADC 數(shù)據(jù)寄存器地址DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&( ADCx->DR ));// 存儲(chǔ)器地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;// 數(shù)據(jù)源來(lái)自外設(shè)DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;// 緩沖區(qū)大小,應(yīng)該等于數(shù)據(jù)目的地的大小DMA_InitStructure.DMA_BufferSize = NOFCHANEL;// 外設(shè)寄存器只有一個(gè),地址不用遞增DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;// 存儲(chǔ)器地址遞增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// 外設(shè)數(shù)據(jù)大小為半字,即兩個(gè)字節(jié)DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_HalfWord;// 內(nèi)存數(shù)據(jù)大小也為半字,跟外設(shè)數(shù)據(jù)大小相同DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;// 循環(huán)傳輸模式DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// DMA 傳輸通道優(yōu)先級(jí)為高,當(dāng)使用一個(gè) DMA 通道時(shí),優(yōu)先級(jí)設(shè)置不影響DMA_InitStructure.DMA_Priority = DMA_Priority_High;// 禁止存儲(chǔ)器到存儲(chǔ)器模式,因?yàn)槭菑耐庠O(shè)到存儲(chǔ)器DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;// 初始化 DMADMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);// 使能 DMA 通道DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);/* ----------------ADC 模式配置--------------------- */// 只使用一個(gè) ADC,屬于單模式ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;// 掃描模式ADC_InitStructure.ADC_ScanConvMode = ENABLE ;// 連續(xù)轉(zhuǎn)換模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;// 不用外部觸發(fā)轉(zhuǎn)換,軟件開(kāi)啟即可ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;// 轉(zhuǎn)換結(jié)果右對(duì)齊ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;// 轉(zhuǎn)換通道個(gè)數(shù)ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL;// 初始化 ADCADC_Init(ADCx, &ADC_InitStructure);// 配置 ADC 時(shí)鐘N狿 CLK2 的 8 分頻,即 9MHzRCC_ADCCLKConfig(RCC_PCLK2_Div8);// 配置 ADC 通道的轉(zhuǎn)換順序和采樣時(shí)間ADC_RegularChannelConfig(ADCx, ADC_CHANNEL1, 1,ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADCx, ADC_CHANNEL2, 2,ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADCx, ADC_CHANNEL3, 3,ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADCx, ADC_CHANNEL4, 4,ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADCx, ADC_CHANNEL5, 5,ADC_SampleTime_55Cycles5);// 使能 ADC DMA 請(qǐng)求ADC_DMACmd(ADCx, ENABLE);// 開(kāi)啟 ADC ,并開(kāi)始轉(zhuǎn)換ADC_Cmd(ADCx, ENABLE);// 初始化 ADC 校準(zhǔn)寄存器ADC_ResetCalibration(ADCx);// 等待校準(zhǔn)寄存器初始化完成while (ADC_GetResetCalibrationStatus(ADCx));// ADC 開(kāi)始校準(zhǔn)ADC_StartCalibration(ADCx);// 等待校準(zhǔn)完成while (ADC_GetCalibrationStatus(ADCx));// 由于沒(méi)有采用外部觸發(fā),所以使用軟件觸發(fā) ADC 轉(zhuǎn)換ADC_SoftwareStartConvCmd(ADCx, ENABLE);}
雙重 ADC 同步規(guī)則模式采集
參看《零死角玩轉(zhuǎn)STM32—F103指南者》