基础知识回顾

 

 

 

 

 

 

 

 

 

 

一、GPIO(General Purpose Input/Output)通用输入输出

✅ GPIO 输出(Output)

  • 指 MCU 控制引脚电平输出:高电平(如 3.3V)或低电平(0V)。

  • 常用于:

    • 控制 LED 灯亮灭

    • 驱动继电器

    • 控制蜂鸣器

    • 控制电机(结合驱动芯片)

STM32 中设置:

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出

✅ GPIO 输入(Input)

  • 指 MCU 检测外部电平的状态。

  • 常用于:

    • 读取按键是否按下(高/低电平)

    • 接收传感器信号(如红外模块的检测输出)

  • STM32 中设置:

  • GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 悬空输入
    

    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//悬空输入
     

二、DO(Digital Output)数字输出

  • “DO” 是某些模块或传感器手册里的术语,意思是“数字输出”。

  • 一般模块提供 DO 引脚,输出的是 数字信号(高/低电平),适合连接到 MCU 的 GPIO 输入引脚读取。

✅ 举例:

  • 红外避障模块:

    • 检测到障碍 → DO 输出低电平

    • 没检测到 → DO 输出高电平

  • 你可以这样读取:

  • if(GPIO_ReadInputDataBit(GPIO,GPIO_Pin_1)==0)
    {
        //有障碍
    }

 三、AO(Analog Output)模拟输出

  • “AO” 表示“模拟信号输出”,输出是连续电压,不是只有高低电平。

  • 需要 MCU 具备**ADC(模拟转数字)**功能来读取。

✅ 举例:

  • 光敏电阻模块(带 AO 引脚):

    • 白天电压高,晚上电压低

  • STM32 读取方式是 ADC:

  • u16 val = ADC_GetConversionValue(ADC1);//获取模拟值(0~4095)

 ✅ 总结对比表

项目 名称全称 电平类型 接入 MCU 的方式 典型用途
GPIO Output 通用输出 数字(高/低) MCU 控制输出 控制 LED、继电器、电机等
GPIO Input 通用输入 数字(高/低) MCU 读取输入 按键检测、开关检测
DO 数字输出 数字(高/低) MCU 用 GPIO 输入读取 红外、烟雾、震动检测模块等
AO 模拟输出 模拟电压(如 0~3.3V) MCU 用 ADC 通道采集 温度、光强、气体浓度类传感器

STM32指针 

✅ 1. 什么是“指针”?

指针就是保存变量地址的变量。

在 STM32 中,地址代表着 寄存器、IO口、外设控制单元 —— 所以用指针就能直接操作硬件本体

✅ 2. 为什么 STM32 中广泛使用指针?

原因 说明
操作寄存器 STM32 寄存器(如 GPIOA->ODR)本质是“固定地址”,必须通过指针操作
高效率 访问内存、传递数据更快、更节省资源
访问外设 ADC、USART、TIM 等外设驱动库,大量使用结构体指针指向外设基地址
内存操作 在 FreeRTOS 动态内存分配、DMA 传输、缓冲区管理中频繁使用指针

✅ 3. STM32 中常见指针使用案例

 🎯 示例1:GPIO 寄存器地址操作(裸机常见)

#define LED1 (*(volatile unsigned int *)0x4001080C)
// 解释:强制将地址0x4001080C(GPIOC ODR)转换为指向 unsigned int 的指针,并取值

LED1 = 0x00000020; // 设置 PC5 输出高电平

🎯 示例2:结构体指针操作寄存器(STM32官方库用法)

GPIOA->ODR |= (1 << 5); // 置高 PA5(点亮 LED)

GPIOAGPIO_TypeDef 类型的结构体指针,预定义在 stm32f10x.h 中,内部封装了 GPIO 的所有寄存器地址。

🎯 示例3:函数传递指针(高效传参)

void send_data(uint8_t* buffer, uint16_t len) {
    while (len--) {
        USART_SendData(USART1, *buffer++);
    }
}

传递数组时用指针效率更高,适用于 DMA、UART、SPI 数据发送等。

🎯 示例4:动态内存分配与指针(高级用法)

uint8_t* data = (uint8_t*)malloc(100); // 分配100字节空间

✅ 4. STM32 中常用指针类型总结

类型 作用 示例
uint8_t * 指向字节型数据(8位) 串口接收缓冲区指针
uint16_t * 指向半字型数据(16位) ADC结果数组
volatile uint32_t * 指向 32位寄存器,防止编译优化 寄存器直接操作
结构体指针 操作外设寄存器组 GPIOA->CRL, TIM2->CNT

 ✅ 5. 指针关键概念提醒

概念 说明
* 解引用 取出指针所指地址的内容(如 *ptr = 1
& 取地址 得到变量的地址(如 &a
-> 结构体指针访问成员 GPIOA->ODR,等价于 (*GPIOA).ODR
const 指针不可改值或地址,如 const uint8_t*uint8_t* const
volatile 禁止编译器优化,一定要加在寄存器操作中

 ✅ 6. STM32指针+结构体:寄存器访问的底层原理

以 GPIO 为例:

#define GPIOA_BASE (0x40010800UL)
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
  • GPIO_TypeDef 是结构体,包含 CRL, CRH, IDR, ODR 等寄存器

  • 这句宏就是将 GPIOA_BASE 强制转换为指针并访问内部成员

✅ 7. 指针错误常见场景

错误类型 示例 问题描述
空指针使用 uint8_t* ptr = NULL; *ptr = 1; 程序崩溃
未初始化指针 uint8_t* p; *p = 1; 未分配内存
数组越界 for(i=0; i<=len; i++) *(p+i) 内存越界
忘记加 volatile uint32_t *reg = 0x4001100C; 编译器优化掉寄存器读写

结构体

✅ 一、结构体是啥?一句话理解:

结构体是多个不同类型变量的集合,用于描述一个“整体”对象。

举个通俗例子:我们要描述一个“学生”,他有名字、年龄、成绩等。用结构体把这些信息打包在一起,逻辑清晰,操作方便。

 ✅ 二、结构体基本语法

// 定义结构体类型
struct Student {
    char name[20];
    int age;
    float score;
};

// 声明变量
struct Student stu1;

🔎 你可以把 struct Student 看作是自定义的“数据模板”。

✅ 三、结构体变量的使用

strcpy(stu1.name, "张三");  // 字符串复制
stu1.age = 20;             // 成员赋值
stu1.score = 92.5;         // 成员赋值

成员访问用 . 操作符。

✅ 四、结构体指针

struct Student* p = &stu1;
printf("姓名:%s\n", p->name);  // 使用 -> 访问成员

嵌入式开发中大量使用结构体指针,比如 GPIOA->ODR

✅ 五、结构体类型重命名(推荐写法)

为了简洁,我们常用typedef方式:

typedef struct {
    char name[20];
    int age;
    float score;
} Student;

Student stu2;  // 不用再写 struct

 ✅ 六、结构体嵌套使用

typedef struct {
    int year;
    int month;
    int day;
} Date;

typedef struct {
    char name[20];
    Date birthday;  // 结构体中嵌套结构体
    float score;
} Student;

 ✅ 七、结构体数组

Student class1[50];  // 一个有 50 个学生的数组

class1[0].age = 18;
strcpy(class1[1].name, "李四");

 ✅ 八、结构体在STM32中的典型应用

STM32 的寄存器访问就是基于结构体+指针:

GPIOA->ODR |= (1 << 5);  // 设置 PA5 高电平

这是因为 GPIOA 是一个结构体指针:

typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  // ...
} GPIO_TypeDef;

__IO 是 volatile 关键字宏定义,用来防止编译器优化寄存器访问。

✅ 九、结构体作为函数参数(常见于驱动代码)

void printStudent(Student s) {
    printf("Name: %s\n", s.name);
}

// 或使用指针更高效
void printStudentPtr(Student* s) {
    printf("Name: %s\n", s->name);
}

✅ 十、结构体 vs 联合体 vs 枚举(简要对比)

类型 说明 用途
结构体 struct 多成员共享不同内存 组合多个变量
联合体 union 所有成员共用一块内存 节省空间,传感器数据封包
枚举 enum 一组具名整数常量 状态机、命令字、类型标识

✅ 十一、实际开发建议

  • ✅ 写结构体推荐用 typedef,命名更清晰

  • ✅ 结构体中可以嵌套数组、指针、结构体

  • ✅ 多个模块信息封装成结构体,便于管理

  • ✅ STM32 各外设驱动,基本全是结构体+指针组合

  • ✅ 如果你在做 STM32 项目,例如封装一个 按键模块传感器数据结构,结构体是组织数据的最佳方式

✅ 示例:STM32 项目中结构体组织按键状态

typedef struct {
    uint8_t key_id;
    uint8_t is_pressed;
    uint32_t last_press_time;
} KeyInfo;

KeyInfo key1 = {1, 0, 0};

void KeyScan(KeyInfo* k) {
    if (ReadGPIO(k->key_id) == 0) {
        k->is_pressed = 1;
        k->last_press_time = millis();
    }
}

 

枚举

**枚举(enum)**是 C 语言中非常实用的一种数据类型,在嵌入式开发、状态机设计、通信协议、自定义命令字等场景中极其常见,你必须深入掌握。

✅ 一、什么是枚举?

枚举是一种自定义类型,用于表示一组具名的整型常量,让代码更清晰、逻辑更明确。

举个例子:

 

enum Color {
    RED,    // 0
    GREEN,  // 1
    BLUE    // 2
};

就是在定义一个“颜色类型”,每个颜色对应一个整数值,但有名字更有意义

✅ 二、基本语法

enum Weekday {
    MONDAY,     // 0
    TUESDAY,    // 1
    WEDNESDAY,  // 2
    THURSDAY,   // 3
    FRIDAY = 10,// 自定义值,从10开始
    SATURDAY,   // 11
    SUNDAY      // 12
};

默认从 0 开始,后续自动加一。你也可以指定初始值。

✅ 三、枚举变量使用方式

enum Weekday today;

today = FRIDAY;

if (today == SUNDAY) {
    printf("休息!");
}

虽然本质是整数,但使用名字让代码语义清晰。

✅ 四、推荐写法(typedef 简洁定义)

typedef enum {
    OFF = 0,
    ON = 1
} SwitchState;

SwitchState led_state = ON;

这样你使用时就可以省略 enum,代码更整洁。

✅ 五、在 STM32/嵌入式中的典型应用场景

✅ 1. 状态机状态定义

typedef enum {
    IDLE,
    START,
    RUNNING,
    ERROR
} SystemState;

SystemState sys_state = IDLE;

用于状态机控制:

switch(sys_state) {
    case IDLE:     // 初始化或等待输入
        break;
    case START:    // 启动某个流程
        break;
    case RUNNING:  // 正在工作
        break;
    case ERROR:    // 出错处理
        break;
}

✅ 2. 指令类型、传感器状态等

typedef enum {
    CMD_NONE,
    CMD_START,
    CMD_STOP,
    CMD_RESET
} CommandType;

typedef enum {
    SENSOR_OK,
    SENSOR_FAULT,
    SENSOR_DISCONNECTED
} SensorStatus;

✅ 3. 与宏配合增强可读性

#define LED_ON  1
#define LED_OFF 0

typedef enum {
    LED1,
    LED2,
    LED3
} LedType;

void ControlLed(LedType led, uint8_t state);

✅ 六、枚举 vs 宏 vs 结构体

特性 宏定义 (#define) 枚举 (enum) 结构体 (struct)
功能 常量 有名字的常量组 数据集合
是否可调试 ❌ 不可调试 ✅ 可调试 ✅ 可调试
类型安全
表达清晰度 一般
使用场景 单一常量 状态、类型分类 数据打包

 ✅ 七、枚举背后是整数!

enum Level {
    LOW = 0,
    MID = 1,
    HIGH = 2
};

printf("%d", HIGH);  // 输出 2

你可以像整数一样进行比较、赋值、数组索引等操作。

✅ 八、进阶:结合结构体管理状态系统

typedef enum {
    MODE_INIT,
    MODE_IDLE,
    MODE_WORK,
    MODE_SLEEP
} WorkMode;

typedef struct {
    uint8_t id;
    WorkMode mode;
    uint16_t temperature;
} Device;

Device dev = { .id = 1, .mode = MODE_IDLE, .temperature = 0 };

这在 STM32 项目中非常常见,尤其在多模块、复杂逻辑系统中。

✅ 九、常见错误

错误 示例 原因
忘记指定 typedef enum Mode m = 1; 用法繁琐,不推荐
名称冲突 enum LED { ON, OFF }; 与宏重名 建议使用独立命名空间,如 LED_ON, LED_OFF
数值偏移不清楚 enum CMD { A=2, B, C }; 不清楚 B=3, C=4,需注意自增

 ✅ 总结一句话:

枚举是让你的代码“带名字的整数”,用于分类、状态管理、命令控制等场景,是 STM32 工程中不可或缺的核心工具

 

STM32其他外设

✅ STM32常用外设总览(建议收藏)

外设模块 作用 常用功能 项目举例
GPIO 通用输入输出 控制LED、读取按键、电平输入输出 智能门锁、LED跑马灯
EXTI 外部中断 按键中断触发、传感器报警 烟雾报警、红外检测
ADC 模拟信号采集 电压采集、传感器读取 光敏/温湿度传感器
DAC 模拟信号输出 波形生成、音频输出 简易音频输出、模拟电压控制
TIM 定时器 延时、PWM、测频、编码器输入 电机驱动、舵机控制
PWM 脉冲宽度调制 调光、调速、舵机控制 LED调光、风扇速度控制
USART/UART 串口通信 数据通信、模块串口控制 蓝牙通信、调试信息打印
SPI 串行外设接口 OLED、Flash、传感器通信 SPI OLED屏、FLASH存储
I2C 串行通信总线 EEPROM、OLED、温湿度模块 DHT12、I2C OLED
RTC 实时时钟 时钟显示、闹钟功能 智能钟表、定时开关
DMA 内存与外设高速搬运 提高效率,释放CPU 图像数据传输、ADC加速
NVIC 中断控制器 中断优先级管理 多中断协调处理
WDG 看门狗 防止程序死机 系统自动复位保护
FLASH 片上存储器 参数保存 保存配置或解锁记录
SysTick 系统定时器 系统节拍(ms) delay函数、任务调度
RCC 时钟控制 外设/系统时钟配置 时钟优化、低功耗控制
USB 通用串行总线 USB通信 虚拟串口、U盘
CAN 工业级通信协议 车辆/工业设备通信 电动车控制、CAN网关

 ✅ 1. EXTI —— 外部中断

🎯 用途:

  • 当 GPIO 口电平发生变化时,触发中断服务函数

  • 实现响应快、低功耗唤醒

💡 实例:

按键中断、PIR人体红外传感器触发、RFID刷卡通知

📌 配置流程:

  1. 配置引脚为输入

  2. 配置 EXTI 线路

  3. 设置中断优先级

  4. 编写中断服务函数(void EXTIx_IRQHandler(void)

✅ 2. ADC —— 模拟信号采集

🎯 用途:

采集模拟电压,如光敏、温湿度、气体传感器等

💡 实例:

电池电压检测、环境监测、ADC电位器

📌 配置流程:

  1. 开启 ADC 时钟

  2. 配置采样通道和分辨率

  3. 启动转换,读取值

  4. 可选 DMA 加速

📌 读取范围:

STM32F1 ADC 12位 → 04095(对应 03.3V)

✅ 3. TIM+PWM —— 定时与脉宽输出

🎯 用途:

  • 精确延时、定时触发(定时器)

  • 控制 LED 亮度、电机速度(PWM)

💡 实例:

风扇调速、舵机、RGB灯光

 📌 TIM 应用方向:

模式 用途
基本定时 毫秒延时
输出比较 PWM 控制、周期输出
输入捕获 测频、测速
编码器模式 编码器测量电机转动

 ✅ 4. USART/UART —— 串口通信

🎯 用途:

  • 串口调试、外设通信(蓝牙、GPS、WiFi)

  • 通信模块控制(JDY-31、HC-05、ESP8266)

💡 实例:

蓝牙接收手机指令、串口打印调试、与人脸模块通信

📌 常见配置:

  • 波特率(9600, 115200)

  • 接收中断 / DMA

  • 串口重映射(AFIO)

✅ 5. SPI —— 高速串行通信

🎯 用途:

  • 与 OLED、Flash、NRF24L01、SD卡 等设备通信

💡 实例:

驱动 SPI OLED 显示图像,读写 SPI Flash

📌 接线:

引脚 名称 说明
SCK 时钟线
MOSI 主设备输出/从设备输入
MISO 主设备输入/从设备输出
CS 片选信号

 ✅ 6. I2C —— 多设备总线通信

🎯 用途:

  • 简化连线,与传感器/模块进行通信

  • 支持多个设备挂载在同一总线上(唯一地址)

💡 实例:

接入 OLED、AT24C02、DHT12、MPU6050 等模块

📌 接线:

只需要两根线:SCL(时钟)、SDA(数据)

✅ 7. RTC —— 实时时钟

🎯 用途:

  • 保持年月日时间、设定闹钟

  • 使用外部低速晶振 LSE 保证掉电不丢失时间

💡 实例:

智能门锁记录时间、蔬菜烘干机自动定时、智能衣柜紫外消毒

✅ 8. DMA —— 内存外设搬运器

🎯 用途:

  • 提高数据传输效率,不占用 CPU

  • 常用于 ADC+DMA、SPI+DMA、UART+DMA

💡 实例:

音频数据、图像帧缓存、ADC 采样波形

✅ 9. WDG —— 看门狗(程序自恢复机制)

🎯 用途:

  • 防止程序死循环或卡死,自动复位

  • 两种类型:独立看门狗 IWDG、窗口看门狗 WWDG

💡 实例:

工业级稳定控制、长时间运行系统保护

✅ 10. SysTick —— 系统节拍定时器

🎯 用途:

  • 实现毫秒级定时(配合 delay_ms、FreeRTOS)

数组

✅ 1. STM32 里的数组

📌 什么是数组?

数组是 一组相同类型变量的集合,在内存中连续存储,方便统一管理和访问。

int a[5] = {1, 2, 3, 4, 5};

你可以通过下标访问:

a[0] = 10;    // 修改第一个元素
printf("%d", a[2]);  // 输出第3个元素:3

🔧 在 STM32 中数组的应用场景:

场景 示例
存储ADC采样数据 uint16_t adc_buf[100];
OLED图像数据缓存 uint8_t oled_buf[1024];
USART串口接收缓冲区 uint8_t uart_rx[128];
按键状态集合 uint8_t key_status[4];

 ✅ 2. CRL、CRH、IDR、ODR 是什么?

它们是 GPIO 寄存器(register) 的组成部分,用于配置和操作 IO 口的行为。

STM32 中每个 GPIO 端口(如 GPIOA、GPIOB)都对应一个寄存器结构体:

typedef struct
{
  __IO uint32_t CRL;   // 配置低8位IO口(PIN0~PIN7)
  __IO uint32_t CRH;   // 配置高8位IO口(PIN8~PIN15)
  __IO uint32_t IDR;   // 输入数据寄存器(读取IO电平)
  __IO uint32_t ODR;   // 输出数据寄存器(设置IO输出电平)
  // ...
} GPIO_TypeDef;

📌 各成员功能:

名称 作用 说明
CRL (Config Reg Low) 设置 PIN0~7 的输入/输出模式 比如设置 PA0 为输出
CRH (Config Reg High) 设置 PIN8~15 的模式 比如设置 PA13 为浮空输入
IDR (Input Data Reg) 读取当前 GPIO 电平 读按键、传感器输入状态
ODR (Output Data Reg) 设置输出电平 点亮 LED,控制继电器

✅ 示例:

GPIOA->ODR |= (1 << 5);   // 设置 PA5 为高电平
uint8_t val = GPIOB->IDR & (1 << 1);  // 读取 PB1 输入状态

✅ 3. CNT 是什么?

这是 定时器(TIM)模块的计数器寄存器

TIM2->CNT

📌 功能说明:

  • CNT 用于存储当前定时器的计数值

  • 你可以读取它来获得计时/测速/编码器位置信息

✅ 示例应用:

uint16_t timer_val = TIM2->CNT;  // 获取定时器当前值

✅ 4. 什么是寄存器(Register)?

在 STM32 中,寄存器是 MCU 芯片内部的一段特殊内存,用于控制外设行为

🔧 举例:

  • 想设置 LED 开关,你不是直接操作 LED,而是去写 GPIO 的 ODR 寄存器

  • 想设置 USART 波特率,你要去写 USART 的 BRR 寄存器

🧠 通俗类比:

寄存器就像一个“开关面板”,STM32 芯片内部有成百上千个这样的“按钮”,你控制这些按钮,才能让 LED亮/电机转/数据发/屏幕显。

✅ 5. 什么是动态内存(Dynamic Memory)?

在 C 语言中,有两种内存分配方式:

类型 特点 示例函数 生命周期
静态内存 编译时分配 全局变量、数组 程序运行期间
动态内存 运行时手动申请 malloc() free() 手动释放,否则内存泄漏

✅ 示例:

int* p = (int*)malloc(10 * sizeof(int));  // 分配 10 个 int 空间
p[0] = 123;
free(p);  // 手动释放内存

⚠️ 注意:

STM32中默认不推荐大量使用 malloc/free,因为:

  • 内存很小(一般只有几十 KB)

  • 容易内存碎片

  • 不适合实时系统(FreeRTOS除外)

占位符 含义
%d 十进制整数(int)
%f 浮点数
%c 字符(char)
%s 字符串(char*)
%x 十六进制输出
%% 输出一个百分号 %

✅ 总结回顾

概念 解释 示例
数组 连续同类型变量集合 int a[5];
CRL/CRH 设置 GPIO 口模式 GPIOA->CRL = ...
IDR/ODR GPIO 输入输出 val = GPIOA->IDR;
CNT 定时器当前值 TIM2->CNT
寄存器 控制 MCU 外设的地址接口 USART1->DR
动态内存 程序运行时分配内存 malloc()
%s 格式符:字符串 printf("str: %s", str);

✅ 一、/ 是“除法运算符”(division)

📌 基本含义:

int a = 10 / 3;  // 结果是 3(整数除法,舍去小数部分)

 如果你除的是两个整数,结果还是整数,小数部分会被截断(向零舍弃)

🔍 示例:

int x = 13 / 4;       // 结果是 3(不是 3.25)
float y = 13.0 / 4;   // 结果是 3.25

✅ 二、% 是“取模运算符”(modulo,求余数)

📌 基本含义:

int a = 10 % 3;  // 结果是 1

也就是说,a = 10 除以 3 的余数

🔍 示例:

int x = 13 % 4;   // 结果是 1,因为 13 = 3×4 + 1
int y = 20 % 5;   // 结果是 0,因为能整除

✅ 三、取模 % 的实际用途非常广!

✅ 1. 控制“循环步进”或“周期性计数”

int i = 0;
i = (i + 1) % 4;  // i 从 0 到 3 循环变化

📌 用于:

  • 状态机 0~3 状态轮换

  • 限制数组下标不越界(如环形缓冲区)

✅ 2. 判断是否能整除

if (num % 2 == 0) {
    // num 是偶数
}

📌 用于:

  • 判断奇偶

  • 判断 10 的倍数、100 的倍数

✅ 3. 控制 LED 闪烁频率

if (tick % 500 == 0) {
    LED_Toggle();
}

📌 每 500 个时钟节拍闪烁一次

✅ 四、组合应用:除法 + 取模

int time = 3661; // 3661 秒 = 1 小时 1 分钟 1 秒

int hours = time / 3600;            // 1 小时
int minutes = (time % 3600) / 60;   // 1 分钟
int seconds = time % 60;            // 1 秒

✅ 五、注意点(⚠️常见误区)

误区 说明
% 不能用于浮点数 表达式如 5.5 % 2.0 是错误的
/ 整数除法可能丢失精度 5 / 2 = 2,不是 2.5
% 结果与符号有关(负数) -5 % 3 结果是 -2,不是 1

 ✅ 六、应用于 STM32 项目的例子

🎯 1. LED 每秒闪烁一次

if (SysTick_Counter % 1000 == 0) { // 每 1000ms 触发
    Toggle_LED();
}

🎯 2. 环形缓冲区写入接收数据

uint8_t buffer[64];
uint8_t write_index = 0;

void USART1_IRQHandler() {
    buffer[write_index] = USART1->DR;
    write_index = (write_index + 1) % 64;  // 防止越界
}

✅ 七、总结对比

运算符 名称 功能 示例 结果
/ 除法 整数或小数相除 13 / 4 3(整数)
% 取模 整数余数 13 % 4 1

✅ 结语

/% 是组合使用频率极高的两个运算符,不仅用于算法计算,还被广泛用于状态控制、数据帧拆分、环形数组等嵌入式工程中。

 

 USE_STDPERIPH_DRIVER

OD:开漏输出模式
PP:推挽模式


 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐