問題原由
粉絲提問,STM32如何驅(qū)動ADC0809芯片
,恰好我有空,時間來得及,粉絲有需求,小哈哥必須安排,這次發(fā)文總結(jié)一下,希望可以幫助大家。
- Keil 5
- 主芯片為STM32F103RET6
- 下載工具為JLINK
- XCOM V2.0串口助手
- PC為Win10
微信公眾號后臺回復(fù)“Q&A3”,可以下載工程源碼。
習(xí)慣購買元器件多買一個,方便替換驗證。
因為做過一次驗證之后,這個板子就沒有用了,所以購買DIP-28寬體底座,讓底座焊板子上,芯片插底座上,方便芯片的二次使用,節(jié)約成本。
粉絲買的下圖這種模塊:
STM32要想驅(qū)動ADC0809這個芯片需要很多個引腳(不考慮復(fù)用的話,需要16個引腳),如果這些引腳都用杜邦線連接的話會很亂,如果哪個杜邦線再接觸不好,那么對于程序的調(diào)試很不方便,所以我就采用核心板+底板的形式來實現(xiàn),避免使用過多的杜邦線。
現(xiàn)在打樣很便宜,線很多,時間來得及的話,推薦使用線路板的方式來驗證。
我這次網(wǎng)友問答超時了,買件+PCB打樣+調(diào)試程序,一共用了9天時間,如果不需要打樣的實例,一周之內(nèi)應(yīng)該可以完成的。
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)換起??刂贫恕?/p>
3)轉(zhuǎn)換時間為100μs(時鐘為640KHz時),130μs(時鐘為500KHz時)。
4)單個+5V電源供電
5)模擬輸入電壓范圍0~+5V,不需零點(diǎn)和滿刻度校準(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,正在進(jìn)行轉(zhuǎn)換。EOC=1,轉(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)用圖:
注意:ADC0809_D0為輸出數(shù)據(jù)的最低位,ADC0809_D7為輸出數(shù)據(jù)的最高位。
(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ù)便可以讀取了。
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 V\r\n",sum,adc);
return adc;
}
要想ADC0809芯片能夠正常的進(jìn)行AD轉(zhuǎn)換,必須給CLOCK引腳提供一個時鐘脈沖信號,脈沖的頻率范圍為:
這個脈沖信號可以采用定時器中斷的方式來產(chǎn)生脈沖信號或者使用PWM的方式來產(chǎn)生PWM信號,本實例采用PWM的方式,引腳選擇了一個帶有PWM功能的引腳PA7:TIM3_CH2。
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
因為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 V\r\n",sum,adc);
我們用杜邦線將IN0與板子上的GND、3.3V、5V依次相連,串口助手輸出結(jié)果如下:
好了,今天的網(wǎng)友問答就分享到這里,各位可以利用咱們的核心板,自己做一個底板,玩起來哈。
文章如果覺得不錯,賞個三連鼓勵一下哈!~~~
一個專注于嵌入式知識分享,學(xué)習(xí)路上不迷路的公眾號,歡迎關(guān)注。