STM32+L298N+PWM可调速小车(四驱)

完整工程代码已放到百度网盘,链接如下:

链接:https://pan.baidu.com/s/16zcnfLt2iYlrDdN-N6tKbA 
提取码:dn54

一、L298N电机驱动板

在这里插入图片描述
电源引脚

VCC 外接直流电源引脚,电压范围在5~35V之间
GND GND是接地引脚,连接到电源负极
5V 驱动芯片内部逻辑供电引脚,如果安装了5V跳帽,则此引脚可输出5V电压,为微控板或其他电路提供电力供给,如果拔掉5V跳帽,则需要独立外接5V电源

控制引脚

  1. IN1 & IN2 电机驱动器A的输入引脚,控制电机A转动及旋转角度
    IN1输入高电平HIGH,IN2输入低电平LOW,对应电机A正转
    IN1输入低电平LOW,IN2输入高电平HIGH,对应电机A反转
    IN1、IN2同时输入高电平HIGH或低电平LOW,对应电机A停止转动
    调速就是改变IN1、IN2高电平的占空比(需拔掉ENA处跳帽)

  2. IN3 & IN4 电机驱动器B的输入引脚,控制电机B转动及旋转角度
    IN3输入高电平HIGH,IN4输入低电平LOW,对应电机B正转
    IN3输入低电平LOW,IN4输入高电平HIGH,对应电机B反转
    IN3、IN4同时输入高电平HIGH或低电平LOW,对应电机B停止转动
    调速就是改变IN3、IN4高电平的占空比(需拔掉ENB处跳帽)

输出引脚

  1. OUT1 & OUT2 电机驱动器A的输出引脚,接直流电机A或步进电机的A+和A-
  2. OUT3 & OUT3 电机驱动器B的输出引脚,接直流电机B或步进电机的B+和B-

调速控制引脚

  1. ENA 电机A调速开关引脚,拔掉跳帽,使用PWM对电机A调速,插上电机A高速运行
  2. ENB 电机B调速开关引脚,拔掉跳帽,使用PWM对电机B调速,插上电机B高速运行

OUT1、OUT2和OUT3、OUT4之间分别接两个直流电机Motor1、Motor2,IN1、IN2、IN3、IN4引脚从单片机接入控制电平,控制电机的正反转,ENA、ENB接控制使能端,控制电机调速,L298N控制逻辑关系图如下:
在这里插入图片描述


二、STM32的PWM输出

1、通用定时器(TIM2 ~ TIM5)
每个定时都有 4个独立通道作为输出
在这里插入图片描述
2、高级控制定时器(TIM1 & TIM8)
该款定时器可产生7路 PWM输出:
在这里插入图片描述
3.STM32F1的TIM3输出引脚
本文用到STM32F1的TIM3的通道1~4,下面对TIM3的引脚作简要介绍:
本实验选择没有重映像的四个引脚,即PA6、PA7、PB0、PB1(有无重映像会在TIM3初始化部分的代码有所体现)

三、硬件连接

本设计用到两个L298N驱动板,四个小黄电机,一块STM32F103ZET6开发板
第一块L298N接左前电机和左后电机:
ENA—PA6,ENB—PA7
左前电机:IN1—PB7,IN2—PB6
左后电机:IN3—PB9,IN4—PB2

第二块L298N接右前电机和右后电机:
ENA—PB0,ENB—PB1
左前电机:IN1—PB13,IN2—PB12
左后电机:IN3—PB15,IN4—PB14

四、主要代码

timer.c

#include "timer.h"
#include "led.h"
#include "usart.h"

void TIM3_Int_Init(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 

	TIM_TimeBaseStructure.TIM_Period = arr; 
	TIM_TimeBaseStructure.TIM_Prescaler =psc;  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); 
	TIM_Cmd(TIM3, ENABLE);  							 
}

//TIM3 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数

void TIM3_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); 
	
		//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //这句话是正点原子官方例程“PWM输出实验”中给的,目的是Timer3部分重映射,将TIM3_CH2->PB5。本实验不用重映像


//设置PA6和PA7为复用输出功能,输出TIM3 CH1和TIM3 CH2的PWM脉冲波形
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 |GPIO_Pin_6; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

//设置PB0和PB1为复用输出功能,输出TIM3 CH3和TIM3 CH4的PWM脉冲波形
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
//初始化TIM3	
	TIM_TimeBaseStructure.TIM_Period = arr;
	TIM_TimeBaseStructure.TIM_Prescaler =psc; 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 
	
	//初始化TIM3 Channel 1 PWM	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; 
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
	TIM_OC1Init(TIM3, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
 
 	//初始化TIM3 Channel 2 PWM	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
	TIM_OC2Init(TIM3, &TIM_OCInitStructure); 
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); 
 
  	//初始化TIM3 Channel 3 PWM	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
	TIM_OC3Init(TIM3, &TIM_OCInitStructure);  
	TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); 
 
   	//初始化TIM3 Channel 4 PWM	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; 
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
	TIM_OC4Init(TIM3, &TIM_OCInitStructure); 
	TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); 
	
	TIM_ARRPreloadConfig(TIM3,ENABLE);//使能自动重装载寄存器,arr的预装载
	TIM_Cmd(TIM3, ENABLE);//使能TIM3 
}

timer.h

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"

void TIM3_Int_Init(u16 arr,u16 psc);
void TIM3_PWM_Init(u16 arr,u16 psc);
#endif

MTR_GPIO.c(电机驱动部分)

#include "MTR_GPIO.h"

//刹车
void MTR_CarBrakeAll(void){
	MTR1_BRAKE;
	MTR2_BRAKE;
	MTR3_BRAKE;
	MTR4_BRAKE;
}

//右转
void MTR_CarRight(void){
	MTR1_CW;
	MTR2_CW;
	MTR3_CCW;
	MTR4_CCW;
}

//左转
void MTR_CarLeft(void){
	MTR1_CCW;
	MTR2_CCW;
	MTR3_CW;
	MTR4_CW;
}

//后退
void MTR_CarBack(void){
	MTR1_CCW;
	MTR2_CCW;
	MTR3_CCW;
	MTR4_CCW;
}

//前进 
void MTR_CarForward(void){
	MTR1_CW;
	MTR2_CW;
	MTR3_CW;
	MTR4_CW;
}

void MTR_GPIOInit(void){
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(MTR1_GPIO_CLK|MTR2_GPIO_CLK|MTR3_GPIO_CLK|MTR4_GPIO_CLK,ENABLE);
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;


	//电机1
	GPIO_InitStructure.GPIO_Pin = MTR1_GPIO_PIN;
	GPIO_Init(MTR1_GPIO_PORT, &GPIO_InitStructure);
	//电机2
	GPIO_InitStructure.GPIO_Pin = MTR2_GPIO_PIN;
	GPIO_Init(MTR2_GPIO_PORT, &GPIO_InitStructure);
	//电机3
	GPIO_InitStructure.GPIO_Pin = MTR3_GPIO_PIN;
	GPIO_Init(MTR3_GPIO_PORT, &GPIO_InitStructure);
	//电机4
	GPIO_InitStructure.GPIO_Pin = MTR4_GPIO_PIN;
	GPIO_Init(MTR4_GPIO_PORT, &GPIO_InitStructure);
}

MTR_GPIO.h

#ifndef __MTR_GPIO_H
#define __MTR_GPIO_H

#include "stm32f10x.h"


#define MTR1_GPIO_PORT		GPIOB
#define MTR1_GPIO_CLK 	    RCC_APB2Periph_GPIOB
#define MTR1_GPIO_PIN		GPIO_Pin_6|GPIO_Pin_7
#define MTR1_CW				{GPIO_ResetBits(MTR1_GPIO_PORT,GPIO_Pin_6);GPIO_SetBits(MTR1_GPIO_PORT,GPIO_Pin_7);}
#define MTR1_CCW			{GPIO_SetBits(MTR1_GPIO_PORT,GPIO_Pin_6);GPIO_ResetBits(MTR1_GPIO_PORT,GPIO_Pin_7);}
#define MTR1_BRAKE			GPIO_ResetBits(MTR1_GPIO_PORT,MTR1_GPIO_PIN);

#define MTR2_GPIO_PORT    	GPIOB
#define MTR2_GPIO_CLK 	    RCC_APB2Periph_GPIOB
#define MTR2_GPIO_PIN		GPIO_Pin_2|GPIO_Pin_9
#define MTR2_CW				{GPIO_ResetBits(MTR2_GPIO_PORT,GPIO_Pin_2);GPIO_SetBits(MTR2_GPIO_PORT,GPIO_Pin_9);}
#define MTR2_CCW			{GPIO_SetBits(MTR2_GPIO_PORT,GPIO_Pin_2);GPIO_ResetBits(MTR2_GPIO_PORT,GPIO_Pin_9);}
#define MTR2_BRAKE			GPIO_ResetBits(MTR2_GPIO_PORT,MTR2_GPIO_PIN);

#define MTR3_GPIO_PORT    	GPIOB
#define MTR3_GPIO_CLK 	    RCC_APB2Periph_GPIOB
#define MTR3_GPIO_PIN		GPIO_Pin_12|GPIO_Pin_13
#define MTR3_CW				{GPIO_ResetBits(MTR3_GPIO_PORT,GPIO_Pin_12);GPIO_SetBits(MTR3_GPIO_PORT,GPIO_Pin_13);}
#define MTR3_CCW			{GPIO_SetBits(MTR3_GPIO_PORT,GPIO_Pin_12);GPIO_ResetBits(MTR3_GPIO_PORT,GPIO_Pin_13);}
#define MTR3_BRAKE			GPIO_ResetBits(MTR3_GPIO_PORT,MTR3_GPIO_PIN);

#define MTR4_GPIO_PORT    	GPIOB
#define MTR4_GPIO_CLK 	    RCC_APB2Periph_GPIOB
#define MTR4_GPIO_PIN		GPIO_Pin_14|GPIO_Pin_15
#define MTR4_CW				{GPIO_ResetBits(MTR4_GPIO_PORT,GPIO_Pin_14);GPIO_SetBits(MTR4_GPIO_PORT,GPIO_Pin_15);}
#define MTR4_CCW			{GPIO_SetBits(MTR4_GPIO_PORT,GPIO_Pin_14);GPIO_ResetBits(MTR4_GPIO_PORT,GPIO_Pin_15);}

#define MTR4_BRAKE			GPIO_ResetBits(MTR4_GPIO_PORT,MTR4_GPIO_PIN);

void MTR_CarBrakeAll(void);
void MTR_CarRight(void);
void MTR_CarLeft(void);
void MTR_CarBack(void);
void MTR_CarForward(void);
void MTR_GPIOInit(void);

#endif

main.c

#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
#include "MTR_GPIO.h"

//主函数改编自正点原子“PWM输出实验”,驱动四个电机输出PWM信号即电机转速可变
 int main(void)
 {		
 	u16 led0pwmval=0;
	u8 dir=1;	
	delay_init();	    	 	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 
	uart_init(115200);
 	TIM3_PWM_Init(899,0);	 //不分频,PWM频率=72000000/900=80Khz
   MTR_GPIOInit();	
	 while(1)
	{
 		delay_ms(10);	 
		if(dir)led0pwmval++;
		else led0pwmval--;
		MTR_CarForward();
 		if(led0pwmval>800)dir=0;
		if(led0pwmval==0)dir=1;										 
		TIM_SetCompare1(TIM3,led0pwmval);	
		TIM_SetCompare2(TIM3,led0pwmval);	
		TIM_SetCompare3(TIM3,led0pwmval);	
		TIM_SetCompare4(TIM3,led0pwmval);	
	}	 
 }


  • 91
    点赞
  • 743
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 47
    评论
1.时钟源 外部时钟 2.GPIO (实验:点亮LED灯,获取引脚的电平高低,将对应引脚置高置低)。 3.PWM-脉宽调制 主要是调节占空比(在小车中用来实现小车的加减速)。 4.TIMX定时器 5.红外遥控 主要运用了EXTI(外部中断/事件控制器),系统延时(系统滴答定时器SysTick)。 6.超声波避障 了解了超声波工作的原理,主要运用了TIM2定时器(用来定时测距),GPIO口。 7.红外探测 通过对障碍物和光的感应来返回电平的状态,从而达到避障和巡线效果。 8.测速码盘 (通过检测码盘上的凹槽数来获取脉冲数,通过计算公式得到小车当前速度) TIM3定时器(定时测速)。 9.PID算法 为了使小车的速度更快的达到目标值,获取更稳定的速度。 10.系统的使用 我们在小车内加入系统,对小车的数据获取,状态实现任务化,使小车内的运作更加有序。我们主要使用μC/OS-II系统内核来实现系统。在实现过程中,我们了解了系统的任务调度以及任务运行和处理器之间的关系(多任务同时运行)。 μC/OS-II内核中的任务控制块,任务状态,以及多任务和任务的优先级类似操作系统中的进程操作。 11.任务间的通信 主要用到信号量(主要就是PV操作 P操作:占用资源。V操作:释放资源);邮箱(邮箱可以使一个任务或者中断服务子程序向另一个任务发送指针型的变量,通常该指针指向包含了“消息”特定的数据结构)。
L298N是一种常用的直流电机驱动芯片,它可以用来控制直流电机的转速和方向。下面是一个使用L298N进行PWM调速的代码示例: ```c int ENA = 9; // 使能A引脚 int IN1 = 8; // 输入1引脚 int IN2 = 7; // 输入2引脚 void setup() { pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); } void loop() { // 设置占空比为50%的PWM信号 analogWrite(ENA, 128); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); delay(2000); // 延迟2秒 // 设置占空比为25%的PWM信号 analogWrite(ENA, 64); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); delay(2000); // 延迟2秒 } ``` 上述代码中,我们使用了一个PWM信号来控制电机的转速。首先,我们通过analogWrite函数将PWM信号输出到ENA引脚,占空比为0-255之间的值。其中,占空比为0表示停止电机,占空比为255表示全速旋转。然后,我们通过digitalWrite函数设置IN1和IN2引脚的电平来确定电机的转动方向。 在循环中,我们先设置占空比为50%的PWM信号,将电机设置为正向转动2秒钟,然后设置占空比为25%的PWM信号,将电机继续正向转动2秒钟。你可以根据实际需求修改占空比和延迟时间来调整电机的转速和运行时间。 需要注意的是,以上代码只是一个简单的示例,实际应用中可能还需要考虑保护电路、输入检测等其他因素。同时,根据不同的硬件连接方式和引脚定义,代码中的引脚号可能需要进行相应的修改。请根据你的具体情况进行调整。
评论 47
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓shuo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值