問題原由
粉絲提問,STM32 如何驅(qū)動 ADC0809 芯片
,時間來得及,粉絲有需求,小哈哥必須安排,這次發(fā)文總結(jié)一下,希望可以幫助大家。
開發(fā)環(huán)境與工具
- Keil 5主芯片為 STM32F103RET6下載工具為 JLINKXCOM V2.0 串口助手PC 為 Win10
程序源碼
微信公眾號后臺回復(fù)“Q&A3”,可以下載工程源碼及 ADC0809 數(shù)據(jù)手冊。
準(zhǔn)備工作
購買 ADC0809 芯片
習(xí)慣購買元器件多買一個,方便替換驗證。
因為做過一次驗證之后,這個板子就沒有用了,所以購買 DIP-28 寬體底座,讓底座焊板子上,芯片插底座上,方便芯片的二次使用,節(jié)約成本。
PCB 打板
粉絲買的下圖這種模塊:
STM32 要想驅(qū)動 ADC0809 這個芯片需要很多個引腳(不考慮復(fù)用的話,需要 16 個引腳),如果這些引腳都用杜邦線連接的話會很亂,如果哪個杜邦線再接觸不好,那么對于程序的調(diào)試很不方便,所以我就采用核心板+底板的形式來實現(xiàn),避免使用過多的杜邦線。
現(xiàn)在打樣很便宜,線很多,時間來得及的話,推薦使用線路板的方式來驗證。
我這次網(wǎng)友問答超時了,買件+PCB 打樣+調(diào)試程序,一共用了 9 天時間,如果不需要打樣的實例,一周之內(nèi)應(yīng)該可以完成的。
ADC0809 簡介
ADC0809 是采樣精度為 8 位的、以逐次逼近原理進(jìn)行模—數(shù)轉(zhuǎn)換的器件。其內(nèi)部有一個 8 通道多路開關(guān),它可以根據(jù)地址碼鎖存譯碼后的信號,只選通 8 路模擬輸入信號中的一個進(jìn)行 A/D 轉(zhuǎn)換。
主要特性
1)8 通道輸入,擁有一個 8 位的 A/D 轉(zhuǎn)換器,即分辨率 8 位;
2)具有轉(zhuǎn)換起停控制端;
3)轉(zhuǎn)換時間為 100μs(時鐘為 640KHz 時),130μs(時鐘為 500KHz 時);
4)單個+5V 電源供電;
5)模擬輸入電壓范圍 0~+5V,不需零點和滿刻度校準(zhǔn);
6)工作溫度范圍為 -40~+85 攝氏度;
7)低功耗,約 15mW。
引腳圖與功能
管腳功能說明:
IN0-IN7:模擬量輸入通道,共計 8 個通道;
ADD A-C:通道選擇引腳,通過這三根地址線的不同組合選擇 IN0 - IN7 中的一個作為模擬量的輸入通道;
ALE:地址鎖存允許信號;
START:啟動 A/D 轉(zhuǎn)換信號;
D0-D7:數(shù)據(jù)輸出口,ADC 轉(zhuǎn)換后的結(jié)果通過這 8 個引腳并行輸出;
OE(OUTPUT ENABLE):輸出允許信號,此引腳為輸入端,高電平有效。當(dāng) A/D 轉(zhuǎn)換結(jié)束時,此端輸入一個高電平,才能打開輸出三態(tài)門,輸出數(shù)字量;
CLOCK:時鐘信號,輸入脈沖。ADC0809 內(nèi)部沒有時鐘電路,需由外部提供時鐘脈沖信號。時鐘頻率范圍為 10KHz-1280KHz,典型值 640KHz;
EOC:轉(zhuǎn)換結(jié)束狀態(tài)信號。輸出信號,EOC=0,標(biāo)識正在進(jìn)行轉(zhuǎn)換。EOC=1,標(biāo)識轉(zhuǎn)換結(jié)束,可以進(jìn)行下一步輸出操作;即當(dāng) A/D 轉(zhuǎn)換結(jié)束時,此端輸出一個高電平(轉(zhuǎn)換期間一直為低電平);
Vref(+)、Vref(-):參考電壓(基準(zhǔn)電壓)。參考電壓用來與輸入的模擬量進(jìn)行比較,作為測量的基準(zhǔn)。一般 Vref(+)=+5V ,Vref(-)=0V;
VCC:電源引腳,單電源 +5V;
GND:地 。
原理圖
數(shù)據(jù)手冊中的典型應(yīng)用圖:
STM32 與 ADC0809 接線
ADC0809 引腳 | STM32 引腳 | GPIO 方向 |
---|---|---|
START | PA2 | 輸出 |
EOC | PA3 | 輸入 |
OE | PA4 | 輸出 |
CLOCK | PA7 | 輸出 |
ALE | PA6 | 輸出 |
ADD A | PA5 | 輸出 |
ADD B | PB10 | 輸出 |
ADD C | PB11 | 輸出 |
ADC0809_D0 | PA11 | 輸入 |
ADC0809_D1 | PA12 | 輸入 |
ADC0809_D2 | PC10 | 輸入 |
ADC0809_D3 | PC11 | 輸入 |
ADC0809_D4 | PC12 | 輸入 |
ADC0809_D5 | PD2 | 輸入 |
ADC0809_D6 | PB13 | 輸入 |
ADC0809_D7 | PB12 | 輸入 |
注意:ADC0809_D0 為輸出數(shù)據(jù)的最低位,ADC0809_D7 為輸出數(shù)據(jù)的最高位。
時序圖
ADC0809 工作過程
(1)控制與 ADDA~ADDC 相連的引腳,選擇一個模擬輸入端;
(2)CLOCK 端輸入一個時鐘信號,本文通過 STM32 的 PWM 實現(xiàn)此脈沖,脈沖頻率 100 KHz;
(3)將 ALE 由低電平置為高電平,從而將 ADDA-ADDC 送進(jìn)的通道代碼鎖存,經(jīng)譯碼后被選中的通道的模擬量送給內(nèi)部轉(zhuǎn)換單元;
(4)給 START 一個正脈沖。當(dāng)上升沿時,所有內(nèi)部寄存器清零。下降沿時,開始進(jìn)行 A/D 轉(zhuǎn)換;在轉(zhuǎn)換期間,START 保持低電平;
(5)讀取 EOC 引腳的狀態(tài),A/D 轉(zhuǎn)換期間,EOC 輸入低電平;A/D 轉(zhuǎn)換結(jié)束,EOC 引腳輸入高電平;
(6)當(dāng) A/D 轉(zhuǎn)換結(jié)束后,將 OE 設(shè)置為 1,這時 D0-D7 的數(shù)據(jù)便可以讀取了。
AD 轉(zhuǎn)換的代碼實現(xiàn)
float get_adc0809()
{
int i=0;
u8 sum=0;
float adc=0;
int AD_DATA[8] = {0};
ADC0809_ALE=0;
ADC0809_START=0;
delay_us(10);
ADC0809_ALE=1;
ADC0809_START=1;
delay_us(10);
ADC0809_ALE=0;
ADC0809_START=0; // 啟動 AD 轉(zhuǎn)換
while(0==ADC0809_EOC); // 等待轉(zhuǎn)換結(jié)束
ADC0809_OE=1;
AD_DATA[0]=ADC0809_D0*1 ;
AD_DATA[1]=ADC0809_D1*2 ;
AD_DATA[2]=ADC0809_D2*4 ;
AD_DATA[3]=ADC0809_D3*8 ;
AD_DATA[4]=ADC0809_D4*16 ;
AD_DATA[5]=ADC0809_D5*32 ;
AD_DATA[6]=ADC0809_D6*64 ;
AD_DATA[7]=ADC0809_D7*128 ;
ADC0809_OE=0;
for(i=0; i<8; i++)
{
sum += AD_DATA[i];
}
adc = (float)sum*5/256;
printf("sum=%d ad=%0.2f Vrn",sum,adc);
return adc;
}
CLOCK 時鐘信號
要想 ADC0809 芯片能夠正常的進(jìn)行 AD 轉(zhuǎn)換,必須給 CLOCK 引腳提供一個時鐘脈沖信號,脈沖的頻率范圍為:
這個脈沖信號可以采用定時器中斷的方式來產(chǎn)生脈沖信號或者使用 PWM 的方式來產(chǎn)生脈沖信號,本實例采用 PWM 的方式,引腳選擇了一個帶有 PWM 功能的引腳PA7:TIM3_CH2。
PWM 初始化
PWM 初始化之后,直接使能 PWM 的輸出,即始終有占空比 50%的脈沖信號輸入到 ADC0809 芯片的 CLOCK 引腳中。
//arr 為重載值
//psc 為預(yù)分頻系數(shù)
void Clock_PWM_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_DeInit(TIM3);
/* Time Base configuration */
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = psc;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //TIM3_CH2
TIM_CtrlPWMOutputs(TIM3, ENABLE);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_Cmd(TIM3, ENABLE);
TIM_SetCompare2(TIM3,arr/2);
}
main 函數(shù)中調(diào)用如下:
Clock_PWM_Init(720-1,0); //PWM 頻率=72000/720 = 100Khz
AD 結(jié)果轉(zhuǎn)換
因為 ADC0809 為 8 位的 AD 芯片,所以我們將 8 位數(shù)據(jù)中的每一位數(shù)據(jù)緩存至一個數(shù)組中,然后對這個數(shù)組中的值求和即為此次 AD 的采樣值。
因為參考電壓 Vref(+)=+5V ,Vref(-)=0V ,所以 8 位數(shù)的最大值 0xFF 對應(yīng) 5V,0x00 對應(yīng) 0V,所以 AD 采樣值和電壓值的換算公式為:adc = (float)sum*5/256; 。
具體換算的代碼如下:
u8 sum=0;
float adc=0;
int AD_DATA[8] = {0};
AD_DATA[0]=ADC0809_D0*1 ;
AD_DATA[1]=ADC0809_D1*2 ;
AD_DATA[2]=ADC0809_D2*4 ;
AD_DATA[3]=ADC0809_D3*8 ;
AD_DATA[4]=ADC0809_D4*16 ;
AD_DATA[5]=ADC0809_D5*32 ;
AD_DATA[6]=ADC0809_D6*64 ;
AD_DATA[7]=ADC0809_D7*128 ;
for(i=0; i<8; i++)
{
sum += AD_DATA[i];
}
adc = (float)sum*5/256;
printf("sum=%d ad=%0.2f Vrn",sum,adc);
結(jié)果展示
我們用杜邦線將 IN0 與板子上的 GND、3.3V、5V 依次相連,串口助手輸出結(jié)果如下:
好了,今天的網(wǎng)友問答就分享到這里,各位可以利用咱們的核心板,自己做一個底板,玩起來哈。