嵌入式面试八股文(十八)·初识STM32芯片

目录
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 文件!


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



所有评论(0)