Part 1
Part 2
Part 3
Part 4.1
Prologue
Opinions were different about the analysis of the code and its necessity in general. In this article I tried to implement the “golden section” method,
therefore:
a) at the end of the article the source code will be attached to the
experts not to read further
b) I will give the algorithm of work and analyze it
c) explain how to use SPL libraries
d) in the volume of the article I will tell you how to use a certain periphery, I will show the implementation of working with it in the code
e) I will describe in a separate paragraph work with ILI9341, since the topic is quite chewed up, then I’ll just tell you about the main thing - how to think about implementing the initialization function (on the Internet I saw only a code with the phrase: “here’s the initialization, copy and don’t think about it”) and run it through hardware SPI.
Too detailed analysis of the code you will not see here, everything will be in moderation, otherwise I will have to write a book of pages in 200-250. Therefore, study datasheets and other documentation (
links will be ) before you start writing a program. Those who sit for the first time in the MK - do not be afraid if I have any questions, I will tell you and help, so you will master this code.
What is the development environment and is it possible to make life easier for libraries?
I will say right away - the
code in this article is not “native”, but it has been tested and it works! Since IAR is not the most convenient software for newbies, and somehow many people bypass it because of too much functionality or even some other reasons, it was decided for the educational article to move the project to “coconut” (
CooCoxIDE 1.7.7 ). I also decided to move away from the registers and write the code in
SPL.
')
SPL - is the standard library from ST to work with the periphery of the MK STM32. Now the replacement came new libraries HAL, but so far they have not supplanted the first in many projects. You can deduct advantages and advantages in Google.
I chose
SPL - because I like the final code more after the “hard optimization”, they are more intuitive, HAL is more adapted to work with various
RTOS. This is purely my opinion, I do not ask anyone to take it on faith and tell in the comments that it is better or worse, not worth it.
As I wrote above - there was a transition from registers to libraries, what is the difference:
Pros:
a) readability of code written using SPL is simply excellent, and in articles with a bias for learning this is the most important thing;
b) the speed of writing the code is much higher, it took me 1.5 hours to write the code from scratch for the existing algorithm and debug it;
c) easier moving from stone to stone, well, suddenly you do not have STM32F103RBT6, but there is STM32F105VCT6 and you will be collecting on it.
Minuses:
a) SPL functions are more cumbersome and take up more memory, and also take longer to execute.
But this applies only to the initialization functions, everything else has the same speed;
b) in datasheets, all parsing is done on registers and this is the main disadvantage.
My result:
You can safely work in CoIDE and write programs using SPL exactly to the level while you consider yourself an amateur. As soon as you have a goal to design serious devices or start making money with electronics - immediately transfer to IAR and smoke datasheets with their registers.
We make the algorithm of our program
To begin, let's figure out the hell to the nose of the overall functional structure of the device:
Figure 1 - Flowchart for the control program
Now we can see what our part of the device should measure and how to deal with the data obtained. All measured voltages and currents should be output to the TFT panel, whether the voltage falls within the normal range (
according to GOST ), and at the end multiply the output current with the output voltage and obtain the power consumption of the load. It seems that everything is simple and clear.
Also, our board should measure the temperature, display it on the screen, in case of emergency,
85 o C should
turn off the device by filing a
log. 1 on the feet of the
SD driver
IR2110 in the power boards. As well as according to the results of the measured temperature, the value of the duty ratio of the PWM controlling the coolers should be regulated.
All alarm conditions should also be displayed on the LED display, which is used to display
"serious things" system problems or device failure.
The functionality of this unit is not complicated, and therefore it will not be difficult to implement it.
What needs to be done before continuing to study the article?
1)
Download the software with which we will work. This will be
CooCoxIDE 1.7.7 , below I have attached a reference to my poison, where you can download the folder with this version of the program, already with
SPL installed in it, as well as with the already downloaded compiler so that you don’t suffer and do not search. Everything to start work there is:
CooCoxIDE 1.7.7
2) Download the
holy manuscript called datashit on
STM32F103 :
Datasheet STM32F103
3) Download at least a
scripture called reference manual, which is Googleed as
RM0008 and has an epic volume of 1128 pages. This is the most extensive scientific writing that I have mastered, although there were still all volumes of Landau-Livshits, but there are several books all the same ... I’m for something - I advise you to refer to this file with any misunderstandings and curiosities.
RM0008
4) Another very strongly I advise the blog of one boy with a level of knowledge of ST - God, he has there chewed a periphery for beginners and quite complex and interesting tasks:
Nikolay Gorbunov
5) And the last ... run to download a very useful program
STM32CubeMX -
Official site ST
I hope you downloaded everything that I advised you and now you can start writing the program.
We collect the project
1) We choose the periphery with which we have to work
Figure 2 - A repository for selecting the periphery that we will use
Now briefly who and for what answers:
a)
CMSIS core - first of all we tick on this library, several more libraries will be connected immediately. This is the minimum you can work with. This library, as its name implies, connects the “core”, the basic functions through which the rest of the peripherals will work
b) The
RCC is the library responsible for the clocking of the microcontroller, this is a separate tricky moment that I will consider today. This library allows you to select the source of generation, as well as set the frequency division factor for each periphery.
c)
GPIO - library of work with input / output ports. It also allows you to carry out all the initial settings for the rest of the periphery.
d)
DMA - this library allows you to work with direct memory access. This can be read in great detail on the Internet - the topic is chewed, for beginners it is enough to understand that this principle allows increasing the speed of the entire device.
e)
SPI - a library for working with the
SPI interface, which allows you to exchange data with a bunch of devices. In our case, through it we communicate with the
TFT screen on the
ILI9341 .
f)
TIM - a library for working with a timer. Here I think everything is clear, it will allow us to run
PWM to control the coolers and of course to implement delays and generate interrupts.
g)
ADC is a library for working with our main periphery with an
analog-to-digital converter (ADC), which measures all of our voltages and currents.
We proceed to writing the program.
I was not going to give lessons on
C , but since I am guided by an audience of people who were afraid to take up studying MK and I want to push them, I will describe the main points. The first 2 teams:
1)
define is a command that serves to substitute one value instead of another. Half here did not understand, as I did when I studied)
Example 1:
We have a program that lights the LED with the team
GPIO_SetBits (GPIOA, GPIO_Pin_1); and turns it off with the command
GPIO_ResetBits (GPIOA, GPIO_Pin_1); . Now you do not need to think about these commands. As you can see, the command is quite complicated and in the process of writing the code you don’t want to rewrite it 100 times, and even more so you don’t want to remember how to turn on / off the LED every time. Therefore, we proceed as follows, we write:
#define LED_ON GPIO_SetBits(GPIOA, GPIO_Pin_1) #define LED_OFF GPIO_ResetBits(GPIOA, GPIO_Pin_1)
What have we done? And simplify your life. Now every time we write in the text of the program
LED_ON; (
semicolon is required ), then this phrase will be replaced with the
GPIO_SetBits command
(GPIOA, GPIO_Pin_1); The same with shutdown.
Example 2:
You write a program that counts the days of the year. In order not to write the number
365 in the program each time (and in fact there can be any complex number, even though Pi), we act like the previous example and write:
#define Year 365
It is worth noting that since
365 is just a constant and not a command, there is no need to put a semicolon after it. Otherwise, it will insert not
365 , but
365; and when used in the same formula will be perceived as an error.
The #define X1 Y2 command simply replaces all X1 with Y2 in the code.
I hope there are no questions left and go to a simpler, but perhaps the most important team:
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 library ticks in the repository and Coconut took and copied the files with libraries into the folder with our project. This is not enough, we need to attach them in our
main file
.
I have not yet begun to attach all the libraries, ADCs, timers, etc. that we mentioned above and did not add here. Attached the main library, so at this stage not to bother.
We get this 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 where we got this incomprehensible file, you need to look into the project tree:
Figure 3 - Project Tree with Required Libraries
As you can see, all that we have attached is in this "tree". This is a library of CMSIS and others. Here you should pay attention to four points:
a) I think the moment with the connection is clear, but I will clarify -
#include the “file name” This is how you should include the file, indicating its name in brackets and do not put a semicolon at the end of the line.
b) if you noticed, then I connect only files with the extension
.h , you should always do this way. What is the difference between a file with a
.h extension and a file with a
.c extension
?
c) there are 2 files when using
SPL libraries, which are always connected to
main .
#include "stm32f10x_conf.h" #include "stm32f10x.h"
d) apparently the file
font.h I did not connect to the main file
main , since I have it connected in the
TFT library file
ILI9341.h Why is that? FONT is a library with fonts and is used only in the functions of working with the TFT panel. In order not to clutter up the main file, I attached fonts using
#include inside the
TFT file
ILI9341.h .
3)
Differences between .h and .c files
Any decent library consists of two files, one of them has the
.c permission. This file contains all the functions and their implementations. The file with this extension is the main one for the
.h file and therefore is attached inside the latter.
The second part of the library file
.h contains just all the necessary inclusions, such as
FONT for
TFT ILI9341 . It also describes all
define , declared constants. To work with this library, as you saw above, we include this particular file, and the
.c file comes as a “tail” inside
.h
Fuh ... everything, if your brain doesn’t explode, then just relax, have some tea and go on for the most interesting.
Clocking microcontrollers STM32
Getting to the most responsible and cunning item. Clocking
STM ok is not like AVR and peaks. There, the frequency of quartz is simply taken and chased into stone.
The STM32 is done like this:
a) MK always starts from
HSI - this is an internal 8 MHz oscillator
b) Then the MK switches to
HSE - this is an external quartz resonator
c) Next, the signal goes to the PLL, where the frequency is multiplied and goes to the periphery.
It is because of the last point, when I switched to STMs, I had a stupor: I connected the quartz to 8 MHz, and everything works at 72 MHz. Therefore, typical quartz is 8, 16, 24 MHz. Further, the frequency is multiplied inside the microcontroller.
All this can be seen in the following diagram from the datasheet, it is on page 14. That is why I included this manuscript in the mandatory)
Figure 4 - The timing scheme of the periphery of the microcontroller STM32
I also ask you to note that when the clock frequency is taken from the
PLL (frequency multiplier) and then distributed around the periphery and set using a divider. There are two buses:
APB2 and
APB1 , on each hanging a certain periphery. Each bus has a frequency limit: 72 MHz for APB2 and 36 MHz for APB1, that is, on the 1st bus, the frequency is equal to
1/2 of the clock frequency with
PLL .
Let me give an example: with
SPI1, the power comes from the APB2 bus with a maximum frequency of 72 MHz, and the
SPI2 hangs on the APB1 bus with a frequency of 36 MHz and this means that the SPI2 speed will be lower.
It is worth considering!
Now let's turn to the function that performs all the tire settings. The
RCC library is responsible for clocking, so the function should be searched for in the
stm32f10x_rcc.h file, which we connected to our project at the very beginning.
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 let's remember that before using a function, you need to declare it at the beginning of the program, so in the end we will get such a piece of code that will customize your clocking. It will work on any MK F10x series, so you can save it as a 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 the clocking I described more or less in detail, now I need to disassemble the periphery.
Work with I / O ports
GPIO is our input / output ports. This is the foundation of before using any other peripherals, it is necessary to configure the ports to which it is derived.
I will lead the story about this periphery using the example of the LED display in our circuit. From the
previous article we will take the connection:
a) LED â„–1 (LED1) is connected to PB12
b) LED No. 2 (LED2) is connected to PB13
c) LED â„–3 (LED3) is connected to PB14
d) LED â„–4 (LED4) is connected to PB15
e) LED No. 5 (LED5) is connected to the PC6
What does this mean ... STM has ports, they have 16 pins from 0 to 15. True, there are exceptions, some ports do not always have 16 legs, but they can, for example, only 4 or 5. The designation
PB12 means that this is port B and 12th conclusion. Now open the previously downloaded
STM32CubeMX and see where these legs are and whether it will be convenient for us to plant them.
Figure 5 - Selecting the location of the periphery in the program STM32CubeMX
The great beauty of STM is that their
“flexibility” allows you to use any legs for I / O, and the entire periphery can be transferred to alternative legs (a fallback), the so-called
Remap . All this allows very high quality, fast and convenient to part fee, so beginners learn to use all that gives us the developers of ST.
Now we need to work with the display, that is, light the LEDs in certain situations. Now we go and see how to do it, we need to set our output to
log.1 , because the anodes are connected to the MC, and the cathodes with the minus circuit. To do this, open the
stm32f10x_gpio.h file and scroll down the file, there is a list of all available functions:
Figure 6 - Functions available when working with GPIO
There we see the functions of setting and resetting the output state:
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: copy it, apparently the first entry in brackets
GPIO_TypeDef * GPIOx , as is clear, instead of
“x” you need to specify the port, we have ports B and C, we get
GPIOB . Here we recall the functions from the beginning of the article, which I requested not to eat too much, it is already time). We look at the second part in the brackets
uint16_t GPIO_Pin , here we see the variable
GPIO_Pin , we also see that the type of this variable is unsigned,
16 bits in size, that is,
2 16 or
65536 . But we do not need so much, I think it is clear that here we need to specify the number of output (pin)
from 0 to 15. As a result, we get
GPIO_Pin_12 . Given all this, we write 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, every time we remember which leg we connected the LED to, write extra letters, when the code is at least 5,000 lines, oh how important it is)) Therefore, we remember the remarkable feature of the
#define command and 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's unforgettable to make a function that will also turn off our “light bulbs”. To do this, we change the current
SetBits function to
ResetBits - I think everything is very clear here. We end up with this end 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 the LED it is enough to write
LED1_ON; To turn it off, we also write LED1_OFF;
It seems everything is simple? But no! There was the last moment that had to be shown at the beginning, but he would probably have scared half of the people. Although it is simple, but the performance depends on it - this is the
initialization of the GPIO periphery . It is necessary to indicate the port from where to get him the clock frequency, on which one to work and in what mode. All this is done in the same
stm32f10x_gpio.h library, but now you also need to connect the clocking library
stm32f10x_rcc.h to it.
Before you
need to do something with any peripherals,
you need to enable its clocking , this is done in
stm32f10x_rcc.h , go there and see what function to do it, their list is also at the end of the file:
Figure 7 - Clocking Functions
Here we see the familiar APB2 and APB1, the buses to which our ports are connected. In this case, both C and B are on APB2, I highlighted this function on the screen. It is the simplest: in the first part it is necessary to write the name of the periphery, in the second to indicate the status. There can be two
statuses :
ENABLE (enabled) and
DISABLE. Xs why, but it’s important to write status in large letters, otherwise Coco will not highlight the text.
Now you need somewhere to get the correct name of the periphery. Therefore, we go to the library file
stm32f10x_rcc.h and presses
Ctrl + F - this is a search in the file, write RCC_APB2Periph to it and click
Find . And we poke
Find several times until we reach such a list, where all the states that this inscription can accept are indicated. Select the desired peripherals:
Figure 8 - Search function values ​​by library
And so ... how to enable clocking figured out, we got this line, or rather 2 lines, because use two ports B and C:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
Everything, with the clocking library, let's finish it now and go to the
stm32f10x_gpio.h file
. Go to the end and look for the initialization function, they are usually called
Init , there’s a complete captaincy if you know English at least a little. Next, copy the name of the function
GPIO_Init and then follow the standard
Ctrl + F :
Figure 9 - This is what the function in the list looks like
Next, we poke
Find a couple of times until we get to the moment there will be a description of the function and what it looks like:
Figure 10 - Initialization Function
so it looks and consists of 3 components:
a) GPIO_Pin - here we indicate how the output is set up
b) GPIO_Speed ​​- here we indicate the speed / frequency maximum at which the controller's foot can work
c) GPIO_Mode - set the foot operation mode
If you select each component, press
Ctrl + F and paste and press
Find , then there will be a list of what you can write with 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); //
Details about the settings can be read in datashit or google, some of the other modes of operation will be found further, so choose how you will study.
I set the maximum frequency to 2 MHz, since in this mode, the periphery consumes a little less current. If this would be a setting for
SPI , then you need to specify the maximum,
so that there is no limit . I think everything is clear, if not ready to answer in a personal.
As a result, after today's part, we should get such a code . It is for learning, but complementing it in the future we will get the final source:
disassembled and understandable to everyone!
#include #include #include #include #include #include #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 how to adjust the clocking from quartz for high accuracy, disassembled how to use SPL libraries and how to configure GPIO and use them. We also mentioned the main functions of ala define and incloud, with parsing of their application in real code.
Epilogue
Yeah, the article really strained my head, because Sensei is bad for me, and they asked me to tell in detail about the firmware. I hope it worked out for me and those who are only planning to start studying the programming of microcontrollers will be able to understand me, my descriptions and advice.
It so happened that this part is not the last, there
will be another 4.3 , where we will analyze the remaining periphery and complete the program. , , .
4.3 , .
— , .
—
« 0-60 20». , .
, . !
Part 5
Part 6