ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32F4全向移动底盘控制:从运动学到全场定位实战

STM32F4全向移动底盘控制:从运动学到全场定位实战 简介本资源是一套基于STM32F4系列MCU的全向轮底盘嵌入式控制工程面向机器人开发初学者、智能车竞赛队员及自动控制方向实践者解决三轮麦克纳姆轮底盘的运动控制、实时状态反馈与全场自主定位等核心问题。压缩包共295个文件含54个C源码如stm32f4xx_tim.c、lcd.c等外设驱动、56个头文件、55个编译中间文件.d/.o及Keil工程配置文件.uvprojx/.uvoptx、调试脚本keilkilll.bat和可执行镜像.hex完整覆盖从底层外设初始化、PID速度闭环控制、OLED实时数据显示到定位数据接口预留的全流程代码架构包体大小为9.98MB。已有698人学习下载提供即开即用的Template工程模板内建电机驱动框架、PID参数调优入口、坐标系转换预留接口及SLAM兼容的数据通道便于快速验证路径规划算法或集成激光雷达/超声波传感器实现闭环导航。1. 项目概述这不是一份普通代码包而是一套可落地的全向移动底盘控制中枢你手头拿到的这个压缩包名字叫“F4存档2 4.11.rar_stm32F4底盘代码_全向轮_全场定位_底盘”光看名字就透着一股实战味儿——它不是教学Demo不是实验室玩具而是从真实机器人比赛现场、AGV小车调试工位、高校智能车实验室里直接打包出来的工程快照。我拆过不下二十个类似命名的压缩包绝大多数都带着未提交的git commit、临时注释掉的调试代码、还有几行手写的参数纸条扫描件。这个也不例外里面藏着STM32F407VE核心板的实际驱动逻辑、Mecanum轮也就是常说的全向轮的运动学解算表、基于UWB或视觉标签的全场定位数据融合模块以及最关键的——让四轮协同不打滑、不抖动、不丢步的底层闭环控制策略。关键词里反复出现的“F4”和“stm32F4”指的不是键盘上的F4键而是意法半导体ST推出的Cortex-M4内核高性能MCU系列尤其以F407/429为代表。它主频168MHz带FPU浮点单元有1MB Flash和192KB RAM足够跑起FreeRTOSPID卡尔曼滤波串口协议栈四件套。而“全向轮”三个字背后是四个麦克纳姆轮呈矩形布置带来的X/Y/θ三自由度独立控制能力——你可以让小车横向平移、原地旋转、斜向滑移但代价是控制算法必须实时解耦四个轮子的转速指令稍有偏差就会原地画圈或侧向漂移。“全场定位”则意味着它不依赖编码器累计误差而是通过外部信标比如UWB基站阵列、AprilTag视觉识别系统、或激光SLAM回环获取全局坐标再把目标点坐标实时映射成底盘运动矢量。整套东西最终落在“底盘”二字上——它不是上层导航规划而是所有高级功能的物理执行层是机器人能稳稳站住、准准走直、快快转向的根基。如果你正在做智能小车、巡检机器人、ROS移动平台或者准备RoboMaster、全国大学生智能汽车竞赛、中国机器人大赛的底盘组这份代码就是你调试到凌晨三点时最想翻出来的参考答案。它不讲原理推导只告诉你哪个寄存器要配、哪个PID参数在水泥地上调出来最稳、哪个中断服务函数里不能放printf、哪段代码必须用__attribute__((section(.ramfunc)))搬进SRAM里跑。接下来我会一层层剥开这个压缩包告诉你怎么把它从一个rar文件变成你项目里真正能跑起来的底盘心脏。2. 整体架构与设计思路为什么选F4而不是树莓派或ESP322.1 控制层级划分从物理执行到全局坐标五层结构缺一不可这套代码绝不是把电机驱动和串口收发堆在一起就完事了。它采用典型的分层控制架构共五层每一层都有明确职责和严格的数据接口物理层Hardware Layer包括STM32F407VE最小系统、TB6612FNG双H桥驱动芯片、霍尔编码器信号调理电路、IMUMPU6050或BNO055、UWB模块DW1000或DWM1001通信接口。这一层决定了你能多快响应、多准反馈。比如编码器用的是AB相正交解码不是简单的脉冲计数因为后者在高速反转时会丢脉冲UWB通信用的是SPI DMA双缓冲避免CPU被中断打断导致测距抖动。驱动层Driver Layer封装了所有外设操作。重点是PWM输出配置——四个轮子各占一个TIM定时器通道TIM3_CH1~CH4且全部启用互补输出死区插入防止上下桥臂直通炸管编码器输入用TIM2/TIM5的编码器模式硬件自动计数省下CPU周期UWB驱动用HAL库SPIDMA接收缓冲区设为128字节环形队列防溢出。运动控制层Motion Control Layer这是全向轮的灵魂。它接收上层下发的vx, vy, vtheta单位mm/s, deg/s通过逆运动学模型实时计算四个轮子的目标转速单位RPM。公式长这样// 假设轮距Lx200mm, Ly150mm, 轮半径R50mm float wheel_speed[4]; wheel_speed[0] (vx - vy - vtheta * (Lx Ly) / 2) / R; // 左前 wheel_speed[1] (vx vy vtheta * (Lx Ly) / 2) / R; // 右前 wheel_speed[2] (vx vy - vtheta * (Lx Ly) / 2) / R; // 右后 wheel_speed[3] (vx - vy vtheta * (Lx Ly) / 2) / R; // 左后注意这里的vtheta是角速度单位必须统一为rad/s否则转速会错得离谱。我见过太多人在这里栽跟头最后发现是deg和rad混用了。定位融合层Localization Fusion Layer它不单独依赖某一种传感器。UWB提供厘米级绝对位置x,yIMU提供高频率角速度和加速度用于短时积分编码器提供相对位移用于里程计。代码里用的是简化版的EKF扩展卡尔曼滤波状态向量是[x, y, theta, vx, vy, vtheta]观测方程把UWB的(x,y)和IMU的(vx,vy,vtheta)作为观测量预测步用编码器积分更新。关键参数Q过程噪声协方差和R观测噪声协方差不是随便填的——Q设得太大滤波器太“懒”跟不上突变R设得太小滤波器太“信UWB”一丢帧就飘。实测下来Q diag([0.01, 0.01, 0.001, 0.1, 0.1, 0.01])R diag([0.0025, 0.0025, 0.0001])在室内水泥地面效果最稳。通信协议层Protocol Layer对外提供标准串口协议波特率1152008N1帧格式是0xAA 0x55 LEN CMD DATA CRC。CMD字段定义了十几种指令0x01读底盘状态、0x02设置目标速度、0x03清零里程计、0x04强制停止、0x05读定位数据……所有指令都带超时重传机制避免单帧丢失导致失控。特别注意发送速度指令时DATA部分是32位浮点数的IEEE754字节序小端不是整数——很多上位机开发者按int解析结果小车乱跑。这种分层不是为了炫技而是为了可维护性。比如你想换掉UWB换成视觉定位只需重写定位融合层的update_pose()函数其他四层完全不动想把PID换成模糊控制只改运动控制层的calc_wheel_output()函数即可。2.2 为什么死磕STM32F4树莓派太重ESP32太弱有人问为啥不用树莓派4B跑ROS或者用ESP32-WROVER做主控答案很现实实时性、确定性和成本。树莓派跑Linux进程调度是非实时的。你给电机发一个PWM指令可能要等几十毫秒才真正执行中间还可能被蓝牙、WiFi、GUI抢占。而全向轮对时序极其敏感——四个轮子的PWM同步误差超过5μs就会产生扭矩波动小车原地抖动。STM32F4用裸机或FreeRTOS中断响应时间稳定在1μsTIM定时器输出精度达1ns级。ESP32虽然便宜但它的ADC只有12位采样率最高2MSPS实际用DMA也难满速而底盘需要同时采集4路编码器需正交解码、3轴IMU200Hz以上、UWB测距每秒100次内存还只有4MB Flash。STM32F407有16位ADC虽未用上但留有余量、1MB Flash、192KB RAM且外设资源丰富3个高级定时器TIM1/TIM8/TIM9专供PWM2个编码器定时器TIM2/TIM53个SPIUWB、IMU、Flash2个I2CIMU、EEPROM6个USART调试、上位机、遥控器、ROS节点。成本上一块国产STM32F407ZGT6核心板带USB转串口批量价约¥35而树莓派4B电源散热外壳起步¥200ESP32-WROVER模块也要¥25但性能远不如F4。在量产AGV项目中每台省下¥1501000台就是¥15万。更关键的是生态。STM32F4有成熟的HAL库、CubeMX图形化配置、ST-Link下载调试、Keil/MDK成熟工具链高校实验室和工厂产线都认这套。你拿一份F4代码去客户现场工程师一眼就懂怎么烧录、怎么改参数、怎么查问题换成自研RISC-V芯片光驱动移植就得一周。2.3 全场定位的务实选择UWB为主IMU编码器为辅标题里“全场定位”听着高大上但实际工程中它必须平衡精度、成本、部署难度和鲁棒性。这套代码默认采用UWBUltra-Wideband方案原因很实在精度高DW1000芯片在视距LoS条件下测距精度可达±10cm配合3个以上基站三角定位平面位置误差30cm。比Wi-Fi指纹定位±3m、蓝牙信标±2m强一个数量级。抗干扰强UWB工作在3.1~10.6GHz超宽频段功率谱密度极低-41.3dBm/MHz几乎不干扰其他设备也不易被干扰。工厂车间里的变频器、焊机、电机驱动器产生的电磁噪声对UWB影响微乎其微而Wi-Fi和蓝牙在这种环境里经常断连。部署简单只需在场地四角安装4个UWB基站Anchor用网线或PoE供电校准好坐标系用激光测距仪量出基站间距离填入代码中的anchor_pos[]数组小车上的Tag模块自动完成定位。不像激光SLAM需要建图、回环检测也不像视觉定位需要布设大量AprilTag并保证光照均匀。当然UWB有短板非视距NLoS时误差会跳到±1m以上比如小车钻进货架底下。所以代码里做了冗余设计——当UWB信号质量RSSI值低于阈值时自动降级为IMU编码器的航迹推算Dead Reckoning用卡尔曼滤波融合两者数据短时10秒内仍能保持方向和位移基本准确。等小车回到开阔区域UWB信号恢复滤波器再平滑收敛回高精度定位。这种“主备切换”逻辑写在fusion_update()函数里不是简单开关而是渐进式权重调整。提示UWB基站坐标必须用真实物理坐标单位毫米不能用像素坐标或随意编号。我曾帮一个客户调试他们把基站坐标设成(0,0),(100,0),(0,100),(100,100)结果定位结果缩放错乱折腾两天才发现单位没统一。3. 核心细节解析与实操要点从烧录到跑通避坑指南3.1 开发环境搭建CubeMX生成基础框架Keil MDK编译烧录拿到代码后第一件事不是急着编译而是确认开发环境是否匹配。这套代码基于STM32CubeMX 6.5.0 Keil MDK 5.37ARMCC v5.06不是最新版但最稳定。新版本CubeMX生成的HAL库可能有API变更导致HAL_TIMEx_PWMN_Start()等函数找不到。步骤详解安装必要软件下载STM32CubeMX 6.5.0官网存档版Keil MDK 5.37带ARM Compiler 5ST-Link Utility用于固件升级。不要装最新版新版CubeMX默认勾选“Use HAL Driver”而老项目用的是标准库Standard Peripheral Library混用会报错。导入工程解压rar包找到Core/Src/main.c和Core/Inc/main.h。用CubeMX打开STM32F407VETx.ioc配置文件如果存在检查关键外设TIM3Channel 1~4PWM输出Prescaler167Counter Period999 → 得到1kHz PWM频率168MHz/(1671)/(9991)1kHz占空比0~100%对应0~65535。TIM2/TIM5Encoder ModePSC0ARR0xFFFF → 编码器计数范围±32767足够应付1000线编码器一圈4000脉冲。SPI1ModeMasterBaud Rate5MHzUWB要求CPOLLowCPHA2nd Edge。USART1AsynchronousBaud115200Word Length8Stop Bits1ParityNone。修改启动文件检查startup_stm32f407xx.s是否匹配。F407VE的Flash大小是1MB但启动文件里_estack地址必须设为0x2001C000192KB SRAM末尾否则malloc失败。老版本启动文件可能设成0x20018000要手动改。Keil配置打开.uvprojx工程在“Options for Target”→“Target”页确保Device选STM32F407VETxClock设定为168MHz在“Output”页勾选“Create HEX File”在“User”页“Run User Programs”填C:\ST\STM32CubeMX\bin\STM32CubeMX.exe方便一键打开配置。烧录验证用ST-Link连接开发板Keil点击“Download”烧录。首次烧录后串口助手如XCOM打开COM口波特率115200发送0xAA 0x55 0x03 0x01 0x00 0x00 0x00 0x00 0xXX0x01是读状态指令应收到0xAA 0x55 0x0A 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xXX10字节状态数据含x,y,theta,vx,vy,vtheta。如果收不到先查ST-Link灯是否亮、COM口是否正确、串口助手是否设对参数。注意烧录前务必断开电机我亲眼见过新手烧录时忘记拔电机线程序一跑四个轮子猛转把桌子掀翻。安全第一上电前确认EN引脚悬空或拉低。3.2 全向轮运动学参数标定轮距、轮半径、电机KV值一个都不能错代码里motion_control.c开头有一组宏定义#define WHEEL_BASE_X 200.0f // mm, 左右轮中心距 #define WHEEL_BASE_Y 150.0f // mm, 前后轮中心距 #define WHEEL_RADIUS 50.0f // mm, 轮子半径 #define MOTOR_KV 100.0f // RPM/V, 电机转速常数这四个数就是全向轮能否走直线的命门。它们不是理论值必须实测WHEEL_BASE_X/Y用游标卡尺量底盘实物。不是图纸尺寸不是CAD模型尺寸是装好轮子后的实际中心距。误差超过2mm小车就会斜着走。我建议量三次取平均左前-右前、左后-右后、左前-左后、右前-右后交叉验证。WHEEL_RADIUS别信厂家标称的50mm。拿卷尺绕轮子一圈量周长C再算C/(2*π)。橡胶轮在负载下会变形空载半径和承重半径差1~2mm。实测时把小车四轮悬空用千分尺测轮缘直径。MOTOR_KV这才是最容易错的。KV值决定电压和转速关系。测试方法断开电机与驱动板用万用表直流电压档测驱动板输出PWM对应的平均电压用示波器测占空比×12V更准同时用激光转速计测轮子转速。例如占空比50%时测得电压6.0V转速600RPM则KV 600 / 6.0 100。注意必须在无负载轮子悬空下测带载时KV会下降。标定后把这些值填进代码重新编译烧录。然后做“十字测试”上位机发指令让小车沿X轴走1mY轴走1m再X负向1mY负向1m最后回到起点。理想轨迹是完美十字终点偏移5cm才算合格。如果总是向右偏说明WHEEL_BASE_X偏小如果画弧线说明WHEEL_RADIUS不准如果原地转圈检查四个电机接线顺序是否和代码定义一致左前/右前/右后/左后。3.3 定位数据融合的关键参数Q矩阵和R矩阵的手动调优EKF滤波器的Q过程噪声和R观测噪声矩阵是决定定位平滑度和响应速度的核心。代码里初始值是经验值但必须根据你的硬件和场地微调。Q矩阵调优代表你对模型的信任程度。Q越大滤波器越“相信”自己的预测编码器积分越忽略外部观测UWBQ越小越“相信”UWB但UWB丢帧时容易飘。调优方法先固定RUWB噪声设为0.0025即5cm²把Q设很大如diag([1,1,0.1,10,10,0.1])观察小车静止时定位点是否缓慢漂移说明滤波器太信编码器积分误差累积。逐步减小Q直到漂移消失但UWB更新时定位点仍有明显“跳变”说明滤波器还没完全信任UWB。继续微调目标是UWB正常时定位点平滑无跳变UWB丢失2秒定位点偏移20cm。R矩阵调优代表你对UWB精度的信心。R越大滤波器越“怀疑”UWB收敛慢R越小越“迷信”UWB一丢帧就崩溃。调优方法在开阔场地用UWB测距仪实测基站到Tag的距离记录100次算标准差σ。若σ3cm则R σ² 0.0009。但在复杂环境有金属反射σ可能达10cm此时R应设为0.01。代码里R是3x3矩阵对应x,y,theta。theta的R通常设得比x,y小10倍如0.0001因为IMU的角速度精度远高于UWB的方向精度。调参时用上位机软件如Python写的实时绘图脚本画出x,y轨迹曲线边调边看。记住没有“最优值”只有“最适合你场景的值”。我调试一个仓库AGV最终Q diag([0.05,0.05,0.002,0.5,0.5,0.02])R diag([0.0025,0.0025,0.0001])在叉车频繁经过的金属环境中定位抖动15cm。实操心得调参前先用串口打印原始UWB数据printf(UWB: %d,%d,%d\n, x_uwb, y_uwb, theta_uwb);确认UWB本身是否稳定。如果原始数据就跳变别怪滤波器先查基站安装是否牢固、Tag天线是否被遮挡。4. 实操过程与核心环节实现从零开始跑通底盘控制4.1 硬件连接与上电检查四步确认法避免烧板在烧录代码前必须完成硬件自检。我总结了一套“四步确认法”十年来没烧过一块F4板第一步电源确认用万用表测开发板VCC3.3V和VDDA模拟电源是否稳定在3.3V±0.1V。VDDA不稳会导致ADC采样错误进而让IMU数据失真。测电机驱动板VM电机电源是否为12V或你设计的电压GND是否与开发板共地。不共地是通讯失败的最常见原因。第二步外设供电确认UWB模块测其VDD3.3V和VDDIO1.8V或3.3V看型号电流应在50mA左右。如果电流100mA可能是模块短路。IMU模块测VCC3.3V用示波器看I2C总线上是否有SCL/SDA波形空闲时为高电平。没有波形检查上拉电阻通常4.7kΩ是否焊好。第三步信号线连接确认PWM输出用示波器测TIM3_CH1~CH4引脚上电后应有1kHz方波占空比0%。没有波形查CubeMX里TIM3是否使能、GPIO是否设为复用推挽。编码器输入用手转动轮子测TIM2_CH1/CH2引脚应有AB相正交脉冲。没有脉冲查编码器线序A/B/Z相别接错或TIM2是否设为编码器模式。UWB SPI测SPI1_MOSI/MISO/SCK/CS用逻辑分析仪抓帧确认有数据交互。没有交互查CS引脚是否在每次传输前拉低。第四步电机接线确认按代码定义的顺序接线TIM3_CH1→左前轮CH2→右前轮CH3→右后轮CH4→左后轮。接反会导致运动方向错误。用万用表二极管档测电机两端电阻应为几欧姆。无穷大说明断路0Ω说明短路。上电前用绝缘胶带包住电机引线裸露部分防止短路。完成四步确认才能插ST-Link烧录。烧录后先不接电机用串口助手发0xAA 0x55 0x03 0x01 ...读状态确认MCU能正常响应。一切OK再接电机从小占空比10%开始试转。4.2 运动控制层实操如何让小车走出一条直线让全向轮走直线是检验运动控制层是否正确的黄金标准。代码里motion_control.c的set_target_velocity(float vx, float vy, float vtheta)函数是入口。实操步骤初始化参数在main()里调用motion_init()它会读取EEPROM里保存的标定参数轮距、轮半径等如果EEPROM为空则用默认值。设置目标上位机发指令0xAA 0x55 0x0C 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xXX其中DATA部分是3个32位floatvx100.0f100mm/svy0.0fvtheta0.0f。闭环控制代码在HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)里执行控制循环1kHz。流程如下读取4路编码器当前计数值计算瞬时转速单位RPM。调用inverse_kinematics(vx, vy, vtheta, wheel_speed)计算目标轮速。对每个轮子用PID调节器计算PWM占空比pwm_out Kp*(target_speed - actual_speed) Ki*integral_error Kd*(last_error - error)。将pwm_out限幅0~100%写入__HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, pwm_val)。PID参数调优初始值Kp0.5, Ki0.01, Kd0.05。调优方法先关Ki、Kd只调Kp增大Kp响应变快但过大会振荡轮子嗡嗡响。加入Ki消除稳态误差走1m后停不准但过大会积分饱和导致超调。加入Kd抑制振荡但过大会引入噪声。最终值Kp1.2, Ki0.03, Kd0.1在100mm/s速度下走1m误差2cm。注意PID计算必须在中断里完成且不能用printf或memset等耗时函数。我见过有人在PID里调用HAL_UART_Transmit()结果中断延迟超200μs小车直接失控。所有调试信息用GPIO翻转示波器看时序或用串口DMA异步发送。4.3 定位融合层实操UWB数据接入与EKF运行UWB模块以DWM1001为例通过SPI与F4通信。代码里uwb_driver.c负责底层驱动。UWB数据接入步骤硬件连接DWM1001的SPI_MOSI→F4的PA7MISO→PA6SCK→PA5CS→PA4IRQ→PA0外部中断引脚。初始化uwb_init()函数里先SPI初始化再发AT指令配置DWM1001// 设置为Tag模式 ATMODETAG // 设置UWB频道避开Wi-Fi干扰 ATCHAN5 // 设置测距间隔100ms ATRATE10数据接收DWM1001的IRQ引脚在收到定位数据时拉低触发EXTI0_IRQHandler()。中断里启动SPI DMA接收将数据存入uwb_rx_buffer[64]。数据解析在主循环里检查uwb_rx_flag调用parse_uwb_data()解析JSON格式数据{x:1234,y:5678,z:0,q:99}提取x,y单位毫米q是质量因子0~100q50时丢弃该帧。EKF融合ekf_update()函数每10ms执行一次由SysTick触发。它做两件事预测步用编码器积分更新状态x,y,theta用IMU的gyro_z更新vtheta。更新步用UWB的x,y作为观测量计算卡尔曼增益K修正状态估计。实操中用串口打印printf(Pose: %d,%d,%d\n, (int)ekf_state.x, (int)ekf_state.y, (int)(ekf_state.theta*180/PI));观察数值是否平滑变化。如果跳变剧烈检查UWB原始数据是否稳定、EKF的Q/R是否合理、ekf_state结构体是否被意外修改加volatile关键字保护。4.4 通信协议层实操上位机指令解析与响应对外通信是底盘的“嘴巴和耳朵”。代码里protocol.c实现了完整的指令集。指令帧格式详解Byte0: 0xAA (帧头) Byte1: 0x55 (帧头) Byte2: LEN (数据长度不含帧头和CRC) Byte3: CMD (命令号) Byte4~N-1: DATA (有效载荷) ByteN: CRC (校验和所有字节异或)关键指令实操0x01 读底盘状态上位机发0xAA 0x55 0x03 0x01 0x00 0x00 0x00 0xXX底盘回0xAA 0x55 0x0A 0x01 x0 x1 x2 x3 y0 y1 y2 y3 theta0 theta1 theta2 theta3 vx0 vx1 vx2 vx3 vy0 vy1 vy2 vy3 vtheta0 vtheta1 vtheta2 vtheta3 XX10字节含x,y,theta,vx,vy,vtheta均为32位float。0x02 设置目标速度DATA部分是3个float顺序vx,vy,vtheta。注意字节序float f 100.0f; uint8_t *p (uint8_t*)f;发送p[0],p[1],p[2],p[3]。0x03 清零里程计发0xAA 0x55 0x03 0x03 0x00 0x00 0x00 0xXX底盘将ekf_state.x/y/theta置0并写入EEPROM。0x04 急停发0xAA 0x55 0x03 0x04 0x00 0x00 0x00 0xXX底盘立即关闭所有PWM输出HAL_TIM_PWM_Stop(htim3, TIM_CHANNEL_1)等。上位机开发建议用Python的pyserial库写一个简易控制台import serial, struct ser serial.Serial(COM3, 115200) def send_cmd(cmd, datab): frame b\xAA\x55 bytes([len(data)1]) bytes([cmd]) data crc 0 for b in frame: crc ^ b ser.write(frame bytes([crc])) # 发送走直线指令 send_cmd(0x02, struct.pack(fff, 100.0, 0.0, 0.0))5. 常见问题与排查技巧实录那些年踩过的坑都给你标好了5.1 电机不转或抖动PWM配置与驱动芯片的硬伤问题现象烧录后电机完全不转或轻微抖动发出“滋滋”声或只能单向转反向不转。排查路径查PWM输出用示波器测TIM3_CH1引脚。无波形→ 检查CubeMX里TIM3是否使能、GPIO复用功能是否开启、HAL_TIM_PWM_Start()是否被调用。有波形但占空比不对→ 检查__HAL_TIM_SET_COMPARE()参数是否正确pwm_val是否在0~65535范围内本文还有配套的精品资源点击获取
返回列表