Get the Flash Player to see this player.

time2online Joomla Extensions: Simple Video Flash Player Module
Pierwszy program STM32

Naukę każdego mikroprocesora należy zacząć od wystawiania napięcia na określoną nóżkę oraz odczytania stanu danego pinu. Następnie należy nauczyć się obsługi timerów, interfejsów i dodatkowych urządzeń takich jak przetwornik ADC i termometr wewnętrzny. Dopiero po takim przygotowaniu możemy zacząć zabawę z mikroprocesorem.W Atolic TrueStudio sprawa jest ułatwiona, ponieważ wszystkie biblioteki dostarczone są razem ze środowiskiem. Po pierwszym uruchomieniu dostajemy cały pakiet dostępnych bibliotek. Wystarczy tylko wybrać interesujący nas procesor i programator.

Do obsługi portów wejścia/wyjścia służy rejestr GPIO. Obsługa tego rejestru różni się od procesorów z rodziny AVR, ale nie aż tak bardzo. W STM32 można na bieżąco odczytywać stan portu nawet jeśli jest on ustawiony jako wyjście. Drugą różnicą jest prędkość odczytu z portu. Jest to czas po którym możemy znowu odczytać wartość portu. A trzecią najbardziej istotną różnicą jest to, że wszystkie urządzenia w STM32 standardowo są wyłączone i trzeba je włączyć. W AVR wszystko było już załączone. Nie będę się tu długo rozpisywał ponieważ znalazłem artykuł dotyczący Timerów i GPIO na forbocie, dlatego podsyłam link oraz skorzystam z ich przykładu :) :

http://www.forbot.pl/forum/topics49/kurs-stm32-czesc-1-narzedzia-vt5733,25.htm?sid=092cc1eabf3b3d7bd6cac0d8caae753f

http://www.forbot.pl/forum/topics49/kurs-stm32-czesc-2-pierwszy-projekt-vt5905.htm

Za konfigurację GPIO w naszym kodzie odpowiedzialna jest poniższa funkcja:

<code>void konf_led_buzz(void)
{
 GPIO_InitTypeDef GPIO_InitStruct;//1

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);//2

 GPIO_StructInit(&GPIO_InitStruct);//3
 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;//4
 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//5
 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;//6
 GPIO_Init(GPIOE, &GPIO_InitStruct);//7
 GPIO_WriteBit(GPIOE, GPIO_Pin_14 | GPIO_Pin_15, Bit_SET);//8

}</code>

W pierwszej linijce deklarujemy strukturę. W drugiej załączamy port GPIOE do którego przyczepione są diody i buzzer.  W czwartej linijce deklarujemy piny do których ta struktura się tyczy. W piątej linijce ustalamy kierunek portu, pull-down, pull-up itp. W szóstej linijce podajemy szybkość portu. Dla przykładu jeśli chcemy oprogramować przycisk, to możemy użyć GPIO_Mode_IPU (załączony wewnętrzny pull up), GPIO_Mode_IPD (załączony wewnętrzny pull down) lub GPIO_Mode_IN_FLOATING (stan wysokiej impedancji, czyli trzeba podciągnąć ten przycisk zewnętrznym pull-up'em lub pull-down'em). Dla Wejścia analogowego należy wybrać opcję GPIO_Mode_AIN, a dla diodek GPIO_Mode_Out_OD lub GPIO_Mode_Out_PP.

Zapewne jesteście ciekawi skąd wiedziałem, że wpisanie GPIO_Mode_Out_PP spowoduje ustawienie pull-up oraz jakie dostępne są opcje dla danego procesora. Odpowiedź jest prosta należy otworzyć katalog Libraries->STM32F10x_StdPeriph_Driver->stm32f10x_gpio.h tak jak na obrazku poniżej

W bibliotekach stworzonych przez Atolic mamy dostępne biblioteki co widać po lewej stronie. Programista musi tylko nauczyć się korzystać z tych bibliotek. Jest to duże ułatwienie dla hobbystów takich jak ja. Poniżej prezentuje kod całego pliku main.c pobrany z forbot'a, który uruchamia i gasi na zmianę diodę 1 i 2 oraz buzzer.

#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>
#include "stm32f10x_flash.h"
#include "misc.h"


//////////////////////////////// makra led1 i led2 ///////////////////////////////
#define LED1_ON        GPIO_ResetBits(GPIOE, GPIO_Pin_15)
#define LED1_OFF    GPIO_SetBits(GPIOE, GPIO_Pin_15)
#define LED1_INV    ((GPIOE->ODR & GPIO_Pin_15)?(LED1_ON):(LED1_OFF))
#define LED2_ON        GPIO_ResetBits(GPIOE, GPIO_Pin_14)
#define LED2_OFF    GPIO_SetBits(GPIOE, GPIO_Pin_14)
#define LED2_INV    ((GPIOE->ODR & GPIO_Pin_14)?(LED2_ON):(LED2_OFF))
#define buzz_ON        GPIO_ResetBits(GPIOE, GPIO_Pin_13)
#define buzz_OFF    GPIO_SetBits(GPIOE, GPIO_Pin_13)

//////////////////////////////// deklaracje //////////////////////////////////
void konf_led_buzz(void);
void konf_zegary(void);
void Delay(volatile unsigned);
/////////////////////////////// zmienne globalne //////////////////////////////


/////////////////////////////  MAIN ////////////////////////////////////////////////
int main(void) {


 konf_zegary();
 konf_led_buzz();

 while (1)
 {
 LED1_ON;
 Delay(1000000);
 LED2_ON;
 Delay(1000000);
 LED1_OFF;
 Delay(1000000);
 LED2_OFF;
 Delay(1000000);
 buzz_ON;
 Delay(1000000);
 buzz_OFF;
 Delay(1000000);


 }
}

/////////////////////////////// Konfiguracja zegarow do 72mhz //////////////////////
void konf_zegary(void)
{
 ErrorStatus HSEStartUpStatus;

 // Reset ustawien RCC
 RCC_DeInit();
 // Wlacz HSE
 RCC_HSEConfig(RCC_HSE_ON);
 // Czekaj za HSE bedzie gotowy
 HSEStartUpStatus = RCC_WaitForHSEStartUp();
 if(HSEStartUpStatus == SUCCESS)
 {
 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
 // zwloka dla pamieci Flash
 FLASH_SetLatency(FLASH_Latency_2);
 // HCLK = SYSCLK
 RCC_HCLKConfig(RCC_SYSCLK_Div1);
 // PCLK2 = HCLK
 RCC_PCLK2Config(RCC_HCLK_Div1);
 // PCLK1 = HCLK/2
 RCC_PCLK1Config(RCC_HCLK_Div2);
 // PLLCLK = 8MHz * 9 = 72 MHz
 RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
 // Wlacz PLL
 RCC_PLLCmd(ENABLE);
 // Czekaj az PLL poprawnie sie uruchomi
 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
 // PLL bedzie zrodlem sygnalu zegarowego
 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
 // Czekaj az PLL bedzie sygnalem zegarowym systemu
 while(RCC_GetSYSCLKSource() != 0x08);
 }
}

/////////////////////////////// Konfiguracja LEDOW i GLOSNIKA //////////////////////
void konf_led_buzz(void)
{
 GPIO_InitTypeDef GPIO_InitStruct;

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

 GPIO_StructInit(&GPIO_InitStruct);
 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
 GPIO_Init(GPIOE, &GPIO_InitStruct);
 GPIO_WriteBit(GPIOE, GPIO_Pin_14 | GPIO_Pin_15, Bit_SET);

}
void Delay(volatile unsigned count) {
 while(count--);
}


Aby wgrać nasz program wystarczy podłączyć naszego JTAG'a i wcisnąć znaczek zielonego robaka. Pojawi się nam konfiguracja debugera w której wystarczy zmienić nasz programator i wybrać program, który ma być debugowany.

Gdy otworzy się nam okno z programem wciskamy zielony przycisk play, a program sam wgra się do procesora:

Gdy naciśniemy czerwony kwadrat, wyjdziemy z trybu debugowania i wrócimy do programu. Oczywiście tryb debugowania umożliwia nam podglądanie programu w czasie rzeczywistym i wychwytywanie błędów na bieżąco, ale mi wystarcza wgrywanie programu.