COIDE İLE NUCLEO-F401RE PROGRAMLAMA – ADC Uygulaması

Bu uygulamamızda kitimize bağlayacağımız bir potansiyometre üzerinden okuyacağımız gerilim değerine göre ledin ışık şiddetini ayarlayacağız. Gerilim okuyabilmek için mikrokontrolümüz içerisinde bulunan analog dijital çeviriciyi (ADC) kullanacağız. Bunun için NUCLEO kitimizin PA0 pinine bir potansiyometre bağlayacağız. NUCLEO kitinin kullanıcı klavuzundan aldığım aşağıdaki resimde görüldüğü gibi PA0 pini Arduino konnektörünün A0 pinine bağlı. Potansiyometrenin orta pinini A0’a, diğer iki pinini ise 3.3V ve GND’ye bağlamamız gerekiyor.

coide_adc_1

coide_adc_3

Bağlantıları yaptıktan sonra kodumuzu oluşturuyoruz.

#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_adc.h"

uint16_t ADC1ConvertedValue = 0;

void Set_Duty(uint32_t Duty);

int main(void)
{

/* GPIO init */
// LED PIN AYARI
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // A portunun saat darbesini aktifleştidik.

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 5 numaralı pin için ayarlıyoruz.
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // Pin çıkış tipini ayarladık.
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // Pinimizi output olarak ayarladık.
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // Pull Up direncini pasif yaptık.
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // Pinin maksimum çalışma frekansını ayarladık.
GPIO_Init(GPIOA, &GPIO_InitStructure); // Ayarları uyguluyoruz.
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_TIM2);

/* Configure ADC1 Channel0 pin as analog input ******************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = (SystemCoreClock / 10000 ) - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

/* Channel 1 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

TIM_OCInitStructure.TIM_Pulse = 0; // Duty değeri
TIM_OC1Init(TIM2, &TIM_OCInitStructure);

/* TIM2 counter enable */
TIM_Cmd(TIM2, ENABLE);

/* TIM2 Main Output Enable */
TIM_CtrlPWMOutputs(TIM2, ENABLE);
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;

/* Enable ADC1 clock so that we can talk to it */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* ADC Common Init **********************************************************/
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);

/* ADC1 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);

/* ADC1 regular channel0 configuration *************************************/
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);

/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
while (1)
{
ADC_SoftwareStartConv(ADC1);

/* Test EOC flag */
while ( ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC ) == RESET );

/* Get ADC1 converted data */
ADC1ConvertedValue = ADC_GetConversionValue( ADC1 );

Set_Duty((ADC1ConvertedValue*100) /255); // ADC değerini % olarak ayarladık.

}

}// main sonu.

void Set_Duty(uint32_t Duty)
{
TIM_SetCompare1(TIM2, (Duty * ((SystemCoreClock / 10000 ) - 1)) / 100); // Duty değerini ayarla.
}

Şimdi adım adım kodumuzu inceleyelim:

Öncelikle projemize ADC kütüphanesini ekledik.

uint16_t  ADC1ConvertedValue = 0;

Okunan ADC değerinin tutulacağı değişkeni tanımladık.

/* Configure ADC1 Channel0 pin as analog input ******************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);

Potansiyometreyi bağladığımız PA0 pinini analog giriş olarak ayarladık.

/* ADC Common Init **********************************************************/
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);

ADC’yi bağımsız çalışacak şekilde ayarladık. ADC’nin kullandığı clock frekansını ikiye böldük, DMA kullanmayacağımız için disable yaptık. İki ADC dönüşümü arasında beklenecek clock sayısını ayarladık.

/* ADC1 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);

ADC çözünürlüğünü 8 bit olarak ayarladık, böylece adc sonucu çıkacak olan değer 0-255 arası olacak.

ADC birden fazla kanalı tarayarak farklı pinlere bağlanmış gerilimleri ölçebilir. Biz sadece bir pinden ölçüm yapacağımız için scan modu disable ettik.

Sürekli ölçüm yapmaması için continous modu disable ettik. Ana program içerisinde ölçüme başlaması için komut göndereceğiz.


/* ADC1 regular channel0 configuration *************************************/
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);

/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);

ADC1 kanal0 ayarlamasını yaptık. Kontrollörün kataloğunda görüldüğü gibi PA0 pini ADC1’in sıfırıncı kanalına denk geliyor.

coide_adc_2

Son olarak ADC’yi aktifleştirdik.


while (1)
{
ADC_SoftwareStartConv(ADC1);

/* Test EOC flag */
while ( ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC ) == RESET );

/* Get ADC1 converted data */
ADC1ConvertedValue = ADC_GetConversionValue( ADC1 );

Set_Duty((ADC1ConvertedValue*100) /255); // ADC değerini % olarak ayarladık.

}

ADC ölçümünü başlattıktan sonra ölçüm tamamlanana kadar bekledik, ve ölçülen değeri okuduk. Okuduğumuz bu değeri yüzdeye çevirip PWM fonksiyonuna duty olarak atadık. Böylece potansiyometeyi çevirdikçe ışık şiddetini ayarlamış olduk.

Proje dosyasını linkten indirebilirsiniz. –> coide_ADC_uygulamasi

Etiket(ler): , , , , , .Yer işareti koy Kalıcı Bağlantı.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir