江协科技51单片机学习- p33 PWM呼吸灯和直流驱动电机调速

🚀write in front🚀

🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流

🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​

💬本系列哔哩哔哩江科大51单片机的视频为主以及自己的总结梳理📚

前言:

本文是根据哔哩哔哩网站上"江协科技51单片机"视频的学习笔记,在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了江协科技51单片机教学视频和链接中的内容。

引用:

51单片机-直流电机和PWM-呼吸灯和直流电机调速_单片机20khzpwm调速程序-CSDN博客

51单片机(十五)直流电机驱动(PWM)_直流电机驱动程序-CSDN博客

【嵌入式 · 单片机】一文带你搞懂电机驱动模块_桥式驱动单片机-CSDN博客

51单片机---直流电机(PWM)含源码、小白可入_51单片机_King~30+-GitCode 开源社区

51单片机学习笔记-13直流电机_单片机跟直流电机分别供电-CSDN博客

江协科技 51单片机 直流电机驱动(PWM) 学习笔记_单片机电机驱动电路-CSDN博客

(十五)51单片机------呼吸灯与直流电机调速(PWM)_51单片机pwm控制直流电机-CSDN博客

正文:

0. 🌿概述

在淘宝上购买了江协科技51单片机开发板套件(普中科技STC51单片机A2型号),就上在上一篇博文里说的自己计划学习下江协科技51单片机开发教程,通过STC51单片机这种MCU这种贴近于裸机的开发来增加对于系统硬件层面知识的了解和掌握。

术语和缩略语

|-----|------------------------|--------|
| 缩写 | 全称 | 说明 |
| PWM | Pulse Width Modulation | 脉冲宽度调制 |
| | | |
| | | |

1. 🚀 直流电机介绍

直流电机介绍:

  • 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极,当电极正节的时,电机正传,当电极反接时,电机反转。
  • 直流电机主要由永磁体(定子),线圈(动子)和换向器组成
  • 除直流电机外,常见的电机还有步进电机,舵机,无刷电机,空心杯电机等。

步进电机的介绍

  • 除了直流电机之外还有步进电机,步进电机的结构中,外壳一整圈都分布着磁铁,中间有个转子,转子也是永磁体;通过对不同角度的磁铁进行通电,从而产生不同方向的磁力,改变转子的角度,最终吸引转子朝着特定的方向转动; 其好处就是,转子转动的速度,完全是由我们代码写入的通电时间决定的;

舵机可以输出固定的角度;常用与小车的转向电机;

无刷电机一般在四轴飞行器中会用到;其转速非常快,适合为飞机起飞提供强劲的动力;功率比较大,动力比较足

直流电机是一种功率比较大的负载,直接接在单片机的IO口上肯定是不能直接驱动的二期也可能会损坏单片机的IO口,所以需要再IO和直流电机负载之间加上驱动电路:

常见的驱动电路有两种

  • 第一种是大功率器件直接驱动。这种驱动的特点是它驱动电机只能朝一个方向转,因为它不具有调换电机正反方向的功能
  • 第二种是H桥驱动,H桥驱动方式是电机驱动里面非常有名的一种驱动方式;这种方式可以控制电机正反转;所以如果我们需要驱动电机正反转,那么就选H桥驱动电路;
  • 🌳大功率器件驱动电路,需要通过的电流较大需要功率比较大的器件通常使用达林顿三极管或者MOS三极管,并且电路中需要加一个续流二极管。续流二极管的作用是保护电路的。
  • 🌳为什么需要这个续流二极管哪? 因为电机这种负载都是感性负载原件,驱动的时候需要注意它电感的特性,它可能会感应出很大的电压,那为什么会这样哪?
  • 🌳这里来分析一下:
    当IO控制口输出低电平三极管导通的时候,电流通过直流电机驱动直流电机转动;
    当IO控制口输出高电平,驱动电路断开,由于直流电机是感性负载原件具有电感的特性,在电路断开的瞬间电感具有保持电流不能突变的特性,在电路断开的瞬间,电机中中的电感想要保持电流不发生突变,但是电路中的开关已经断开,阻止了电路中电流的位置,电感为了对抗这种阻力就会感应出很大的电压来克服这种阻力来维持电流,最终就是电感感应出的电压和三极管开关之间的对抗,电机在电路断开的瞬间感应出的高电压可能就会击穿三极管开关。
  • 🌳而如果我们加上了续流二极管,当电极驱动电路断开的瞬间,电机感性器件感应出来的电流就会通过二极管形成回路,从而保护电路中不会感应出高电压。

1.1 ULN2003 驱动电路

1.2H桥驱动

因为整体的形状像是H,所以这个电路被称为H桥;

  • 如果使Q1和Q4两个三极管导通,而Q3和Q2两个三极管断开,那么电流就是从左上角流向右下角,如上图所示,这样电机就会朝着一个方向转动;
  • 如果反过来,Q3和Q2两个三极管导通,Q1和Q4两个三极管断开,则电流就是从右上角流向左下角,如下图所示,这样电机就会朝着另一个方向转动;
  • 通过这种方式控制电机的正反转,因为电流方向既可以向右又可以向左;

因为电机的电流放行既可以往左又可以往右,电机也就没有办法加续流二极管,这就要求我们的晶体管具有很高的耐压特性能够抗的住电机感应出来的高电压,这对器件的要求还是比较高的。

但在实际设计电路中,我们更经常使用集成电路驱动器件,因为这些集成器件是固定的我们可以选择很多的电机驱动芯片,可以自己搜索一下,有了这种芯片之后我们自己就不用自己设计这些复杂的电路,只需要按照芯片手册按照它的要求哪里接电机哪里连输出,这样就可以很轻松的控制电机,如果你对这些电路知识不是很了解的话,那也推荐你去搜索一下电机驱动的芯片,电机驱动的芯片还是非常多的。

2. 🚀PWM介绍

有了电机驱动电路之后,我们在来关心下一个问题,电机调速。如果给电机通上电,电机就会全速运转,如果电机没有通电,电机就会停下来,那么如何让电机保持一个中间的速度哪?这就需要用到PWM(Pulse Width Modulation)进行调速。

什么是PWM:

PWM(脉冲宽度调制),在具有惯性的系统中,可以通过对一系列脉冲进行调制来等效的获得所需要的模拟参量,常应用于电机控速,开关电源等领域。

注意,PWM脉冲宽度调制提到了"在具有惯性的系统中" ,什么事具有惯性的系统哪?例如,电机转动是具有惯性的,当我们短时间断掉电机的电流的时候,点击因为具有惯性它不会立即停还会继续转动,如果我们给电机转1ms停1ms,转1ms停1ms,电机就会因为惯性转动,如果想要电机转动的更快,可以让电机转5ms然后停1ms,转5ms然后停1ms,这样电机就保持一个更快的速度转动。

LED也是具有惯性的系统,当LED点亮之后给LED断电LED灯也不是立马熄灭的它有一个余晖,虽然这个时间不是很长,但它也是立马熄灭的。

2.1 PWM只适用于惯性系统

PWM只能用于惯性系统,不能用于无惯性系统,那么是什么事无惯性系统哪,例如,用PWM给单片机供电,因为单片机不是惯性系统给单片机断电之后单片机立即就停止运行了。

在PWM波形中有几个重要的参数,分别是:频率、占空比以及精度;

  • 🌳频率:是指一个PWM波形周期的倒数;一个周期即为高低电平的总和;
  • 🌳占空比:即高电平占据整个周期的比值,占空比越大,高电平时间越长,其转速越高;
  • 🌳精度:即占空比变化的步距,占空比变化的步距越小,速度改变的每次就越小,其精度就越高;

频率越高越平滑,如果频率过低可能就会出现电机的抖动。

占空比,一个百分比,占空比越大高电平时间越长转速越快。

精度,就是占空比变化的步距,精度越高每次调节的精度就越高。

通常会保持PWM的一个周期的时间是一样的,当然也可以不用保持每个周期的时间是一样的,但是一般情况下我们习惯保持PWM的一个周期的时间是一样的。

3. 🚀PWM程序电机调速程序

3.1 实验:LED呼吸灯(PWM调节的原理)

第一个实验我们做LED呼吸灯的,LED呼吸灯的实验也就是使用PWD亮度调节的原理,通过调整每个周期内LED点亮的占比来调整LED的亮度,最后实现LED灯亮度不断变化形成呼吸灯的效果。

第一个实验,单独点亮LED灯,在循环里不操作LED灯,LED灯一直点亮,可以看到LED灯的亮度是最亮的。

cpp 复制代码
#include <REGX52.H>
#include <INTRINS.H>

sbit LED=P2^0;

void Delay(unsigned int t)
{
	while(t--);
}

void main()
{
	unsigned char Time;
	unsigned char i;
	LED = 0;            //点亮LED灯
	
	while(1)
	{

	}
}

第二个实验,在main函数的While循环里不断的点亮和关闭LED灯,可以看到实验的效果是LED的亮度变暗。

cpp 复制代码
#include <REGX52.H>
#include <INTRINS.H>

sbit LED=P2^0;

void Delay(unsigned int t)
{
	while(t--);
}

void main()
{
	unsigned char Time;
	unsigned char i;
	LED = 0;            //点亮LED灯
	
	while(1)
	{
        LED = 0;       //点亮LED灯   
        LED = 1;       //关闭LED灯
	}
}

第三个对比实验,进一步增大main函数循环中LED灯熄灭的时间,实验的效果是随着LED灯熄灭的时间占比增加,观察实验开发板的结果是LED亮度进一步变暗。

cpp 复制代码
#include <REGX52.H>
#include <INTRINS.H>

sbit LED=P2^0;

void Delay(unsigned int t)
{
	while(t--);
}

void main()
{
	unsigned char Time;
	unsigned char i;
	LED = 0;            //点亮LED灯
	
	while(1)
	{
        LED = 0;       //点亮LED灯   
        LED = 1;       //关闭LED灯
        LED = 1;
        LED = 1; 
        LED = 1;
        LED = 1; 
        LED = 1;
        LED = 1; 
        LED = 1;
        LED = 1; 

	}
}

为了方便控制LED灯点亮和熄灭的时间,我们写了一个'Delay()'延时函数,使用空循环的方式来控制延时的时间长短。保持每个周期的LED灯点亮和熄灭的总时间相等,我们使用数值'100'来控制LED灯点亮和熄灭的一个周期延时的总时间。最后的LED灯呼吸灯的源码如下:

mani.c

cpp 复制代码
#include <REGX52.H>
#include <INTRINS.H>

sbit LED=P2^0;

void Delay(unsigned int t)
{
	while(t--);
}

void main()
{
	unsigned char Time;
	unsigned char i;
	LED = 0;
	
	while(1)
	{
		for(Time=0; Time<100; Time++){
			for(i=0; i<10; i++)		//在每个亮度保持一段时间
			{
				LED = 0;
				Delay(Time);
				LED = 1;
				Delay(100-Time);
			}

		}
		for(Time=100; Time>0; Time--){
			for(i=0; i<10; i++)		//在每个亮度保持一段时间
			{
				LED = 0;
				Delay(Time);
				LED = 1;
				Delay(100-Time);
			}

		}
	}
}

在这个实验里我们在程序的主循环里通过"Delay()"延时时间长短的的方法来控制LED亮灭的(模拟PWM),这种方式的优点非常简单,这种方式有缺点也是非常显而易见的,它需要占用我们的主循环来不断的延时来翻转IO口,那在这一段时间内呼吸灯的整个过程中主循环是没法干其他事情的。

通常我们会将PWM给写到定时器里面去,二线现在稍微高级一点的单片机,像STC的12系列,15系列都会具有硬件的PWM,或者STM32单片机也会就有硬件的PWM,因为不断反转IO口是一种比较简单比较占用CPU的操作,所以通常我们会用硬件来实现PWM,而且硬件实现通常会寄生到定时器里面去,定时器既可以定时还可以兼具PWM的功能,像一些最新的单片机它的定时器都会有输出PWM的功能。

但是我们的STC89C52是没有的,所以我们就用定时器中断来实现这个功能,如果你了解了顶你时期中断的功能,那以后你再去结束硬件的PWM模块的话你会更加方便的理解。

3.2 实验:PWM直流电机调速

使用定时器中断中的计数器值和比较值进行比较,来控制输出高电平还是低电平来控制PWD(脉冲宽度调制)中高电平的占空比来调节直流电机的转速:

  • 🌳在定时器中断里增加计数器的值,并且比较计数器的值和用户设置的比较值,当计数器的值小于用户设置比较值时输出高电平,当计数器的值大于等于比较值时输出低电平。
  • 🌳定时器中断计数器的值自增到大于等于100的时候,计数器的值重新开始从0开始计数。这样保证了一个PWM调制的每个周期的时间长度是一样的。

源码如下:

main.c

cpp 复制代码
#include <REGX52.H>
#include <INTRINS.H>
#include "time0.h"
#include "Nixie.h"
#include "key.h"
#include "delay.h"

sbit Moto=P1^3;
unsigned char PWM_Threshold = 0;
unsigned char KeyNum;

void main()
{
	Timer0_Init();		//定时器初始化
	
	Nixie(1,0);
	
	//Moto = 1;
	
	while(1)
	{
		KeyNum = Key();
		if(KeyNum)
		{
			if(KeyNum == 1)
			{
				Nixie(1,1);
				PWM_Threshold = 30;
			}
			else if(KeyNum == 2)
			{
				Nixie(1,2);
				PWM_Threshold = 60;
			}
			else if(KeyNum == 3)
			{
				Nixie(1,3);
				PWM_Threshold = 90;
			}
			else if(KeyNum == 4)
			{
				Nixie(1,0);
				PWM_Threshold = 0;
			}
		}
	}
}

/**
  * @brief  定时器0中断处理函数模版
  * @param  无
  * @retval 无
  */
void Timer0_Routine(void) interrupt 1
{
	static unsigned int count = 0;
	
	count++;
	if(count < PWM_Threshold){
		Moto = 1;				//ULN2003输出低电平,电机转动
	}
	else{
		Moto = 0;				//ULN2003输出高电平,电机停止
	}
	if(count >= 100)
		count = 0;
	
	//定时器溢出之后需要重新装载
	TH0 = (65535 - 1000) / 256;					//12MHz晶振,12分频
	TL0 = (65535 - 1000) % 256 + 1; 			//
}

4. PWM直流电机调速实验结果

PWM直流电机调速实验结果,如下:

相关推荐
安和昂1 小时前
【iOS】UICollectionView的学习
学习·ios·cocoa
HelpLook HelpLook1 小时前
高新技术行业中的知识管理:关键性、挑战、策略及工具应用
人工智能·科技·aigc·客服·知识库搭建
Mephisto.java1 小时前
【大数据学习 | Spark-Core】广播变量和累加器
大数据·学习·spark
Liang_GaRy1 小时前
云计算-SRE-架构师-心得
学习
ThreeYear_s2 小时前
FPGA学习-FFT变换-解决频率低信号进行FFT运算的取点问题
学习·fpga开发
zmd-zk2 小时前
flink学习(6)——自定义source和kafka
大数据·hadoop·学习·flink·kafka·实时
赔罪2 小时前
C 语言变量说明符
c语言·开发语言·c++·学习·算法·objective-c
xiandong202 小时前
241123_基于MindSpore学习Bert
人工智能·学习·bert
@小博的博客2 小时前
C++初阶学习 第十二弹——stack与queue的介绍和使用
开发语言·数据结构·c++·学习
小A1593 小时前
STM32完全学习——使用标准库完成PWM输出
stm32·单片机·学习