一、STM32 外设基础(GPIO / TIM / EXTI)
1. GPIO:控制引脚的高低电平
核心概念
- GPIO = 单片机的一根根引脚。
- 引脚有两种身份:
- 输出:程序决定输出高电平(约 3.3V)或低电平(0V)。
- 输入:读取外部电路给引脚的电平。
必须记住的函数
// 输出高电平:点亮 / 使能
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_13, GPIO_PIN_SET);
// 输出低电平:熄灭 / 关闭
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_13, GPIO_PIN_RESET);
// 翻转电平
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_13);
// 读输入电平:返回 GPIO_PIN_SET 或 GPIO_PIN_RESET
HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
记忆口诀
WritePin:写,也就是输出。ReadPin:读,也就是输入。WritePin三个参数:端口、引脚、电平。
2. 定时器 TIM:精确定时
核心概念
- 定时器本质是一个计数器:来一个时钟脉冲,计数 +1;数到上限后归零,触发“更新事件”。
- 两个关键参数:
- PSC(预分频):把时钟分频变慢。
- ARR(自动重载值):计数上限。
更新频率公式
更新频率 = 定时器时钟 / ((PSC + 1) × (ARR + 1))
定时中断关键函数
// 启动 TIM2,并以中断方式计数
HAL_TIM_Base_Start_IT(&htim2);
// 每次 TIM2 计数到 ARR 归零,都会进这个回调
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
// 这里周期性执行,比如每 1ms 一次
}
}
记忆点
- 定时中断的回调是
HAL_TIM_PeriodElapsedCallback。 - 中断回调要短小,别放延时、打印这类重活。
3. TIM 输出 PWM:驱动电机速度
核心概念
- PWM = 在固定周期里,改变高电平所占比例(占空比),从而改变平均电压和转速。
- 占空比由比较值 CCR 决定:
占空比 = CCR / (ARR + 1)
关键函数
// 启动 PWM 输出
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
// 设置占空比:CCR 取 0 ~ ARR,对应 0% ~ 100%
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 25);
记忆点
HAL_TIM_PWM_Start:启动 PWM。__HAL_TIM_SET_COMPARE:改 CCR,也就是改占空比。- PID 算出的输出量,最终就是通过它写成 PWM 占空比去驱动电机。
4. 外部中断 EXTI:及时响应引脚变化
核心概念
- 中断 = 让外部事件“打断”当前流程,优先去处理一件事。
- 轮询容易漏,中断可以一有跳变就立刻响应。
关键函数
// 引脚发生指定边沿跳变时进入
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_13) {
// PC13 触发了中断
}
}
记忆点
- 外部中断回调是
HAL_GPIO_EXTI_Callback。 - 中断回调里只做置标志位、计数器 +1 这类轻量操作。
二、通信(UART / CAN / SPI)
总印象:三种方式都是“传数据”
| 总线 | 一句话比喻 | 特点 | 主要用途 |
|---|---|---|---|
| UART | 两个人打电话 | 异步、一对一,靠波特率对齐 | 调试打印 |
| CAN | 群聊喊话,带 ID | 多主、差分、抗干扰 | 控制 DJI 电机 |
| SPI | 老板和员工同步交换资料 | 同步、全双工、高速 | 读高速传感器 |
1. UART:调试打印
核心概念
- 异步:没有共同时钟线,双方靠约定的波特率对齐。
- 两根线:
- TX:发送
- RX:接收
- 连接要交叉:A 的 TX 接 B 的 RX,A 的 RX 接 B 的 TX。
- 波特率 115200 表示每秒 115200 个比特,不是字节。
发送
char msg[] = "hello\n";
HAL_UART_Transmit(&huart2, (uint8_t *)msg, sizeof(msg) - 1, 100);
四个参数:
&huart2:用哪个串口。(uint8_t *)msg:要发送数据的地址。sizeof(msg) - 1:要发送的字节数。100:超时时间,单位 ms。
printf 重定向
int fputc(int ch, FILE *f) {
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 10);
return ch;
}
配置一次后,以后直接:
printf("speed = %d\n", speed);
接收
uint8_t buf[8];
HAL_UART_Receive(&huart2, buf, 8, 100); // 阻塞等待收满 8 字节
记忆点
- 发文本要用字符串;直接发
int的地址,发的是内存里的二进制字节,串口工具可能显示乱码。 - 实际工程常用中断接收或 DMA 接收,避免阻塞。
2. CAN:控制 DJI 电机
核心概念
- 基本单位是一帧报文,每帧包含:
- ID:这条消息“关于谁、发给谁”。
- DLC:数据区有多少字节,范围 0 ~ 8。
- Data:最多 8 个字节。
- 常用电机:M3508(3508)、GM6020(6020)。
- DJI 电机默认波特率通常为 1 Mbps。
发送一帧
CAN_TxHeaderTypeDef txHeader;
uint8_t txData[8] = {0};
txHeader.StdId = 0x200; // 标准帧 ID,3508 通常从 0x200 起
txHeader.ExtId = 0;
txHeader.IDE = CAN_ID_STD; // 标准帧
txHeader.RTR = CAN_RTR_DATA; // 数据帧
txHeader.DLC = 8; // 数据区 8 字节
txHeader.TransmitGlobalTime = DISABLE;
uint32_t mailbox;
HAL_CAN_AddTxMessage(&hcan1, &txHeader, txData, &mailbox);
接收一帧
CAN_RxHeaderTypeDef rxHeader;
uint8_t rxData[8];
if (HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rxHeader, rxData) == HAL_OK) {
// rxHeader.StdId:发回方的 ID
// rxData:收到的数据
}
记忆点
- 发送:
HAL_CAN_AddTxMessage。 - 接收:
HAL_CAN_GetRxMessage。 - 3508 电流指令就是把每个电机的
int16_t电流值按字节塞进txData。 - 电机反馈需要按手册把
rxData的高位、低位拼成角度 / 转速 / 电流。
3. SPI:高速读传感器
核心概念
- 主从、同步、全双工。
- 四根线:
| 线 | 作用 |
|---|---|
| SCK | 时钟,主机提供节拍 |
| MOSI | 主机出、从机入 |
| MISO | 主机入、从机出 |
| CS(NSS) | 片选,拉低选中从机 |
收发代码
uint8_t tx[2] = {0x00, 0x00};
uint8_t rx[2] = {0};
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // 拉低 CS,选中从机
HAL_SPI_TransmitReceive(&hspi1, tx, rx, 2, 100); // 同时收发
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // 拉高 CS,释放从机
记忆点
- SPI 发一个字节的同时收一个字节。
- 读传感器前通常要先发一个“读命令”字节。
- CS 拉低 = 选中从机;CS 拉高 = 释放从机。
三、核心函数速查表
| 模块 | 作用 | 关键函数 / 关键字 |
|---|---|---|
| GPIO | 输出电平 | HAL_GPIO_WritePin |
| GPIO | 读取电平 | HAL_GPIO_ReadPin |
| TIM | 定时中断 | HAL_TIM_Base_Start_IT |
| TIM | 定时中断回调 | HAL_TIM_PeriodElapsedCallback |
| TIM | 启动 PWM | HAL_TIM_PWM_Start |
| TIM | 设置占空比 | __HAL_TIM_SET_COMPARE |
| EXTI | 外部中断回调 | HAL_GPIO_EXTI_Callback |
| UART | 发送 | HAL_UART_Transmit |
| UART | 接收 | HAL_UART_Receive |
| CAN | 发送帧 | HAL_CAN_AddTxMessage |
| CAN | 接收帧 | HAL_CAN_GetRxMessage |
| SPI | 同时收发 | HAL_SPI_TransmitReceive |
四、概念
- GPIO:写引脚输出、读引脚输入。
- TIM:定时中断 + 输出 PWM。
- EXTI:引脚一有跳变就回调。
- UART:把数据发到电脑上看。
- CAN:把指令发给 DJI 电机并收反馈。
- SPI:快速读传感器数据。