Sıfırdan STM32F0 Dersleri – ADC

stm32f0discoveryBu yazıda ADC örneği yapacağız.ADC ölçümü için potansiyometre ile gerilimi ölçüp USART ile bilgisayara aktaracağız. ADC bildiğiniz üzere Analog Dijital Converter. ADC de bilinmesi gereken özelliklerden biri çözünürlük. STM32F0 da 12-10-8-6 bit seçenekleri mevcut.Değerleri dijital olarak alacağımızdan olabildiğince hassas olarak alabilmek için 12 bit çözünürlük kullanıyoruz.Seçtiğimiz çözünürlük bize kaç adım(Step-ADC Value) verecek bunu hesaplayalım.Oldukça basit 2^(bit) 12 bit için 2^(12) = 4096 eder.

 

Şimdi işlemci 3.3V seviyesinde çalışıyor peki her adc adımı kaç volta denk geliyor buna bakalım.
3.3/4096 = ( 0,0008056640625 )
Yani gerilimi ölçmek için bu değeri okuduğumuz adc değeri ile çarpacağız ve gerilimi elde edeceğiz.Kite bir adet potansiyometre bağlayalım.Orta bacağı GPIOA.2 bağlayalım ve diğer bacakların birini VDD diğerini GND ye bağlayalım.
Şimdi önceki derslerden hatırladığımız üzere RCC, GPIO, USART, TIM3, NVIC çevre birimlerini hazırlayalım. TIM3 kesme olarak kullandım.1/2 saniyeye ayarlıyoruz.Kesme geldiğinde ölçüm yapıp gönderme işlemini yapacağız. Sırayla başlayalım.

static void RCC_Config(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,    ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,   ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,   ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
}

Buradaki tek farklı durum A.2 yi AN yani Analog olarak ayarlamamız.

static void GPIO_Config(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9 | GPIO_Pin_10; 	   //USART 1 : PA9 = TX, PA10 = RX
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

UART’ı ayarlıyoruz.TX modda olması yeterli, zaten belirli aralıklar ile sadece gönderme yapacağız.

static void UART_Config(void)
{
    USART_InitTypeDef USART_InitStructure;

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10,GPIO_AF_1);

    USART_InitStructure.USART_BaudRate            = 9600;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Tx;
    USART_InitStructure.USART_Parity              = USART_Parity_No;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;

    USART_Init(USART1, &USART_InitStructure);
    USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
    USART_Cmd(USART1, ENABLE);
}

Kesmemiz için TIM3 ve NVIC’i unutmuyoruz.

static void TIM3_Config(void)
{
    TIM_TimeBaseInitTypeDef TIM3_InitStructure;

    TIM3_InitStructure.TIM_Prescaler         = 2000;
    TIM3_InitStructure.TIM_CounterMode       = TIM_CounterMode_Up;
    TIM3_InitStructure.TIM_Period            = 48000;
    TIM3_InitStructure.TIM_ClockDivision     = TIM_CKD_DIV1;

    TIM_TimeBaseInit(TIM3, &TIM3_InitStructure);
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM3, ENABLE);
}

static void NVIC_Config(void)
{
    NVIC_InitTypeDef  NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);
}

void TIM3_IRQHandler(void)
{
   if(TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) != RESET)
      flag = 1;
   TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}

ADC değerlerimiz float olacak.Bu float veriyi USART üzerinden bilgisayara atmak için string’e çevirmek daha mantıklı olacaktır.Bu stringleri yollayacak basit bir fonksiyon oluşturdum.Global olabilmesi için registerlerden yaptım.

static void USART_SendString(USART_TypeDef* USARTx, char* s)
{
    while(*s)
    {
        while(!(USARTx->ISR & ((uint32_t)0x00000040)));
        USARTx->TDR = (*s & (uint16_t)0x01FF);
        s++;
    }
    USARTx->TDR = ('\r' & (uint16_t)0x01FF);
    USARTx->TDR = ('\n' & (uint16_t)0x01FF);;
}

Tabi float değerleri stringe çevirmek için de sprintf’i kullandım.

static char* FloatToString(float f)
{
    char MyText[16];

    sprintf(MyText, "%1.3f Volt", f);
    return (MyText);
}

Önemli Not ! : Sprintf ile float’ı kullanabilmek için projede build options >Debug>Compiler Settings>Other Options’a gelerek ilk tırnak arasındaki değeri eklemelisiniz.  “-u _printf_float”
Sağ olsun Muhittin ağabey çözmüş bende kendisinden öğrendim.

Şimdi ADC kurulumuna geçebiliriz.İşlemler oldukça basit. Structure tanımlıyoruz ve parametreleri giriyoruz.Önemli bir kaç noktayı değinmekte fayda var.Önce çözünürlüğü belirtiyoruz.Alacağımız data’nın sağa mı sola mı yaslanacağını belirtiyoruz.Diğer ayarlar ise spesifik.Detayları inceleye bilirsiniz(Sağ tıkla kaynağına git şeklinde) Ayarları yükleyip init ettikten sonra.ADC pinin belirtiyoruz.Ben ADC1 deki ADC_Channel_2 yi kullandım.Yani GPIOA.2 cmd.CMD ile çalıştırarak ADC_FLAG_ADRDY ile hazır olana kadar bekliyoruz.ADC kesmesini kullanmadığımdan kapattım.Ve okuma işlemi için ADC hazır.

static void ADC1_Config(void)
{
    ADC_InitTypeDef   ADC_InitStructure;

    ADC_DeInit(ADC1);
    ADC_StructInit(&ADC_InitStructure);

    ADC_InitStructure.ADC_Resolution            = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ContinuousConvMode    = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge  = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign             = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_ScanDirection         = ADC_ScanDirection_Upward;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_ChannelConfig(ADC1, ADC_Channel_2, ADC_SampleTime_239_5Cycles);

    ADC_Cmd(ADC1, ENABLE);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY));
    ADC_StartOfConversion(ADC1);
    ADC_ITConfig(ADC1,ADC_IT_EOC, DISABLE);
}

Basit bir fonksiyonda kuma yapabiliriz.

static float ADC_ReadVoltage(ADC_TypeDef* ADCx)
{
    float voltage;

    voltage = ADC_GetConversionValue(ADCx);
    voltage *= (0.0008056640625);

    return (voltage);
}

Main içerisinde bayrağı kontrol ederek okuduğumuz gerilimi bilgisayara aktaralım.

int main(void)
{
    RCC_Config();
    GPIO_Config();
    UART_Config();
    ADC1_Config();
    TIM3_Config();
    NVIC_Config();

    while(1)
    {
        if(flag == 1)
        {
            USART_SendString(USART1, FloatToString(ADC_ReadVoltage(ADC1)));
            flag = 0;
        }
    }
    return (0);
}

Kodların tamamı.

#include "stm32f0xx_conf.h"

static void RCC_Config(void);
static void GPIO_Config(void);
static void ADC1_Config(void);
static void UART_Config(void);
static void TIM3_Config(void);
static void NVIC_Config(void);

static float ADC_ReadVoltage(ADC_TypeDef* ADCx);
static char* FloatToString(float f);
static void USART_SendString(USART_TypeDef* USARTx, char* s);

static uint8_t flag = 0;

void TIM3_IRQHandler(void)
{
    if(TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) != RESET)
        flag = 1;
    TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}

int main(void)
{
    RCC_Config();
    GPIO_Config();
    UART_Config();
    ADC1_Config();
    TIM3_Config();
    NVIC_Config();

    while(1)
    {
        if(flag == 1)
        {
            USART_SendString(USART1, FloatToString(ADC_ReadVoltage(ADC1)));
            flag = 0;
        }
    }
    return (0);
}

static void RCC_Config(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_USART1, ENABLE);
}

static void GPIO_Config(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9 | GPIO_Pin_10; //USART 1 : PA9 = TX, PA10 = RX
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

static void UART_Config(void)
{
    USART_InitTypeDef USART_InitStructure;

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10,GPIO_AF_1);

    USART_InitStructure.USART_BaudRate            = 9600;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Tx;
    USART_InitStructure.USART_Parity              = USART_Parity_No;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;

    USART_Init(USART1, &USART_InitStructure);
    USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
    USART_Cmd(USART1, ENABLE);
}

static void ADC1_Config(void)
{
    ADC_InitTypeDef   ADC_InitStructure;

    ADC_DeInit(ADC1);
    ADC_StructInit(&ADC_InitStructure);

    ADC_InitStructure.ADC_Resolution            = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ContinuousConvMode    = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge  = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign             = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_ScanDirection         = ADC_ScanDirection_Upward;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_ChannelConfig(ADC1, ADC_Channel_2, ADC_SampleTime_239_5Cycles);

    ADC_Cmd(ADC1, ENABLE);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY));
    ADC_StartOfConversion(ADC1);
    ADC_ITConfig(ADC1,ADC_IT_EOC, DISABLE);
}

static void TIM3_Config(void)
{
    TIM_TimeBaseInitTypeDef TIM3_InitStructure;

    TIM3_InitStructure.TIM_Prescaler         = 1000;
    TIM3_InitStructure.TIM_CounterMode       = TIM_CounterMode_Up;
    TIM3_InitStructure.TIM_Period            = 24000;
    TIM3_InitStructure.TIM_ClockDivision     = TIM_CKD_DIV1;

    TIM_TimeBaseInit(TIM3, &TIM3_InitStructure);
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM3, ENABLE);
}

static void NVIC_Config(void)
{
    NVIC_InitTypeDef  NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel          = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority  = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd       = ENABLE;

    NVIC_Init(&NVIC_InitStructure);
}

static float ADC_ReadVoltage(ADC_TypeDef* ADCx)
{
    float voltage;

    voltage = ADC_GetConversionValue(ADCx);
    voltage *= (0.0008056640625);

    return (voltage);
}

static char* FloatToString(float f)
{
    char MyText[16];

    sprintf(MyText, "%1.3f Volt", f);
    return (MyText);
}

static void USART_SendString(USART_TypeDef* USARTx, char* s)
{
    while(*s)
    {
        while(!(USARTx->ISR & ((uint32_t)0x00000040)));
        USARTx->TDR = (*s & (uint16_t)0x01FF);
        s++;
    }
    USARTx->TDR = ('\r' & (uint16_t)0x01FF);
    USARTx->TDR = ('\n' & (uint16_t)0x01FF);
}

Şimdilik bu kadar.

Esen kalın.

You may also like...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir