目录

1.  STM32是什么

2.  STM32芯片分类

3.  命名规则

4.  最小系统

4.1  复位电路

4.2  BOOT启动电路

4.3  晶振电路

4.4  下载调试电路

5.  C语言基础知识复习

5.1  stdint.h简介

5.2  位操作

5.3  宏定义

5.4  条件编译

5.4.1  头文件的条件编译

5.4.2  代码条件编译

5.5  extern声明

5.6  类型别名(typedef)

5.7  const 关键字

5.8  volatile 关键字

6.  单片机的程序在哪里存储

7.  BIN 文件和 HEX 文件的区别


1.  STM32是什么

ST:表示意法半导体

M:表示MCU/MPU

32:表示32位

ST累计推出了:5大类、18个系列、1000多个型号的Cortex内核微控制器

2.  STM32芯片分类

ST中文社区网:意法半导体STM32/STM8技术社区 - 提供最新的ST资讯和技术交流

ST官网:st.com/content/st_com/en.html

相关分类: 

3.  命名规则

4.  最小系统

        保证MCU正常工作的最小电路组成单元。

4.1  复位电路

        STM32复位引脚NRST保持低电平状态时间1~4.5ms即可复位

4.2  BOOT启动电路

        STM32 的 Boot 电路是决定芯片启动模式的核心外围电路,通过配置 BOOT0、BOOT1(部分型号仅 BOOT0)引脚的电平,选择芯片复位后从不同存储区域加载程序,是 STM32 开发和量产中必须掌握的基础电路。

BOOT0 BOOT1(F1)/ nBOOT1(F4) 启动模式 适用场景
0 X(无关) 主闪存存储器(Flash) 正常运行(量产默认)
1 0 系统存储器(System Flash) ISP 下载(串口 / USB 烧录程序)
1 1 内置 SRAM 调试 / 临时程序运行(掉电丢失)

4.3  晶振电路

        STM32 的晶振电路是芯片时钟系统的核心,决定了芯片的运行主频、外设时序稳定性,分为高速外部晶振(HSE) 和低速外部晶振(LSE) 两类:

类型 频率范围 核心作用 适用场景
HSE 4~26MHz(常用 8/12/16/25MHz) 作为系统主时钟源,分频 / 倍频后驱动 CPU 和外设 正常运行(量产 / 开发)
LSE 32.768kHz 驱动 RTC 实时时钟、待机模式时钟 需要精准计时、低功耗待机

4.4  下载调试电路

5.  C语言基础知识复习

5.1  stdint.h简介

        stdint.h 是从 C99 中引进的一个标准 C 库的文件

        路径:D:\MDK5.34\ARM\ARMCC\include

        配置MDK支持C99:

5.2  位操作

运算符

含义

运算符

含义

&

按位与

~

按位取反

|

按位或

<<

左移

^

按位异或

>>

右移

按位与 结果
0 & 0 0
1 & 0 0
0 & 1 0
1 & 1 1
按位或 结果
0 | 0 0
1 | 0 1
0 | 1 1
1 | 1 1
按位异或 结果
0 ^ 0 0
1 ^ 0 1
0 ^ 1 1
1 ^ 1 0
按位取反 结果
~ 11100100 00011011
左移 结果
11100100 << 2 10010000
右移 结果
11100100 >> 2 00111001

如何给寄存器某个位赋值?

举个例子:uint32_t temp = 0; 

假如给第六位赋值1:

方法一:

temp &= 0xFFFFFFBF;
temp |= 0x00000040;

方法二:

temp &= ~(1<<6);                  
temp |= 1<<6;

5.3  宏定义

        宏定义可以:提高效率、可读性、易改性,核心是替换

#define   标识符   字符串

        标识符:宏定义的名字

        字符串:常数、表达式、格式串等

#define     PI           3.14159
#define     HSE_VALUE    8000000U 

带参数的宏定义:

#define LED1(x)   do{  x ? \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_SET) : \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_RESET); \
                  }while(0)

        建议大家使用  do{ ... }while(0) 来 构造宏定义。

        这样不会受到大括号、分号、运算符优先级等的影响,总是会按你期望的方式调用运行。

5.4  条件编译

        让编译器只对满足条件的代码进行编译,不满足条件的不参与编译!

指令

作用

#if

编译预处理条件指令,类似if

#ifdef

判断某个宏是否已被定义

#ifndef

判断某个宏是否未被定义

#elif

若前面的条件不满足,则判定新的条件,类似else if

#else

若前面的条件不满足,则执行后面的语句,类似else

#endif

#if#ifdef#ifndef的结束标志

5.4.1  头文件的条件编译

#ifndef 	_LED_H
#define 	_LED_H
#include "./SYSTEM/sys/sys.h"
code
#endif

5.4.2  代码条件编译

#if   SYS_SUPPORT_OS
       code
#endif

5.5  extern声明

        放在函数/变量前,表示此函数/变量在其他文件定义,以便本文件引用

extern uint16_t g_usart_rx_sta;
extern void delay_us(uint32_t nus);

5.6  类型别名(typedef)

        为现有数据类型创建一个新的名字,或称为类型别名,用来简化变量的定义:

typedef   现有类型   新名字

例如: 

typedef   unsigned  char 			uint8_t;
typedef   unsigned  short  int 		uint16_t;
typedef   unsigned  int 			uint32_t;

类型别名应用:

Struct GPIO_TypeDef
{
     __IO uint32_t   CRL;
     __IO uint32_t   CRH;
     …
};
Struct    GPIO_TypeDef    gpiox
typedef struct
{
     __IO uint32_t   CRL;
     __IO uint32_t   CRH;
     …
} GPIO_TypeDef;
GPIO_TypeDef    gpiox

5.7  const 关键字

        在 C 和 C++ 中,const 是一个关键字,用来声明常量或指示某个值不能被修改。通过使用 const,程序员可以确保某个变量、指针或函数的参数在某些条件下不可被修改,从而增强程序的安全性和可维护性。与volatile合称“cv特性”,指定变量不可被当前线程/进程改变,当 const 用于声明变量时,表示该变量的值是只读的,不能在程序中被修改:

#include <stdio.h>
 
int main() 
{
    const int num = 10;
    
    num = 20; // 错误:无法修改const变量
    
    printf("num: %d\n", num);
    return 0;
}
 

5.8  volatile 关键字

        当一个变量声明为 volatile 时,编译器会告诉编译器不要对该变量进行优化。编译器会确保每次访问该变量时,都会从内存中读取其最新的值,而不是从寄存器或缓存中读取:

#include <iostream>
 
volatile int counter = 0;  // 变量可能被中断服务程序修改
 
void interrupt_handler() {
    // 假设这是一个中断处理程序
    counter++;  // 中断发生时增加计数
}
 
int main() {
    while (counter < 5) {
        // 主程序中,计数器的变化不能被优化掉
        std::cout << "Counter: " << counter << std::endl;
    }
    return 0;
}

6.  单片机的程序在哪里存储

        我们首先来了解一张图片:

其中:

  • Code:为程序代码部分。
  • Ro-data:表示程序定义的常量(const 修饰的常量、#define 宏定义等)。
  • Rw-data:表示已初始化的全局变量。
  • Zi-data:表示未初始化的全局变量(Zi-data 可以表示 RAM 未上电时整个区域的状态,或者上电初始化之后未被使用的区域,上表仅仅描述的是 ROM 区域的空间分布)。

        而栈区(stack)、堆区(heap)、全局区(静态区)(static)、文字常量区和程序代码区和上面所介绍的 Code、Ro-data 等的关系。

  • 栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。这些值是可读写的,那么 stack 应该被包含在 RW-data(读写数据存储区),也就是单片机的 SRAM 中。
  • 堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由 OS 回收。可以理解,这些也是被包含在单片机的 SRAM 中的。
  • 全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统释放。这些数据也是可读可写的,和 stack、heap 一样,被包含在 RAM 中。
  • 文字常量区:常量字符串就是放在这里的。这些数据是只读的,分配在 Ro-data(只读数据存储区),则被包含在 flash 中。
  • 程序代码区:存放函数体的二进制代码,可以想象也是被包含在 flash,因为对于 MCU 来说,当其重新上电,代码还会继续运行,并不会消失,所以存储在 flash 中。

        在初始化之前,RAM 里面所有区域都是随机的值,运行时的单片机程序在 RAM 内的分布:

        初始化的时候会由 Boot 程序(进入 main 函数之前)拷贝 Flash 里面的 Rw-data 区域到 RAM:

        初始化之后 Flash 的 Rw-data 就不会再使用了,除非重新上电、复位了 boot 才会重新从 ROM(Flash)中拷贝 Rw-data 区域到 RAM 中去,运行时,根据上一节对哈佛模型的描述(51 内核、Cortex-M3、Cortex-M4 是哈佛模型),程序存储区对应 ROM(Flash)数据存储区对应 RAM,如此这般两个区域就是物理上的分开的–经典的哈佛模型:

7.  BIN 文件和 HEX 文件的区别

  • Bin 文件是存放在 Flash 上的文件。
  • HEX 文件,需要将 Bin 文件转为 Hex 文件是一种文件中有地址的文件,其目的是便于单片机烧录工具按照文件中地址进行烧录。

运行时:单片机程序运行起来以后,代码是在 ROM(Nor Flash)上面跑的,数据是在 RAM 上面的,描述的就是 ROM 和 RAM 两个层面。

非运行时:单片机程序没有运行时(没有上电),针对的描述是单片机程序(bin)文件在 ROM(Flash)上的分布。

注意,如果使用 Flash 读取工具从单片机的 Flash 上完整读出来的文件可能是 bin 文件但绝对不是 hex 文件!

千题千解·嵌入式工程师八股文详解_时光の尘的博客-CSDN博客

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐