51 MCU engineers to jump to stm32 method

What you may have been learning or doing before is a 4-bit or 8-bit microcontroller, such as a 51-class microcontroller. Because 51 is so deeply rooted in people's minds, you can easily get a lot of learning materials about him. In the bookstore, 51 kinds of books and textbooks are even placed on several shelves. The most popular development board on a certain treasure must be 51 development boards, rarely Which embedded engineer or student has avoided 51 and went directly to other platforms. We learned the concept of MCU from 51 and learned the concept of control. But today, 51's low cost, easy to use, is no longer dominant. In contrast, the current application in the field of micro-control, the resource requirements for MCU are getting higher and higher, 51 is getting more and more unsuitable.

The resources of a 51-bit MCU with an 8-bit kernel are often a maximum of K-100K of flash. 100-Kbytes of RAM, IO, serial port, timer, 8-bit data bus, AD and other simple resources. Goal is determined, single. The structure is simple and the instructions are simple. Easy to understand and operate, these characteristics are also factors that can be deeply rooted in people's hearts. It is still the leading experimental platform for colleges and universities. It is also an application platform for many companies.

With the rise of STM32 in the coretex-m3 core in China, it attracted the attention of 51 users. For my understanding when I first entered, I think STM32 is very fast, and flash and ram are big. It can operate the SD card, which is equivalent to the microcontroller's hard disk. Usb function, a thing that has never been seen before 51, can finally communicate with the computer without a serial port. With so many timers, how much PWM control can I do? The 16-bit FSMC bus, which enables high-resolution LCDs, can also be controlled at high speed. No longer, 51 can only use some low-resolution and expensive LCMs such as 12864. Ucos ucgui, which was previously thought of at 51, can be played on STM32. There are a lot of good features, and the controller can easily implement can communication and Ethernet applications that were previously possible to combine circuits. This is the true meaning of the SOC chip in the field of micro-control.

Initially into STM32, perhaps the most intimate is the keil used in 51, at 51 it is called keil c51, in arm it is called RealviewMKD-ARM, referred to as MDK, the current version is MDK4.22, the operation method is basically similar to keil. In addition to editing the project, compiling the code, we also use the download and debug. At 51, there may be very few people using the simulation function, because 51 is simple enough, and the brain is often what you see. Downloading directly to the target board is faster for you. So the most common one at 51 is the downloader. But in the arm phase, the resources are complicated and the registers are complicated. There are so many variables, and without an emulator, you will feel so helpless. Therefore, users of coretex-m3 basically have emulators, which are generally divided into ST-LINK ULINK and JLINK, especially JLINK is most popular in China. The reason we all understand, the cost performance of JLINK V8 is the best of these. So, you need to have a JLINK after you get the MDK. It not only supports STM32, it supports the vast majority of ARM chips.

51 When a user first enters STM32, there is a short process in which platform conversion brings confusion, which is a cognitive difference caused by a large change in device type.

But adjust it, this discomfort will soon pass.

▶▶1 First look at the 51 and STM32 which are the same type of resources. Depending on how familiar you are with 51, you will see it in the STM32 manual. These tend to be simpler and the easiest to understand. Such as IO line control, and so on.

▶▶2 STM32 Advanced resources often require more energy to understand. This can be learned after getting started, such as USB, SDIO, etc.

▶▶4 Different programming methods, such as 51, can be easily controlled by setting or resetting instructions. In STM32, the function of all resources is related to the operation of the 32-bit register group corresponding to the resource. Therefore, for the setting and operation of resources, it is necessary to operate one or more registers. If multiple instructions are used to control, it will cause reading obstacles, and the code maintenance will be complicated in the future. Therefore, ST Company introduced the concept of library functions. Solve the problem of complex resource operations by executing library functions.

▶▶4 The MDK project of the STM32 routine has a similar program structure. Combined with the manual to see the routines, you will quickly form an understanding of the STM32 routine template. Once this understanding is formed, the remaining code details are like The blank fill you predicted.

When you are ready to learn a new platform, then don't hesitate to invest in the embrace of CORETEX-M3. It will make you progress to a new level. Bring you a pleasant technical enjoyment.

How to quickly get started with STM32 microcontroller?

There is a big god on the Internet saying that if you can 51 SCM and C language can get started STM32, only one day, is it really so fast. This depends on the standard of getting started for yourself.

Getting started in my eyes: (provided you have learned 51 microcontrollers and C language)

▶▶1 Know what information to refer to the official to learn, rather than getting caught in a lot of information.

▶▶2 know how to refer to the official manual and the official code to write your own program independently, instead of blindly seeing the code written by others, it feels very good.

▶▶3 Eliminate the fear of STM32 and eliminate the fear of library development. Learning is a happy and fulfilling process.

When you read this article, it will work better with the GPIO chapter of the STM32 Chinese Reference Manual, especially when it comes to register descriptions.

1, 51 and STM32 Introduction

51 is an entry-level classic MCU in embedded learning. Because of its simple structure, easy to teach, and can be programmed through serial port without additional emulator, it is widely used in teaching. So many universities are embedded in it. It is still used in teaching. 51.51 Born in the 1970s, it belongs to the traditional 8-bit single-chip microcomputer. Nowadays, after years of baptism, it has both its brilliance and its shortcomings. Today's market products are highly competitive and extremely cost sensitive, and the requirements for MCUs are more demanding: more features, lower power consumption, easy-to-use interfaces and multitasking. Faced with these demands, 51 existing resources seem to be stretched. Therefore, no matter whether it is college teaching or market demand, a new MCU is urgently needed to inject new vitality into this field.

Based on the needs of this market, ARM introduced its new 32-bit Cortex-M3 microcontroller core based on the ARMv7 architecture. Shortly thereafter, ST (STMicroelectronics) introduced the MCU-STM32 based on the Cortex-M3 core. With its diversified product line, cost-effective, and easy-to-use library development, STM32 quickly became the brightest star in many Cortex-M3 MCUs. As soon as the STM32 went on the market, it quickly occupied the middle and low-end MCU market. It was favored by the market and engineers, and it was quite a spark.

As a qualified embedded engineer, in the face of emerging technologies, we are not deaf to the ears, but to meet the needs of the market as soon as possible, to keep up with the trend of technology. The emergence of STM32 is now a trend, a trend, what we have to do is to catch this fast train and make our technology more competitive.

51 Differences with STM32 architecture

We first popularize a concept, what is inside the microcontroller (ie MCU). The most important thing for a person is the brain, and all parts of the body work under the command of the brain. The MCU is very similar to the human body. Simply put, it is composed of one of the most important cores and other peripherals. The kernel is equivalent to the human brain, and the peripherals are like the various functional organs of the human body.

Let us briefly introduce the structure of the 51 and STM32.

1 51 System Structure

51 System Block Diagram

Figure 1 51 System block diagram

We say 51 generally refers to the 51 series of single-chip microcomputers, there are many models, the common ones are STC89C51, AT89S51, of which the most used in China is STC89C51/2, below we will explain with STC89C51, and with 51 abbreviation.

Kernel

51 consists of an IP core and on-chip peripherals. The IP core is the CPU in the above figure. The on-chip peripherals are as shown in the above figure: clock circuit, SFR and RAM, ROM, timer/counter, parallel I/O port, serial I/O port, interrupt system. The IP core is connected to the peripheral by the system bus and is 8bits with limited speed.

The 51 core was designed by Intel in the 1970s, and the speed is only 12M. The peripherals are added by the IC manufacturer (STC) based on the kernel. Different IC manufacturers will add different peripherals on the core to design Each unique microcontroller. Here intel belongs to the IP core manufacturer, and STC belongs to the IC manufacturer. The same is true for STM32, which we will talk about later. ARM is an IP core vendor, ARM is authorized by ST, and ST has designed an STM32 microcontroller based on the Cortex-M3 core.

Peripheral

When we were learning 51, there were fewer contacts on the kernel, and the most used ones were on-chip peripherals, which we operated while programming.

The registers that are operated during programming are located in the SFR and RAM sections, where the SFR (Special Function Register) occupies 128 bytes (actually only 26 bytes are used, only 26 registers, others belong to the reserved area), and the RAM occupies 128 bits. Bytes, the variables we define in the program are placed in RAM. The SFR and RAM are coincident in address, all in the 80~FF address range, but they are separated in the physical range, so the 51 RAM has 256 bytes.

The programmed program is written to the ROM area. The remaining peripherals are the IO ports we are familiar with, serial ports, timers, and interrupts.

2 STM32 system structure

STM32 system block diagram

Figure 2 STM32 system block diagram

Kernel

In terms of system architecture, STM32 and 51 are both microcontrollers, which are composed of core and on-chip peripherals. Only the Cortex-M3 core used by STM32 is much more complex and superior than 51. It also supports much more peripherals than 51, and the bus width also rises to 32bit, regardless of speed, power consumption, and peripherals.

From the block diagram, there is only one bus for comparing the 51 cores, and the fetch and fetch are shared. There are several bus interfaces inside the Cortex-M3 so that the CM3 can simultaneously address and access (access memory). They are:

Instruction memory bus (two), system bus, private peripheral bus. There are two code memory areas that are responsible for accessing the code memory area (ie, the FLASH peripheral), the I-Code bus and the D-Code bus.

I-Code is used for indexing, and D-Code is used for table lookup operations, which are optimized for optimal execution speed.

The system bus is used to access memory and peripherals. The area covered includes SRAM, on-chip peripherals, off-chip RAM, off-chip expansion devices, and part of the system-level memory area.

The private peripheral bus is responsible for accessing a portion of the private peripherals, primarily accessing the debug components. They are also in system level storage.

There is also an MDA bus. Literally, DMA is the meaning of data memory access. It is a bridge between the kernel and peripherals. It can access peripherals, memory, transfer without CPU control, and is two-way communication. In short, this guy is a data porter who is fast and not controlled by the boss. This is not available in 51.

Peripheral

From the block diagram, STM32 has much more peripherals than 51. There are 51 STM32 peripherals such as serial port, timer, and IO port. STM32 also has a number of special peripherals: FSMC, SDIO, SPI, I2C, etc. These peripherals are mounted on the three buses AHB, APB2, and APB1 according to the speed.

3, summary

Comparing the two aspects of the kernel and peripherals, STM32 is an upgraded version of the microcontroller. It adapts to the market, drains the trend, and shines in the low-end and mid-range microcontrollers.

2, the difference between learning methods

Learn 51 to learn the STM32 library with registers.

When we learn before 51, using a method of programming a register, want to achieve what effect, directly to the registers inside the assignment, the advantage is intuitive, simple and crude, know exactly did what, my heart at ease.

The reason why the direct operation register is feasible at 51, I think there are two reasons:

▶▶1 51 The main frequency is not high, the resources are limited, you must pay attention to the efficiency of program execution, and you can only operate the registers directly. The key places have to be compiled, not suitable for firmware libraries.

We must know that when we were learning 51 microcontrollers, we used assembly, even the current C programming is not, let alone library function programming.

▶▶2 51 The function is simple and there are not many registers. Domestic most widely popular STC89C52 for example, register all add up to less than 30. According to the function distinction, you can read the back of each register, and the function of each bit of the register can be remembered, and it is done at the time of programming.

Nowadays, from the 51 to the STM32 learning, many people still like to follow the 51 learning method. I can't accept the library. When I was learning the library, I was lost in confusion. After a few months of going back and forth, I didn't know if I had learned STM32. Because I was calling the library function in this way, I didn't operate the register at all. The heart is very unreliable. In fact, when you call the library function, there is no doubt in the mind, how is the bottom of the library implemented? Is there no courage to find out the bottom of the library? Finally, when we start tracking the bottom of the library function, we see a bunch of macro definitions, structures, pointers, various file inclusions, and the comments are all in English, is not a jealous.

In view of this, I want to summarize the reasons why many beginners are afraid that the library will not use the library for two reasons.

▶▶1 lack of C language knowledge points

The macro definition used by the library in implementing the register image, the cast, the structure used in defining the register, the pointer used in the peripheral initialization function, and the C language knowledge used in organizing the header file, etc., in the university course It is rarely involved, and most teachers are basically not talking about it. This knowledge is rarely used in some simple 51 microcontroller programming. Learning microcontrollers, doing embedded development, in fact, 80% of the work is related to C language programming, the remaining 20% ​​of the work is to read a variety of data manuals, familiar with a variety of hardware peripherals. So mastering these basic C language knowledge is a hurdle in embedded learning, and the STM32 library gives us a chance to improve C. Anything that can be found in books, I believe that we can basically learn, many beginners are not smart or diligent, just lack of directional guidance. For this lack of knowledge, we can take a little time to master, and the rest is constantly practicing debugging. Here I recommend a C book "C and Pointer" for everyone.

▶▶2 lack of program architecture design ideas

This is more difficult to do, and many people who learn well in C language are more difficult to master. Fortunately, we encountered the STM32 library, which gave us an excellent opportunity to learn and improve the C language. How the entire architecture of the library is built, how the code is written step by step: from the register image, to the encapsulation of the register, and then to the writing of the function, to the driver file corresponding to each peripheral function, which A lot of conditional compilation, the idea of ​​the file, is a nightmare for beginners who have just written a few lines of 51 microcontrollers. However, if you understand the relationship of this series, then you can understand the whole structure of the library, and you don't have to talk about operating the registers in the future.

If you don't like to use the library at first, it is taboo for library development, then ask yourself: Is my C language not good enough? The library is a new way of learning, it is a trend, I see it as another experience and promotion with the C language. Whether you use the library, only you have a shiny look.

3, use the register to light the LED

In order to make a smooth transition to library development, at the beginning of STM32 programming, we will show you how to illuminate an LED with 51. How to use STM32 to illuminate an LED by operating the register, and then slowly explain what is the library, let Everyone knows the relationship between the library and the register.

1 illuminate an LED with 51

Before lighting an LED with STM32, let's review how to illuminate an LED with 51.

On the hardware, we assume that the 0th bit of the P0 port of the 51 MCU is connected to an LED, and the negative logic is on. If we want to light this LED, we will write this on the code:

Here we use the bus operation method, which means that 8 IOs of P0 port operate simultaneously, but only P0^0 is active.

In addition to this bus operation method, we also learn the bitwise operation. Using the 51 compiler's keyword sbit, we can define a bit variable:

Then LED = 0; the LED is lit, LED = 1; the LED is turned off. In order for the program to appear to be known, we define two macros:

The code to illuminate and turn off the LED becomes:

The above bus and bit manipulation methods, friends who have learned 51 are very familiar and easy to understand.

Then let's talk about a few points of knowledge that are easy to ignore.

▶▶ 1 What is a register?

When lighting the LED, we all use the method of operating the register to achieve, then everyone thought about it, what is this register? Why can we operate P0 directly?

Before answering the above questions, let's briefly introduce the main components of the 51 MCU, which is good for us to learn other MCUs.

Taking the domestic STC89C51 as an example, the MCU is mainly composed of 51 cores, peripheral IP, and bus. The kernel is produced by Intel Corporation. The peripheral IP is added by STC based on the kernel, such as timer, serial port, IO port, etc. The bus is the interface unit used to connect the kernel and peripherals. Intel is an IP nuclear design company here, and STC is an IC design company. There are only a handful of companies in the world that can design IP cores. The ARM company we are very familiar with is an IP core design company. ARM licenses other companies. Other IC companies design unique MCUs on the ARM core. The STM32 we will learn later belongs to the MCU based on the ARM core. .

The registers are built into each IP peripheral and are a type of memory used to configure peripheral functions. They are a type of memory and have the address you want to correspond to. Learning C language, we know that to operate these memories, you can use the pointers in the C language to operate these memory-registers with special functions by addressing. For example, if the address corresponding to the P0 port is 0X80, then if we want to modify the content of the memory corresponding to the address 0X80, we can do this according to common sense:

But when we compile, the compiler will report an error. In 51, only the SFR and SBIT keywords can be used to implement the register image. The address corresponding to the register cannot be directly manipulated. This is 51 different from STM32.

51 These registers of MCU are located in addresses 80H~FFH, corresponding to 128 addresses, but not every address is valid. There are 21 single-chip microcomputers of 51 series and 26 of 52 series. Others are reserved areas. .

Figure 3 51 Register Map

▶▶2 register map

In fact, when we are programming, we do not operate the registers by pointers, but directly assign values ​​to the port registers P0 and P1. Then how these peripheral resources establish a one-to-one correspondence with the address (register map definition), which benefits from the two unique keywords of 51: SFR and sbit, other microcontrollers do not, can only use other ways to implement registers Mapping. These two keywords help us to define all the registers, so we can manipulate the registers like one of the normal variables. In fact, the code that lights up the LEDs we mentioned at the beginning should look like this:

For convenience, we can write all the register maps in a header file, instead of defining them once for each register. In fact, this work does not need us to do, we will add a header file at the beginning when programming:

This header file has been implemented to define all the registers, which are included with the keil and can be found in the installation directory: Keil\C51\INC. This file implements the definition of byte registers and bit registers.

▶▶3 startup file—STARTUP.A51

There is also a startup code, this is also a place that many beginners can easily ignore. For this part, we mainly summarize its functions, and explain the code inside.

After the MCU resets, the first execution is the startup file - STARTUP.A51, instead of the main function we usually see. When we create a new 51 project, there will be a prompt: whether to copy the startup code to the current project, we generally choose Yes.

Figure 4 Whether to add the startup code

The startup code is written in assembly language and mainly implements the following functions: clear internal data memory, clear external data memory, clear external page memory, initialize re-stack and pointer in small mode, initialize re-stack in large mode, and Pointers, initialize restacks and pointers in compact mode, initialize 8051 hardware stack pointers, pass control commands that initialize global variables, or pass commands to the main function when global variables are not initialized. Then the program jumps to the main function and comes to the familiar C world.

▶▶4 summary

When explaining the use of 51 to illuminate the LED, we added what is the contents of the register, register mapping, and startup code. These three parts were originally explained in STM32, but considering that everyone already has the basis of 51. And I am familiar with 51, then I will add some content, everyone is naturally not so resistant, and can practice according to the above, and learn more deeply. Then when I explain these things in STM32, everyone will compare and learn, and there is no such jealousness for STM32.

2 Light up an LED with STM32

In contrast to the 51 way to illuminate the LED, we first use the STM32 to illuminate an LED, and then step through the code to build the simplest library function, let us know how the library is built.

Before we write the code, let's build a project. It should be noted that although 51 and STM32 are both keil, the MCU is different. The software should be installed in different directories during installation and cannot be installed in the English directory, otherwise it will conflict. We are using keil5, MDK5.15 version here.

▶▶1 New construction

Create a new project with KEIL5, put the project in a pre-built folder, and save the project named REG. Then add the startup file in the project directory: startup_stm32f10x_hd.s, which can be found from the KEIL5 installation directory, or from the ST library, and then add the startup file to the project.

▶▶2 startup file—startup_stm32f10x_hd.s

The startup file is written in assembly language, and the specific function is similar to the startup file in 51: STARTUP.A51.

The startup file of STM32 is mainly implemented:

1. Set the initial SP.

2, set the initial PC = Reset_Handler

3. Set the vector table entry address and initialize the vector table.

4. Call the library function SystemInit to configure the system clock to 72M. SystemInit is defined in the library file system_stm32f10.c.

5. Jump to the label _mian and finally come to the world of C. Here we first remove the details of the branches, focus on the main points, mainly understand the fourth and fifth points, in the 147~155 lines of the startup file, is the reset processing function, the code is as follows:

Here we briefly introduce the 10 lines of code.

The first line is the program comment, and the comment in the assembly is ";", which is different from the C language.

The second line defines a subroutine: Reset_Handler. PROC is a subroutine definition directive. The general usage is:

Where NEAR and FAR are attribute words. NEAR attribute (near in the segment): The calling program and subroutine are in the same code segment and can only be called by other programs in the same code segment. FAR attribute (distance between segments): The calling program and the subprogram are not in the same code segment and can be called by programs of the same or different code segments.

The third line EXPORT indicates that the subroutine Reset_Handler can be called by other modules.

The keyword [WEAK] indicates a weak definition. If the compiler finds a function with the same name defined elsewhere, it will link with the address elsewhere when linking. If the definition is not defined elsewhere, the compiler will not report an error. .

The fourth and fifth lines IMPORT indicate that the two labels SystemInit and __main are in other files, and you need to go to other files to find them when linking.

SystemInit is implemented in the library file system_stm32f10x.c to initialize a series of clocks for STM32 and set the system clock to 72 MHz. The STM32's clock is more complex than the 51 MCU and requires a series of configurations to achieve stable operation.

__main is not actually defined by us. When the compiler compiles, this function is defined whenever the label is encountered. The main function of the function is: responsible for initializing the stack, heap, configuring the system environment, and jumping to user-defined at the end. The main function has since come to the world of C.

The sixth line loads the address of SystemInit into register R0.

The seventh line of the program jumps to the address execution program in R0, after which the system clock is set to 72 MHz.

The eighth line loads the address of _main into register R0.

The ninth line of the program jumps to the address execution program in R0. After the execution, it goes to the well-known C world.

The tenth line indicates the end of the subroutine.

To sum up, the Reset_Handler function performs two function calls, one is SystemInit, sets the system clock to 72M, makes one __main, initializes the system environment, and finally calls the main of C, and then goes to the world of C.

When we light the LED, the easiest way is to use the internal LSI clock (8MHZ) as the master clock, without using the external clock LSE.

The __main function is generated by the compiler and is responsible for initializing the stack, heap, etc., and finally jumps to the user-defined main() function to the world of C.

▶▶3New main.c

Use Notepad to create a new main.c file and put it in the project directory, then add main.c to the project.

Now we can start writing the program. Let's write a main function, there is no such thing, it is empty. This is not very similar to writing a 51 program.

Now we can compile and see if there is a flaw.

At this time, the following error occurred:

The error message says that SystemInit is not defined. From the analysis of the startup file, we know that Reset_Handler calls this function to initialize the system clock, and the function is implemented in the library file system_stm32f10x.c. We can rewrite a function like this, and implement the function completely, but for the sake of simplicity, we define a SystemInit empty function in the main file, in order to fool the compiler and remove this error. We will write simple code later on configuring the system clock.

At this time, we have no mistakes to compile again, and it is perfectly solved. Another way to do this is to comment out the code for SystemInit in the startup file. The code looks like this:

▶▶4 control IO port

Below we explain the difference between STM32's IO and 51 when controlling LEDs. For the description of the registers of the STM32 IO, we can see the eighth chapter of the STM32 Chinese Reference Manual. The IO registers mentioned below are from the second subsection of this chapter: 8.2 GPIO Register Description

Level control

If the IO port of the MCU is to output 1 and 0, it can be directly assigned without controlling other registers.

The STM32 IO port is more complicated. If you want to output 1 and 0, you need to control it by the port output data register ODR. The ODR is: short for the output data register. In STM32, the named names of the registers are in English. Shorthand, it's easy to remember. From the manual we know that the ODR is a 32-bit register, the lower 16 bits are valid, and the upper 16 bits are reserved. The lower 16 bits correspond to IO0~IO16, and you can output low or high level by writing 0 or 1 to the corresponding position.

PB0 output low level, the code is as follows:

At this time, we will find that there is an error saying that GPIOB_ODR is not defined, but we do not define it. In the 51 MCU, we can assign the value directly to the P0 port. That is because the image of the P0 port register is implemented in the reg51.h header file, which is defined by the 51 unique keyword SFR.

STM32 is not the same as 51. There is no SFR. The register image can only be implemented in other ways. Because the register is actually a memory with special functions, we can implement the register image through the macro definition. In fact, this method is also used in the ST library function.

From the manual we see that the address offset of the ODR register is: 0CH, which is based on the start address of the port. In STM32, each peripheral has a starting address called the peripheral base address. The peripheral registers are arranged in this order based on the base address, which is similar to the members in the structure.

The base address of all peripherals can be found in the 2.3: Memory Image section of Chapter 2: Memory and Bus Architecture in the manual, as follows:

Figure 5 STM32 Register Group Start Address

The starting address of the GPIOB is: 0X4001 0C00, so that the address of the GPIOB_ODR register can be calculated as: 0X4001 0C00 + 0X0C = 0X4001 0C0C. Now we can define the GPIOB_ODR register, the code is as follows:

With this register definition, we can directly operate GPIOB_ODR.

Direction control

Although the ODR register is configured, the LED cannot be lit at this time because the STM32's IO port is also configured with direction, which is controlled by the port configuration register. The port configuration register is divided into two high and low, one IO port is controlled every 4 bits, so the port configuration low register: CRL controls the lower 8 bits of this IO port, and the port configuration high register: CRH controls the upper 8 bits of this IO port. Among the 4-bit control bits, CNFy[1:0] is used to control the input and output of the port, and MODEy[1:0] is used to control the rate of the output mode, that is, the speed at which the IO level is inverted when outputting.

The input has three modes, the output has 4 modes, and we select the universal push-pull output when controlling the LED.

There are three modes of output rate: 2M, 10M, 50M, here we choose 2M.

Like GPIOB_ODR, we can also calculate the address of GPIO_CRL: 0x40010C00. Then set PB0 to the general push-pull output, and the output rate is 2M. The code is as follows:

Clock control

When we set the direction of the IO port and input the value in the corresponding output register, we think that the LED can now be lit, but it is still the last step.

There are many STM32 peripherals. In order to reduce power consumption, each peripheral corresponds to a clock. These clocks are turned off during system reset. If you want the peripheral to work, you must turn on the corresponding clock.

The clocks for all peripherals of the STM32 are managed by a dedicated peripheral called RCC (reset and clockcontrol), which is in Chapter 6 of the STM32 Chinese Reference Manual.

The peripherals of STM32 are respectively mounted on three main systems because of different speeds: AHB, APB2, APB1, APB is the high-speed bus, APB2 is the second, and APB1 is again. Therefore, the IO ports are mounted on the APB2 bus and belong to high-speed peripherals. The clock is controlled by the APB2 Peripheral Clock Enable Register (RCC_APB2ENR), where the clock to the PB port is enabled by a '1' on Bit 3 of this register.

With ODR and CRL, we can calculate the address of RCC_APB2ENR: 0x40021018. Then enable the clock code of the PB port as follows:

If you are careful enough, you will find that although we have opened the port clock, how big is this clock? Where did the clock come from?

If we are using a library, then there is a library function SystemInit that will help us set the system clock to 72M. Now that we are not using the library, what is the clock now? The answer is 8M. When the external HSE is not turned on or fails, the system clock is provided by the internal low-speed clock LSI. Now we do not turn on the HSE, so the default clock of the system is LSI=8M. For more in-depth details, we will analyze it in detail later in the RCC clock tree. If you want to try it yourself, look at the RCC peripherals: the clock control register (RCC_CR) and the clock configuration register (RCC_CFGR).

Water

Controlled the level, configured the direction, turned on the clock, after these three steps, we can finally control an LED. Compared to the 51 direct output level, there are two more steps to control the IO of the STM32: the configuration direction turns the clock on. Compared to the AVR and PIC, there are more steps to turn on the clock.

Now we have a complete code to control an LED with STM32:

Many people say that learning STM32 is difficult, a bunch of registers, I don't know how to operate, especially those who have just finished 51, I don't know how to overdo it. Here we compare the programming method of 51, and write a simple way to illuminate the LED with the STM32 register, hoping to play a role in attracting jade.

4, make persistent efforts - the prototype of the building library

Learning STM32 has a controversial point of using registers or libraries, just as programming is better with assembly or with C. In fact, the market is self-determined and the user group explains everything.

Although we have lit the LEDs with registers, it looks like the code is very simple, but we don't have to be lucky to use register development in the future.在用寄存器点亮LED 的时候,我们是否发现STM32 的寄存器都是32 位的,在配置的时候非常容易出错,而且代码还很不好理解。所以学习TM32 最好的方法是用库,然后在库的基础上了解底层,看遍所有寄存器。

但是很多人对库还是很忌惮,因为一开始用库的时候有很多代码,很多文件,不知道如何入手。不知道你是否认同这么一句话:一切的恐惧都来源于认知的空缺。我们对库忌惮那是因为我们不知道什么是库,不知道库是怎么实现的。

接下来,我们在寄存器点亮LED 的代码上继续完善,把代码一层层封装,实现库的最初的雏形,相信经过这一步的学习后,你会对库的运用做到游刃有余。这里我们只讲关于GPIO 库,其他外设的我们直接参考库学习即可,不必自己写。

1 定义外设寄存器结构体

上面我们在操作寄存器的时候,操作的是寄存器的绝对地址,如果每个寄存器都这样操作,那将非常麻烦。

我们考虑到外设寄存器的地址都是基于外设基地址的偏移地址,都是在外设基地址上逐个连续递增的,每个寄存器占32 个或者16 个字节,这种方式跟结构体里面的成员类似。所以我们可以定义一种外设结构体,结构体的地址等于外设的基地址,结构体的成员等于寄存器,成员的排列顺序跟寄存器的顺序一样。这样我们操作寄存器的时候就不用每次都找到绝对地址,只要知道外设的基地址就可以操作外设的全部寄存器,即操作结构体的成员即可。

下面我们先定义一个GPIO 寄存器结构体,结构体里面的成员是GPIO 的寄存器,成员的顺序按照寄存器的偏移地址从低到高排列,成员类型跟寄存器类型一样。

在《STM32 中文参考手册》8.2 寄存器描述章节,我们可以找到结构体里面的7 个寄存器描述。在点亮LED 的时候我们只用了CRL 和ODR 这两个寄存器,至于其他寄存器的功能大家可以自行看手册了解。

在GPIO 结构体里面我们用了两个数据类型,一个是uint32_t,表示无符号的32 位整型,因为GPIO 的寄存器都是32 位的。这个类型声明在标准头文件stdint.h 里面,我们在程序上只要包含这个头文件即可。

另外一个是__IO,这个是我们自己定义的,原型是volatile,作用就是告诉编译器不要因优化而省略此指令,必须每次都直接读写其值,这样就能确保每次读或者写寄存器都真正执行到位。

关于这两个数据类型,我们添加如下代码:

2 外设声明

现在GPIO 寄存器结构体已经定义好了,STM32F1 系列的GPIO 端口分A~G,即GPIOA、GPIOB。 . . . . . GPIOG。每个端口都含有GPIO_TypeDef 结构体里面的寄存器,我们可以根据各个端口的基地址把GPIO 的各个端口定义成一个GPIO_TypeDef 类型的指针,然后我们就可以根据端口名(实际上现在是结构体指针了)来操作各个端口的寄存器,码实现如下:

对于其他外设我们也可以这样把外设的名字定义成一个外设寄存器结构体类型的指针,这里我们只讲GPIO。

对于每个GPIO 的基地址我们可以从《STM32 中文参考手册》2.3 小节:存储器映像中找到,如下所示:

图6 APB2 总线外设寄存器起始地址

3 外设内存映射

讲到基地址的时候我们再引人一个知识点:Cortex-M3 存储器系统,这个知识点在《Cortex-M3 权威指南》第5 章里面讲到。CM3 的地址空间是4GB,如下图所示:

图7 CM3 内存映射

我们这里要讲的是片上外设,就是我们所说的寄存器的根据地,其大小总共有512MB,512MB 是其极限空间,并不是每个单片机都用得完,实际上各个MCU 厂商都只是用了一部分而已。STM32F1 系列用到了:0x4000 0000 ~0x5003 FFFF。

▶▶1 APB1、APB2、AHB 总线基地址

现在我们说的STM32 的寄存器就是位于这个区域,这里面ST 设计了三条总线:AHB、APB2 和APB1,其中AHB 和APB2 是高速总线,APB1 是低速总线。不同的外设根据速度不同分别挂载到这三条总线上。从下往上依次是:APB1、APB2、AHB,每个总线对应的地址分别是:APB1:0x40000000,APB2:0x4001 0000,AHB:0x4001 8000。

这三条总线的基地址我们是从《STM32 中文参考手册》2.3 小节—存储器映像得到的:APB1 的基地址是TIM2 定时器的起始地址,APB2 的基地址是AFIO 的起始地址,AHB 的基地址是SDIO 的起始地址。

其中APB1 地址又叫做外设基地址,是所有外设的基地址,叫做PERIPH_BASE。

现在我们把这三条总线地址用宏定义出来,以后我们在定义其他外设基地址的时候,只需要在这三条总线的基址上加上偏移地址即可,代码如下:

▶▶2 GPIO 端口基地址

因为GPIO 挂载到APB2 总线上,那么现在我们就可以根据APB2 的基址算出各个GPIO 端口的基地址,用宏定义实现代码如下:

现在我们把上面的代码稍微整理下,如下:

在点亮LED 的时候,我们还开了GPIO 的时钟,用到了RCC 这个外设,现在我们也定义一个RCC 寄存器结构体,加上那些地址定义,总体代码如下:

跟GPIO 不同的是,RCC 这个外设是挂载到AHB 总线上。

现在我们点亮LED 的函数就变成了

对比之前的代码

一个用的是结构体,一个用的是宏,仅仅从这三行代码看不出有啥区别,但是如果要操作其他寄存器的时候,用结构体就可以直接操作,用宏就还要一个个找到寄存器的绝对地址重新定义。

比如我们要操作GPIOB 的BSRR(bit reset register)的时候,用结构体时我们就可以这样操作:

这时候PB0 就输出低电平,LED 被点亮。注意:BRR 低16 位有效,只能以字的形式操作,功能是复位相应的IO 口,写1 清0,写0 没有影响。

图8 GPIO 端口位清除寄存器

现在我们再整理下代码,如下所示:

4 小结流程

现在我们来总结下上面代码实现的过程,这个过程也是我们从零开始点亮LED 的过程,代码全部由我们自己编写(除了启动代码),每一行都有根有据,都可以从《STM32中文参考手册》查到。

①、定义一个外设(GPIO)寄存器结构体,结构体的成员包含该外设的所有寄存器,成员的排列顺序跟寄存器偏移地址一样,成员的数据类型跟寄存器的一样。

②外设内存映射,即把地址跟外设建立起一一对应的关系。51 单片机中用SFR 实现,STM32 中用宏定义实现。

③外设声明,即把外设的名字定义成一个外设寄存器结构体类型的指针。

④操作寄存器,实现点亮LED。

5 新建头文件stm32f10x.h

为了使代码看起来不那么臃肿,我们这里引入文件的概念,让不同功能的代码放在不同的文件里面。在main.c 里面我们只保留main 函数和一些头文件,把其他的宏定义放到一个单独的文件。

新建一个stm32f10x.h,跟寄存器相关的代码都放在这里,主要是寄存器映像,跟51单片机里面的reg51.h 这个头文件差不多。然后我们在main.c 里面包含这个头文件即可,现在我们的主函数就变成这样:

6 新建tm32f10x_gpio.h

上面我们在控制GPIO 输出内容的时候控制的是ODR(Output data register)寄存器,ODR 是一个16 位的寄存器,必须以字的形式控制,相当于51 里面的总线操作。

其实我们还可以控制BSRR 和BRR 这两个寄存器来控制IO 的电平,下面我们简单介绍下BRR 寄存器的功能,BSRR 自行看手册研究。

BRR:bit reset register

图9 GPIO 端口位清除寄存器

位清除寄存器BRR 只能实现位清0 操作,是一个32 位寄存器,低16 位有效,写0 没影响,写1 清0。

现在我们要使PB0 输出低电平,点亮LED,则只要往BRR 的BR0 位写1 即可,其他位为0,代码如下:

这时PB0 就输出了低电平,LED 就被点亮了。

如果要PB2 输出低电平,则是:

如果要PB3/4/5/6。 . . . . .这些IO 输出低电平呢?道理是一样的,只要往BRR 的相应位置赋不同的值即可。因为BRR 是一个16 位的寄存器,位数比较多,赋值的时候容易出错,而且从赋值的16 进制数字我们很难清楚的知道控制的是哪个IO。这时,我们是否可以把BRR 的每个位置1 都用宏定义来实现,如GPIO_Pin_0 就表示0X0001,GPIO_Pin_2 就表示0X0004。只要我们定义一次,以后都可以使用,而且还见名知意。

GPIO_pins_define 代码如下:

这时PB0 就输出了低电平的代码就变成了:

为了不使main 函数看起来冗余,GPIO_pins_define 的代码不应该放在main 里面,因为其是跟GPIO 相关的,我们可以把这些宏放在一个单独的头文件里面。

在工程目录下新建stm32f10x_gpio.h,把GPIO_pins_define 代码放里面,然后把这个文件添加到工程里面。这时我们只需要在main.c 里面包含这个头文件即可。

7 新建stm32f10x_gpio.c

我们点亮LED 的时候,控制的是PB0 这个IO,如果LED 接到的是其他IO,我们就需要把GPIOB 修改成其他的端口,其实这样修改起来也很快很方便。但是为了提高程序的可读性和可移植性,我们是否可以编写一个专门的函数用来复位GPIO 的某个位,这个函数有两个形参,一个是GPIOX(X=A...G),另外一个是GPIO_Pin(0...15),函数的主体则是根据形参GPIOX 和GPIO_Pin 来控制BRR 寄存器,代码如下:

这时,PB0 输出低电平,点亮LED 的代码就变成了:

同样,因为这个函数是控制GPIO 的函数,我们可以新建一个专门的文件来放跟gpio有关的函数。

在工程目录下新建stm32f10x_gpio.c,把GPIO 相关的函数放里面。

这时我们是否发现刚刚新建了一个头文件stm32f10x_gpio.h,这两个文件存放的都是跟外设GPIO 相关的。C 文件里面的函数会用到h 头文件里面的定义,这两个文件是相辅相成的,故我们在stm32f10x_gpio.c 文件中也包含stm32f10x_gpio.h 这个头文件。别忘了把stm32f10x.h 这个头文件也包含进去,因为有关寄存器的所有定义都在这个头文件里面。

如果我们写其他外设的函数,我们也应该跟GPIO 一样,新建两个文件专门来存函数,比如RCC 这个外设我们可以新建stm32f10x_rcc.c 和stm32f10x_rcc.h。其他外依葫芦画瓢即可。

stm32f10x_gpio.c 文件代码如下:

我们还要记得把void GPIO_ResetBits()在stm32f10x_gpio.h 里面声明下,这样其他文件只要包含stm32f10x_gpio.h 这个头文件就可以使用GPIO_ResetBits()这个函数了。以后不论新增加了什么函数都应该在自己的头文件下声明,这是个C 语言的常识问题。

点亮LED 会了,那关闭LED 怎么办,我们可以控制BSRR 这个寄存器来实现,这里我就直接写代码了:

先写一个GPIO 端口置位函数,放到stm32f10x_gpio.c 文件中,同样在 stm32f10x_gpio.h 头文件声明。

PB0 输出高电平,关闭LED,代码如下:

Dynamometer

Dynojet Dyno,Dynamometer For Sale,Dyno Motor,Dyno Machine

GALOCE (XI'AN) M&C TECHNOLOGY CO., LTD. , https://www.galoce-meas.com