基于 STM32 的四路 PWM 控制智能小车运动的模块化控制程序

今天简单实现一下,智能小车的运动模块程序.

实现小车的前进,后退,转向,就是通过电机IO口输出PWM,控制电机转速,实现上述功能.

主函数

复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "car.h"
#include "Key.h"




uint8_t i;


int main(void)
{
robot_Init();    // 机器人初始化
Key_Init();      // 按键初始化


while (1)
	{
if(Key_GetNum() == 1)
		{
		 makerobo_run(70,5000);//前进1S
		 makerobo_brake(500);//停止0.5S
		 makerobo_back(70,5000); //后退1s
   	}


	}
}

key.c函数详解

复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"


void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);


	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}


uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0;
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) == 0)
	{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) == 0);
Delay_ms(20);
		KeyNum = 1;
	}
return KeyNum;
}

首先将PA15初始化为上拉输入模式

按键的逻辑:

  • 你只有在 :"检测到按下 → 消抖 → 等待松开 → 再次消抖"完成之后,才会返回 1
  • 如果你一直按住按键,这个函数的 while 会阻塞,直到你松开才结束。

PWM.函数详解

复制代码
#include "stm32f10x.h"                  // Device header


void PWM_Init(void)
{
	  GPIO_InitTypeDef GPIO_InitStructure;
      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
      TIM_OCInitTypeDef TIM_OCInitStructure;


      //使能定时器TIM4时钟,注意TIM4时钟为APB1
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
      //使能PWM输出GPIO时钟
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); 


      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//定时器TIM4的PWM输出通道1,TIM4_CH1
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO


      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//定时器TIM4的PWM输出通道2,TIM4_CH2
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO


      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//定时器TIM4的PWM输出通道3,TIM4_CH3
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO


      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//定时器TIM4的PWM输出通道4,TIM4_CH4
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO


      TIM_TimeBaseStructure.TIM_Period = 100 - 1;//arr;//自动重装值
      TIM_TimeBaseStructure.TIM_Prescaler =36 - 1;//psc; //时钟预分频数
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式
      TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //初始化TIM4


      //初始化TIM4_CH1的PWM模式
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//??PWM??1
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//??????
      TIM_OCInitStructure.TIM_Pulse = 0; //
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//??????
      TIM_OC1Init(TIM4, &TIM_OCInitStructure);//???TIM4_CH1


      //初始化TIM4_CH2的PWM模式
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
       //TIM4_CH2初始化,OC2
      TIM_OC2Init(TIM4, &TIM_OCInitStructure);


       //初始化TIM4_CH3的PWM模式
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OC3Init(TIM4, &TIM_OCInitStructure);


      //初始化TIM4_CH4的PWM模式
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OC4Init(TIM4, &TIM_OCInitStructure);


      //使能4个通道的预装载寄存器
      TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC1
      TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC2
      TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC3
      TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC4
      TIM_ARRPreloadConfig(TIM4, ENABLE); //使能重装寄存器


      TIM_Cmd(TIM4, ENABLE);//使能定时器TIM4,准备工作 
}

这段代码是 STM32 上使用 定时器 TIM4 产生 四路 PWM 信号 的完整初始化过程。用于控制四个电机通道

分段详解

① 开启时钟

复制代码
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);       

// 开启 TIM4 时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);      

// 开启 GPIOB 时钟
  • TIM4 属于 APB1 总线外设,需要使能其时钟。
  • GPIOB 属于 APB2 总线外设,也要开启时钟。

② 初始化 GPIO:PB6~PB9 为复用推挽输出

复制代码
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  

// 复用功能推挽输出(用于 PWM)

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

// I/O 速度选择为 50MHz

然后四次初始化:

  • GPIO_Pin_6:对应 TIM4_CH1
  • GPIO_Pin_7:对应 TIM4_CH2
  • GPIO_Pin_8:对应 TIM4_CH3
  • GPIO_Pin_9:对应 TIM4_CH4

🧠 PWM 信号必须由"复用功能引脚"输出。


③ 配置定时器基本参数(频率、模式)

复制代码
复制代码
TIM_TimeBaseStructure.TIM_Period = 100 - 1;//arr;//自动重装值
TIM_TimeBaseStructure.TIM_Prescaler =36 - 1;//psc; //时钟预分频数
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //初始化TIM4
复制代码

计数频率计算公式:

PWM计数频率 = 主频 / (PSC + 1) = 72MHz / 36 = 2MHz

PWM输出频率 = 计数频率 / (ARR + 1) = 2MHz / 100 = 20KHz

即:输出一个周期为 20KHz 的 PWM 波形,占空比由后面设置的 CCR 值决定。


④ 配置每个通道的 PWM 模式(4次)

复制代码
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;       // PWM 模式1

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能

TIM_OCInitStructure.TIM_Pulse = 0;                       // 初始脉宽占空比 = 0%

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;   // 高电平有效

然后依次配置:

  • TIM_OC1Init(TIM4, &TIM_OCInitStructure);:CH1(PB6)
  • TIM_OC2Init(...):CH2(PB7)
  • TIM_OC3Init(...):CH3(PB8)
  • TIM_OC4Init(...):CH4(PB9)

⑤ 使能预装载寄存器(可动态更新 PWM)

复制代码
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);

TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);

TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);

TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);

TIM_ARRPreloadConfig(TIM4, ENABLE);  // 使能自动重装载寄存器

预装载作用:

  • 修改 PWM 占空比不会立刻生效,而是到下一个计数周期才会更新,防止中间跳变问题

⑥ 启动定时器

复制代码
TIM_Cmd(TIM4, ENABLE);

TIM4 开始工作,四路 PWM 信号就开始输出了!

智能小车的运动控制函数

就是控制智能小车的四个电机通道的PWM,控制小车的前进,转向,后退

复制代码
#include "stm32f10x.h"                  // Device header
#include "PWM.h"
#include "Delay.h"
// 机器人初始化
void robot_Init(void)
{
  PWM_Init(); 
}


//四路PWM控制速度调节
void robot_speed(uint8_t left1_speed,uint8_t left2_speed,uint8_t right1_speed,uint8_t right2_speed)
{	
      TIM_SetCompare1(TIM4,left1_speed);
      TIM_SetCompare2(TIM4,left2_speed);
      TIM_SetCompare3(TIM4,right1_speed);
      TIM_SetCompare4(TIM4,right2_speed);
}


// 基本的运动函数
// 机器人前进
void makerobo_run(int8_t speed,uint16_t time)  //前进函数
{
      if(speed > 100)
			{
				speed = 100;
			}
      if(speed < 0)
			{
				speed = 0;
			}
	    robot_speed(speed,0,speed,0);
            Delay_ms(time);                 // 时间为毫秒
            robot_speed(0,0,0,0);           // 机器人停止


}


void makerobo_brake(uint16_t time) //刹车函数
{
robot_speed(0,0,0,0);     // 电机停止 
Delay_ms(time);          // 时间为毫秒   
}


void makerobo_Left(int8_t speed,uint16_t time) //左转函数
{
	    if(speed > 100)
			{
				speed = 100;
			}
if(speed < 0)
			{
				speed = 0;
			}
         robot_speed(0,0,speed,0);
         Delay_ms(time);                 //时间为毫秒  
	  robot_speed(0,0,0,0);           // 机器人停止


}


void makerobo_Spin_Left(int8_t speed,uint16_t time) //左旋转函数
{
		  if(speed > 100)
			{
				speed = 100;
			}
                 if(speed < 0)
			{
				speed = 0;
			}  
    robot_speed(0,speed,speed,0);
    Delay_ms(time);                    //时间为毫秒 
    robot_speed(0,0,0,0);           // 机器人停止			
}


void makerobo_Right(int8_t speed,uint16_t time) //右转函数
{
	    if(speed > 100)
			{
				speed = 100;
			}
           if(speed < 0)
			{
				speed = 0;
			}
         robot_speed(speed,0,0,0);
         Delay_ms(time);                 //时间为毫秒  
	  robot_speed(0,0,0,0);           // 机器人停止


}


void makerobo_Spin_Right(int8_t speed,uint16_t time) //右旋转函数
{
		  if(speed > 100)
			{
				speed = 100;
			}
                 if(speed < 0)
			{
				speed = 0;
			}  
            robot_speed(speed,0,0,speed);
            Delay_ms(time);                    //时间为毫秒 
            robot_speed(0,0,0,0);           // 机器人停止			
}


void makerobo_back(int8_t speed,uint16_t time)  //后退函数
{
      if(speed > 100)
			{
				speed = 100;
			}
      if(speed < 0)
			{
				speed = 0;
			}
	    robot_speed(0,speed,0,speed);
            Delay_ms(time);                 // 时间为毫秒
            robot_speed(0,0,0,0);           // 机器人停止


}

分段详解

一、初始化函数

复制代码
void robot_Init(void)

PWM_Init();

// 调用 PWM 初始化函数(定义在 PWM.c 中)

作用:配置好 TIM4 输出四路 PWM,控制机器人四个电机的速度。


二、电机速度设置函数

复制代码
robot_speed(uint8_t left1_speed,uint8_t left2_speed,uint8_t right1_speed,uint8_t right2_speed)

TIM_SetCompare1(TIM4,left1_speed);   

// 设置PWM通道1输出占空比

TIM_SetCompare2(TIM4,left2_speed);   

// 设置PWM通道2

TIM_SetCompare3(TIM4,right1_speed);  

// 设置PWM通道3

TIM_SetCompare4(TIM4,right2_speed);  

// 设置PWM通道4

控制四个电机的转动速度,分别为:

left1 左前

left2 左后

right1 右前

right2 右后


三、基本运动函数

makerobo_run(int8_t speed,uint16_t time)

------ 前进
robot_speed(speed,0, speed,0);// 左前电机和右前电机正转
Delay_ms(time);// 持续运动一段时间
robot_speed(0,0,0,0);// 停止运动


makerobo_back(int8_t speed,uint16_t time)

------ 后退
robot_speed(0, speed,0, speed);// 左后、右后电机正转,实现后退
Delay_ms(time);
robot_speed(0,0,0,0);


makerobo_Left(int8_t speed,uint16_t time)

------ 向左转弯
robot_speed(0,0, speed,0);// 仅右前电机动,车向左偏转
Delay_ms(time);
robot_speed(0,0,0,0);


makerobo_Right(int8_t speed,uint16_t time)

------ 向右转弯
robot_speed(speed,0,0,0);// 仅左前电机动,车向右偏转
Delay_ms(time);robot_speed(0,0,0,0);


四、原地旋转函数

makerobo_Spin_Left(int8_t speed,uint16_t time) ------ 原地左旋转

robot_speed(0, speed, speed,0);// 左后电机反转(速度为正,装反电源),右前电机正转
// 实现两边相反转动,原地逆时针旋转
Delay_ms(time);
robot_speed(0,0,0,0);


makerobo_Spin_Right(int8_t speed, uint16_t time) ------ 原地右旋转

robot_speed(speed,0,0, speed);// 左前、右后电机正转,原地顺时针旋转
Delay_ms(time);
robot_speed(0,0,0,0);


五、刹车函数

复制代码
makerobo_brake(uint16_t time)
robot_speed(0, 0, 0, 0); 
// 所有电机停止
Delay_ms(time);          
// 刹车等待时间
相关推荐
智者知已应修善业2 小时前
【51单片机用数码管显示流水灯的种类是按钮控制数码管加一和流水灯】2022-6-14
c语言·经验分享·笔记·单片机·嵌入式硬件·51单片机
智商偏低8 小时前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen9 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森11 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白11 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D12 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术15 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt15 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘16 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang16 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c