Sıfırdan STM32F0 Dersleri

Başlatan baran123, 06 Haziran 2015, 00:34:09

baran123

Daha önceden MrDarK hocam ile yaptığımız "Baştan Sona STM32F0 Discovery Uygulamaları" konulu çalışmayı daha düzenli ve ayrıntılı halde toparlama karar verdik.Baştan sona yeniden ayrıntılı bir hali ile burada paylaşıma devam edeceğim.
Lütfen bu konu altına herhangi bir ileti atmayınız.Soru vs iletileri diğer konuda yazabilirsiniz.
Konu için : https://www.picproje.org/index.php/topic,58660.0.html

baran123

Bu örnekler de STM32F0 Discovery Kiti kullancağız.Üzerinde STM32F051R8T6 işlemcisini barındırıyor.Kit ile ilgili teknik dökümanları kaydetmekte fayda var.Ara ara inceleyeceğiz.IDE ve Compiler olarak Emblocks ve GCC kullanacağız.IDE kendi içinde Compiler olarak standart GCC'yi barındırıyor.Ayrıca Standart Peripheral Library de IDE tarafından ekli şekilde geliyor.

Kullanacağımız board : http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF253215?sc=internet/evalboard/product/253215.jsp

STM32F0 Ailesi Referance Design Guide : http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031936.pdf

STM32F051R8 Datasheet : http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00039193.pdf

Emblocks : http://www.emblocks.org/web/downloads-main

Dökümanları hazırlayıp Emblocks programını kurduktan sonra şimdi bir proje oluşturalım.

https://www.youtube.com/watch?v=yqR0lawed6o

baran123

#2
Giriş kısmından sonra bu yazıda işlemcimizin çalışma frekansı ayarlarını yaptıktan sonra GPIO kullanımını anlatacağım.Öncelikle yapmamız gereken projemizin src klasörü altında bulunan src\system_stm32f0xx.c dosyasını açıp RCC(Reset And Clock Cofiguration) ayarlarını yapmak.Burada yapacağımız ayar işlemcimizin harici mi(HSE = High Speed External - Yüksek Hızlı Harici) yoksa dahili(HSI = High Speed Internal - Yüksek hızlı Dahili) kristalden mi çalışacağını belirtmek.Biz HSI ya göre ayarları yapacağız çünkü STM32F0 Discovery kitte harici kristal takılı değil.Fakat pinler mevcut isterseniz siz lehimleyebilirsiniz.(8MHz)

Şimdi system_stm32f0xx.c dosyasında gerekli tanımlamaları yapalım.Öncelikle PLL kaynağımızı belirten bir makro tanımlayalım.Biz HSI tanımalamasını aktif ediyoruz.

#define PLL_SOURCE_HSI // HSI (~8MHz) used to clock the PLL, and the PLL is used as system clock source
//#define PLL_SOURCE_HSE // HSE (8MHz) used to clock the PLL, and the PLL is used as system clock source
//#define PLL_SOURCE_HSE_BYPASS

Clock ayarları SetSysClock fonksiyonunda yapılıyor.

static void SetSysClock(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK configuration ----------------------------------------*/
#if defined (PLL_SOURCE_HSI)
/* At this stage the HSI is already enabled */
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
/* PLL configuration = (HSI/2) * 12 = ~48 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL12);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
#else
#if defined (PLL_SOURCE_HSE)
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
#elif defined (PLL_SOURCE_HSE_BYPASS)
/* HSE oscillator bypassed with external clock */
RCC->CR |= (uint32_t)(RCC_CR_HSEON | RCC_CR_HSEBYP);
#endif /* PLL_SOURCE_HSE */
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
/* PLL configuration = HSE * 6 = 48 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL6);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
#endif /* PLL_SOURCE_HSI */
}

Tabi her işlemciye göre register ayarları farklılık göstereceğinden bu kısma dikkat etmekde fayda var.Lakin başka bir işlemci kullanıyorsanız örn 32f4 bu ayarlar farklılık gösterecektir.Bunun için datasheetden RCC ayarlarını takip ederek kendiniz yapacaksınız yada internetten HSI ya göre ayarlanmış system_stm32f0xx.c dosyasını bulacaksınız.İşlemcinin hız ayarları bu kadar artık uygulama yapmaya başlayabiliriz.

İşlemci hızı ve clock ayarlarını yaptıktan sonra artık GPIO fonksiyonları ile ilk ledi yakabiliriz.Öncelikle bir portu kullanabilmemiz için o porta Clock vermemiz gerekir.Bir nevi uyandırma enerjileme diyebiliriz.Bu kısımları SPL->src altında bulunan stm32f0xx_gpio.c dosyasını açıp en üstteki açıklamada "How to use this driver " kısmından adımları takip ederek öğrenebiliriniz.

Bunun için RCC_AHBPeriphClockCmd fonksiyonu kullanılıyor.Tabi bu fonskiyonlar işlemciye göre değişebilir biz STM32F0 a göre ilerliyoruz.Bu fonksiyon 2 parametre alır.Bunlar port ismi ve durumdur.Biz A potunun 0.bitini High yapalım.

Port isimleri şu şekilde tanımlanmıştır.
#define RCC_AHBPeriph_GPIOA   RCC_AHBENR_GPIOAEN
#define RCC_AHBPeriph_GPIOB   RCC_AHBENR_GPIOBEN
#define RCC_AHBPeriph_GPIOC   RCC_AHBENR_GPIOCEN
#define RCC_AHBPeriph_GPIOD   RCC_AHBENR_GPIODEN
#define RCC_AHBPeriph_GPIOE   RCC_AHBENR_GPIOEEN /*!< Only applicable for STM32F072 devices */
#define RCC_AHBPeriph_GPIOF   RCC_AHBENR_GPIOFEN

Durum olarak ENABLE yani yazdığımız port'u clock vererek bir nevi uyandırma(enerjileme) işlemi yapıyoruz.
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);[\code]

Şimdi yapmamız gereken bu portun ayarlarını yapmak.Bunun için bir struct tanımlıyoruz.
[code]GPIO_InitTypeDef    GPIO_InitStructure;[\code]

Bu yapıya ayarları yükleyeceğiz.Toplamda 5 ayar var.

GPIO_Pin, GPIO_Mode, GPIO_Speed, GPIO_OType, GPIO_PuPd

GPIO_Pin : Hangi pinleri kullanacağımız seçmemize yarıyor.Örneğin 0.biti kullanmak istesek şöyle yapacaktık;
[code]
GPIO_InitTypeDef.GPIO_Pin = GPIO_Pin_0;
//Birden fazla pin için;
GPIO_InitTypeDef.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

GPIO_Mode : Belirtilen pinlerin hangi modda çalışacağını ayarlıyor.4 Mod mevcut.
Giriş, Çıkış, AF, AN (Alternatif fonksiyon = SPI, UART vb, AN = Analog Giriş)

4 değeri vardır.
  
GPIO_Mode_IN  = 0x00  /*!< GPIO Input Mode */
GPIO_Mode_OUT = 0x01  /*!< GPIO Output Mode */
GPIO_Mode_AF  = 0x02  /*!< GPIO Alternate function Mode */
GPIO_Mode_AN  = 0x03  /*!< GPIO Analog Input Mode */
LED uygulaması için Çıkış seçiyoruz.
  
GPIO_InitTypeDef.GPIO_Mode = GPIO_Mode_OUT;

GPIO_Speed : Pinin hızını belirtir.
   
#define GPIO_Speed_2MHz  GPIO_Speed_Level_1   /*!< I/O output speed: Low 2 MHz */
#define GPIO_Speed_10MHz GPIO_Speed_Level_2  /*!< I/O output speed: Medium 10 MHz */
#define GPIO_Speed_50MHz GPIO_Speed_Level_3
Başlangıç için 2Mhz verebiliriz.
GPIO_InitTypeDef.GPIO_Speed = GPIO_Speed_2MHz;

GPIO_OType : Çıkış bağlantısı denenebilir.Output open-drain: Pinin çıkış bacağı, P-Mos ile N-Mos mosfetleri arasında bulunmaktadır.Eğer çıkışı open-drain ayarlarsanız, pin bacağı GND'ye bağlanır. VDD ile arasında sonsuz empedans oluşur.Bu durumda pini high olarak çıkış vermek için dışarıdan pull-up dirençleri eklemeniz gerekmekte. Bu özellikle, çıkışa bağlanacak olan devre elemanının daha fazla akım çekmesi sağlanabilmektedir. Röle gibi akım gerektiren devre elemanlarını sürmek için kullanılır. Akım mikroişlemciden değil, pull-up direnci üzerinden çekilir.Output push-pull:  Pin bacağı P-Mos mosfeti ile VDD pinine bağlanır. Akım gerektirmeyen işlemlerde, çıkışı logik 1 yapmak için bu mod kullanılır.Yüksek akım gerektirmediğinden PP = Push-Pull kullanıyoruz.

Bir diğer mod ise Open Drain
GPIO_OType_PP = 0x00,
GPIO_OType_OD = 0x01
 
Biz PP seçiyoruz.
GPIO_InitStructure.GPIO_OType  = GPIO_OType_PP;

Son olarak GPIO_PuPd : Çıkışa dahili olarak Pull-Up yada Pull-Down direnci eklememizi sağlıyor.Örneğin buton kullanımların da işimize yarayacak bir özellik.Ama şuan için gerek yok.

3 Değeri vardır;
       
GPIO_PuPd_NOPULL= 0x00 //dahili direnç kapalı
GPIO_PuPd_UP     = 0x01 //dahili pull up
GPIO_PuPd_DOWN    = 0x02 //dahili pull down
 
Ve son olarak dahili direnç seçmiyoruz.
   
GPIO_InitStructure.GPIO_PuPd   = GPIO_PuPd_NOPULL;

Şimdi bu ayarların bulunduğu structure'ın adresini kullanacağımız porta göndermemiz gerekiyor.Bunun için GPIO_Init fonksiyonu ile ayarları porta yüklüyoruz.Tabi ayarları yüklemek için pointer adresini veriyoruz.
1.Parametre : Port, 2.Parametre : Structure adresi
      
GPIO_Init(GPIOA,&GPIO_InitStructure);


Pin artık işleme hazır.Şimdi bu pine seri olarak 220 Ohm direnç ile bağlı olan ledi high yapalım.
        
//GPIO_SetBits(GPIOA,  GPIO_Pin_0); //A0 High(SET-1) yapılır.
//GPIO_ResetBits(GPIOA,GPIO_Pin_0); //A0 Low(RESET-0) yapılır.
  
#include "stm32f0xx_conf.h"

int main(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOA,&GPIO_InitStructure);

    GPIO_SetBits(GPIOA,GPIO_Pin_0);

    while(1)
    {
    }
}
 

Şimdi buton kullanımı işleyelim.Butona bastığımızda yanan bıraktığımızda sönen LED uygulaması yapalım.
Öncelikle Clock ayarlarını kontrol edelim.Daha sonra main dosyamızda LED ve buton ayarlarını yapmaya başlayalım.Öncelikle LED için önceki uygulamadaki kodları kullanabiliriz.Öncelikle şunu belirtmekte fayda var.Bu kitte kullanabileceğimiz 2 tane LED ve 1 tanede buton mevcut.Kitin şemasıan bakarak bunları hangi pine denk geldiklerini görebiliriz.Buton A portunun 0.bitinde bulunuyor.Bu pini giriş olarak seçip pull-down olarak ayarlıyoruz.Ayarları yapıyoruz daha sonra C portunun 8.bitin deki mavi renkli ledi çıkış yapıyoruz.Bu uygulamada 2 port kullanıldığından A ve C portlarına clock vermeyide unutmuyoruz.

#include "stm32f0xx_conf.h"

void main(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_Level_1;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_8;    // LED çıkış yapıldı
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP; 
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_Level_1;

    GPIO_Init(GPIOC, &GPIO_InitStructure);

    while(1)
    {
        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) // GPIOA(A portunun) 0 nolu pini tru mu ? (Butona basıldı mı ?) 
            GPIO_SetBits(GPIOC, GPIO_Pin_8);// LED'i yak.
        else
            GPIO_ResetBits(GPIOC, GPIO_Pin_8);//Hayır ise LED'i söndür.
    }
}

baran123

#3
Merhabalar,

Bu yazıda STM32F0 ile External Interrupt (Harici Kesme) yi göreceğiz.Kesmelerden biraz bahsetmek gerekli.Kesmeyi en iyi örnek ile anlayabiliriz.Ana program da bir sürü işimiz var ama arada sırada 1 saniyelik bekleme yapmamız gerekiyor.Bu beklemeleri yaparsak diğer işlerimiz aksayacak o zaman ne yapabiliriz ? Mesela bir timer kurarız.Bu timer 1 saniyeye ayarlanır ve her saniyede bir kere kesme üretir.Kesme oluştuğunda bir değişkeni set ederiz ve ana programda bunu kontrol ederiz.Bu sayede hiç bir işi aksatmadan 1 saniyelik aralıklar ile hiç bir şeyi aksatmadan istediğimiz yapabiliriz.Hatta günlük hayatta bile kullanırız.Yemek pişirirken başında bekliyoruz.Kapı çaldı ocağı söndürmeyiz dimi ? Kapıya koşar misafiri karşılarız.Tabi bir gözümüz ocakta ! Yemek pişince cosss ! diye bir ses, kapıdaki kişiye ara verip yemeğe koşarız.Bu süper örneği kim anlattı bilmiyorum ama bence artık projeye geçelim.Laf lafı açıyor. :) Bildiğimiz üzere harici kesme herhangi bir pini(Bu özelliği olan pinler) High to low yada Low to high geçişini algılayarak oluşturulan kesmeye denir.Bu pin logic konumda olmalıdır.Ayarlarımıza göre bu pini lojik 0 dan lojik 1'E geçtiği anda kesme üretebilecek şekilde kontrol edebiliriz.Buton okuma işlemi gibi düşünebiliriz ama butonu sürekli kontrol etmemize gerek yoktur çünkü herhangi bir geçişte otomatik kesme üretir.L-H, H-L özelliğine yükselen kenar(Rising) - Düşen kenar(Falling)denir.Biz butona bastığımızda kesme üreten ve her bastığımızda LED'i Toggle eden bir uygulama yapalım.Bu uygulamada Rising kullanalım.Bu durumda bu pini low da tutmak için pull-down yapalım.Kitin kendi üzerinde 2 adet LED ve bir adet kullanıcı bulunuyor.Kitin şemasında görüldüğü üzere C portunun 8. ve 9. pinlerinde LED ler A portunun 0.pinin de ise button mevcut.Şimdi kesmelere ufak bir giriş yapmadan önce NVIC den bahsetmek istiyorum.NVIC birden fazla kesme olduğundan bu kesmelerin bir arada uyumlu çalışmasını sağlamak için yapılmış bir sistem olarak yorumlayabiliriz.Bir örnek düşünelim. Timer kesmesi olsun ve harici kesme de aktif olsun.Timer bir saniyelik kesme oluştursun.Bu kesme tam oluşurken butona basıp harici kesme oluşturduk.Olmaz demiyoruz teorik olarak bir düşünelim. :) Yani iki kesme çakıştı.Önceliği hangisine vereceğimiz NVIC ile ayarlıyoruz.NVIC in bir diğer özelliği kesme fonksiyonlarının isimlerinin belirtmesidir.Şimdi kodlar ile bu işi nasıl yaptığımızı görelim.

Öncelikle Clock verme işlemlerini yapıyoruz.
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOC, ENABLE); // Button ve LED için
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);                       //External Interrupt için
Daha sonra structure ları tanımlıyoruz.
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO init işlemlerini yapıyoruz.A portunun 0. pinine bağlı butonu kullanacağımız için pini giriş olarak tanımladık ve dahili olarak pull-down direncini kullandık. C portunun 8. bitin deki mavi LED' i çıkış olarak ayarladık.
GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;
GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
Şimdi hangi portun hangi bitini harici kesme olarak kullanacağımızı belirtiyoruz ve ayaları yapıyoruz.
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);//A portu 0. biti

EXTI_InitStructure.EXTI_Line = EXTI_Line0;//
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//kesme modu
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //Yükselen
EXTI_InitStructure.EXTI_LineCmd = ENABLE;           //aktif
EXTI_Init(&EXTI_InitStructure);                     //ayaları yükle
NVIC ile ilgili süper örneğim den sonra kod üzerinde şu şekilde göstereyim. :)
IRQChannel ile kesme fonsiyonunun prototipinin veriyoruz.Bunlar belirlidir.Hangisi nedir diye öğrenmek istersek stm32f0xx.h'ı açıp 210 nolu satıra gidiyoruz.
NVIC_IRQChannelPriority ile bu kesmenin önceliğini belirtiyoruz.(0-3)Aktifleştirip ayarları yüklüyoruz.
NVIC_InitStructure.NVIC_IRQChannel 		= EXTI0_1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority	= 0;
NVIC_InitStructure.NVIC_IRQChannelCmd 	   	= ENABLE;
NVIC_Init(&NVIC_InitStructure);
Şimdi butona her basıldığında kesme içinde bir değişkenin herhangi bir bitini tersleyelim.
static uint8_t LedState = 0;//başlangıç değeri 0 olsun.

void EXTI0_1_IRQHandler(void)
{
   if(EXTI_GetITStatus(EXTI_Line0) != RESET)//kesme bayrağı 1?
   {
      LedState ^= (1 << 0);//tersle
   }
   EXTI_ClearITPendingBit(EXTI_Line0);// kesme bayrağını temizle
}
Bu değişikliği main içerisinde kontrol ederek LED durumunu değiştirebiliriz.Yada kesme içinde değiştiririz.Ama Gökhan ağabeyden öğrendiğim gibi "Kesme içinde iş yapılmaz.Değişken set edilir ana programda kontrol edilir." :)

while(1)
{
   if(LedState)
      GPIO_SetBits(GPIOC, GPIO_Pin_8);
   else
      GPIO_ResetBits(GPIOC, GPIO_Pin_8);
}
Kodların tamamı;
#include "stm32f0xx_conf.h"

static uint8_t LedState = 0;

void EXTI0_1_IRQHandler(void)
{
   if(EXTI_GetITStatus(EXTI_Line0) != RESET)
   {
      LedState ^= (1 << 0);
   }
   EXTI_ClearITPendingBit(EXTI_Line0);
}

int main(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   EXTI_InitTypeDef EXTI_InitStruct;
   NVIC_InitTypeDef NVIC_InitStruct;

   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOC, ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
   GPIO_Init(GPIOA,&GPIO_InitStructure);

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
   GPIO_Init(GPIOC,&GPIO_InitStructure);

   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);

   EXTI_InitStruct.EXTI_Line = EXTI_Line0;
   EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
   EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
   EXTI_InitStruct.EXTI_LineCmd = ENABLE;
   EXTI_Init(&EXTI_InitStruct);

   NVIC_InitStruct.NVIC_IRQChannel = EXTI0_1_IRQn;
   NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
   NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStruct);

   while(1)
   {
      if(LedState == 0x01)
         GPIO_SetBits(GPIOC, GPIO_Pin_8);
      else
         GPIO_ResetBits(GPIOC, GPIO_Pin_8);
   }
   return (0);
}

baran123

#4
Merhabalar,
Bu yazımda sizlere Timer dan bahsedeceğim.Timer adındanda anlaşılacağı üzere sayıcıdır.Ayarladığımız değerlere göre arkada planda sayım yapar ve bu ayarladığımız değer belirli bir süreye denk gelir ve bu süre dolunca yani timer taşınca bir kesme oluşturur.
Yani Timer kesmesi diyebiliriz.Ben bu yazıda kesme özelliğini anlatmaya çalışacağım.İlerki yazılarda PWM içinde kulanıldığını göreceğiz.STM32F051 de bir den çok timer bulunmakta biz 16 bitlik olan Timer3'ü kullanacağız.
Peki bu timer bize ne kazandıracak ? ne işe yarayacak ? Kesme özelliğini kullanıp belirli zamanlarda işlem yapmamızı sağlayabilir.Yani herhangi bir bekleme yapmayarak diğer işlemleri aksatmadan zamanlı olarak çalışmamızı sağlayacak.Timer'ın hesaplanmasına bakalım şimdi.
Basit bir formülü var.Bende bu formülü biraz karıştırdım sağ olsun "justice_for_all" yardım etti.Kendisine teşekkürler. :)
Timer3 16 bitlikdir yani maximum 2^16 dan 65536 olur.(0 - 65535)

1 saniyelik kemse için bir örnek üzerinde hesaplayalım.
      (Period) * (Prescaler)
sn   = ----------------------
	  (Clock Speed)


       (48.000)  *  (1.000)
1   = ----------------------
	  (48.000.000)


          (48.000.000)
1   = ----------------------
	  (48.000.000)
         
1  =  1 :)
1 saniyelik kesmeyi hesapladık.Şimdi kodlar üzerinde işleyelim.

Öncelikle yapıları tanımlıyorum.
GPIO_InitTypeDef        GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM3_InitStructure;
NVIC_InitTypeDef        NVIC_InitStructure;
Daha sorna led için C portuna ve timer için APB1'e clock veriyoruz.
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
LED'i hazırlayalım.Basit GPIO işlemi
GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC,&GPIO_InitStructure);
Şimdi Timer ayarlarına bakalım.
TIM3_InitStructure.TIM_Prescaler         = 1000; //Prescaler değeri.
TIM3_InitStructure.TIM_CounterMode       = TIM_CounterMode_Up; //Timer yukarı sayacak şekilde ayarlandı.
TIM3_InitStructure.TIM_Period            = 48000;//Period değeri.
TIM3_InitStructure.TIM_ClockDivision     = TIM_CKD_DIV1;//Bölme oranı 1 yani geçersiz-kapalı.
TIM_TimeBaseInit(TIM3, &TIM3_InitStructure);//Ayarları yükle
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // Kesmeyi aktif ediyoruz.
Bu kesmeyi belirtmek için yine NVIC'i ayarlıyoruz.
NVIC_InitStructure.NVIC_IRQChannel          = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority  = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd       = ENABLE;
NVIC_Init(&NVIC_InitStructure);
Ve işlemler bitince Timer'ı çalışırıyoruz.
TIM_Cmd(TIM3, ENABLE);
Kesme fonskiyonu
static unsigned char Led_State = 0x00;

void TIM3_IRQHandler(void)
{
    if(TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) != RESET) //Timer update bayrağı reset'e(reset = 0) değil ise ?
        Led_State ^= (1 << 0); // Led_State in 0. bitini tersle
    TIM_ClearITPendingBit(TIM3, TIM_FLAG_Update); //Bayrağı temizle
}
Ana programda bunu kontrol ediyoruz.
while(1)
{
   if(Led_State == 0x01) // 0b 0000 0001 mi ? (çünkü 0.biti terliyoruz)
      GPIO_SetBits(GPIOC, GPIO_Pin_8); //evet ise ledi yak
   else//değil ise
      GPIO_ResetBits(GPIOC, GPIO_Pin_8);//ledi söndür
}
return (0);//yukarıda sonsuz döngü olduğundan program buraya düşmez.Gereksiz gibi gözükebilir.İsterseniz silebilirsiniz. :)
Ana program
#include "stm32f0xx_conf.h"

static unsigned char Led_State = 0x00;

void TIM3_IRQHandler(void)
{
    if(TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) != RESET)
        Led_State ^= (1 << 0);
    TIM_ClearITPendingBit(TIM3, TIM_FLAG_Update);
}

int main(void)
{
    GPIO_InitTypeDef        GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM3_InitStructure;
    NVIC_InitTypeDef        NVIC_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOC,&GPIO_InitStructure);

    TIM3_InitStructure.TIM_Prescaler         = 1000;
    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);

    NVIC_InitStructure.NVIC_IRQChannel          = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority  = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd       = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_Cmd(TIM3, ENABLE);

    while(1)
    {
        if(Led_State == 0x01)
            GPIO_SetBits(GPIOC, GPIO_Pin_8);
        else
            GPIO_ResetBits(GPIOC, GPIO_Pin_8);
    }
    return (0);
}

baran123

Merhabalar,

Bu yazında en sevdiğim çevre birimi olan USART dan bahsedeceğim.USART : Universal Synchronous/Asynchronous Receiver/Transmitter olarak açılır.Açılımındanda anlaşılacağı üzere senkron ve asenkron olarak çalışabilir.
Temelde 2 pin kullanılır.TX ve RX.
TX Transmitter(Verici) RX Receiver(Alıcı) Anlamına gelir.Herhangi bir cihaz ile bağlantı yapılırken çapraz bağlantı yapılır.
Yani,
TX --> RX
RX --> TX
şeklinde bağlantı yapılır.Bunun sebebi verici pin alıcıya gönderdiğindendir.

USART'ın ilk yapılması gereken ayarı BAUD Rate dir.Baud Rate bir nevi hızdır.Çeşitli baudlar bulunmaktadır ve donanıma göre baud hızı arttıkça iletişimde sapmalar olabilir.Bunu kullancağımız ürünün datasheet inden bakabilirsiniz.Örnek olarak baud rateler :

-2400
-4800
-9600
-115200

Bir diğer nokta ise her seferinde kaç bit gideceğidir.Bizim uygulamada 8 bit kullandık.Parity biti kullanmadık yani N(none) Stop iti ise 1 olarak ayarlayacağız.Son olarak CTS, ve RTS pinleri kapalı.
Bunu 8N1 olarak da görebilirsiniz. USART çok derin bir konu olduğundan fazla giremeyeceğim.Detayları kitaplardan okumanızı tavsiye ederim.
Bu uygulamada bilgisayarın seri portu ile iletişim kuracağız.Masaüstü bilgisayarlarda seriport mevcut.Fakat bu seri port'un volt değerleri biraz farklı.Bunu Normal lojik seviyeye indirmek için ayrı bir devre yapılır.
Bu çok zahmetli olabilir veya bilgisayarda seri port olmayabilir.
Bunun için USB/Seri çevirici kullanacağım.Hem küçük hemde bilgisayarda seri port olmasına gerek kalmadan kendi çipi ile sanal bir port oluşturup kullanılabiliyor.
Dikkat edilmesi gereken nokta çeviricinin TX-RX pinleri 3.3V seviyesinde olmalı.Yoksa Discovery kit zarar görür.Bilgisayar ile STM iletişimi için bir çok hazır terminal programı var.
Fakat ben biraz C# cı olduğum için kendim bir tane hazırladım. Siz hazır bir program kullanırsanız COM porta dikakt ediniz seri çevirici taktığınızda oluşan sanal portu seçip öyle port açmalısınız.USART'ı STM de nasıl kullanacağımızı öğrenmeye başlayalım.Standart olarak LED kontrolü yapıp bu LED durumunu bilgisayara gönderelim.

Öncelikle yapılarımızı tanımlıyoruz.
GPIO_InitTypeDef    GPIO_InitStructure;
USART_InitTypeDef   USART_InitStrutcure;
NVIC_InitTypeDef    NVIC_InitStructure;
Daha sonra clock işlemlerini yapıyoruz.Bu uygulamada kullanılan USART1 APB2 olarak clock veriliyor.
USART1 Pinleri şu şekilde;

A9  -> TX
A10 -> RX

LED hazırlama işlemi
GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_8;
GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
Şimdi USART1 için AF modda gereken ayarları yapalım.Öncelikle A9 ve A10 pinlerini AF(Alternative Function - Alternatif fonksiyon) moduna alıyoruz.Push-pull, pin numaraları, pull-up, ve 50mhz'e göre ayarladıktan sonra init ediyoruz.
GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
Dikkat edilmesi gereken bir noktaherhangi bir pini AF modda kullanacaksak o pini Afconfig fonksiyonu ile ayarlamamız gerekiyor.Bu fonskiyon 3 parametre alıyor.Port, source, af.USART1 A portunda.Pinsource ise 9 ve 10 yani pinleri belirtiyoruz.Hangi AF seçeneğinde kullanıldığı parametrenin kaynağına giderek inceleyebilirsiniz. USART1 için AF1 denmiş.Bu bilgiler datasheet de mevcut. Dökümanlar sürekli açık bulunsun ara ara incelemek de fayda var.
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9,  GPIO_AF_1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
Şimdi USART ayarlarını yapabiliriz. Baud olarak 9600 veya 115200 kulanabiliriz. Yeter ki 2 tarafta da aynı baud seçili olsun. WordLength ile kaç bit göndereceğimiz belirliyoruz. 8b seçtik.Parity biti None(yok) stop biti 1 ve USART_HardwareFlowControl_None ile CTS,RTS kapalı.Son olarak hem data gönderip hem alacağımız için hem TX hemde RX modunu seçiyoruz.Ayarları yüklüyoruz.Bir diğer özellik ise USART bir veri alırsa kesme oluşturabilsin diye RXNE kesmesini aktif ediyoruz.Bir çok kesme mevcut.Bunları inceleyebilirsiniz. USART_CMD ile çalıştırıp hazır hale getiriyoruz.
USART_InitStrutcure.USART_BaudRate     = 115200;
USART_InitStrutcure.USART_WordLength   = USART_WordLength_8b;
USART_InitStrutcure.USART_Parity       = USART_Parity_No;
USART_InitStrutcure.USART_StopBits     = USART_StopBits_1;
USART_InitStrutcure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStrutcure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

USART_Init(USART1, &USART_InitStrutcure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);

What is the next step ? :) Kesme olurda NVIC olmaz mı !
USART ın kesme ismi bu şekilde verilmiş.Aman ezberden yapmıyoruz.Mesela USART1_IRQn'e sağ tıklayıp "Find declaration of "USART1_IRQn"" dersek bizi stm23f0xx.h dosyasında bir kısıma götürecek bu kısımda kesme başlıklarını öğrenebilirsiniz.Mesela timer6 kullansaydık.TIM6_IRQn değil TIM6_DAC_IRQn kullanacaktık.Bu arada o dosyadaki makrolara dikkat edin 32f051 için olan kısım biraz yukarıda.
NVIC_InitStructure.NVIC_IRQChannel          = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd       = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPriority  = 0;
NVIC_Init(&NVIC_InitStructure);
Sonunda USART çalıştı. USB/Seri çevirici ile (TX-RX, RX-TX, çapraz bağlantı)yaptık.Peki şimdi ne yapabiliriz.Bilgisayardan 1 ve 0 yollayalım. STM ile 1 ve 0 ı kontrol edip LED durumunu değiştirelim ve bilgisayara LED açık LED kapalı gibi bir metin gönderelim.Şimdi kesme fonksiyonunu belirtelim.
static unsigned int LEDState = 0;

void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        if((char)USART_ReceiveData(USART1) == '1')
            LEDState = 2;

        if((char)USART_ReceiveData(USART1) == '0')
            LEDState = 1;
    }
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
USART kesmesinde RXNE yi kontrol edelim.TRUE ise USART dan 1 gelmiş iseLEDState'i 2 0 gelmiş ise 1 yapalım.Başlangıç durumu 0 olsun.Okuma işlemi oldukça basit.USART_ReceiveData(USART1) fonksiyonuna tek parametre veriyoruz.USART numarası. ve bize 8 bitlik bir değer döndürüyor bunu hex yerine char olarak alıp 1 ve 0 ile kontrolünü yaptık.İşimiz bittiğinde ise bayrağı temizledik.Şimdi ana programda bunu kontrol ettirelim.
while(1)
{
	if(LEDState == 2) {
	    GPIO_SetBits(GPIOC, GPIO_Pin_8);
	    USART_SendString(USART1, "LED On\r\n");
	    LEDState = 0;
	}
	if(LEDState == 1) {
	    GPIO_ResetBits(GPIOC, GPIO_Pin_8);
	    USART_SendString(USART1, "LED Off\r\n");
	    LEDState = 0;
	}
}
Burada duruma göre işlemler yapıp LEDState'i sıfır yapıyoruz.
USART_SendString diye bir fonskiyon oluşturdum.Bu fonksiyon USART dan string göndermemizi sağlıyor.Normalde C de string yoktur ama bir kaç trick ile benzer bir işlem yapabiliriz. :)
static void USART_SendString(USART_TypeDef* USARTx, char* s)
{
   while(*s)
   {
      while(!USART_GetFlagStatus(USARTx, USART_FLAG_TC));
      USART_SendData(USARTx, *s);
      s++;
   }
}
Şimdi elimden geldiğince her şeyi açıklamaya çalışıyorum.Biraz C çalışmakta fayda var ben burada biraz zorlanmıştım.Fonksiyon ilk parametresi USART numarası.Diğeri ise char s'in pointer adresi.Burada yaptığımız olay string in sırayla karakterlerini gönderip(TC flag'ı RESET ise yani Transmission Complete ise) s++ ile bir sonraki karaktere geçip s* '\0'(string sonu) olana kadar bu işlemi yapıyoruz.Sondaki"\r\n" ise
\r = CR (Carriage Return) // Used as a new line character

\n = LF (Line Feed) // Used as a new line character

\r\n = CR + LF // Used as a new line character in Windows

imiş. :) Yani gönderme bitti enter yap yeni bir şey gönderebilirim anlamında.

En üstte prototipini tanımlayarak işlemi bitirebiliriz.
static void USART_SendString(USART_TypeDef* USARTx, char* _string);
Kodların tamamı
#include "stm32f0xx_conf.h"

static unsigned int LEDState = 0;
static void USART_SendString(USART_TypeDef* USARTx, char* s);

void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        if((char)USART_ReceiveData(USART1) == '1')
            LEDState = 2;

        if((char)USART_ReceiveData(USART1) == '0')
            LEDState = 1;
    }
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}

int main(void)
{
    GPIO_InitTypeDef    GPIO_InitStructure;
    USART_InitTypeDef   USART_InitStrutcure;
    NVIC_InitTypeDef    NVIC_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &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;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

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

    USART_InitStrutcure.USART_BaudRate              = 115200;
    USART_InitStrutcure.USART_WordLength            = USART_WordLength_8b;
    USART_InitStrutcure.USART_Parity                = USART_Parity_No;
    USART_InitStrutcure.USART_StopBits              = USART_StopBits_1;
    USART_InitStrutcure.USART_HardwareFlowControl   = USART_HardwareFlowControl_None;
    USART_InitStrutcure.USART_Mode                  = USART_Mode_Tx | USART_Mode_Rx;

    USART_Init(USART1, &USART_InitStrutcure);
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    USART_Cmd(USART1, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel          = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd       = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPriority  = 0;
    NVIC_Init(&NVIC_InitStructure);

    while(1)
    {
        if(LEDState == 2) {
            GPIO_SetBits(GPIOC, GPIO_Pin_8);
            USART_SendString(USART1, "LED On\r\n");
            LEDState = 0;
        }
        if(LEDState == 1) {
            GPIO_ResetBits(GPIOC, GPIO_Pin_8);
            USART_SendString(USART1, "LED Off\r\n");
            LEDState = 0;
        }
    }
    return (0);
}

static void USART_SendString(USART_TypeDef* USARTx, char* s)
{
    while(*s)
    {
        while(!USART_GetFlagStatus(USARTx, USART_FLAG_TC));
        USART_SendData(USARTx, *s);
        s++;
    }
}


Son olarak çalışma videosu sizlerle.
https://www.youtube.com/watch?v=0yjwHbt9974

baran123

#6
Merhabalar,

Bu yazıda SPI kullanımı öğrenerek bir OLED Display süreceğiz.Başlamadan önce ben 128x64 OLED Display kullanacağımı belirteyim.Bu SSD1306 ile sürülen bir Display.Sürücü dosyası mevcut gerekli kodları paylaşacağım.Bu örnek de SPI ile süreceğimiz OLED resmi aşağıda mevcut.



Serial Peripheral Interface Bus ya da SPI veri yolu full duplex modda çalışan senkron bir seri veri bağlantısı standardıdır.Master-Slave şeklinde çalışır.Yani bir Master ile bir çok Slave ile haberleşebilirsiniz. Birden çok Slave için CS pini kullanılır. Temelde 4 pin ile kullanılır.Bu pinler MOSI, MISO, SCLK, CS dir.

MOSI = Master Out Slave In(Master data gönderir Slave alır gibi düşünülebilir)
MISO = Master In Slave Out (Master data alır, Slave gönderir gibi düşünülebilir)
SCLK = Serial Clock (Seri Clock pinidir)
CS/SS = Chip Select/Slave Select

Bazı işlemciler de;

MOSI = SDO (Serial Data Out)
MISO = SDI (Serial Data In)

olarak görebilirsiniz.

Bağlantı şekli aşağıdadır.



Burada CS/SS pini donanımsal olarak 1 adet mevcuttur.Fakat biz GPIO(Out) olarak tanımladığımız pinleri CS/SS olarak kullanabiliriz.Birden çok Slave kullanımı için bağlantı şekli aşağıdadır.



Hangi CS/SS pinini LOW'a çekersek, o Slave ile haberleşiriz.Diğerleri HIGH konumunda olmalı.Devrenizde bir tane Slave var ise Slave'in CS/SS pinini direk LOW'a bağlayabilirsiniz.
SPI da daha göndermeyi şu şekilde yorumlayabiliriz.
Elimizde bir hex sayı olsun bu sayıyı göndermek için yapılan işlemler şu şekildedir.
Önce Hex sayının bitlerini sırayla tek tek al.
Baktığımız bit 1 ise MOSI'yi HIGH, 0 ise LOW yap.
SCLK ile bir Clock ver.
1 bit gönderildi.
Diğer bit için aynı işlemi yap.
Bu fonksiyonu şu şekilde oluşturabiliriz.

void SPI_SendData(uint8_t  data)
{                                  
    uint8_t i;       

    for(i = 0x80; i > 0; i >>= 1)
    {                                
        if(i & data) 
        {
            SPI_MOSI = 1;
        }
        else 
        {
            SPI_MOSI = 0;
        }
        SPI_SCLK = 1;          
        SPI_SCLK = 0;
    }                               
}
Tabi bu yazılımsal SPI.Biz donanımsal olarak bunu SPI_SendData8 fonksiyonu ile yapacağız.Kodlara geçmeden önce bir iki noktadan daha bahsetmek istiyorum ki bu çok önemli.
SPI Modları denen bir durum var.Genelde şu şekilde kullanılıyor."MODE 0,0, MODE 0,1" gibi
Bu mod kavramını belirleye 2 unsur bulunmakta.Bunlar CPOL ve CPHA

CPOL = Clock Polarity
CPHA = Clock Phase

Bu parametreler 1,0 değerlerini alıyor.Kullanacağınız cihaz hangi modda çalışıyor ise ona göre ayarlama yapmalısınız.Bu kavramlar SCLK pininin karakteristliği ile alakalı bir durum.Bunu en iyi şu şekilde görebiliriz.

SPI_Edges


Detaylar için :
http://dlnware.com/theory/SPI-Transfer-Modes
http://www.rosseeld.be/DRO/PIC/SPI_Timing.htm

Linklerini inceleyebilirsiniz.Kaynak olarak kullandım.
Bu arada bu uygulamada MISO kullanmayacağız sadece OLED ekrana yazı basacağımız için ekrana data gönderme yani MOSI kullanacağız.Maalesef elimde SPI dan Data alabileceğim donanım bulunmuyor. Ama siz mevcut ise 2 kiti veya başka bir donanım ile bu işi yapabilirsiniz.SPI da Receive kesmesi mevcut.
Kod kısmında yapmamız gereken ilk adım Clockları vermek.

/***********************************************************
* Function Name  : Init_RCC
* Description    : RCC clockları verilir.
* Input          : void
* Return         : void
***********************************************************/
static void Init_RCC(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
}
Şimdi GPIO hazırlama işlemini gerçekleştirelim.SPI1 kullanacağız.SPI1 in pinleri A portunun 4,5,6,7 .pinlerine denk geliyor.Başka pinler içinde kullanılabilir.Bunu Datasheetden öğrenebilirsiniz.Bu pinler için AF0 kullanıldığını da belirtelim.
Bu uygulamada CS pinin yazılımsal olarak kullanacağımdan dolayı C.1 'i CS olarak kullanacağım.Aslında tek Slave olduğu için GND ye çekebiliriz fakat kütüphane bu tanımlamayı kullanıyor.Bir diğer pin ise C.0.Bu Displaye özel bir pin.D/C ye bağlanacak.Bu pin 0 da iken komut(command) 1 de iken veri(data) alacak.Son olarak AF ile SPI pinsource larını belirtiyoruz.

A4 = CS/SS/NSS
A5 = SCLK
A6 = MISO
A7 = MOSI
/***********************************************************
* Function Name  : Init_GPIO
* Description    : GPIO lar hazırlanır.
* Input          : void
* Return         : None
***********************************************************/
static void Init_GPIO(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin    = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode   = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed  = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType  = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd   = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0); //spi
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_0); //spi
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0); //spi
}
SPI ayarların da öncelikle Structure tanımlıyoruz.
SPI_InitTypeDef  SPI_InitStructure;

SPI ayarlarında sadece gönderme yapacağımız için Tx modu seçiyorum.Master moda ayarlayıp.CPOL ve CPHA ayarlarını yapıp CS pinini yazılımsal olarak ayarlıyoruz.Gönderme MSB ile başlayacak ve bölücü ayarı 2(maksimum) yani çalışma frekansı / 2 den SPI 24 MHz de çalışacak.Son olarak Rx kesmesini kapatıp ayarları yüklüyoruz ve SPI1'i çalıştırıyoruz.
/***********************************************************
* Function Name  : Init_SPI1
* Description    : SPI1 hazırlanır.
* Input          : void
* Return         : void
***********************************************************/
static void Init_SPI1(void)
{
    SPI_InitTypeDef  SPI_InitStructure;

    SPI_InitStructure.SPI_Direction         = SPI_Direction_Tx;
    SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize          = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL              = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA              = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial     = 7;

    SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, DISABLE);
    SPI_Init(SPI1,&SPI_InitStructure);
    SPI_Cmd(SPI1,ENABLE);
}
SPI hazırlama bittikten sonra Oled kütüphanesinin fonksiyonları ile ekrana yazı basabiliriz.
#include "stm32f0xx_conf.h"
#include "ssd1306.h"
#include "font.h"

static void Init_RCC(void);
static void Init_GPIO(void);
static void Init_SPI1(void);

/***********************************************************
* Function Name : main
* Description : Ana program burada doner.
* Input : void
* Return : int
***********************************************************/
int main(void)
{
 Init_RCC();
 Init_GPIO();
 Init_SPI1();
 Init_OLED();

 Oled_SetFont(Terminal12x16, 12, 16, 32, 127);

 Oled_ConstText("OLED", 0, 0);
 Oled_ConstText("128x64", 0, 2);
 Oled_ConstText("Baran", 0, 4);
 Oled_ConstText("EKREM", 0, 6);

 while(1)
 {

 }
}

/***********************************************************
* Function Name : Init_RCC
* Description : RCC clocklarý verilir.
* Input : void
* Return : void
***********************************************************/
static void Init_RCC(void)
{
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
}

/***********************************************************
* Function Name : Init_GPIO
* Description : GPIO lar hazýrlanýr.
* Input : void
* Return : None
***********************************************************/
static void Init_GPIO(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOA, &GPIO_InitStructure);

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOC, &GPIO_InitStructure);

 GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0); //spi
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_0); //spi
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0); //spi
}

/***********************************************************
* Function Name : Init_SPI1
* Description : SPI1 hazýrlanýr.
* Input : void
* Return : void
***********************************************************/
static void Init_SPI1(void)
{
 SPI_InitTypeDef SPI_InitStructure;

 SPI_InitStructure.SPI_Direction = SPI_Direction_Tx;
 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
 SPI_InitStructure.SPI_CRCPolynomial = 7;

 SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, DISABLE);
 SPI_Init(SPI1,&SPI_InitStructure);
 SPI_Cmd(SPI1,ENABLE);
}
SSD1306.c
#include "stm32f0xx_conf.h"
#include "ssd1306.h"

const uint8_t *font, *font2;
uint8_t width, height, min, max;

void Init_OLED(void)
{
 Oled_Command(0xAE);
 Oled_Command(0x81);
 Oled_Command(0xCF);
 Oled_Command(0xA4);
 Oled_Command(0xA6);
 Oled_Command(0x20);
 Oled_Command(0x02);
 Oled_Command(0x00);
 Oled_Command(0x10);
 Oled_Command(0xB0);
 Oled_Command(0x40);
 Oled_Command(0xA1);
 Oled_Command(0xA8);
 Oled_Command(0x3F);
 Oled_Command(0xC8);
 Oled_Command(0xD3);
 Oled_Command(0x00);
 Oled_Command(0xDA);
 Oled_Command(0x12);
 Oled_Command(0xD5);
 Oled_Command(0x80);
 Oled_Command(0xD9);
 Oled_Command(0xF1);
 Oled_Command(0xDB);
 Oled_Command(0x40);
 Oled_Command(0x8D);
 Oled_Command(0x14);
 Oled_Command(0xAF);

 Oled_FillScreen(0x00);
}

void Oled_Command(uint8_t Command)
{
 GPIO_ResetBits(LCD_DC_PORT,LCD_DC_PIN);
 GPIO_ResetBits(LCD_CS_PORT,LCD_CS_PIN);
 SPI_SendData8(SPI1, Command);
 while (SPI1->SR & SPI_SR_BSY);
 GPIO_SetBits(LCD_CS_PORT,LCD_CS_PIN);
}

void Oled_WriteRam(uint8_t Data)
{
 GPIO_ResetBits(LCD_CS_PORT,LCD_CS_PIN);
 GPIO_SetBits(LCD_DC_PORT,LCD_DC_PIN);
 SPI_SendData8(SPI1, Data);
 while (SPI1->SR & SPI_SR_BSY);
 GPIO_SetBits(LCD_CS_PORT,LCD_CS_PIN);
}

void Oled_SetPointer(uint8_t seg, uint8_t pag)
{
 uint8_t low_column, hig_column;

 low_column = (seg & 0b00001111);
 hig_column = (seg & 0b11110000)>>4;
 hig_column = hig_column | 0b00010000;
 pag = (pag & 0b00000111);
 pag = (pag | 0b10110000);
 Oled_Command(low_column);
 Oled_Command(hig_column);
 Oled_Command(pag);
}

void Oled_SetFont(const uint8_t *_font, uint8_t _width, uint8_t _height, uint8_t _min, uint8_t _max)
{
 font2 = _font;
 width = _width;
 height = _height / 8;
 min = _min;
 max = _max;
}

void Oled_WriteChar(uint8_t c, uint8_t seg, uint8_t pag)
{
 uint8_t i, j, k, l;
 uint8_t x_seg, y_pag;

 x_seg = seg;
 y_pag = pag;
 font = font2;
 k = c - min;
 l = (width * height);

 for(j = 0; j < k; j++)
 {
 for(i = 0; i < l; i++)
 {
 font++;
 }
 }

 for(i = 0; i < width; i++)
 {
 y_pag = pag;
 for(j = 0; j < height; j++)
 {
 if(x_seg < 128)
 {
 Oled_SetPointer(x_seg, y_pag);
 Oled_WriteRam(*font);
 }
 y_pag++;
 font++;
 }
 x_seg++;
 }
}

void Oled_ConstText(char *buffer, uint8_t seg, uint8_t pag)
{
 uint8_t x_seg = seg;

 while(*buffer)
 {
 Oled_WriteChar(*buffer, x_seg, pag);
 x_seg = x_seg + width;
 buffer++;
 }
}

void Oled_Text(char *buffer, uint8_t seg, uint8_t pag)
{
 uint8_t x_seg = seg;

 while(*buffer)
 {
 Oled_WriteChar(*buffer, x_seg, pag);
 x_seg = x_seg + width;
 buffer++;
 }
}

void Oled_FillScreen(uint8_t pattern)
{
 unsigned char i, j;

 for(i = 0; i < 8; i++)
 {
 Oled_SetPointer(0, i);
 for(j = 0; j < 128; j++)
 {
 Oled_WriteRam(pattern);
 }
 }
}

void Oled_Image(const uint8_t *buffer)
{
 unsigned char i, j;

 for(i = 0; i < 8; i++)
 {
 Oled_SetPointer(0, i);
 for(j = 0; j < 128; j++)
 {
 Oled_WriteRam(*buffer);
 buffer++;
 }
 }
}

void Right_HorizontalScroll(uint8_t start_page, uint8_t end_page, uint8_t set_time)
{
 Deactivate_Scroll();
 Oled_Command(0x26);
 Oled_Command(0x00);
 Oled_Command(start_page);
 Oled_Command(set_time);
 Oled_Command(end_page);
 Oled_Command(0x00);
 Oled_Command(0xFF);
 Activate_Scroll();
}

void Left_HorizontalScroll(uint8_t start_page, uint8_t end_page, uint8_t set_time)
{
 Deactivate_Scroll();
 Oled_Command(0x27);
 Oled_Command(0x00);
 Oled_Command(start_page);
 Oled_Command(set_time);
 Oled_Command(end_page);
 Oled_Command(0x00);
 Oled_Command(0xFF);
 Activate_Scroll();
}

void VerticalRight_HorizontalScroll(uint8_t start_page, uint8_t end_page, uint8_t set_time)
{
 Deactivate_Scroll();
 Oled_Command(0x29);
 Oled_Command(0x00);
 Oled_Command(start_page);
 Oled_Command(set_time);
 Oled_Command(end_page);
 Oled_Command(0x01);
 Activate_Scroll();
}

void VerticalLeft_HorizontalScroll(uint8_t start_page, uint8_t end_page, uint8_t set_time)
{
 Deactivate_Scroll();
 Oled_Command(0x2A);
 Oled_Command(0x00);
 Oled_Command(start_page);
 Oled_Command(set_time);
 Oled_Command(end_page);
 Oled_Command(0x01);
 Activate_Scroll();
}

void Deactivate_Scroll(void)
{
 Oled_Command(0x2E);
}

void Activate_Scroll(void)
{
 Oled_Command(0x2F);
}
SSD1306.h
#ifndef SSD1306_H
#define SSD1306_H

void Init_OLED(void);
void Activate_Scroll(void);
void Deactivate_Scroll(void);
void Oled_Command(uint8_t cmd);
void Oled_WriteRam(uint8_t dat);
void Oled_Image(const uint8_t *buffer);
void Oled_FillScreen(uint8_t pattern);
void Oled_SetPointer(uint8_t seg, uint8_t pag);
void Oled_WriteChar(uint8_t c, uint8_t seg, uint8_t pag);
void Oled_Text(char *buffer, uint8_t seg, uint8_t pag);
void Oled_ConstText(char *buffer, uint8_t seg, uint8_t pag);
void Left_HorizontalScroll(uint8_t start_page, uint8_t end_page, uint8_t set_time);
void Right_HorizontalScroll(uint8_t start_page, uint8_t end_page, uint8_t set_time);
void VerticalLeft_HorizontalScroll(uint8_t start_page, uint8_t end_page, uint8_t set_time);
void VerticalRight_HorizontalScroll(uint8_t start_page, uint8_t end_page, uint8_t set_time);
void Oled_SetFont(const uint8_t *_font, uint8_t _width, uint8_t _height, uint8_t _min, uint8_t _max);

//OLED Display CS Port
#ifndef LCD_CS_PORT
 #define LCD_CS_PORT GPIOC
#endif
//OLED Display CS Pin
#ifndef LCD_CS_PIN
 #define LCD_CS_PIN GPIO_Pin_1
#endif
//OLED Display DC Port
#ifndef LCD_DC_PORT
 #define LCD_DC_PORT GPIOC
#endif
//OLED Display DC Pin
#ifndef LCD_DC_PIN
 #define LCD_DC_PIN GPIO_Pin_0
#endif

#define PAGE0 0
#define PAGE1 1
#define PAGE2 2
#define PAGE3 3
#define PAGE4 4
#define PAGE5 5
#define PAGE6 6
#define PAGE7 7
#define FRAME_2 7
#define FRAME_3 4
#define FRAME_4 5
#define FRAME_5 0
#define FRAME_25 6
#define FRAME_64 1
#define FRAME_128 2
#define FRAME_256 3

#endif /* SSD1306_H_INCLUDED */
Font.h
#ifndef FONT_H
#define FONT_H

const uint8_t Terminal12x16[2304] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (space)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0xFE, 0x67, 0xFE, 0x67, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // !
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "
0x00, 0x00, 0x00, 0x04, 0x20, 0x3C, 0x20, 0x3F, 0xE0, 0x07, 0xFC, 0x04, 0x3C, 0x3C, 0x20, 0x3F, 0xE0, 0x07, 0xFC, 0x04, 0x3C, 0x00, 0x20, 0x00, // #
0x00, 0x00, 0x00, 0x00, 0xF0, 0x08, 0xF8, 0x19, 0x98, 0x19, 0xFE, 0x7F, 0xFE, 0x7F, 0x98, 0x19, 0x98, 0x1F, 0x10, 0x0F, 0x00, 0x00, 0x00, 0x00, // $
0x00, 0x00, 0x00, 0x30, 0x38, 0x38, 0x38, 0x1C, 0x38, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x38, 0x70, 0x38, 0x38, 0x38, 0x00, 0x00, // %
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xB8, 0x3F, 0xFC, 0x31, 0xC6, 0x21, 0xE2, 0x37, 0x3E, 0x1E, 0x1C, 0x1C, 0x00, 0x36, 0x00, 0x22, 0x00, 0x00, // &
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x7E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // '
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0xF8, 0x1F, 0xFC, 0x3F, 0x0E, 0x70, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x0E, 0x70, 0xFC, 0x3F, 0xF8, 0x1F, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // )
0x00, 0x00, 0x00, 0x00, 0x98, 0x0C, 0xB8, 0x0E, 0xE0, 0x03, 0xF8, 0x0F, 0xF8, 0x0F, 0xE0, 0x03, 0xB8, 0x0E, 0x98, 0x0C, 0x00, 0x00, 0x00, 0x00, // *
0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xF0, 0x0F, 0xF0, 0x0F, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, // +
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x7C, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ,
0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, // -
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .
0x00, 0x00, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x00, 0x00, // /
0x00, 0x00, 0xF0, 0x0F, 0xFC, 0x3F, 0x0C, 0x3C, 0x06, 0x66, 0x06, 0x63, 0x86, 0x61, 0xC6, 0x60, 0x66, 0x60, 0x3C, 0x30, 0xFC, 0x3F, 0xF0, 0x0F, // 0
0x00, 0x00, 0x00, 0x00, 0x18, 0x60, 0x18, 0x60, 0x1C, 0x60, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, // 1
0x00, 0x00, 0x38, 0x60, 0x3C, 0x70, 0x0E, 0x78, 0x06, 0x7C, 0x06, 0x6E, 0x06, 0x67, 0x86, 0x63, 0xC6, 0x61, 0xEE, 0x60, 0x7C, 0x60, 0x38, 0x60, // 2
0x00, 0x00, 0x18, 0x18, 0x1C, 0x38, 0x0E, 0x70, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0xCE, 0x73, 0xFC, 0x3E, 0x78, 0x1C, // 3
0x00, 0x00, 0x80, 0x07, 0xC0, 0x07, 0xE0, 0x06, 0x70, 0x06, 0x38, 0x06, 0x1C, 0x06, 0x0E, 0x06, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x06, 0x00, 0x06, // 4
0x00, 0x00, 0x7E, 0x18, 0xFE, 0x38, 0xC6, 0x70, 0xC6, 0x60, 0xC6, 0x60, 0xC6, 0x60, 0xC6, 0x60, 0xC6, 0x60, 0xC6, 0x71, 0x86, 0x3F, 0x06, 0x1F, // 5
0x00, 0x00, 0x80, 0x1F, 0xE0, 0x3F, 0xF0, 0x73, 0xB8, 0x61, 0x9C, 0x61, 0x8E, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x73, 0x00, 0x3F, 0x00, 0x1E, // 6
0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x60, 0x06, 0x78, 0x06, 0x1E, 0x86, 0x07, 0xE6, 0x01, 0x7E, 0x00, 0x1E, 0x00, 0x06, 0x00, // 7
0x00, 0x00, 0x00, 0x1E, 0x78, 0x3F, 0xFC, 0x73, 0xCE, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0xCE, 0x61, 0xFC, 0x73, 0x78, 0x3F, 0x00, 0x1E, // C8
0x00, 0x00, 0x78, 0x00, 0xFC, 0x00, 0xCE, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x71, 0x86, 0x39, 0x86, 0x1D, 0xCE, 0x0F, 0xFC, 0x07, 0xF8, 0x01, // 9
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1C, 0x70, 0x1C, 0x70, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // :
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x4E, 0x38, 0x7E, 0x38, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ;
0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xC0, 0x03, 0xE0, 0x07, 0x70, 0x0E, 0x38, 0x1C, 0x1C, 0x38, 0x0E, 0x70, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, // <
0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x00, 0x00, // =
0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x0E, 0x70, 0x1C, 0x38, 0x38, 0x1C, 0x70, 0x0E, 0xE0, 0x07, 0xC0, 0x03, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, // >
0x00, 0x00, 0x38, 0x00, 0x3C, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x06, 0x6F, 0x86, 0x6F, 0xC6, 0x01, 0xEE, 0x00, 0x7C, 0x00, 0x38, 0x00, 0x00, 0x00, // ?
0x00, 0x00, 0xF0, 0x1F, 0xFC, 0x3F, 0x0E, 0x30, 0xE6, 0x67, 0xF6, 0x6F, 0x36, 0x6C, 0xF6, 0x6F, 0xF6, 0x6F, 0x0E, 0x6C, 0xFC, 0x07, 0xF0, 0x03, // @
0x00, 0x00, 0x00, 0x70, 0x00, 0x7E, 0xC0, 0x0F, 0xF8, 0x0D, 0x3E, 0x0C, 0x3E, 0x0C, 0xF8, 0x0D, 0xC0, 0x0F, 0x00, 0x7E, 0x00, 0x70, 0x00, 0x00, // A
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0xCE, 0x61, 0xFC, 0x73, 0x78, 0x3F, 0x00, 0x1E, 0x00, 0x00, // B
0x00, 0x00, 0xE0, 0x07, 0xF8, 0x1F, 0x1C, 0x38, 0x0E, 0x70, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x0E, 0x70, 0x1C, 0x38, 0x18, 0x18, 0x00, 0x00, // C
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x0E, 0x70, 0x1C, 0x38, 0xF8, 0x1F, 0xE0, 0x07, 0x00, 0x00, // D
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x06, 0x60, 0x06, 0x60, 0x00, 0x00, // E
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, // F
0x00, 0x00, 0xE0, 0x07, 0xF8, 0x1F, 0x1C, 0x38, 0x0E, 0x70, 0x06, 0x60, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x8E, 0x7F, 0x8C, 0x7F, 0x00, 0x00, // G
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x00, // H
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x06, 0x60, 0xFE, 0x7F, 0xFE, 0x7F, 0x06, 0x60, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // I
0x00, 0x00, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x70, 0xFE, 0x3F, 0xFE, 0x0F, 0x00, 0x00, // J
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x80, 0x01, 0xC0, 0x03, 0xE0, 0x07, 0x70, 0x0E, 0x38, 0x1C, 0x1C, 0x38, 0x0E, 0x70, 0x06, 0x60, 0x00, 0x00, // K
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, // L
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x3C, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0xC0, 0x03, 0xF0, 0x00, 0x3C, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x00, // M
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x1C, 0x00, 0x70, 0x00, 0xE0, 0x01, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x38, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x00, // N
0x00, 0x00, 0xE0, 0x07, 0xF8, 0x1F, 0x1C, 0x38, 0x0E, 0x70, 0x06, 0x60, 0x06, 0x60, 0x0E, 0x70, 0x1C, 0x38, 0xF8, 0x1F, 0xE0, 0x07, 0x00, 0x00, // O
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x8E, 0x03, 0xFC, 0x01, 0xF8, 0x00, 0x00, 0x00, // P
0x00, 0x00, 0xE0, 0x07, 0xF8, 0x1F, 0x1C, 0x38, 0x0E, 0x70, 0x06, 0x60, 0x06, 0x6C, 0x0E, 0x7C, 0x1C, 0x38, 0xF8, 0x7F, 0xE0, 0x67, 0x00, 0x00, // Q
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x06, 0x03, 0x06, 0x03, 0x06, 0x07, 0x06, 0x0F, 0x06, 0x1F, 0x8E, 0x3B, 0xFC, 0x71, 0xF8, 0x60, 0x00, 0x00, // R
0x00, 0x00, 0x78, 0x18, 0xFC, 0x38, 0xCE, 0x71, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x86, 0x61, 0x8E, 0x73, 0x1C, 0x3F, 0x18, 0x1E, 0x00, 0x00, // S
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, // T
0x00, 0x00, 0xFE, 0x0F, 0xFE, 0x3F, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x70, 0xFE, 0x3F, 0xFE, 0x0F, 0x00, 0x00, // U
0x00, 0x00, 0x0E, 0x00, 0x7E, 0x00, 0xF0, 0x03, 0x80, 0x1F, 0x00, 0x7C, 0x00, 0x7C, 0x80, 0x1F, 0xF0, 0x03, 0x7E, 0x00, 0x0E, 0x00, 0x00, 0x00, // V
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x38, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x38, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x00, // W
0x00, 0x00, 0x06, 0x60, 0x1E, 0x78, 0x38, 0x1C, 0x60, 0x06, 0xC0, 0x03, 0xC0, 0x03, 0x60, 0x06, 0x38, 0x1C, 0x1E, 0x78, 0x06, 0x60, 0x00, 0x00, // X
0x00, 0x00, 0x06, 0x00, 0x1E, 0x00, 0x78, 0x00, 0xE0, 0x01, 0x80, 0x7F, 0x80, 0x7F, 0xE0, 0x01, 0x78, 0x00, 0x1E, 0x00, 0x06, 0x00, 0x00, 0x00, // Y
0x00, 0x00, 0x06, 0x60, 0x06, 0x78, 0x06, 0x7C, 0x06, 0x66, 0x86, 0x63, 0xC6, 0x61, 0x66, 0x60, 0x3E, 0x60, 0x1E, 0x60, 0x06, 0x60, 0x00, 0x00, // Z
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // [
0x00, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x00, // BackSlash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x00, //
0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, // _
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x7E, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // `
0x00, 0x00, 0x00, 0x1C, 0x40, 0x3E, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0xE0, 0x3F, 0xC0, 0x3F, 0x00, 0x00, // a
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x80, 0x61, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x71, 0x80, 0x3F, 0x00, 0x1F, 0x00, 0x00, // b
0x00, 0x00, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xC0, 0x18, 0x80, 0x08, 0x00, 0x00, // c
0x00, 0x00, 0x00, 0x1F, 0x80, 0x3F, 0xC0, 0x71, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x61, 0x80, 0x61, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x00, // d
0x00, 0x00, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x3B, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0xC0, 0x13, 0x80, 0x01, 0x00, 0x00, // e
0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0xF8, 0x7F, 0xFC, 0x7F, 0x8E, 0x01, 0x86, 0x01, 0x86, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, // f
0x00, 0x00, 0xC0, 0x01, 0xE0, 0x63, 0x70, 0x67, 0x30, 0x66, 0x30, 0x66, 0x30, 0x66, 0x30, 0x66, 0x30, 0x73, 0xF0, 0x3F, 0xF0, 0x1F, 0x00, 0x00, // g
0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x80, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0x80, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, // h
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x30, 0xEC, 0x3F, 0xEC, 0x3F, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // i
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x70, 0x00, 0x60, 0x30, 0x60, 0xF6, 0x7F, 0xF6, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // j
0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x06, 0x00, 0x0F, 0x80, 0x1F, 0xC0, 0x39, 0xC0, 0x70, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, // k
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x60, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // l
0x00, 0x00, 0xE0, 0x3F, 0xC0, 0x3F, 0xE0, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0xC0, 0x3F, 0xE0, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0x80, 0x3F, 0x00, 0x00, // m
0x00, 0x00, 0x00, 0x00, 0xE0, 0x3F, 0xE0, 0x3F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0x80, 0x3F, 0x00, 0x00, // n
0x00, 0x00, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x1F, 0x80, 0x0F, 0x00, 0x00, // o
0x00, 0x00, 0xF0, 0x7F, 0xF0, 0x7F, 0x30, 0x06, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x70, 0x0E, 0xE0, 0x07, 0xC0, 0x03, 0x00, 0x00, // p
0x00, 0x00, 0xC0, 0x03, 0xE0, 0x07, 0x70, 0x0E, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x06, 0xF0, 0x7F, 0xF0, 0x7F, 0x00, 0x00, // q
0x00, 0x00, 0x00, 0x00, 0xE0, 0x3F, 0xE0, 0x3F, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x00, // r
0x00, 0x00, 0x00, 0x00, 0xC0, 0x11, 0xE0, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x3F, 0x40, 0x1E, 0x00, 0x00, 0x00, 0x00, // s
0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFE, 0x1F, 0xFE, 0x3F, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, // t
0x00, 0x00, 0xE0, 0x0F, 0xE0, 0x1F, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0xE0, 0x3F, 0xE0, 0x3F, 0x00, 0x00, // u
0x00, 0x00, 0x60, 0x00, 0xE0, 0x01, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x38, 0x00, 0x38, 0x00, 0x1E, 0x80, 0x07, 0xE0, 0x01, 0x60, 0x00, 0x00, 0x00, // v
0x00, 0x00, 0xE0, 0x07, 0xE0, 0x1F, 0x00, 0x38, 0x00, 0x1C, 0xE0, 0x0F, 0xE0, 0x0F, 0x00, 0x1C, 0x00, 0x38, 0xE0, 0x1F, 0xE0, 0x07, 0x00, 0x00, // w
0x00, 0x00, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x1D, 0x80, 0x0F, 0x00, 0x07, 0x80, 0x0F, 0xC0, 0x1D, 0xE0, 0x38, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, // x
0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xF0, 0x40, 0xC0, 0x73, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, // y
0x00, 0x00, 0x60, 0x30, 0x60, 0x38, 0x60, 0x3C, 0x60, 0x36, 0x60, 0x33, 0xE0, 0x31, 0xE0, 0x30, 0x60, 0x30, 0x20, 0x30, 0x00, 0x00, 0x00, 0x00, // z
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0xFC, 0x1F, 0x7E, 0x3F, 0x07, 0x70, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x00, 0x00, 0x00, 0x00, // {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7F, 0x7E, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |
0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x07, 0x70, 0x7E, 0x3F, 0xFC, 0x1F, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, // }
0x00, 0x00, 0x10, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x10, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, // ->
0x00, 0x00, 0x00, 0x0F, 0x80, 0x0F, 0xC0, 0x0C, 0x60, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x60, 0x0C, 0xC0, 0x0C, 0x80, 0x0F, 0x00, 0x0F, 0x00, 0x00  // �<-
};

const uint8_t Font_6x8[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (space)
0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, // !
0x00, 0x07, 0x00, 0x07, 0x00, 0x00, // "
0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, // #
0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, // $
0x23, 0x13, 0x08, 0x64, 0x62, 0x00, // %
0x36, 0x49, 0x55, 0x22, 0x50, 0x00, // &
0x00, 0x05, 0x03, 0x00, 0x00, 0x00, // '
0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, // (
0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, // )
0x08, 0x2A, 0x1C, 0x2A, 0x08, 0x00, // *
0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, // +
0x00, 0x50, 0x30, 0x00, 0x00, 0x00, // ,
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, // -
0x00, 0x30, 0x30, 0x00, 0x00, 0x00, // .
0x20, 0x10, 0x08, 0x04, 0x02, 0x00, // /
0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, // 0
0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, // 1
0x42, 0x61, 0x51, 0x49, 0x46, 0x00, // 2
0x21, 0x41, 0x45, 0x4B, 0x31, 0x00, // 3
0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, // 4
0x27, 0x45, 0x45, 0x45, 0x39, 0x00, // 5
0x3C, 0x4A, 0x49, 0x49, 0x30, 0x00, // 6
0x01, 0x71, 0x09, 0x05, 0x03, 0x00, // 7
0x36, 0x49, 0x49, 0x49, 0x36, 0x00, // 8
0x06, 0x49, 0x49, 0x29, 0x1E, 0x00, // 9
0x00, 0x36, 0x36, 0x00, 0x00, 0x00, // :
0x00, 0x56, 0x36, 0x00, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
0x14, 0x14, 0x14, 0x14, 0x14, 0x00, // =
0x41, 0x22, 0x14, 0x08, 0x00, 0x00, // >
0x02, 0x01, 0x51, 0x09, 0x06, 0x00, // ?
0x32, 0x49, 0x79, 0x41, 0x3E, 0x00, // @
0x7E, 0x11, 0x11, 0x11, 0x7E, 0x00, // A
0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, // B
0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, // C
0x7F, 0x41, 0x41, 0x22, 0x1C, 0x00, // D
0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, // E
0x7F, 0x09, 0x09, 0x01, 0x01, 0x00, // F
0x3E, 0x41, 0x41, 0x51, 0x32, 0x00, // G
0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, // H
0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, // I
0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, // J
0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, // K
0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, // L
0x7F, 0x02, 0x04, 0x02, 0x7F, 0x00, // M
0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, // N
0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, // O
0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, // P
0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, // Q
0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, // R
0x46, 0x49, 0x49, 0x49, 0x31, 0x00, // S
0x01, 0x01, 0x7F, 0x01, 0x01, 0x00, // T
0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, // U
0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, // V
0x7F, 0x20, 0x18, 0x20, 0x7F, 0x00, // W
0x63, 0x14, 0x08, 0x14, 0x63, 0x00, // X
0x03, 0x04, 0x78, 0x04, 0x03, 0x00, // Y
0x61, 0x51, 0x49, 0x45, 0x43, 0x00, // Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
0x02, 0x04, 0x08, 0x10, 0x20, 0x00, // "\"
0x41, 0x41, 0x7F, 0x00, 0x00, 0x00, // ]
0x04, 0x02, 0x01, 0x02, 0x04, 0x00, // ^
0x40, 0x40, 0x40, 0x40, 0x40, 0x00, // _
0x00, 0x01, 0x02, 0x04, 0x00, 0x00, // `
0x20, 0x54, 0x54, 0x54, 0x78, 0x00, // a
0x7F, 0x48, 0x44, 0x44, 0x38, 0x00, // b
0x38, 0x44, 0x44, 0x44, 0x20, 0x00, // c
0x38, 0x44, 0x44, 0x48, 0x7F, 0x00, // d
0x38, 0x54, 0x54, 0x54, 0x18, 0x00, // e
0x08, 0x7E, 0x09, 0x01, 0x02, 0x00, // f
0x08, 0x14, 0x54, 0x54, 0x3C, 0x00, // g
0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, // h
0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, // i
0x20, 0x40, 0x44, 0x3D, 0x00, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, // l
0x7C, 0x04, 0x18, 0x04, 0x78, 0x00, // m
0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, // n
0x38, 0x44, 0x44, 0x44, 0x38, 0x00, // o
0x7C, 0x14, 0x14, 0x14, 0x08, 0x00, // p
0x08, 0x14, 0x14, 0x18, 0x7C, 0x00, // q
0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, // r
0x48, 0x54, 0x54, 0x54, 0x20, 0x00, // s
0x04, 0x3F, 0x44, 0x40, 0x20, 0x00, // t
0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, // u
0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, // v
0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, // w
0x44, 0x28, 0x10, 0x28, 0x44, 0x00, // x
0x0C, 0x50, 0x50, 0x50, 0x3C, 0x00, // y
0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, // z
0x00, 0x08, 0x36, 0x41, 0x00, 0x00, // {
0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, // |
0x00, 0x41, 0x36, 0x08, 0x00, 0x00, // }
0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, // ->
0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, // <-
};

const uint8_t Segment_25x40[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char .
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char /
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xC4, 0xFF, 0xC1, 0xFF, 0x11, 0x8C, 0xFF, 0x80, 0xFF, 0x18, 0x1C, 0x7F, 0x00, 0x7F, 0x1C, 0x3C, 0x00, 0x00, 0x00, 0x1E, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x3C, 0x00, 0x00, 0x00, 0x1E, 0x1C, 0x7F, 0x00, 0x7F, 0x1C, 0x8C, 0xFF, 0x80, 0xFF, 0x18, 0xC4, 0xFF, 0xC1, 0xFF, 0x11, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x80, 0xFF, 0x80, 0xFF, 0x00, 0xC0, 0xFF, 0xC1, 0xFF, 0x01, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x04, 0x00, 0xC0, 0xFF, 0x11, 0x0C, 0x00, 0x88, 0xFF, 0x18, 0x1C, 0x00, 0x1C, 0x7F, 0x1C, 0x3C, 0x00, 0x3E, 0x00, 0x1E, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x3C, 0x00, 0x3E, 0x00, 0x1E, 0x1C, 0x7F, 0x1C, 0x00, 0x1C, 0x8C, 0xFF, 0x08, 0x00, 0x18, 0xC4, 0xFF, 0x01, 0x00, 0x10, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x0C, 0x00, 0x08, 0x00, 0x18, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x3C, 0x00, 0x3E, 0x00, 0x1E, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x3C, 0x00, 0x3E, 0x00, 0x1E, 0x1C, 0x7F, 0x1C, 0x7F, 0x1C, 0x8C, 0xFF, 0x88, 0xFF, 0x18, 0xC4, 0xFF, 0xC1, 0xFF, 0x11, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 3
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0x80, 0xFF, 0x08, 0x00, 0x00, 0x00, 0x7F, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7F, 0x1C, 0x7F, 0x00, 0x80, 0xFF, 0x88, 0xFF, 0x00, 0xC0, 0xFF, 0xC1, 0xFF, 0x01, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 4
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0xC4, 0xFF, 0x01, 0x00, 0x10, 0x8C, 0xFF, 0x08, 0x00, 0x18, 0x1C, 0x7F, 0x1C, 0x00, 0x1C, 0x3C, 0x00, 0x3E, 0x00, 0x1E, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x3C, 0x00, 0x3E, 0x00, 0x1E, 0x1C, 0x00, 0x1C, 0x7F, 0x1C, 0x0C, 0x00, 0x88, 0xFF, 0x18, 0x04, 0x00, 0xC0, 0xFF, 0x11, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 5
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xC0, 0xFF, 0xC1, 0xFF, 0x11, 0x80, 0xFF, 0x88, 0xFF, 0x18, 0x00, 0x7F, 0x1C, 0x7F, 0x1C, 0x00, 0x00, 0x3E, 0x00, 0x1E, 0x00, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x1E, 0x00, 0x00, 0x1C, 0x7F, 0x1C, 0x00, 0x00, 0x88, 0xFF, 0x18, 0x00, 0x00, 0xC0, 0xFF, 0x11, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 6
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x7F, 0x00, 0x7F, 0x00, 0x8C, 0xFF, 0x80, 0xFF, 0x00, 0xC4, 0xFF, 0xC1, 0xFF, 0x01, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xC4, 0xFF, 0xC1, 0xFF, 0x11, 0x8C, 0xFF, 0x88, 0xFF, 0x18, 0x1C, 0x7F, 0x1C, 0x7F, 0x1C, 0x3C, 0x00, 0x3E, 0x00, 0x1E, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x3C, 0x00, 0x3E, 0x00, 0x1E, 0x1C, 0x7F, 0x1C, 0x7F, 0x1C, 0x8C, 0xFF, 0x88, 0xFF, 0x18, 0xC4, 0xFF, 0xC1, 0xFF, 0x11, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x07, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0xC4, 0xFF, 0x01, 0x00, 0x00, 0x8C, 0xFF, 0x08, 0x00, 0x00, 0x1C, 0x7F, 0x1C, 0x00, 0x00, 0x3C, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x00, 0x3C, 0x00, 0x3E, 0x00, 0x00, 0x1C, 0x7F, 0x1C, 0x7F, 0x00, 0x8C, 0xFF, 0x88, 0xFF, 0x00, 0xC4, 0xFF, 0xC1, 0xFF, 0x01, 0xE0, 0xFF, 0xE3, 0xFF, 0x03, 0xF0, 0xFF, 0xF7, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 9
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x3C, 0x00, 0x00, 0x00, 0x1E, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x3C, 0x00, 0x00, 0x00, 0x1E, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Code for char :
};
#endif
SPI hakkında anlatabileceklerim bunlardan ibaret.Açıklamalarım da herhangi bir hata görürseniz yorum veya mail yolu ile bildirebilirsiniz.
Ve son olarak uygulamadan bir kare.



baran123

#7
Merhabalar,

Bu 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üş bunu bende kendisinden faydalandım :)

Ş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);
}

Son olarak bir çalışma videosu sizlerle.
http://youtu.be/Z4YpCCKWyJ8