.
摘要
今天完成了 PWM 驱动舵机的参数理解与按键控制,并开始编写直流电机驱动模块。重点不是新增了多少代码,而是确认了几类非常典型的 C 语言工程错误:函数原型拼写不一致、函数被隐式声明、变量大小写不一致、标准库函数名大小写写错、PWM 通道接口未统一,以及函数名中误插入空格。舵机已验证可以按照设定角度转动;电机模块的编译问题已解决,实物正反转与调速效果待确认。
开发环境
- MCU:STM32F103 系列
- IDE:Keil μVision 5
- 编译器:ARMCC V5.06 update 7
- 固件库:STM32F10x 标准外设库
- 调试器:ST-LINK
- 本次外设:舵机、按键、OLED、直流电机驱动接口
- PWM 定时器:TIM2
- 舵机 PWM 输出:TIM2_CH2,对应 PA1
- 按键输入:PB1、PB11
一、舵机 PWM 中 ARR、PSC、CCR 到底怎样对应
现象:定时器配置为 ARR=20000-1、PSC=72-1,已经知道 ARR+1=20000,但不理解为什么 CCR=500 被课程当作舵机 0°。
|
TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; // ARR |
原因:按 72 MHz 定时器时钟计算,经过 72 分频后 CNT 计数频率为 1 MHz,即每个计数为 1 μs。ARR+1=20000,所以 PWM 周期为 20 ms,频率为 50 Hz。CCR 在当前参数下可直接看作高电平持续的微秒数。
|
CCR = 500 → 高电平 0.5 ms |
CCR=500 并不是天生代表 0°,而是当前程序采用“0.5 ms→0°、1.5 ms→90°、2.5 ms→180°”的舵机映射。
解决方法:把角度 0~180°线性映射到 CCR 500~2500。
|
void Servo_SetAngle(float Angle) |
|
角度 |
CCR |
高电平时间 |
占空比 |
|
0° |
500 |
0.5 ms |
2.5% |
|
90° |
1500 |
1.5 ms |
7.5% |
|
180° |
2500 |
2.5 ms |
12.5% |
验证结果:舵机在修正后可以按照设定角度转动。

图 1 课程中的 PWM 频率、占空比和分辨率计算示意。
二、OLED 角度变化,但舵机不跟随转动
现象:按键读取正常,OLED 上的角度值可以递增,但舵机不随角度变化。Keil 提示 Servo_SetAngle 被隐式声明。
|
warning: #223-D: function "Servo_SetAngle" declared implicitly |
原因:Servo.h 中把函数名写成 Servo_SetAngel,实际定义和调用是 Servo_SetAngle。函数原型没有被正确包含,ARMCC 虽继续编译,但浮点参数传递可能与实际函数定义不一致。
|
// 错误 |
解决方法:统一 Servo.h、Servo.c 和 main.c 中的函数名与参数类型;Servo.c 同时包含 Servo.h;保存后执行 Rebuild all target files。
|
#ifndef __SERVO_H |
验证结果:隐式声明警告消失,舵机可以按照程序设定角度正常转动。

图 2 Servo_SetAngle() 缺少正确函数原型时的隐式声明警告。
三、Motor.c 中标准库函数和变量名写错
现象:编写电机正反转和速度控制函数时,Keil 报告 GPIO_ReSetBits 被隐式声明,speed 未定义。
原因:STM32 标准库正确函数名是 GPIO_ResetBits;函数参数定义为 Speed,但代码使用 speed。C 语言严格区分大小写。
解决方法:统一标准库函数名和变量名。
|
void Motor_SetSpeed(int8_t 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) |
验证结果: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 |
验证结果:该问题已经解决,相关编译错误和隐式声明警告消失。直流电机实物正反转与调速效果待确认。
固定排查清单
- 出现 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。
- 软件编译通过不等于硬件验证完成,电机方向、转速和供电仍需实物测试。

4163

被折叠的 条评论
为什么被折叠?



