STM32 小白实战 04:PWM 驱动舵机与直流电机,函数声明和大小写错误排查
.摘要今天完成了 PWM 驱动舵机的参数理解与按键控制并开始编写直流电机驱动模块。重点不是新增了多少代码而是确认了几类非常典型的 C 语言工程错误函数原型拼写不一致、函数被隐式声明、变量大小写不一致、标准库函数名大小写写错、PWM 通道接口未统一以及函数名中误插入空格。舵机已验证可以按照设定角度转动电机模块的编译问题已解决实物正反转与调速效果待确认。开发环境MCUSTM32F103 系列IDEKeil μVision 5编译器ARMCC V5.06 update 7固件库STM32F10x 标准外设库调试器ST-LINK本次外设舵机、按键、OLED、直流电机驱动接口PWM 定时器TIM2舵机 PWM 输出TIM2_CH2对应 PA1按键输入PB1、PB11一、舵机 PWM 中 ARR、PSC、CCR 到底怎样对应现象定时器配置为 ARR20000-1、PSC72-1已经知道 ARR120000但不理解为什么 CCR500 被课程当作舵机 0°。TIM_TimeBaseInitStructure.TIM_Period 20000 - 1; // ARRTIM_TimeBaseInitStructure.TIM_Prescaler 72 - 1; // PSCTIM_OCInitStructure.TIM_Pulse 0; // CCR原因按 72 MHz 定时器时钟计算经过 72 分频后 CNT 计数频率为 1 MHz即每个计数为 1 μs。ARR120000所以 PWM 周期为 20 ms频率为 50 Hz。CCR 在当前参数下可直接看作高电平持续的微秒数。CCR 500 →高电平0.5 msCCR 1500 →高电平1.5 msCCR 2500 →高电平2.5 msCCR500 并不是天生代表 0°而是当前程序采用“0.5 ms→0°、1.5 ms→90°、2.5 ms→180°”的舵机映射。解决方法把角度 0180°线性映射到 CCR 5002500。void Servo_SetAngle(float Angle){PWM_SetCompare2(Angle / 180.0f * 2000.0f 500.0f);}角度CCR高电平时间占空比0°5000.5 ms2.5%90°15001.5 ms7.5%180°25002.5 ms12.5%验证结果舵机在修正后可以按照设定角度转动。图1课程中的PWM频率、占空比和分辨率计算示意。二、OLED 角度变化但舵机不跟随转动现象按键读取正常OLED 上的角度值可以递增但舵机不随角度变化。Keil 提示 Servo_SetAngle 被隐式声明。warning: #223-D: function Servo_SetAngle declared implicitly原因Servo.h 中把函数名写成 Servo_SetAngel实际定义和调用是 Servo_SetAngle。函数原型没有被正确包含ARMCC 虽继续编译但浮点参数传递可能与实际函数定义不一致。//错误void Servo_SetAngel(float Angle);//正确void Servo_SetAngle(float Angle);解决方法统一 Servo.h、Servo.c 和 main.c 中的函数名与参数类型Servo.c 同时包含 Servo.h保存后执行 Rebuild all target files。#ifndef __SERVO_H#define __SERVO_Hvoid Servo_Init(void);void Servo_SetAngle(float Angle);#endif验证结果隐式声明警告消失舵机可以按照程序设定角度正常转动。图2 Servo_SetAngle()缺少正确函数原型时的隐式声明警告。三、Motor.c 中标准库函数和变量名写错现象编写电机正反转和速度控制函数时Keil 报告 GPIO_ReSetBits 被隐式声明speed 未定义。原因STM32 标准库正确函数名是 GPIO_ResetBits函数参数定义为 Speed但代码使用 speed。C 语言严格区分大小写。解决方法统一标准库函数名和变量名。void Motor_SetSpeed(int8_t Speed){if (Speed 0){GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_ResetBits(GPIOA, GPIO_Pin_5);PWM_SetCompare3(Speed);}else{GPIO_ResetBits(GPIOA, GPIO_Pin_4);GPIO_SetBits(GPIOA, GPIO_Pin_5);PWM_SetCompare3(-Speed);}}验证结果GPIO_ReSetBits 和 speed 对应的编译错误消失。图3 Motor.c中函数名和变量名大小写错误。四、链接阶段提示 Undefined symbol PWM_SetCompare1现象语法编译通过但链接阶段报告 Undefined symbol PWM_SetCompare1并指出由 main.o 引用。Undefined symbol PWM_SetCompare1 (referred from main.o)原因main.c 调用了 PWM_SetCompare1()但当前 PWM 模块实际提供的是通道 3 接口 PWM_SetCompare3()。声明、定义和调用的 PWM 通道没有统一。解决方法主函数通过 Motor_SetSpeed() 使用电机模块不再调用不存在的 PWM_SetCompare1()PWM.h、PWM.c 和 Motor.c 统一使用 PWM_SetCompare3。void PWM_SetCompare3(uint16_t Compare){TIM_SetCompare3(TIM2, Compare);}验证结果PWM_SetCompare1 未定义的链接错误消失工程进入后续编译检查。五、Motor.h 中函数名被空格拆开现象Motor.h 报 incomplete type、expected a ;main.c 同时提示 Motor_SetSpeed 被隐式声明。void Motor _SetSpeed(int8_t Speed);原因Motor 和 _SetSpeed 之间多了一个空格编译器无法把它识别为函数名 Motor_SetSpeed导致头文件声明无效。解决方法删除多余空格并在头文件中包含能够定义 int8_t 的头文件。#ifndef _MOTOR_H#define _MOTOR_H#include stm32f10x.hvoid Motor_Init(void);void Motor_SetSpeed(int8_t Speed);#endif验证结果该问题已经解决相关编译错误和隐式声明警告消失。直流电机实物正反转与调速效果待确认。固定排查清单出现 declared implicitly 时先检查对应 .h 是否有正确函数原型。函数声明、函数定义和函数调用的名字及参数类型必须完全一致。C 语言区分大小写重点检查 Speed/speed、Reset/ReSet。错误来自 main.o 时优先在 main.c 搜索对应调用。Undefined symbol 属于链接错误要检查函数是否真正定义、源文件是否加入工程、接口名是否统一。PWM 通道必须一致初始化 CH3就使用 TIM_SetCompare3() 和 PWM_SetCompare3()。头文件中的函数名不能包含意外空格。每个 .c 文件尽量包含自己的 .h让接口不一致尽早暴露。修改头文件或接口后执行 Rebuild all target files。软件编译通过不等于硬件验证完成电机方向、转速和供电仍需实物测试。