STM32的ADC模塊中,**采樣時機(Sampling Time)**和**轉換時機(Conversion Time),獲取數據的時機詳解

在STM32的ADC模塊中,**采樣時機(Sampling Time)轉換時機(Conversion Time)**是ADC工作流程中的兩個關鍵階段,直接影響采樣精度和系統實時性。以下是詳細解析:


1. 采樣時機(Sampling Time)

(1)定義
  • 采樣階段:ADC對輸入信號進行保持和穩定的過程。
  • 采樣時間:由ADC_SMPRx寄存器配置,決定采樣電容充電時間。
(2)配置參數

STM32F103的采樣時間可設置為:

typedef enum {ADC_SampleTime_1Cycles5,    // 1.5周期ADC_SampleTime_7Cycles5,    // 7.5周期ADC_SampleTime_13Cycles5,   // 13.5周期ADC_SampleTime_28Cycles5,   // 28.5周期ADC_SampleTime_41Cycles5,   // 41.5周期ADC_SampleTime_55Cycles5,   // 55.5周期ADC_SampleTime_71Cycles5,   // 71.5周期ADC_SampleTime_239Cycles5   // 239.5周期(用于高阻抗信號)
} ADC_SampleTime;
(3)選擇原則
信號類型推薦采樣時間原因
低阻抗信號1.5~28.5周期信號源阻抗低(如運放輸出),快速穩定。
高阻抗信號55.5~239.5周期信號源阻抗高(如溫度傳感器、分壓電路),需更長時間充電。
內部通道≥239.5周期內部溫度傳感器和VREFINT阻抗極高,必須延長采樣時間。
(4)代碼示例
// 配置PA0(低阻抗)和溫度傳感器(高阻抗)
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_28Cycles5);  // 快速采樣
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 2, ADC_SampleTime_239Cycles5); // 慢速采樣

2. 轉換時機(Conversion Time)

(1)定義
  • 轉換階段:ADC核心將采樣到的模擬量轉換為數字量的過程。
  • 固定耗時:12位分辨率下恒定為12.5個ADC時鐘周期(與采樣時間無關)。
(2)總轉換時間計算

[
T_{total} = (T_{sampling} + 12.5) \times \frac{1}{f_{ADC}}
]

  • 示例
    • ADC時鐘 = 14 MHz,采樣時間 = 55.5周期
    • 總時間 = (55.5 + 12.5) / 14MHz ≈ 4.86μs
(3)吞吐量限制
  • 理論最大采樣率
    [
    f_{max} = \frac{1}{T_{total}}
    ]
    • T_total=4.86μs,則f_max≈205kHz(單通道)。

3. 采樣與轉換的時序圖

采樣階段                       轉換階段
|-------- Sampling Time --------|-- 12.5 Cycles --|
|<----------- Total Conversion Time ------------>|

4. 關鍵影響因素

(1)ADC時鐘頻率
  • 最大14MHz(STM32F103),需分頻APB2時鐘:
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);  // 72MHz/6=12MHz
    
  • 更高時鐘 → 更快轉換,但可能降低精度。
(2)通道切換延遲
  • 多通道掃描時,每個通道需單獨配置采樣時間,切換通道會增加額外延遲。
(3)觸發方式
  • 硬件觸發(如定時器):精確控制采樣間隔。
  • 軟件觸發:靈活性高但時序不易控制。

5. 優化策略

(1)動態調整采樣時間

根據信號類型切換采樣時間:

void Set_ADC_SampleTime(ADC_TypeDef* ADCx, uint8_t channel, uint8_t isHighImpedance) {ADC_SampleTime time = isHighImpedance ? ADC_SampleTime_239Cycles5 : ADC_SampleTime_28Cycles5;ADC_RegularChannelConfig(ADCx, channel, 1, time);
}
(2)使用注入組中斷

高優先級信號通過注入組立即響應:

// 過壓時緊急采樣
void ADC1_2_IRQHandler(void) {if (ADC_GetITStatus(ADC1, ADC_IT_JEOC)) {uint16_t emergencyData = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);}
}
(3)DMA傳輸規則組數據

避免CPU輪詢,提高效率:

uint16_t adcValues[3];
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adcValues;
ADC_DMACmd(ADC1, ENABLE);

6. 實際應用示例

電機電流監測系統
  • 規則組
    • 通道PA0(電流傳感器),采樣時間7.5周期(低阻抗)。
    • 定時器觸發1kHz采樣,DMA傳輸數據。
  • 注入組
    • 比較器檢測過流時觸發PA8中斷,注入組采集PA1(備份傳感器)。
  • 計算總延遲
    • 采樣+轉換時間 = (7.5 + 12.5) / 14MHz ≈ 1.43μs
    • 1kHz采樣率下,CPU負載極低。

總結

  • 采樣時機:由信號源阻抗決定,需足夠時間穩定信號。
  • 轉換時機:固定12.5周期,與ADC時鐘頻率直接相關。
  • 優化核心:在精度和速度間平衡,優先保證信號完整性。

在STM32的ADC編程中,采樣轉換數據獲取的流程分布在程序的不同位置,具體取決于觸發方式(軟件/硬件)和數據讀取方式(輪詢/DMA/中斷)。以下是基于STM32F103的詳細說明和代碼示例:


1. 采樣(Sampling)

觸發采樣的位置
  • 軟件觸發:在代碼中顯式調用啟動轉換函數。
    // 在需要采樣的地方(如主循環或定時器回調中)
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);  // 啟動規則組采樣
    ADC_SoftwareStartInjectedConv(ADC1);     // 啟動注入組采樣
    
  • 硬件觸發:由定時器、外部中斷等自動觸發,無需手動調用。
    // 配置TIM2觸發規則組采樣(無需在主循環中操作)
    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
    
采樣時間配置

在ADC初始化階段設置:

// 配置規則組通道的采樣時間(在ADC初始化時)
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

2. 轉換(Conversion)

轉換的觸發
  • 轉換由硬件自動完成,無需程序干預
  • 轉換時間固定為12.5個ADC時鐘周期(如14MHz時鐘下約0.89μs)。
判斷轉換完成
  • 輪詢方式:檢查標志位。
    while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));  // 規則組
    while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_JEOC)); // 注入組
    
  • 中斷方式:在中斷服務函數中處理。
    void ADC1_2_IRQHandler(void) {if (ADC_GetITStatus(ADC1, ADC_IT_EOC)) {uint16_t data = ADC_GetConversionValue(ADC1);  // 規則組數據ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);}if (ADC_GetITStatus(ADC1, ADC_IT_JEOC)) {uint16_t data = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);}
    }
    

3. 獲取數據(Data Readout)

規則組數據
  • 輪詢讀取
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    uint16_t adcValue = ADC_GetConversionValue(ADC1);  // 讀取規則組數據
    
  • DMA傳輸(推薦多通道):
    uint16_t adcValues[3];  // 存儲3個通道的數據
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adcValues;
    ADC_DMACmd(ADC1, ENABLE);
    // 數據會自動更新到adcValues數組
    
注入組數據
  • 中斷讀取
    void ADC1_2_IRQHandler(void) {if (ADC_GetITStatus(ADC1, ADC_IT_JEOC)) {uint16_t injData = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);}
    }
    

4. 完整流程示例(規則組+注入組)

初始化配置
void ADC_Init(void) {// 1. 時鐘和GPIO初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);// 2. 規則組配置(PA0)ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;ADC_Init(ADC1, &ADC_InitStructure);// 3. 注入組配置(PA1)ADC_InjectedChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_Ext_IT15);// 4. 啟用中斷ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE);NVIC_EnableIRQ(ADC1_2_IRQn);// 5. 校準和啟動ADC_Cmd(ADC1, ENABLE);ADC_ResetCalibration(ADC1);while (ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1));
}
主程序中的采樣與讀取
int main(void) {ADC_Init();while (1) {// 規則組:手動觸發并讀取ADC_SoftwareStartConvCmd(ADC1, ENABLE);while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));uint16_t regularData = ADC_GetConversionValue(ADC1);// 注入組:由PA8按鍵觸發(中斷中自動處理)Delay_ms(100);  // 模擬其他任務}
}
中斷服務函數
void ADC1_2_IRQHandler(void) {if (ADC_GetITStatus(ADC1, ADC_IT_JEOC)) {uint16_t injectedData = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);// 處理緊急數據(如過壓保護)}
}

5. 關鍵總結

操作程序位置常用函數/配置
采樣觸發主循環/定時器回調/中斷ADC_SoftwareStartConvCmd()
采樣時間ADC初始化階段ADC_RegularChannelConfig()
轉換等待輪詢/中斷ADC_GetFlagStatus() 或中斷標志
數據讀取輪詢/DMA/中斷ADC_GetConversionValue() 或DMA數組
  • 規則組:適合周期性采樣,配合DMA提高效率。
  • 注入組:用于緊急事件,中斷中即時響應。
  • 硬件觸發:精確控制時序,減少CPU干預。

在STM32的ADC配置中,**連續掃描(Scan Mode)連續轉換(Continuous Conversion Mode)**是兩個關鍵的工作模式,它們決定了ADC如何對多個通道進行采樣和數據更新。以下是詳細解釋:


1. 連續掃描模式(Scan Mode)

功能
  • 多通道自動切換:ADC按預設順序依次采樣多個通道(規則組或注入組),無需手動切換。
  • 數據存儲:需配合DMA或中斷將數據存入數組(規則組數據寄存器ADC_DR會被覆蓋)。
配置方法
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;  // 啟用掃描模式
ADC_InitStructure.ADC_NbrOfChannel = 3;       // 通道數量
ADC_Init(ADC1, &ADC_InitStructure);// 設置通道順序(規則組)
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 第1通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); // 第2通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); // 第3通道
典型應用
  • 同時監測多個傳感器(如溫度、電壓、電流)。
  • 需配合DMA傳輸數據:
    uint16_t adcValues[3];  // 存儲多通道數據
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adcValues;
    ADC_DMACmd(ADC1, ENABLE);
    

2. 連續轉換模式(Continuous Conversion Mode)

功能
  • 自動重啟轉換:完成一次轉換后立即開始下一次,無需手動觸發。
  • 單通道/多通道:可與掃描模式組合使用。
配置方法
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  // 啟用連續轉換
ADC_Init(ADC1, &ADC_InitStructure);
典型應用
  • 實時監控信號變化(如音頻采集)。
  • 單通道連續采樣示例:
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);  // 啟動后自動循環采樣
    

3. 組合使用場景

模式對比
模式組合行為適用場景
掃描+單次轉換按順序采樣所有通道后停止定時觸發多通道采樣(如每1秒1次)
掃描+連續轉換循環采樣所有通道,數據持續更新實時多通道監測(如電機控制)
單通道+連續轉換重復采樣同一通道高速信號捕獲(如示波器)
代碼示例(掃描+連續轉換)
// 初始化ADC(多通道循環采樣)
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_NbrOfChannel = 3;
ADC_Init(ADC1, &ADC_InitStructure);// 配置DMA自動傳輸數據
uint16_t adcValues[3];
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adcValues;
ADC_DMACmd(ADC1, ENABLE);// 啟動ADC
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

4. 關鍵注意事項

  1. 數據覆蓋問題

    • 規則組掃描時,ADC_DR寄存器會被新數據覆蓋,必須使用DMA或中斷及時讀取。
  2. 觸發源選擇

    • 連續轉換模式下,硬件觸發(如定時器)可精確控制采樣間隔。
  3. 功耗權衡

    • 連續轉換模式功耗較高,電池供電設備建議使用單次轉換+定時觸發。
  4. 注入組優先級

    • 即使規則組處于連續轉換中,注入組觸發仍會立即中斷當前轉換。

5. 常見問題解答

Q1:掃描模式必須用DMA嗎?
A1:不是必須,但強烈推薦。DMA可避免數據丟失,若用中斷讀取,需確保處理速度夠快。

Q2:如何暫停連續轉換?
A2:調用ADC_ContinuousConvModeCmd(ADC1, DISABLE),或直接關閉ADC:

ADC_Cmd(ADC1, DISABLE);  // 完全停止ADC

Q3:規則組和注入組能同時用掃描模式嗎?
A3:可以!規則組和注入組的掃描相互獨立,但注入組會打斷規則組當前轉換。


總結

  • 掃描模式:解決多通道自動切換問題,需注意數據存儲。
  • 連續轉換:實現無縫采樣,適合實時性要求高的場景。
  • 組合使用:靈活應對復雜需求(如實時監測多個傳感器)。

通過合理配置這兩種模式,可以充分發揮STM32 ADC的性能。

在STM32的ADC模塊中,**連續轉換模式(Continuous Conversion Mode)單次轉換模式(Single Conversion Mode)**的選擇直接影響系統的實時性、功耗和采樣精度。以下是針對您提到的兩點的詳細解釋:


1. 連續轉換模式 + 硬件觸發的精確控制

工作原理
  • 連續轉換模式:ADC完成一次轉換后,立即自動啟動下一次轉換,形成不間斷的采樣循環
  • 硬件觸發(如定時器TIM2):通過外部信號(如定時器更新事件)控制ADC的啟動時機,實現固定間隔采樣。
為何能精確控制采樣間隔?
  • 硬件同步:定時器的時鐘源穩定(如內部72MHz晶振),觸發信號的間隔誤差極小(納秒級)。
  • 規避軟件延遲:相比軟件觸發(需CPU干預),硬件觸發完全由外設自動完成,無調度延遲。
配置示例
// 配置TIM2觸發ADC(1kHz采樣率,即1ms間隔)
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_InitStructure.TIM_Period = 7200 - 1;  // 72MHz / 7200 = 10kHz
TIM_InitStructure.TIM_Prescaler = 0;
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);  // 更新事件觸發ADC// 配置ADC為連續轉換+硬件觸發
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_Init(ADC1, &ADC_InitStructure);

效果:ADC以精確的1ms間隔采樣,適合需要嚴格周期性的應用(如數字濾波器、PWM控制)。


2. 連續轉換模式的功耗問題

高功耗原因
  • ADC持續工作:連續轉換模式下,ADC核心和模擬電路(如采樣保持電路)始終處于活動狀態,電流消耗較大(STM32F103典型值約1mA@14MHz ADC時鐘)。
  • 頻繁數據更新:即使無實際信號變化,ADC仍持續轉換,浪費功耗。
單次轉換+定時觸發的低功耗方案
(1)工作流程
  1. 單次轉換模式:每次觸發后只采樣一次,然后自動停止。
  2. 定時器觸發:按需喚醒ADC(如每秒1次),其余時間ADC處于低功耗狀態。
(2)配置代碼
// 配置ADC為單次轉換+硬件觸發
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  // 單次模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_Init(ADC1, &ADC_InitStructure);// 配置TIM2低速觸發(如1Hz)
TIM_InitStructure.TIM_Period = 72000000 - 1;  // 72MHz / 72000000 = 1Hz
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
(3)功耗對比
模式平均電流(示例)適用場景
連續轉換(1kHz)~1.2mA實時控制、高速信號處理
單次轉換+定時(1Hz)~50μA電池供電的傳感器監測

3. 如何選擇?

選擇連續轉換模式當:
  • 需要高實時性(如電機控制、音頻采樣)。
  • 系統供電充足(如插電設備)。
選擇單次轉換+定時觸發當:
  • 設備由電池供電(如IoT傳感器)。
  • 信號變化緩慢(如溫度、濕度監測)。
折中方案
  • 動態切換模式:根據任務需求靈活調整。
    void Set_ADCMode(uint8_t isHighSpeed) {ADC_ContinuousConvModeCmd(ADC1, isHighSpeed ? ENABLE : DISABLE);TIM_SetAutoreload(TIM2, isHighSpeed ? 7200 - 1 : 72000000 - 1); // 切換采樣率
    }
    

4. 實測建議

  • 測量電流:用萬用表對比兩種模式的功耗差異(注意關閉未用外設)。
  • 喚醒時間:單次模式首次轉換可能有額外延遲(需重新校準)。

通過合理選擇轉換模式,可平衡性能與功耗,滿足不同應用場景需求。

在STM32的ADC應用中,定時器觸發ADC采樣通常不需要在定時器中斷服務函數(如TIMx_IRQHandler)中編寫代碼,而是直接通過定時器的硬件觸發輸出(如TRGO)自動控制ADC啟動。以下是具體說明和代碼示例:


1. 硬件觸發ADC的配置流程

(1)定時器配置
  • 不依賴中斷:僅用定時器的更新事件(UEV)觸發ADC,無需進入中斷。
  • 關鍵步驟
    • 設置定時器周期(決定采樣間隔)。
    • 配置定時器觸發輸出(TRGO)。
// 配置TIM2觸發ADC(1kHz采樣率,72MHz主頻)
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_InitStructure.TIM_Period = 72000 - 1;  // 72000 / 72MHz = 1ms (1kHz)
TIM_InitStructure.TIM_Prescaler = 0;       // 不分頻
TIM_InitStructure.TIM_ClockDivision = 0;
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);// 配置TIM2更新事件觸發TRGO
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
TIM_Cmd(TIM2, ENABLE);  // 啟動定時器
(2)ADC配置
  • 設置為硬件觸發模式,選擇定時器作為觸發源。
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // TIM2觸發
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  // 單次轉換模式(推薦低功耗)
ADC_Init(ADC1, &ADC_InitStructure);

2. 何時需要定時器中斷?

如果需要在定時器事件中執行其他任務(如數據處理、狀態檢查),才需啟用中斷。此時需:

(1)啟用定時器中斷
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  // 允許更新中斷
NVIC_EnableIRQ(TIM2_IRQn);                 // 啟用NVIC中斷
(2)中斷服務函數示例
void TIM2_IRQHandler(void) {if (TIM_GetITStatus(TIM2, TIM_IT_Update)) {// 此處可添加其他任務(如讀取ADC數據、控制邏輯)// 注意:ADC采樣已由硬件自動觸發,無需在此啟動!TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  // 清除中斷標志}
}

3. 完整代碼示例(無中斷方案)

目標:用TIM2以1kHz觸發ADC采樣,DMA傳輸數據。
#include "stm32f10x.h"uint16_t adcValue;  // 存儲ADC數據void ADC_TIM_Config(void) {// 1. 啟動時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);// 2. 配置GPIO(PA0為ADC輸入)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);// 3. 配置TIM2(1kHz觸發)TIM_TimeBaseInitTypeDef TIM_InitStructure;TIM_InitStructure.TIM_Period = 72000 - 1;  // 1ms間隔TIM_InitStructure.TIM_Prescaler = 0;TIM_TimeBaseInit(TIM2, &TIM_InitStructure);TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);  // 更新事件觸發ADCTIM_Cmd(TIM2, ENABLE);// 4. 配置ADC1(單次轉換+定時器觸發)ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  // 單次轉換ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfChannel = 1;ADC_Init(ADC1, &ADC_InitStructure);// 5. 配置ADC通道ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);// 6. 啟用ADCADC_Cmd(ADC1, ENABLE);ADC_ResetCalibration(ADC1);while (ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1));
}int main(void) {ADC_TIM_Config();while (1) {// 數據通過DMA或中斷自動更新(此處為輪詢示例)if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)) {adcValue = ADC_GetConversionValue(ADC1);ADC_ClearFlag(ADC1, ADC_FLAG_EOC);}}
}

4. 關鍵注意事項

  1. 無需中斷觸發ADC:硬件觸發本身不需要CPU干預,直接由定時器信號啟動ADC。
  2. 中斷的用途:僅當需要在定時器事件中執行額外邏輯(如數據處理、狀態機更新)時才啟用中斷。
  3. DMA推薦:高頻采樣時,務必使用DMA傳輸數據,避免CPU輪詢開銷。

總結

  • 純硬件觸發:配置定時器TRGO + ADC外部觸發,無需中斷,效率最高。
  • 中斷的適用場景:同步執行其他任務(如報警檢查、數據打包)。
  • 低功耗設計:單次轉換模式 + 定時器觸發,適合電池供電設備。
    在STM32的ADC應用中,定時器觸發的是ADC的啟動時機,即控制何時開始一次完整的“采樣+轉換”過程。以下是關鍵概念的分步解釋和代碼實現:

1. 定時器觸發的本質

  • 觸發的內容:定時器觸發的是ADC的完整轉換流程,包括:
    1. 采樣階段(Sampling Phase):ADC對輸入信號進行采樣保持(時間由ADC_SampleTime決定)。
    2. 轉換階段(Conversion Phase):ADC將采樣值轉換為數字量(固定12.5個ADC時鐘周期)。
  • 定時器的作用:精確控制每次“采樣+轉換”的啟動時刻,而非單獨控制采樣或轉換。

2. 數據獲取的位置

(1)DMA自動傳輸(推薦方式)
  • 配置步驟
    uint16_t adcValue;  // 存儲ADC數據// 啟用ADC DMA
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&adcValue;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = 1;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    ADC_DMACmd(ADC1, ENABLE);
    
  • 數據獲取
    定時器觸發ADC后,轉換結果會自動通過DMA傳輸到adcValue變量,無需程序干預
(2)中斷中讀取
  • 配置步驟
    // 啟用ADC轉換完成中斷
    ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
    NVIC_EnableIRQ(ADC1_2_IRQn);// 中斷服務函數
    void ADC1_2_IRQHandler(void) {if (ADC_GetITStatus(ADC1, ADC_IT_EOC)) {adcValue = ADC_GetConversionValue(ADC1);ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);}
    }
    
  • 數據獲取
    每次轉換完成后,在中斷中讀取ADC_DR寄存器。
(3)輪詢方式(低效,僅用于測試)
// 主循環中等待轉換完成
while (1) {ADC_SoftwareStartConvCmd(ADC1, ENABLE);  // 定時器觸發時無需此句while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));adcValue = ADC_GetConversionValue(ADC1);
}

3. 完整代碼示例(定時器觸發+DMA)

目標:TIM2以1kHz觸發ADC1采樣PA0,DMA自動傳輸數據。
#include "stm32f10x.h"uint16_t adcValue;  // 存儲ADC數據void ADC_Config(void) {// 1. 啟用時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// 2. 配置PA0為模擬輸入GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);// 3. 配置TIM2(1kHz觸發)TIM_TimeBaseInitTypeDef TIM_InitStructure;TIM_InitStructure.TIM_Period = 72000 - 1;  // 72MHz / 72000 = 1kHzTIM_InitStructure.TIM_Prescaler = 0;TIM_TimeBaseInit(TIM2, &TIM_InitStructure);TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);  // 更新事件觸發ADCTIM_Cmd(TIM2, ENABLE);// 4. 配置DMADMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&adcValue;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_Init(DMA1_Channel1, &DMA_InitStructure);DMA_Cmd(DMA1_Channel1, ENABLE);// 5. 配置ADCADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  // 單次轉換ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfChannel = 1;ADC_Init(ADC1, &ADC_InitStructure);// 6. 配置ADC通道ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);// 7. 啟用ADC和DMAADC_DMACmd(ADC1, ENABLE);ADC_Cmd(ADC1, ENABLE);ADC_ResetCalibration(ADC1);while (ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1));
}int main(void) {ADC_Config();while (1) {// adcValue已通過DMA自動更新,可直接使用float voltage = adcValue * 3.3f / 4095;  // 轉換為電壓值}
}

4. 關鍵總結

問題答案
定時器觸發的內容觸發完整的ADC轉換流程(采樣+轉換)
采樣時刻控制由定時器的觸發信號決定
數據獲取位置DMA自動傳輸到變量 / 中斷中讀取 / 輪詢ADC_DR寄存器
最優方案定時器硬件觸發 + DMA傳輸(無CPU干預,高效低功耗)

通過這種方式,STM32可以實現精確的定時采樣,同時最小化CPU負載。

在STM32的ADC應用中,定時器觸發ADC采樣時,選擇單次轉換模式(Single Conversion)還是連續轉換模式(Continuous Conversion),取決于具體的應用場景和需求。以下是兩者的對比分析和配置建議:


1. 單次轉換模式(Single Conversion)

特點
  • 工作流程
    每次定時器觸發后,ADC執行一次完整的采樣+轉換,然后自動停止,等待下一次觸發。
  • 功耗:較低(僅在觸發時激活ADC)。
  • 數據更新:每次觸發后數據更新一次。
適用場景
  • 低頻采樣:如溫度監測(每秒幾次)。
  • 電池供電設備:需要最小化功耗。
  • 事件觸發采樣:如按鍵按下后采集一次數據。
配置代碼
// ADC初始化配置
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  // 單次轉換模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // TIM2觸發
ADC_Init(ADC1, &ADC_InitStructure);// 啟動ADC(首次啟動后,后續由定時器自動觸發)
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

2. 連續轉換模式(Continuous Conversion)

特點
  • 工作流程
    定時器首次觸發后,ADC持續循環執行采樣+轉換,直到手動停止。
    (注:在硬件觸發下,連續轉換模式仍依賴定時器的周期性觸發。)
  • 功耗:較高(ADC持續運行)。
  • 數據更新:數據持續刷新,速率由定時器觸發頻率決定。
適用場景
  • 高頻實時采樣:如音頻信號處理(>1kHz)。
  • 控制環路:如電機PID控制,需要嚴格周期性的數據更新。
  • 多通道掃描:配合DMA實現無縫數據流。
配置代碼
// ADC初始化配置
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  // 連續轉換模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // TIM2觸發
ADC_Init(ADC1, &ADC_InitStructure);// 啟動ADC(首次啟動后,ADC會持續運行,但每次轉換仍由定時器觸發)
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

3. 關鍵區別與選擇建議

特性單次轉換模式連續轉換模式
觸發后行為采樣一次后停止持續采樣,直到手動停止
功耗低(適合電池供電)高(適合持續供電場景)
數據更新頻率由定時器觸發頻率決定由定時器觸發頻率決定
硬件資源占用ADC間歇工作ADC持續占用
典型應用溫度傳感器、低速監測電機控制、音頻采集
選擇原則
  1. 單次轉換模式

    • 需要低功耗非連續采樣時使用。
    • 即使定時器觸發頻率很高(如1kHz),每次觸發仍只采樣一次。
  2. 連續轉換模式

    • 需要無縫數據流嚴格實時性時使用。
    • 注意:在硬件觸發下,連續轉換模式的實際采樣率仍由定時器決定,但ADC核心會保持活躍狀態。

4. 常見問題解答

Q1:連續轉換模式下,定時器觸發還有意義嗎?
  • 有意義!連續轉換模式只是保持ADC核心處于工作狀態,但每次轉換的啟動時刻仍由定時器精確控制。
  • 若禁用硬件觸發(如用軟件觸發),ADC會以最大速度連續采樣(不推薦,可能丟失時序精度)。
Q2:單次模式是否會漏掉定時器觸發信號?
  • 不會。每次定時器觸發都會啟動一次新的轉換,即使前一次轉換已完成。
  • 但需確保兩次觸發的間隔大于單次轉換的總時間(采樣時間 + 12.5周期)。
Q3:如何動態切換模式?
// 運行時切換為單次模式
ADC_ContinuousConvModeCmd(ADC1, DISABLE);// 運行時切換為連續模式
ADC_ContinuousConvModeCmd(ADC1, ENABLE);

5. 完整示例(單次轉換 + 定時器觸發 + DMA)

#include "stm32f10x.h"uint16_t adcValue;void ADC_Config(void) {// 1. 啟用時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// 2. 配置PA0為模擬輸入GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);// 3. 配置TIM2(100Hz觸發)TIM_TimeBaseInitTypeDef TIM_InitStructure;TIM_InitStructure.TIM_Period = 720000 - 1;  // 72MHz / 720000 = 100HzTIM_InitStructure.TIM_Prescaler = 0;TIM_TimeBaseInit(TIM2, &TIM_InitStructure);TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);  // 更新事件觸發ADCTIM_Cmd(TIM2, ENABLE);// 4. 配置DMA(單次傳輸)DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&adcValue;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 1;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  // 循環模式DMA_Init(DMA1_Channel1, &DMA_InitStructure);DMA_Cmd(DMA1_Channel1, ENABLE);// 5. 配置ADC(單次轉換 + TIM2觸發)ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  // 單次模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfChannel = 1;ADC_Init(ADC1, &ADC_InitStructure);// 6. 配置ADC通道ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);// 7. 啟用ADC和DMAADC_DMACmd(ADC1, ENABLE);ADC_Cmd(ADC1, ENABLE);ADC_ResetCalibration(ADC1);while (ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1));
}int main(void) {ADC_Config();while (1) {// adcValue每10ms自動更新一次(由TIM2觸發)float voltage = adcValue * 3.3f / 4095;}
}

總結

  • 單次轉換模式:節能,適合低頻或事件觸發場景。
  • 連續轉換模式:實時性強,適合高頻或控制環路。
  • 硬件觸發:無論哪種模式,定時器均可精確控制采樣間隔。
  • 推薦組合
    • 低功耗應用:單次轉換 + 定時器觸發 + DMA。
    • 實時控制:連續轉換 + 定時器觸發 + DMA。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83319.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83319.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83319.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Pageassist安裝(ollama+deepseek-r1)

page-assist網站&#xff1a;https://github.com/n4ze3m/page-assist 首先電腦配置node.js&#xff0c;管理員打開命令窗口輸入下面命令下載bun npm install -g buncd 到你想要安裝page-assist的地方&#xff08;推薦桌面&#xff09; 輸入下列命令 git clone https://gith…

APC 熒光通道專用!Elabscience? CD11b 抗體激發 / 發射光譜精準匹配流式檢測

內容概要 Elabscience APC Anti-Mouse/Human CD11b Antibody [M1/70]&#xff08;貨號&#xff1a;E-AB-F1081E&#xff09;是一款高特異性熒光標記抗體&#xff0c;適用于流式細胞術&#xff08;FCM&#xff09;&#xff0c;可精準檢測小鼠和人類樣本中的 CD11b 髓系細胞&…

entity線段材質設置

在cesium中,我們可以改變其entity線段材質,這里以直線為例. 首先我們先創建一條直線 const redLine viewer.entities.add({polyline: {positions: Cesium.Cartesian3.fromDegreesArray([-75,35,-125,35,]),width: 5,material:material, 保存后可看到在地圖上創建了一條線段…

大模型數據分析破局之路20250512

大模型數據分析破局之路 本文面向 AI 初學者、數據分析從業者與企業技術負責人&#xff0c;圍繞大模型如何為數據分析帶來范式轉變展開&#xff0c;從傳統數據分析困境談起&#xff0c;延伸到 LLM MCP 的協同突破&#xff0c;最終落腳在企業實踐建議。 &#x1f30d; 開篇導語…

【MySQL】索引太多會怎樣?

在 MySQL 中&#xff0c;雖然索引可以顯著提高查詢效率&#xff0c;但過多的索引&#xff08;如超過 5-6 個&#xff09;會帶來以下弊端&#xff1a; 1. 存儲空間占用增加 每個索引都需要額外的磁盤空間存儲索引樹&#xff08;BTree&#xff09;。對于大表來說&#xff0c;多個…

使用PocketFlowSharp創建一個Human_Evaluation示例

效果 實踐 有時候AI生成的結果我們并不滿意在進入下一步之前&#xff0c;我們需要對AI生成的結果進行人工審核&#xff0c;同意了才能進入下一個流程。 Human_Evaluation就是人工判斷的一個簡單示例。 internal class Program{static async Task Main(string[] args){// Load…

【項目】自主實現HTTP服務器:從Socket到CGI全流程解析

00 引言 ? 在構建高效、可擴展的網絡應用時&#xff0c;理解HTTP服務器的底層原理是一項必不可少的技能。現代瀏覽器與移動應用大量依賴HTTP協議完成前后端通信&#xff0c;而這一過程的背后&#xff0c;是由網絡套接字驅動的請求解析、響應構建、數據傳輸等一系列機制所支撐…

SQL練習(6/81)

目錄 1.尋找連續值 方法一&#xff1a;使用自連接&#xff08;Self-Join&#xff09; 方法二&#xff1a;使用窗口函數&#xff08;Window Functions&#xff09; 2.尋找有重復的值 GROUP BY子句 HAVING子句 常用聚合函數&#xff1a; 3.找不存在某屬性的值 not in no…

【流程控制結構】

流程控制結構 流程控制結構1、順序結構2、選擇結構if基本選擇結構if else語法多重if語法嵌套if語法switch選擇結構 3、循環結構循環結構while循環結構程序調試for循環跳轉語句區別 流程控制結構 1、順序結構 流程圖 優先級 2、選擇結構 if基本選擇結構 單if 語法 if&…

【機器人】復現 UniGoal 具身導航 | 通用零樣本目標導航 CVPR 2025

UniGoal的提出了一個通用的零樣本目標導航框架&#xff0c;能夠統一處理多種類型的導航任務。 支持 對象類別導航、實例圖像目標導航和文本目標導航&#xff0c;而無需針對特定任務進行訓練或微調。 本文分享UniGoal復現和模型推理的過程&#xff5e; 查找沙發&#xff0c;模…

python + flask 做一個圖床

1. 起因&#xff0c; 目的: 對這個網站&#xff1a;https://img.vdoerig.com/ &#xff0c; 我也想實現這種效果。做一個簡單的圖床&#xff0c;后面&#xff0c;可以結合到其他項目中。 2. 先看效果 實際效果。 3. 過程: Grok 聊天&#xff1a; https://img.vdoerig.co…

Java生產環境設限參數教學

哈哈&#xff0c;這個問題問得好&#xff01;咱們用開餐廳的比喻來理解生產環境的四大必須設限參數&#xff0c;保證你聽完再也不會忘&#xff01;&#xff08;搓手手&#xff09; 1. 堆內存上限&#xff1a;-Xmx&#xff08;廚房的最大容量&#xff09; 問題&#xff1a;想象…

電腦出故障驅動裝不上?試試驅動人生的遠程服務支持

在日常工作或學習中&#xff0c;驅動問題時常成為電腦用戶的一大困擾。尤其是在更換硬件、重裝系統、驅動沖突等情況下&#xff0c;許多用戶往往手足無措&#xff0c;不知道從何下手。而“驅動人生”作為國內領先的驅動管理工具&#xff0c;一直以高效、便捷、智能著稱。現在&a…

JS手寫代碼篇---手寫 instanceof 方法

2、手寫 instanceof 方法 instancecof用于檢測一個對象是否是某個構造函數的實例。它通常用于檢查對象的類型&#xff0c;尤其是在處理繼承關系時。 eg: const arr [1,2,3,4,5]console.log(arr instanceof Array); // trueconsole.log(arr instanceof Object); // true那這是…

使用exceljs將excel文件轉化為html預覽最佳實踐(完整源碼)

前言 在企業應用中&#xff0c;我們時常會遇到需要上傳并展示 Excel 文件的需求&#xff0c;以實現文件內容的在線預覽。經過一番探索與嘗試&#xff0c;筆者最終借助 exceljs 這一庫成功實現了該功能。本文將以 Vue 3 為例&#xff0c;演示如何實現該功能&#xff0c;代碼示例…

PMP-第十二章 項目采購管理

項目采購管理核心概念 項目采購管理包括從項目團隊外部采購或獲取所需產品、服務或成果的各個過程項目組織既可以是買方&#xff08;甲方&#xff09; &#xff0c;也可以是賣方&#xff08;乙 方&#xff09;項目采購管理過程圍繞協議來進行&#xff0c;協議是買賣雙方之間具…

maven和npm區別是什么

這是一個很容易搞糊涂新手的問題&#xff0c;反正我剛開始從課堂的知識轉向項目網站開發時&#xff0c;被這些問題弄得暈頭轉向&#xff0c;摸不著頭腦&#xff0c;學的糊里糊涂&#xff0c;所以&#xff0c;寫了這么久代碼&#xff0c;也總結一下&#xff0c;為后來者傳授下經…

Leetcode76覆蓋最小子串

覆蓋最小子串 代碼來自b站左程云 class Solution {public String minWindow(String str, String tar) {char[] s str.toCharArray();char[] t tar.toCharArray();int[] cnt new int[256];for (char cha : t) { cnt[cha]--;}int len Integer.MAX_VALUE;int debt t.length…

Linux du 命令終極指南:從基礎到精通

文章目錄 Linux du 命令終極指南&#xff1a;從基礎到精通du 命令簡介常用參數詳解常見用法示例查看當前目錄總大小查看當前目錄及其子目錄占用空間只顯示當前目錄總占用空間查看目錄下每個文件和子目錄的大小查看某目錄深度為 1 的大小分布查看某目錄并排除日志文件查看多個目…

sychronized原理(嚼碎了喂版)

先說一下心得吧&#xff0c;我們知道硬軟不分家&#xff0c;在學習底層原理的時候我們不需要死扣到底&#xff0c;沒必要把硬件方面全吃透&#xff0c;點到為止&#xff0c;學到能夠幫助理解代碼即可&#xff0c;我們的目標是寫出高性能的代碼&#xff0c;而不是創造出硬軟一體…