要将你当前基于 **TIM3** 的 DShot600 实现改为使用 **TIM8**,需要修改以下几个方面:
1. **时钟使能(RCC)**
2. **GPIO 配置与复用功能映射**
3. **定时器通道对应的 GPIO 引脚**
4. **DMA 流(Stream)和通道(Channel)配置**
5. **DMA 外设地址(CCR 寄存器)**
6. **中断向量或 NVIC 设置(如果涉及)**
—
### ✅ 改动目标:从 TIM3 → TIM8
| 项目 | TIM3 (原) | TIM8 (新) |
|——|———–|———-|
| 定时器 | TIM3 | TIM8 |
| 总线 | APB1 | APB2 |
| GPIO 端口 | PC6~PC9 | PC6~PC9 可用,但需确认复用 |
| DMA 请求源 | TIM3_CHx → DMA1_StreamX | TIM8_CHx → DMA2_StreamX |
| 通道映射 | CH1: CCR1, CH2: CCR2… | 相同逻辑 |
> 注意:虽然引脚仍是 PC6~PC9,但 **TIM8 输出通道对应如下:**
– TIM8_CH1 → PC6
– TIM8_CH2 → PC7
– TIM8_CH3 → PC8
– TIM8_CH4 → PC9
✅ 这些引脚在 STM32F4/F7/H7 等系列中是支持的。
—
## 🔧 修改后的代码(完整替换)
### 1. 修改 `TIM3_PWM_Init` → `TIM8_PWM_Init`
“`c
void TIM8_PWM_Init(u32 arr, u32 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// ① 使能时钟:TIM8 属于 APB2 总线,不是 APB1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
// ② 配置 PC6/7/8/9 为 TIM8 复用
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM8);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_TIM8);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_TIM8);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_TIM8);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// ③ 定时器基本配置
TIM_TimeBaseStructure.TIM_Prescaler = psc;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 高级定时器需要设置此项
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
// ④ PWM 输出模式配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC1Init(TIM8, &TIM_OCInitStructure);
TIM_OC2Init(TIM8, &TIM_OCInitStructure);
TIM_OC3Init(TIM8, &TIM_OCInitStructure);
TIM_OC4Init(TIM8, &TIM_OCInitStructure);
// ⑤ 使能预装载
TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable);
TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable);
TIM_OC3PreloadConfig(TIM8, TIM_OCPreload_Enable);
TIM_OC4PreloadConfig(TIM8, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM8, ENABLE);
// ⑥ 启动定时器
TIM_Cmd(TIM8, ENABLE);
// ⑦ 主输出使能(高级定时器必须调用!)
TIM_CtrlPWMOutputs(TIM8, ENABLE);
}
“`
> ⚠️ 关键点:`TIM_CtrlPWMOutputs(TIM8, ENABLE);` 是高级定时器必需的,否则无输出!
—
### 2. 修改 `MYDMA_Config` 调用中的流和外设基地址
#### 查找 TIM8 对应的 DMA 请求:
– TIM8_CH1 → DMA2_Stream1, Channel_0
– TIM8_CH2 → DMA2_Stream2, Channel_0
– TIM8_CH3 → DMA2_Stream3, Channel_0
– TIM8_CH4 → DMA2_Stream7, Channel_0
> 📌 注意:不同芯片可能略有差异,请参考《STM32F4xx 参考手册》DMA 请求映射表。
我们以 STM32F407/F429 为例:
| TIM8_CHx | DMA Stream | Channel |
|———|————|——–|
| CH1 (CCR1) | DMA2_Stream1 | Ch0 |
| CH2 (CCR2) | DMA2_Stream2 | Ch0 |
| CH3 (CCR3) | DMA2_Stream3 | Ch0 |
| CH4 (CCR4) | DMA2_Stream7 | Ch0 |
—
### 3. 更新 `dshot600_init()` 函数
“`c
void dshot600_init()
{
TIM8_PWM_Init(70 – 1, 2 – 1); // ARR=69, PSC=1 → ~600kHz PWM 载波(具体看主频)
// 配置每个通道的 DMA
MYDMA_Config(DMA2_Stream1, DMA_Channel_0, (uint32_t)&(TIM8->CCR1), (uint32_t)dd1, ESC_CMD_BUFFER_LEN);
MYDMA_Config(DMA2_Stream2, DMA_Channel_0, (uint32_t)&(TIM8->CCR2), (uint32_t)dd2, ESC_CMD_BUFFER_LEN);
MYDMA_Config(DMA2_Stream3, DMA_Channel_0, (uint32_t)&(TIM8->CCR3), (uint32_t)dd3, ESC_CMD_BUFFER_LEN);
MYDMA_Config(DMA2_Stream7, DMA_Channel_0, (uint32_t)&(TIM8->CCR4), (uint32_t)dd4, ESC_CMD_BUFFER_LEN);
// 使能 TIM8 的 DMA 请求
TIM_DMACmd(TIM8, TIM_DMA_CC1, ENABLE);
TIM_DMACmd(TIM8, TIM_DMA_CC2, ENABLE);
TIM_DMACmd(TIM8, TIM_DMA_CC3, ENABLE);
TIM_DMACmd(TIM8, TIM_DMA_CC4, ENABLE);
}
“`
—
### 4. 确保 `MYDMA_Config` 支持 DMA2
你原来的判断逻辑:
“`c
if((u32)DMA_Streamx>(u32)DMA2)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
}else
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);
}
“`
这个写法不严谨。建议改为更清晰的方式:
“`c
if (DMA_Streamx == DMA1_Stream0 || DMA_Streamx == DMA1_Stream1 || … )
enable DMA1
else
enable DMA2
“`
或者直接简化为:
“`c
// 在 dshot600_init 前确保 DMA2 时钟开启
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
“`
或者改进 `MYDMA_Config` 中的时钟使能部分:
“`c
if ((uint32_t)DMA_Streamx >= (uint32_t)DMA2) // 地址上 DMA2 > DMA1
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
}
else
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
}
“`
✅ 对于 F4 系列,DMA2 地址更高,所以上面判断是可以的。
—
## ✅ 最终关键修改总结
| 修改项 | 原值 | 新值 |
|——-|——|——|
| 定时器 | TIM3 | TIM8 |
| 时钟使能 | `RCC_APB1Periph_TIM3` | `RCC_APB2Periph_TIM8` |
| 主输出控制 | 不需要 | 必须加 `TIM_CtrlPWMOutputs(TIM8, ENABLE)` |
| GPIO AF 编号 | `GPIO_AF_TIM3` | `GPIO_AF_TIM8` |
| DMA 模块 | DMA1 | DMA2 |
| DMA Streams | DMA1_Stream4/5/7/2 | DMA2_Stream1/2/3/7 |
| DMA Channel | DMA_Channel_5 | DMA_Channel_0(常见) |
| 外设地址 | `&(TIM3->CCRx)` | `&(TIM8->CCRx)` |
| DMA 请求使能 | `TIM_DMA_CCx` | 同样可用 |
—
## 💡 补充说明:为什么用 TIM8?
– TIM8 是高级定时器,更适合高精度 PWM 和电机控制。
– 支持死区插入、刹车等功能(虽然 DShot 不需要)。
– 更高的频率容忍度(适合 DShot600 协议要求高速更新)。
—









