Geek magazine hacker daily blog

2 years, 11 months ago
Part 1
Part 2
Part 3
Part 4.1

Prolog


Opinions were different in an occasion of analysis of a code and its need in general. I tried to implement a method of "golden ratio" therefore in this article:
a) at the end of article the source code to experts will be attached further not to read
b) I will give algorithm of work and I will sort it
c) I will explain how to use SPL libraries
d) in volume of article I will tell how to use a certain periphery, I will show implementation of work with it in a code
e) separate point I will describe work with ILI9341 since the subject is quite chewed, I will just tell about the main thing — as is considered to implement initialization function (on the Internet saw only a code with the phrase: "there is a working initialization, copy and do not ponder that it") and to start it through hardware SPI.

You will not see too detailed analysis of a code here, everything will be moderately, otherwise I should write the book of pages so in 200-250. Therefore study datashita and other documentation (links will be) before starting writing of the program. Those who the first time will sit down at MK — be not afraid if there are questions I will prompt to you and I will help so you will master this code.

What development environment and whether it is possible to facilitate life libraries?


I will tell at oncea code in this article not "native", but it is tested and works! Since IAR not the most convenient software for beginners and somehow its many avoid because of too big functionality or still some reasons, the decision for educational article to transfer the project to "coco" (CooCoxIDE 1.7.7) was made. Also I decided to depart from registers and to write a code on SPL.

SPL are standard libraries from ST for work with the periphery of MK STM32. Now for replacement there were new libraries HAL, but so far they did not force out the first in many projects. You can subtract pluses and advantages in Google.
I selected SPL — since I like a final code more after "tough optimization", they it is intuitively more clear, HAL are more adapted for work with different RTOS. It especially my opinion, I do not ask anybody to take it on trust and it is not necessary to tell you in comments on what is better or worse.

As I wrote transition from registers to libraries above in what a difference:

Pluses:
a) readability of a code of SPL written with use just excellent, and in articles with a bias under training this most important;
b) speed of writing of a code is much higher, I needed 1,5 hours that under the available algorithm to write a code from scratch and to debug it;
c) easier moving from a stone on a stone, well suddenly you have no STM32F103RBT6, and there is STM32F105VCT6 and you on it will collect.

Minuses:
a) the SPL functions more bulky also occupy more memory, and are also longer executed. But it belongs only to initialization functions, all the rest has the same high-speed performance;
b) in datashita all analysis goes on registers and it is the main minus.

My result:
It is possible to work safely in CoIDE and to write programs with use of SPL exactly to level so far you consider yourself as the fan. As soon as you have a purpose to design serious devices or to begin to earn money with electronics — right there change to IAR and you smoke datashita with their registers.

We make algorithm of our program


For a start we will estimate horse-radish to a nose the general functional structure of the device:

Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 1 — the Flowchart for the program of management

Now we probably that our part has to measure devices and how to arrive with data retrieveds. To bring all measured tension and current to a TFT panel, to define whether tension gets to normal range (according to state standard specification), and at the end to multiply an output current with voltage output and to receive consumption power loading., It seems, everything is simple and clear.
Also our payment has to take temperature, display it, in case of exceeding of abnormal 85 ° C has to switch-off the device by giving a log. 1 on legs of the SD IR2110 driver in power payments. And also by results of the taken temperature value of porosity of ShIMa managing coolers has to be regulated.
All alarm statuses have to be displayed also on LED indication which serves for display of "serious things" of malfunctions in system or failure of the device.
The functionality of this block not difficult, so big work in its implementation will not arise.

What needs to be made before continuing to study article?


1) To download software with which we will work. It will be CooCoxIDE 1.7.7, below I applied a reference on the POISON where you can download the folder with this version of the program, already with set in it to SPL, and also with already downloaded compiler that did not suffer and did not look for. Everything for work start is there:
CooCoxIDE 1.7.7

2) To download sacred manuskrip under the name datashit on STM32F103:
Datasheet STM32F103

3) To download not less Scripture under the name referens a manual which is googled as RM0008 and has epic volume in 1128 pages. This most volume scientific writing which I mastered, the truth were still all volumes of Landau-Livshits, but there several books after all … I to what — advise to address this file at any arising neponyatnka and funny things.
RM0008

4) Still very insistently I advise the blog of one fellow with the level of knowledge of ST — God, the periphery for beginners both rather complex and interesting challenges is chewed there:
Nikolay Gorbunov

5) And the last … we run to download very useful applet of STM32CubeMXthe Official site of ST

I hope you downloaded everything that I advised you and now it is possible to start writing of the program.

We collect the project


1) We select the periphery with which we should work

Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 2 — the Repository for the choice of the periphery which we will use

Now in brief who and what is responsible for:

a) CMSIS core — first of all we tick off on this library, some more libraries will be connected at once. It is a minimum with which it is possible to work. This library as appears from its name connects "kernel" through which basic functions other periphery will work

b) RCC — the library which is responsible for clocking of the microcontroller is the separate cunning moment which today like I will consider. This library allows to select a generation source, and also to expose coefficient of division of frequency for each periphery.

c) GPIO — library of work with input/output ports. Also she allows to carry out all primary settings for other periphery.

d) DMA — this library allows to work with direct memory access. Very in detail it can be read on the Internet — the subject is chewed, for beginners it is still enough to understand that this principle allows to increase the speed of operation of all device.

e) SPI — library for work with the SPI interface, allowing to exchange data with a lot of devices. In our case through it we communicate with the TFT screen on ILI9341.

e) TIM — library for work from the timer. Here I think everything clearly, it will allow us to start PWM for management of coolers and of course for implementation of delays and generation of interruptions.

g) ADC — library for work with our main periphery as the analog digitizer (AD) which measures all our tension and current.

We pass to writing of the program


I was not going to give lessons on With, but as I am guided by audience of people who were afraid to undertake studying of MK and I want to push them, I will describe highlights. First 2 commands:

1) define is a command which serves for substitution of one value instead of another. A half did not understand here, as well as I when studied)

Example 1:

We have a program which lights a LED the GPIO_SetBits command (GPIOA, GPIO_Pin_1); also switches off it the GPIO_ResetBits command (GPIOA, GPIO_Pin_1);. Now you should not think of these commands. As you can see command rather difficult and in the course of writing of a code you do not want to rewrite it 100 times and the more so there is no wish to remember every time how to include/switch off a LED. Therefore we arrive as follows, we write:

#define LED_ON        GPIO_SetBits(GPIOA, GPIO_Pin_1)
#define LED_OFF       GPIO_ResetBits(GPIOA, GPIO_Pin_1)


What did we make? And simplified to themselves life. Now every time when we write in the text of the LED_ON program; (the semicolon is obligatory), there will be a replacement of this phrase by the GPIO_SetBits command (GPIOA, GPIO_Pin_1); Too most with switching off.

Example 2:

You write the program which considers days in a year. That every time in the program not to write number 365 (and actually there can be any difficult number, though Pi) we arrive to similarly previous example and we write:

#define Year   365


It is worth noticing that as 365 just a constant, but not command, after it it is not necessary to put a semicolon. Otherwise will insert not 365, but 365; and when using in the same formula it will be apprehended as an error.

The #define X1 Y2 command just executes replacement of all X1 by Y2 in a code.

I hope questions here did not remain and we pass to simpler, but grant the most important command:

2) include — it allows us to attach other files and libraries to our code.

Example 1:

Any code including ours will begin with this command! We selected in a repository ticks of library and the Coco took and copied files with libraries in the folder with our project. It is not enough, we need to fasten them in our main file.
I did not begin to attach all libraries, ATsP, timers and other yet that we mentioned above and did not add here. Attached the main libraries that at this stage not to stuff the head. We receive such code:

#include "stm32f10x_conf.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_spi.h"

#include "TFT ILI9341.h"



To understand from where we took it unclear the file it is necessary to look in a project tree:
Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 3 — the Tree of the project with necessary libraries

As we see everything that we attached is in this "tree". It is CMSIS library and other. Here it is worth paying attention to four moments:

a) I think the moment about connection it is clear, but I will specify — #include "file name" Quite so it is necessary to include the file, entering his name in brackets and it is not necessary to put a semicolon in a line end.

b) if noticed, then I only connect files with the .h expansion, it is always necessary to do quite so. What the file with the .h expansion and the file with the .c expansion differs in

c) there are 2 files when using SPL libraries which are connected always in main.

#include "stm32f10x_conf.h"
#include "stm32f10x.h"


d) apparently I did not connect the font.h file in the main main file since it at me is connected in the file of TFT ILI9341.h library Why so? FONT — library with fonts is also used only in functions of work with a TFT panel. Not to encumber the main main file I attached fonts with the help #include already in the TFT ILI9341.h file.

3) Differences of files with the permissions of .h and.c

Any decent library consists two files, one of them has permission of .c In this file all functions and their implementations are collected. The file with this expansion is the main for the .h file and therefore it is attached in the last.
The second part of library the .h file contains just all necessary inkluda, such as FONT for TFT ILI9341. Also in it define are described all, constants are declared. For work with this library as you saw higher — we connect this file, and the .c file goes "tail" in.h

Fukh … everything if at you the brain then have just a rest did not blow up, drink tea and we will go further for the most interesting.




Clocking of STM32 microcontrollers



We start the most responsible and cunning point. Clocking of STMok happens not as at AVR and peaks. There just the frequency of quartz undertakes and pursues in a stone.

In STM32 becomes so:

a) MK is always started from HSI - it is the internal generator on 8 MHz
b) Then MK passes to HSE - it is the external quartz resonator
c) Further the signal goes on PLL where frequency is multiplied and goes on the periphery.

Because of the last point when I passed on STM ки at me there was a stupor: I connected quartz on 8 MHz, and everything works for 72 MHz. Therefore typical quartzes it is 8, 16, 24 MHz. Further frequency is multiplied in the microcontroller.
All this can be seen on the following scheme from a datashit, there is it on page 14. For this reason I included given manuskrip in obligatory)

Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 4 — the Scheme of clocking of the periphery of the STM32 microcontroller

Still I ask to pay attention that when clock frequency undertakes with PLL (a frequency multiplier) and then it is distributed on the periphery and is established by means of a divider. There are two buses: APB2 and APB1, hangs on everyone a certain periphery. Each bus has a frequency restriction: 72 MHz at APB2 and 36 MHz at APB1, that is on the 1st bus frequency is equal 1/2 from clock with PLL.

I will give an example: at SPI1 power supply goes from the bus APB2 with the maximum frequency of 72 MHz, and SPI2 hangs on the bus APB1 with a frequency of 36 MHz and it follows from this that the speed of SPI2 will be below. It should be considered!

Now we will address function which performs all tunings of buses. The RCC library therefore function needs to be looked for in the stm32f10x_rcc.h file which we connected to our project right at the beginning is responsible for clocking.

void RCC_Configuration(void)
{
    
    RCC_DeInit();                                               // Выполняем сброс reset 
    RCC_HSEConfig(RCC_HSE_ON);                                  // Включаем тактирование HSE (от кварца) 
    HSEStartUpStatus = RCC_WaitForHSEStartUp();                 // Ждем пока частота кварца стабилизируется

    if (HSEStartUpStatus == SUCCESS)                            // Если все отлично, то переходим на кварц
    {
        
        RCC_HCLKConfig(RCC_SYSCLK_Div1);                        // Выставляет делитель в 1 (Div1), системная частота становится 72 МГц
        RCC_PCLK2Config(RCC_HCLK_Div1);                         // Запитываем APB2 от тактовой частоты PLL в 72 МГц
        RCC_PCLK1Config(RCC_HCLK_Div1);                         // Запитываем APB1 от тактовой частоты PLL в 72 МГц
        RCC_ADCCLKConfig(RCC_PCLK2_Div2);                       // Ставим делитель на 2 (Div2) и получаем частоту 36 МГц вместо 72 МГц
        RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);     // Устанавливаем множитель 9, получаем 8 МГц * 9 = 72 МГц на PLL
        
        RCC_PLLCmd(ENABLE);                                     // Включаем PLL
        
        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {}  // Ждем пока PLL устаканится
        
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);              // Выбираем PLL как источник тактового сигнала

        
        while (RCC_GetSYSCLKSource() != 0x08) {}                // Ждем пока PLL установится как источник тактирования
    }
}


And now we will remember that before using function, it is necessary to declare it in the beginning programs therefore as a result we will receive here such piece of a code which will configure your clocking. It will work at any MK of the F10x series so you can save as library:

/*************************************** Тактирование процессора **********************************/

void RCC_Configuration(void);
ErrorStatus HSEStartUpStatus;
RCC_ClocksTypeDef RCC_Clocks;


void RCC_Configuration(void)
{
    
    RCC_DeInit();                                               // Выполняем сброс reset 
    RCC_HSEConfig(RCC_HSE_ON);                                  // Включаем тактирование HSE (от кварца) 
    HSEStartUpStatus = RCC_WaitForHSEStartUp();                 // Ждем пока частота кварца стабилизируется

    if (HSEStartUpStatus == SUCCESS)                            // Если все отлично, то переходим на кварц
    {
        
        RCC_HCLKConfig(RCC_SYSCLK_Div1);                        // Выставляет делитель в 1 (Div1) и системная частота становится 72 МГц
        RCC_PCLK2Config(RCC_HCLK_Div1);                         // Запитываем APB2 от тактовой частоты PLL в 72 МГц
        RCC_PCLK1Config(RCC_HCLK_Div1);                         // Запитываем APB1 от тактовой частоты PLL в 72 МГц
        RCC_ADCCLKConfig(RCC_PCLK2_Div2);                       // Ставим делитель на 2 (Div2) и получаем частоту 36 МГц вместо входящей 72 МГц
        RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);     // Устанавливаем множитель частоты 9, получаем 8 МГц * 9 = 72 МГц на PLL
        
        RCC_PLLCmd(ENABLE);                                     // Включаем PLL
        
        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {}  // Ждем пока PLL устаканится
        
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);              // Выбираем PLL как источник тактового сигнала

        
        while (RCC_GetSYSCLKSource() != 0x08) {}                // Ждем пока PLL установится как источник тактирования
    }
}


I think clocking I more or less described in detail, now it is necessary to sort the periphery.

Work with input/output ports


GPIO is and there are our input/output ports. It is a basis of bases since before use of any other periphery it is necessary to configure ports to which she is brought.
I will keep the story about this periphery on the example of work of LED indication in our scheme. From the previous article we will take connection:

a) The LED No. 1 (LED1) is connected to PB12
b) The LED No. 2 (LED2) is connected to PB13
c) The LED No. 3 (LED3) is connected to PB14
d) The LED No. 4 (LED4) is connected to PB15
e) The LED No. 5 (LED5) is connected to PC6


That it means … At STM ok there are ports, they have 16 outputs from 0 to 15. The truth is exceptions, some ports not always have the 16th leg, and only 4 or 5 can, for example. The designation PB12 means that it is port the B and 12 output. Now we open STM32CubeMX downloaded earlier and we look where these legs are and whether it will be convenient to us to part them.
Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 5 — the Choice of an arrangement of the periphery in the STM32CubeMX program

The huge charm of STM is that their "flexibility" allows to use any legs for input-output, and all periphery can be transferred to alternative legs (reserve option), so-called Remap. All this allows very qualitatively, quickly and conveniently to part a payment therefore to beginners to learn to use all what the ST developers give us.

Now we need to work with indication, that is to light LEDs in certain situations. Now we go and we look as to do it, we should set our output in log.1 since anodes are connected to MK, and cathodes with scheme "minus". For this purpose we open the stm32f10x_gpio.h file and we go through the file, the list of all available functions down there:
Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 6 — Functions available during the work with GPIO

There we see functions of installation and reset of a status of an output:
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);


How to work with such functions: we copy it, probably that the first record in GPIO_TypeDef brackets * GPIOx as clear instead of "x" it is necessary to specify port, at us is ports B and C, we will receive GPIOB. Here we remember functions from the beginning of article which I asked not to grok especially, here it is already time). We look at the second part in uint16_t GPIO_Pin brackets, here we see the GPIO_Pin variable, we also see that type of this variable unsigned value of 16 bits in size, that is 216 or 65536. But it is so much not necessary for us, I think clear that here we need to specify number of an output (pin) from 0 to 15. As a result we will receive GPIO_Pin_12. Considering all this we write a code:
GPIO_SetBits(GPIOB, GPIO_Pin_12);            // Зажигаем светодиод № 1
GPIO_SetBits(GPIOB, GPIO_Pin_13);            // Зажигаем светодиод № 2
GPIO_SetBits(GPIOB, GPIO_Pin_14);            // Зажигаем светодиод № 3
GPIO_SetBits(GPIOB, GPIO_Pin_15);            // Зажигаем светодиод № 4
GPIO_SetBits(GPIOC, GPIO_Pin_6);             // Зажигаем светодиод № 5


As you can see to remember every time to what leg we connected a LED, to write excess letters when a code at least in 5 000 lines it already oh as is essential)) Therefore we remember remarkable property of the #define command and we modify our code:
#define LED1_ON      GPIO_SetBits(GPIOB, GPIO_Pin_12)            // Зажигаем светодиод № 1
#define LED2_ON      GPIO_SetBits(GPIOB, GPIO_Pin_13)            // Зажигаем светодиод № 2
#define LED3_ON      GPIO_SetBits(GPIOB, GPIO_Pin_14)            // Зажигаем светодиод № 3
#define LED4_ON      GPIO_SetBits(GPIOB, GPIO_Pin_15)            // Зажигаем светодиод № 4
#define LED5_ON      GPIO_SetBits(GPIOC, GPIO_Pin_6)             // Зажигаем светодиод № 5


Now it is unforgettable to make function which will also switch off our "bulbs". For this purpose in the current SetBits function we change for ResetBits — I think everything extremely clearly here. We receive as a result such final code:

#define LED1_ON       GPIO_SetBits(GPIOB, GPIO_Pin_12)              // Зажигаем светодиод № 1
#define LED2_ON       GPIO_SetBits(GPIOB, GPIO_Pin_13)              // Зажигаем светодиод № 2
#define LED3_ON       GPIO_SetBits(GPIOB, GPIO_Pin_14)              // Зажигаем светодиод № 3
#define LED4_ON       GPIO_SetBits(GPIOB, GPIO_Pin_15)              // Зажигаем светодиод № 4
#define LED5_ON       GPIO_SetBits(GPIOC, GPIO_Pin_6)               // Зажигаем светодиод № 5
	
#define LED1_OFF      GPIO_ResetBits(GPIOB, GPIO_Pin_12)            // Гасим светодиод № 1
#define LED2_OFF      GPIO_ResetBits(GPIOB, GPIO_Pin_13)            // Гасим светодиод № 2
#define LED3_OFF      GPIO_ResetBits(GPIOB, GPIO_Pin_14)            // Гасим светодиод № 3
#define LED4_OFF      GPIO_ResetBits(GPIOB, GPIO_Pin_15)            // Гасим светодиод № 4
#define LED5_OFF      GPIO_ResetBits(GPIOC, GPIO_Pin_6)             // Гасим светодиод № 5

Now for simple ignition of a LED it is enough to write LED1_ON; That to switch off it we write also LED1_OFF;

It seems everything is simple? And is not present! There was the last moment which should be shown at the beginning, but it perhaps would frighten off a half of people. Though it and idle time, but working capacity depends on it - it is initialization of the periphery of GPIO. It is necessary to specify to port from where to take it the clock frequency for what to work and in what mode. All this becomes in the same stm32f10x_gpio.h library, but now it is necessary to connect library of clocking stm32f10x_rcc.h to it also.
Before in general to do something with any periphery it is necessary to include its clocking, it becomes in stm32f10x_rcc.h, we go there and we watch what function it to make, their list also at the end of the file:
Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 7 — clocking Functions

Here we see familiar to us APB2 and APB1, buses to which are connected our ports. In this case both With and In sit on APB2, function I selected this on a screen. It is the elementary: in the first part it is necessary to write the name of the periphery, to specify the status in the second. The status can be two: ENABLE (is included) also by DISABLE. Hz why, but essentially to write with capital letters the status, otherwise the Coco will not illuminate the text.
Now it is necessary from where to take the correct name of the periphery. Therefore we go to the file of stm32f10x_rcc.h library and presses Ctrl + F is a search in the file, we write to it RCC_APB2Periph and we press Find. And several times we stick Find we will not reach yet such list where all statuses which this text can accept are specified. We select the necessary periphery:
Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 8 — Search of function value on libraries

And so … how to include clocking understood, we received such line, 2 lines since we use two ports B and C are more right:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);


Everything, with library of clocking we will finish so far and we pass to the stm32f10x_gpio.h file we Go to the end and we look for initialization function, usually they are called Init, here continuous captaincy if know English though a little. We copy GPIO_Init function name further according to the standard Ctrl + F further:
Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 9 — Here so looks function in the list

Further few times we stick Find we will not reach the moment yet there will be a description of function and as it looks:
Implementation of a program code for the indication module on ILI9341 + STM32. Part 4.2
Figure 10 — initialization Function

so it looks and consists of 3 components:
a) GPIO_Pin — here we specify as an output we configure
b) GPIO_Speed — here we specify speed/frequency maximum at which the controller leg can work
c) GPIO_Mode — we set a leg operation mode

If to select each component, to click Ctrl + F and to insert and click Find, then there will be a list of what it is possible to write to each component. Now an example of initialization for our case:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);                          // Включаем тактирование порта

GPIO_InitTypeDef led;                                                          // Даем имя нашей инициализации led

led.GPIO_Pin = (GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15) ;       // Указываем выводы которые подчинятся этой настройке
led.GPIO_Speed = GPIO_Speed_2MHz;                                              // Указываем максимальную частоту работы
led.GPIO_Mode = GPIO_Mode_Out_PP;                                              // Указываем тип настройки ног, тут выход push-pull
GPIO_Init(GPIOB, &led;);                                                        // Запускаем инициализацию


In detail about settings it is possible to esteem in a datashita or to poguglit, the part of other operation modes will meet further therefore select as you will study.
I put the maximum frequency here 2 MHz since in such mode the periphery consumes a little less current. If this is setup for SPI, then it is necessary to specify maximum that there was no restriction. I think everything clearly here if is not present it is ready to answer in a pm.

As a result after today's part we have to receive such here code. It for training, but supplementing it further we will receive the final source code: sorted and clear to everyone!

#include "stm32f10x_conf.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_spi.h"

#include "TFT ILI9341.h"


#define LED1_ON       GPIO_SetBits(GPIOB, GPIO_Pin_12)              // Зажигаем светодиод № 1
#define LED2_ON       GPIO_SetBits(GPIOB, GPIO_Pin_13)              // Зажигаем светодиод № 2
#define LED3_ON       GPIO_SetBits(GPIOB, GPIO_Pin_14)              // Зажигаем светодиод № 3
#define LED4_ON       GPIO_SetBits(GPIOB, GPIO_Pin_15)              // Зажигаем светодиод № 4
#define LED5_ON       GPIO_SetBits(GPIOC, GPIO_Pin_6)               // Зажигаем светодиод № 5
          	
#define LED1_OFF      GPIO_ResetBits(GPIOB, GPIO_Pin_12)            // Гасим светодиод № 1
#define LED2_OFF      GPIO_ResetBits(GPIOB, GPIO_Pin_13)            // Гасим светодиод № 2
#define LED3_OFF      GPIO_ResetBits(GPIOB, GPIO_Pin_14)            // Гасим светодиод № 3
#define LED4_OFF      GPIO_ResetBits(GPIOB, GPIO_Pin_15)            // Гасим светодиод № 4
#define LED5_OFF      GPIO_ResetBits(GPIOC, GPIO_Pin_6)             // Гасим светодиод № 5



/****************************************************************************************************************/
/********************** Функции используемы для работы **********************************************************/
/****************************************************************************************************************/

/*************************************** Тактирование процессора **********************************/

void RCC_Configuration(void);
ErrorStatus HSEStartUpStatus;
RCC_ClocksTypeDef RCC_Clocks;


void RCC_Configuration(void)
{

    RCC_DeInit();                                               // Выполняем сброс reset
    RCC_HSEConfig(RCC_HSE_ON);                                  // Включаем тактирование HSE (от кварца)
    HSEStartUpStatus = RCC_WaitForHSEStartUp();                 // Ждем пока частота кварца стабилизируется

    if (HSEStartUpStatus == SUCCESS)                            // Если все отлично, то переходим на кварц
    {

        RCC_HCLKConfig(RCC_SYSCLK_Div1);                        // Выставляет делитель в 1 (Div1) и системная частота становится 72 МГц
        RCC_PCLK2Config(RCC_HCLK_Div1);                         // Запитываем APB2 от тактовой частоты PLL в 72 МГц
        RCC_PCLK1Config(RCC_HCLK_Div1);                         // Запитываем APB1 от тактовой частоты PLL в 72 МГц
        RCC_ADCCLKConfig(RCC_PCLK2_Div2);                       // Ставим делитель на 2 (Div2) и получаем частоту 36 МГц вместо входящей 72 МГц
        RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);     // Устанавливаем множитель частоты 9, получаем 8 МГц * 9 = 72 МГц на PLL

        RCC_PLLCmd(ENABLE);                                     // Включаем PLL

        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {}  // Ждем пока PLL устаканится

        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);              // Выбираем PLL как источник тактового сигнала


        while (RCC_GetSYSCLKSource() != 0x08) {}                // Ждем пока PLL установится как источник тактирования
    }
}



/************************** Основное тело программы ***********************************************/
/**************************************************************************************************/
/**************************************************************************************************/

int main(void)
{
	 RCC_GetClocksFreq (&RCC;_Clocks);
     RCC_Configuration();
     RCC_GetClocksFreq (&RCC;_Clocks);
     


/************* Настройка портов *****************************************/     

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);                          // Включаем тактирование порта

GPIO_InitTypeDef led;                                                          // Даем имя нашей инициализации led

led.GPIO_Pin = (GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15) ;       // Указываем выводы которые подчинятся этой настройке
led.GPIO_Speed = GPIO_Speed_2MHz;                                              // Указываем максимальную частоту работы
led.GPIO_Mode = GPIO_Mode_Out_PP;                                              // Указываем тип настройки ног, тут выход push-pull
GPIO_Init(GPIOB, &led;);                                                        // Запускаем инициализацию
          	
         

	
	


	while(1)
	{
		
		LED1_ON;
		LED2_OFF;
		LED3_ON;
		LED4_ON;
		LED5_OFF;

	}

}


As a result we learned to configure clocking from quartz for high accuracy, sorted how to use SPL libraries and how to configure GPIO and to use them. Also mentioned basic functions Alya Defayn and inklud, with analysis of their application in a real code.

Epilog


Yes, the article really strained to me the head since the sensei from me bad, and asked to tell in detail about a firmware. I hope at me it turned out also those who are only going to begin studying of programming of microcontrollers I will be able to understand me, my descriptions and to council.
So it turned out that it is part not the last, will be 4.3 more where we will sort the remained periphery and we will add the program. I did not want to do a heap of subsections, but it turns out so that it is impossible to tell even about rather simple code for one scarfs in volume of one article.

Article 4.3 with the termination of a program code will appear about New year, parts with power circuit engineering will be next year. The truth a small bun after all will be — to NG I am going to publish one more article which is not devoted to this cycle about the UPS, but after all having some relation in respect of circuit engineering.
Article will be called — "We manufacture the pulse laboratory power supply unit 0-60B and 20A". The prototype at me is ready, rolled and ready to seem to the public.

Perhaps at me all and a request to cool specialists to leave comments taking into account that it is the training article of initial level and all my dismantling of a code will be such. I thank in advance!

Part 5

This article is a translation of the original post at geektimes.ru/post/268228/
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here: sysmagazine.com@gmail.com.

We believe that the knowledge, which is available at the most popular Russian IT blog geektimes.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.