[CZĘŚĆ 1] STM32Butterfly2: Tetris na STM32 – wprowadzenie do mechanizmu gry
W artykule przedstawiamy sposób prostej implementacji na mikrokontrolerze STM32F107 znanej i popularnej od lat gry Tetris. Autor projektu wykorzystał peryferia zestawu STM32Butterfly2 i moduł z tanim monochromatycznym wyświetlaczem LCD z telefonu Nokia 3310.
Sposób połączenia modułu KAmodLCD z zestawem STM32Butterfly2, który zamienia ten zestaw w konsolę do grania, pokazano na rysunku 1. W aplikacji wykorzystano joystick znajdujący się na płytce „motyla”, który dołączono do wyprowadzeń mikrokontrolera w zestawie „na sztywno”. Do zaprogramowania mikrokontrolera potrzebny będzie programator JTAG, można użyć zgodnego z ST-Link/v2 programatora ZL30PRGv2 (fotografia 2). Projekt programistyczny utworzono za pomocą pakietu Atollic TrueSTUDIO Lite.
Rys. 1. Schemat ilustrujący połączenia niezbędne do prawidłowego działania Tetrisa na STM32Butterfly2
Z istniejących plików projektu interesują nas znajdujące się w katalogu src (pliki źródłowe) plik main.c i stm32f10x_it.c. W pierwszym znajduje się główna część programu, w drugim procedury obsługi przerwań.
Fot. 2. Wygląd programatora JTAG/SWD o nazwie ZL30PRGv2
Funkcja main to główna funkcja każdego programu, od niej rozpoczyna się jego wykonywanie. Na jego początku znajdują się procedury konfigurujące peryferia mikrokontrolera. W przykładowym projekcie procedury konfiguracyjne umieszczono w osobnych funkcjach, które kolejno wywołuje na początku funkcji main(), dlatego przed funkcją main należy umieścić deklaracje funkcji:
void RCC_Configuration(void); void GPIO_Configuration(void); void EXTI_Configuration(void); void NVIC_Configuration(void);
Ciała tych funkcji znajdują się na listingu 1.
List. 1. Ciała funkcji inicjujących mikrokontroler
//Funkcje konfiguracyjne
//Funkcja konfigurująca porty GPIO
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //inicjalizacja struktury konfiguracji GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE); //uruchomienie taktowania dla portu GPIOE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOE, &GPIO_InitStructure); //ustawienie pinów 14 i 15 portu GPIOE jako wyjść
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure); //ustawienie pinów 8, 9, 10, 11 i 12 portu GPIOE jako wejść
}
//Funkcja konfigurująca system sygnałów taktowania
void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus;
RCC_DeInit(); //reset ustawień RCC
RCC_HSEConfig(RCC_HSE_ON); //włącz HSE
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //oczekiwanie na gotowość HSE
if (HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //włączenie buforu dla pamięci Flash
FLASH_SetLatency(FLASH_Latency_2); //ustawienie opóźnień dla pamięci Flash
RCC_HCLKConfig(RCC_SYSCLK_Div1); //taktowanie rdzenia sygnałem 1:1 (72MHz)
RCC_PCLK2Config(RCC_HCLK_Div1); //taktowanie magistrali APB2 sygnałem 1:1 (72MHz)
RCC_PCLK1Config(RCC_HCLK_Div2); //taktowanie magistrali APB1 sygnałem 1:2 (36MHz)
RCC_PREDIV2Config(RCC_PREDIV2_Div5 ); //ustawienie PLL2 1:5*8 (25MHz/5*8=20Mhz)
RCC_PLL2Config(RCC_PLL2Mul_8);
RCC_PLL2Cmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET) {} //oczekiwanie na uruchomienie PLL2
RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2,RCC_PREDIV1_Div5); //ustawienie PLL1 PLL2CLK/5*9 (20MHz/5*9=72MHz)
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
RCC_PLLCmd (ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {} //oczekiwanie na uruchomienie PLL1
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //ustawienie pętli PLL1 jako źródła sygnału zegarowego dla systemu
while (RCC_GetSYSCLKSource() != 0x08) {} //oczekiwanie aż pętla PLL1 stanie się źródłem sygnały zegarowego dla sytemu
}
}
//Funkcja konfigurująca GPIO jako źródła przerwań (kontroler EXTI)
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure; //inicjalizacja struktury konfiguracji przerwań EXTI
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource8); //aktywowanie funkcji EXTI pinów joystick'a
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource9);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource10);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource11);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource12);
EXTI_InitStructure.EXTI_Line = EXTI_Line8 | EXTI_Line9 | EXTI_Line10 | EXTI_Line11 | EXTI_Line12;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //przerwanie przy zboczu opadającym
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //uaktywnienie kontrolera EXTI
EXTI_Init(&EXTI_InitStructure);
}
//Funkcja konfigurująca kontroler przerwań NVIC
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure; //inicjalizacja struktury konfiguracji kontrolera przerwań
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //wybór grupy priorytetów
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //konfiguracja przerwania od GPIO piny od 5 do 9
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //konfiguracja przerwania od GPIO piny od 10 do 15
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}




Technologie End of Life i bezpieczeństwo sieci – wyzwania Europy związane z tzw. długiem technologicznym
Najczęstsze błędy firm przy wyborze dostawcy energii i jak ich uniknąć
Fotorezystor, czyli czujnik światła dwojakiego działania. Przykład innowacji w automatyce i elektronice możliwej dzięki technologii fotooporników 



