KL25Z开发板Keil环境下PWM伺服控制无响应问题排查
伺服电机PWM控制无响应问题修复(Freedom KL25Z)
问题概述
需实现PWM控制伺服电机:初始摆臂处于中位,每0.5秒转动30度。基于Freedom KL25Z开发板的C代码运行后,伺服摆臂完全无响应。
原代码
#include <MKL25Z4.H> #include <stdio.h> #include <math.h> #include "utils.h" int main (void) { SIM->SCGC5 |= 0x1000; /* enable clock to Port D */ PORTD->PCR[2] = 0x0400; /* PTD1 used by TPM0 PIN DEL PRIMER SERVOMOTOR */ SIM->SCGC6 |= 0x01000000; /* enable clock to TPM0 */ SIM->SOPT2 |= 0x01000000; /* use MCGFLLCLK as timer counter clock */ while (1) { TPM0->SC = 0; /* disable timer */ TPM0->CONTROLS[3].CnSC = 0x20 | 0x08; /* edge-aligned, pulse high */ TPM0->MOD = 299999; /* Set up modulo register for 50 Hz */ TPM0->CONTROLS[3].CnV = 15000; /* Set up channel value for 5% dutycycle for 0 degree */ TPM0->SC = 0x0C; /* enable TPM0 with prescaler /16 */ Delay(5000000); TPM0->CONTROLS[3].CnV = 17499; /* Set up channel value for for duty cycle 5.833 30 degree */ Delay(5000000); TPM0->CONTROLS[3].CnV = 19999; /* Set up channel value for duty cycle 6.66333 value 19999 60 degree servo*/ TPM0->SC = 0x0C; Delay(5000000); TPM0->CONTROLS[3].CnV = 22500; TPM0->SC = 0x0C; Delay(5000000); } }
问题分析与修复步骤
1. 定时器时钟未启用
原代码中TPM0->SC = 0x0C仅设置了分频系数(/16),但CMOD位(时钟模式)为0,定时器无法运行。需将CMOD设为01(使用内部时钟),正确的SC值应为0x0D(0x01 | 0x0C)。
2. PWM周期计算错误
伺服电机需要50Hz(20ms周期)的PWM信号:
- 核心时钟MCGFLLCLK默认48MHz,分频/16后计数频率为
48MHz /16 = 3MHz - 20ms对应计数值为
3MHz * 0.02s = 60000,因此MOD寄存器应设为59999(计数值从0到MOD,共60000次),而非原代码的299999(对应10Hz周期)。
3. 引脚复用配置错误
原代码中PORTD->PCR[2] = 0x0400将引脚复用设为ALT2,但TPM0_CH3(对应PTD2)需设置为ALT3,正确配置为PORTD->PCR[2] = 0x0300。同时注释标注的PTD1为错误,需修正为PTD2。
4. CnV值计算错误
基于3MHz计数频率,伺服电机典型脉宽对应CnV值:
- 中位(1.5ms):
3MHz * 0.0015s = 4500 - 30度(1.75ms):
3MHz * 0.00175s = 5250 - 60度(2ms):
3MHz * 0.002s = 6000 - 90度(2.25ms):
3MHz * 0.00225s = 6750
5. 冗余配置优化
无需在while循环中重复配置定时器基础参数(SC、CnSC、MOD),只需初始化时配置一次,循环中仅修改CnV即可。
修复后的代码
#include <MKL25Z4.H> #include "utils.h" int main (void) { // 启用端口D时钟 SIM->SCGC5 |= 0x1000; // 配置PTD2为TPM0_CH3(ALT3) PORTD->PCR[2] = 0x0300; // 启用TPM0时钟 SIM->SCGC6 |= 0x01000000; // 设置定时器时钟源为MCGFLLCLK(48MHz) SIM->SOPT2 |= 0x01000000; // 初始化TPM0参数 TPM0->SC = 0; // 先禁用定时器 TPM0->CONTROLS[3].CnSC = 0x28; // 边沿对齐PWM,高有效(MSB:10, ELSB:01) TPM0->MOD = 59999; // 50Hz PWM周期(20ms) TPM0->SC = 0x0D; // 启用定时器,分频/16,内部时钟 while (1) { TPM0->CONTROLS[3].CnV = 4500; // 中位(1.5ms脉宽) Delay(2500000); // 0.5秒延时(根据实际核心频率调整) TPM0->CONTROLS[3].CnV = 5250; // 30度 Delay(2500000); TPM0->CONTROLS[3].CnV = 6000; // 60度 Delay(2500000); TPM0->CONTROLS[3].CnV = 6750; // 90度 Delay(2500000); } }
额外说明
- 延时函数
Delay()的参数需根据实际核心频率调整,若核心为48MHz,循环计数约2500000次对应0.5秒(可通过示波器校准)。 - 不同伺服电机的脉宽范围可能略有差异,可微调CnV值适配具体电机。
内容的提问来源于stack exchange,提问作者Shash
相关产品推荐
相关产品推荐

