文章目錄
- 一、ADC
- 1.1簡介
- 1. 2逐次逼近型ADC
- 1.3ADC框圖
- 1.4ADC基本結構
- 1.4.1 信號 “上車點”:輸入模塊(GPIO、溫度、V_REFINT)
- 1.4.2 信號 “調度站”:多路開關
- 1.4.3 信號 “加工廠”:ADC 轉換器(規則組 + 注入組)
- 1.4.4信號 “暫存柜”:AD 數據寄存器
- 1.4.5 信號 “監督員”:模擬看門狗
- 1.4.6信號 “報警器”:中斷輸出控制 + NVIC
- 1.4.7 系統 “動力源”:觸發控制 + RCC
- 1.4.8系統 “總開關”:開關控制
- 1.5輸入通道
- 1.6轉換模式
- 1.7觸發控制
- 1.8數據對齊
- 1.9轉換時間
- 1.10校準
- 1.11硬件電路
- 二、AD單通道
- 2.1接線圖
- 2.2代碼
- 2.3ADC 相關 API 函數
- 1. 時鐘配置函數
- 2. GPIO 配置函數
- 3. ADC 配置函數
- 4. ADC 控制函數
- 5. 狀態和數據讀取函數
- 2.4工作現象
- 三、AD多通道
- 3.1接線圖
- 3.2代碼
- 3.3AD單通道未提及的關鍵 API
- 1. ADC 通道配置函數
- 2. 采樣時間說明
- 3. ADC 狀態標志位
- 3.4工作現象
- 1. **光敏傳感器(AO 接 ADC 通道,如 PA0)**
- 2. **聲音傳感器(AO 接 ADC 通道,如 PA1)**
- 3. **紅外避障傳感器(AO 接 ADC 通道,如 PA2)**
- 4. **電位器(中間引腳接 ADC 通道,如 PA3)**
一、ADC
1.1簡介
1. 2逐次逼近型ADC
1.3ADC框圖
1.4ADC基本結構
以下用更通俗的 “信號 journey(旅程)” 邏輯,拆解各模塊咋連接、咋配合干活:
1.4.1 信號 “上車點”:輸入模塊(GPIO、溫度、V_REFINT)
- GPIO(16 路):像 16 個 “小天線”,能接外部五花八門的模擬信號(比如傳感器電壓、旋鈕調節的電平 ),是最常用的信號入口。
- 溫度傳感器:專門測溫度,把溫度變化轉成電壓信號,相當于 “溫度→電信號” 翻譯器。
- V_REFINT:內部精準參考電壓,像 “標準尺”,給 ADC 轉換當基準(比如轉換時拿信號和它比,確定數字值 )。
這些信號要先 “排隊上車”,統一交給 多路開關(下面講它的作用 )。
1.4.2 信號 “調度站”:多路開關
- 作用:當 “交通調度員”,決定讓哪路信號進 ADC 轉換器。
- 邏輯:比如同時有 GPIO、溫度傳感器的信號,它選 1 路(規則組模式)或幾路(注入組模式 ),送往后邊的 ADC 轉換器。
1.4.3 信號 “加工廠”:ADC 轉換器(規則組 + 注入組)
- 規則組(最多 16 路):常規 “生產線”,按預設順序、節奏轉換信號(比如循環采集 16 路 GPIO ),適合普通、批量的轉換需求。
- 注入組(最多 4 路):“加急生產線”,優先級更高!遇到緊急信號(比如關鍵傳感器超閾值 ),能插隊先轉換,靈活處理特殊需求。
不管規則組還是注入組,干的事一樣:把模擬信號(連續電壓 )切成數字信號(0 和 1 組成的編碼 )。
1.4.4信號 “暫存柜”:AD 數據寄存器
- 轉換完的數字信號,得找地方 “臨時存一下”:
- 規則組結果:存在 “規則結果 ×1” 里(1 組數據對應 1 個寄存器 )。
- 注入組結果:存在 “注入結果 ×4” 里(最多存 4 組,方便快速連續處理 )。
- 就像工廠生產完零件,先放倉庫,等 CPU 來 “取貨” 處理。
1.4.5 信號 “監督員”:模擬看門狗
- 作用:當 “質量檢測員”,盯著轉換后的數字信號,看是否超出你設定的范圍(比如溫度不能太高 / 太低 )。
- 觸發:一旦超范圍,立馬發信號(相當于 “報警” ),告訴系統 “這信號有問題!”
1.4.6信號 “報警器”:中斷輸出控制 + NVIC
- 中斷輸出控制:收到模擬看門狗的 “報警” 后,整理信號,決定咋通知系統。
- NVIC(嵌套向量中斷控制器):系統的 “總調度臺”,收到中斷信號后,暫停當前任務,優先處理 “信號異常” 事件(比如觸發緊急程序、記錄日志 )。
1.4.7 系統 “動力源”:觸發控制 + RCC
- RCC(時鐘控制器):給 ADC 整個系統提供 “心跳”(時鐘信號 ),所有模塊得跟著時鐘節奏干活,否則會亂套。
- 觸發控制:決定啥時候啟動 ADC 轉換,像 “開關”:可以軟件手動觸發(程序里寫代碼啟動 ),也能硬件觸發(比如定時器定時啟動 ),發的信號叫 “START”。
1.4.8系統 “總開關”:開關控制
- 簡單粗暴:控制 ADC 模塊整體 “開 / 關”。不用 ADC 時,關掉省點電;要用時,打開干活。
1.5輸入通道
1.6轉換模式
1.7觸發控制
1.8數據對齊
1.9轉換時間
1.10校準
1.11硬件電路
二、AD單通道
2.1接線圖
2.2代碼
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t ADValue; //定義AD值變量
float Voltage; //定義電壓變量int main(void)
{/*模塊初始化*/OLED_Init(); //OLED初始化AD_Init(); //AD初始化/*顯示靜態字符串*/OLED_ShowString(1, 1, "ADValue:");OLED_ShowString(2, 1, "Voltage:0.00V");while (1){ADValue = AD_GetValue(); //獲取AD轉換的值Voltage = (float)ADValue / 4095 * 3.3; //將AD值線性變換到0~3.3的范圍,表示電壓OLED_ShowNum(1, 9, ADValue, 4); //顯示AD值OLED_ShowNum(2, 9, Voltage, 1); //顯示電壓值的整數部分OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2); //顯示電壓值的小數部分Delay_ms(100); //延時100ms,手動增加一些轉換的間隔時間}
}
AD.c
#include "stm32f10x.h" // Device header/*** 函 數:AD初始化* 參 數:無* 返 回 值:無*/
void AD_Init(void)
{/*開啟時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //開啟ADC1的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘/*設置ADC時鐘*/RCC_ADCCLKConfig(RCC_PCLK2_Div6); //選擇時鐘6分頻,ADCCLK = 72MHz / 6 = 12MHz/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //將PA0引腳初始化為模擬輸入/*規則組通道配置*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //規則組序列1的位置,配置為通道0/*ADC初始化*/ADC_InitTypeDef ADC_InitStructure; //定義結構體變量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,選擇獨立模式,即單獨使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //數據對齊,選擇右對齊ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部觸發,使用軟件觸發,不需要外部觸發ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //連續轉換,失能,每轉換一次規則組序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE; //掃描模式,失能,只轉換規則組的序列1這一個位置ADC_InitStructure.ADC_NbrOfChannel = 1; //通道數,為1,僅在掃描模式下,才需要指定大于1的數,在非掃描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure); //將結構體變量交給ADC_Init,配置ADC1/*ADC使能*/ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC開始運行/*ADC校準*/ADC_ResetCalibration(ADC1); //固定流程,內部有電路會自動執行校準while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);
}/*** 函 數:獲取AD轉換的值* 參 數:無* 返 回 值:AD轉換的值,范圍:0~4095*/
uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1, ENABLE); //軟件觸發AD轉換一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC標志位,即等待AD轉換結束return ADC_GetConversionValue(ADC1); //讀數據寄存器,得到AD轉換的結果
}
2.3ADC 相關 API 函數
1. 時鐘配置函數
c
運行
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
-
功能:啟用或禁用 APB2 總線上的外設時鐘(如 ADC1、GPIOA)。
-
參數 :
RCC_APB2Periph
:外設選擇(如RCC_APB2Periph_ADC1
、RCC_APB2Periph_GPIOA
)。NewState
:ENABLE
或DISABLE
。
c
運行
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
-
功能:配置 ADC 時鐘分頻(ADC 時鐘必須 ≤ 14MHz)。
-
參數 :
RCC_PCLK2
:分頻選項(如RCC_PCLK2_Div6
表示 72MHz/6=12MHz)。
2. GPIO 配置函數
c
運行
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
-
功能:初始化 GPIO 引腳。
-
參數 :
GPIOx
:GPIO 端口(如GPIOA
)。GPIO_InitStruct
:GPIO 配置結構體(模式、引腳、速度)。
3. ADC 配置函數
c
運行
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
-
功能:配置規則組通道的轉換順序和采樣時間。
-
參數 :
ADCx
:ADC 外設(如ADC1
)。ADC_Channel
:通道號(如ADC_Channel_0
對應 PA0)。Rank
:序列位置(1~16)。ADC_SampleTime
:采樣周期(如ADC_SampleTime_55Cycles5
)。
c
運行
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
-
功能:初始化 ADC 參數。
-
參數 :
ADCx
:ADC 外設。ADC_InitStruct
:ADC 配置結構體(模式、對齊方式、觸發方式等)。
4. ADC 控制函數
c
運行
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
-
功能:啟用或禁用 ADC。
-
參數 :
ADCx
:ADC 外設。NewState
:ENABLE
或DISABLE
。
c
運行
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
-
功能:軟件觸發 ADC 轉換。
-
參數 :
ADCx
:ADC 外設。NewState
:ENABLE
觸發一次轉換。
c
運行
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
- 功能:ADC 校準流程(復位校準、獲取復位狀態、開始校準、獲取校準狀態)。
5. 狀態和數據讀取函數
c
運行
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
-
功能:檢查 ADC 標志位狀態(如轉換完成標志
ADC_FLAG_EOC
)。 -
參數 :
ADCx
:ADC 外設。ADC_FLAG
:標志位類型。
c
運行
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
-
功能:獲取 ADC 轉換結果(0~4095,12 位分辨率)。
-
參數 :
ADCx
:ADC 外設。
AD.h
#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t AD_GetValue(void);#endif
2.4工作現象
- 初始化階段
- 調用
AD_Init()
后,ADC1 時鐘開啟,GPIOA 引腳配置為模擬輸入模式,規則組通道 0(PA0)完成配置,ADC 進入就緒狀態。 - 校準過程中,
ADC_ResetCalibration
和ADC_StartCalibration
會觸發內部校準電路工作,校準完成后標志位自動清除。
- 調用
- 轉換階段
- 調用
AD_GetValue()
時,軟件觸發轉換(ADC_SoftwareStartConvCmd
),ADC_FLAG_EOC
標志位在轉換完成后置 1,返回值在 0~4095 范圍內(對應輸入電壓 0~3.3V)。 - 若輸入電壓穩定(如接固定電阻分壓),多次讀取的 ADC 值波動較小(通常≤±3LSB)。
- 調用
- 數據對應關系
三、AD多通道
3.1接線圖
3.2代碼
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t AD0, AD1, AD2, AD3; //定義AD值變量int main(void)
{/*模塊初始化*/OLED_Init(); //OLED初始化AD_Init(); //AD初始化/*顯示靜態字符串*/OLED_ShowString(1, 1, "AD0:");OLED_ShowString(2, 1, "AD1:");OLED_ShowString(3, 1, "AD2:");OLED_ShowString(4, 1, "AD3:");while (1){AD0 = AD_GetValue(ADC_Channel_0); //單次啟動ADC,轉換通道0AD1 = AD_GetValue(ADC_Channel_1); //單次啟動ADC,轉換通道1AD2 = AD_GetValue(ADC_Channel_2); //單次啟動ADC,轉換通道2AD3 = AD_GetValue(ADC_Channel_3); //單次啟動ADC,轉換通道3OLED_ShowNum(1, 5, AD0, 4); //顯示通道0的轉換結果AD0OLED_ShowNum(2, 5, AD1, 4); //顯示通道1的轉換結果AD1OLED_ShowNum(3, 5, AD2, 4); //顯示通道2的轉換結果AD2OLED_ShowNum(4, 5, AD3, 4); //顯示通道3的轉換結果AD3Delay_ms(100); //延時100ms,手動增加一些轉換的間隔時間}
}
AD.c
#include "stm32f10x.h" // Device header/*** 函 數:AD初始化* 參 數:無* 返 回 值:無*/
void AD_Init(void)
{/*開啟時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //開啟ADC1的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘/*設置ADC時鐘*/RCC_ADCCLKConfig(RCC_PCLK2_Div6); //選擇時鐘6分頻,ADCCLK = 72MHz / 6 = 12MHz/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //將PA0、PA1、PA2和PA3引腳初始化為模擬輸入/*不在此處配置規則組序列,而是在每次AD轉換前配置,這樣可以靈活更改AD轉換的通道*//*ADC初始化*/ADC_InitTypeDef ADC_InitStructure; //定義結構體變量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,選擇獨立模式,即單獨使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //數據對齊,選擇右對齊ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部觸發,使用軟件觸發,不需要外部觸發ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //連續轉換,失能,每轉換一次規則組序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE; //掃描模式,失能,只轉換規則組的序列1這一個位置ADC_InitStructure.ADC_NbrOfChannel = 1; //通道數,為1,僅在掃描模式下,才需要指定大于1的數,在非掃描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure); //將結構體變量交給ADC_Init,配置ADC1/*ADC使能*/ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC開始運行/*ADC校準*/ADC_ResetCalibration(ADC1); //固定流程,內部有電路會自動執行校準while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);
}/*** 函 數:獲取AD轉換的值* 參 數:ADC_Channel 指定AD轉換的通道,范圍:ADC_Channel_x,其中x可以是0/1/2/3* 返 回 值:AD轉換的值,范圍:0~4095*/
uint16_t AD_GetValue(uint8_t ADC_Channel)
{ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); //在每次轉換前,根據函數形參靈活更改規則組的通道1ADC_SoftwareStartConvCmd(ADC1, ENABLE); //軟件觸發AD轉換一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC標志位,即等待AD轉換結束return ADC_GetConversionValue(ADC1); //讀數據寄存器,得到AD轉換的結果
}
AD.h
#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t AD_GetValue(uint8_t ADC_Channel);#endif
3.3AD單通道未提及的關鍵 API
除了之前提到的 ADC API,這段代碼還涉及以下未詳細說明的函數:
1. ADC 通道配置函數
c
運行
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
-
功能:配置規則組序列中的通道及其采樣時間。
-
參數 :
ADC_Channel
:通道號(如ADC_Channel_0
~ADC_Channel_17
)。Rank
:序列位置(1~16,單通道模式下固定為 1)。ADC_SampleTime
:采樣周期(如ADC_SampleTime_55Cycles5
)。
2. 采樣時間說明
ADC 采樣時間影響轉換精度和速度,可選值包括:
c
運行
ADC_SampleTime_1Cycles5 // 1.5個ADC時鐘周期(最快)
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個周期(最慢,抗干擾最強)
3. ADC 狀態標志位
c
運行
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
-
常用標志位 :
ADC_FLAG_EOC
:規則組轉換完成標志(代碼中使用)。ADC_FLAG_AWD
:模擬看門狗觸發標志(需額外配置)。ADC_FLAG_OVR
:數據溢出標志(連續轉換模式下可能出現)。
3.4工作現象
-
初始化后:ADC1 和 GPIOA 時鐘開啟,PA0~PA3 配置為模擬輸入模式,ADC 處于就緒狀態但未開始轉換(需調用
AD_GetValue()
觸發)。 -
動態通道選擇:每次調用
AD_GetValue(channel)
時,會臨時配置規則組序列 1 為指定通道(如ADC_Channel_2
對應 PA2),然后觸發單次轉換。 -
轉換結果
:返回值范圍為 0~4095,對應輸入電壓 0~3.3V(假設 VREF 為 3.3V)。例如:
- 輸入 1.65V → 返回值約為 2048(1.65V/3.3V × 4095 ≈ 2048)。
- 輸入懸空(無信號)→ 返回隨機值(受噪聲影響)。
1. 光敏傳感器(AO 接 ADC 通道,如 PA0)
-
現象 :
- 光照越強(如手電筒照射),ADC 值 越大(對應電壓越高,假設傳感器輸出與光照正相關);
- 光照越弱(手遮擋),ADC 值 越小,OLED / 串口數據同步變化。
-
原理:光敏電阻阻值隨光照變化,轉換為電壓信號被 ADC 采集。
2. 聲音傳感器(AO 接 ADC 通道,如 PA1)
-
現象 :
- 安靜時,ADC 值 穩定在低范圍(背景噪聲小);
- 拍手 / 說話時,ADC 值 瞬間跳升(聲音越強,跳升幅度越大),數據波動明顯。
-
原理:咪頭采集聲波,轉換為電壓波動,ADC 捕捉瞬時變化。
3. 紅外避障傳感器(AO 接 ADC 通道,如 PA2)
-
現象 :
- 無遮擋時,ADC 值 接近最大值(紅外反射強,輸出電壓高);
- 手靠近遮擋時,ADC 值 驟降(反射弱,電壓低),響應迅速。
-
原理:紅外發射 + 接收,距離 / 遮擋影響反射強度,轉換為電壓變化。
4. 電位器(中間引腳接 ADC 通道,如 PA3)
-
現象 :
- 順時針旋轉:ADC 值 從 0→4095 線性遞增(或遞減,取決于接線方向);
- 逆時針旋轉:ADC 值 反向遞減 / 遞增,變化平滑無跳變。
-
原理:電位器分壓,輸出電壓與旋轉角度線性相關。