• 【51单片机】直流电机驱动(PWM)(江科大)


    1.直流电机介绍

    · 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极,当电极正接时,电机正转,当电极反接时,电机反转
    · 直流电机主要由永磁体(定子)、线圈(转子)和换向器组成
    · 除直流电机外,常见的电机还有步进电机、舵机、无刷电机、空心杯电机等
    在这里插入图片描述

    2.电机驱动

    电机的驱动无法直接使用IO口来进行驱动,所以用驱动电路来进行驱动,如大功率器件直接驱动,H桥驱动。本开发板直接用ULN2300来进行驱动,只需将电机的一端接VCC,另一端接OUT1就可。此时,在IN1输入1,则OUT1输出0,电机旋转;在IN1输入0,则OUT1输出1,电机不旋转
    在这里插入图片描述
    在这里插入图片描述

    3.PWM介绍

    · PWM(Pulse Width Modulation)即脉冲宽度调制,在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速、开关电源等领域
    · PWM重要参数:
    频率=1/Ts
    占空比=ToN/Ts
    精度=占空比变化步距

    通过设置不同的占比来进行控制
    通常一个周期的时间是相同的
    在这里插入图片描述

    4.LED呼吸灯

    LED的IO口为0时,LED亮,为1时,LED灭;10口为1时,LED灯不会立刻熄灭,而是缓慢熄灭(具有惯性)

    所以可以通过控制高电平和低电平的宽度即占空比来控制LED灯的亮度

    通过逐步增加高电平宽度,减少低电平宽度,可使得LED灯越来越暗;反之,逐步增加低电平宽度,减少高电平宽度,可使得LED灯越来越亮

    #include 
    
    sbit LED=P2^0;
    
    void Delay(unsigned int t)
    {
    	while(t--);
    }
    
    void main()
    {
    	unsigned char Time,i;
    	while(1)
    	{
    		for(Time=0;Time<100;Time++)		//改变亮灭时间,由暗到亮
    		{
    			for(i=0;i<20;i++)			//计次延时
    			{
    				LED=0;					//LED亮
    				Delay(Time);			//延时Time
    				LED=1;					//LED灭
    				Delay(100-Time);		//延时100-Time
    			}
    		}
    		for(Time=100;Time>0;Time--)		//改变亮灭时间,由亮到暗
    		{
    			for(i=0;i<20;i++)			//计次延时
    			{
    				LED=0;					//LED亮
    				Delay(Time);			//延时Time
    				LED=1;					//LED灭
    				Delay(100-Time);		//延时100-Time
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    此方案简单,但是需要占用主循环,不断翻转IO口延时,主循环无法做其他事情
    优化
    LED呼吸灯:定时器版

    在实际使用中,都会用定时器来产生PWM,而本51单片机的芯片不具备这一功能,所以用软件来模拟这个功能

    产生PWM方法:
    在这里插入图片描述
    在这里插入图片描述
    通过自增的计数器来和预先设定的比较值来进行比较,计数器的值小于比较值时,输出0,反之输出1,也可以相反。

    先将定时器修改为100us触发一次(电机的频率一般在10K到20KHz之间)

    #include 
    #include "Key.h"
    #include "Timer.h"
    #include "Nixie.h"
    
    sbit LED = P2^0;
    
    //计数值和比较值,用于输出PWM
    unsigned char Counter, Compare;
    unsigned char KeyNum, Speed;
    
    void main()
    {
    	Timer0Init();
    	Compare = 5;
    	
    	while(1)
    	{
    		KeyNum = GetKeyNum();
    		if(KeyNum == 1)
    		{
    			Speed++;
    			Speed %= 4;
    			if(Speed==0){Compare=0;}	//设置比较值,改变PWM占空比
    			if(Speed==1){Compare=50;}
    			if(Speed==2){Compare=75;}
    			if(Speed==3){Compare=100;}
    		}
    		NixieShowNum(1,Speed);
    	}
    }
    
    //定时器0的中断处理函数
    void Timer0_Routine() interrupt 1
    {
    	TL0 = 0x9C;		//设置定时初值
    	TH0 = 0xFF;		//设置定时初值
    	Counter++;
    	Counter %= 100;
    	if(Counter < Compare)
    	{
    		LED = 0;
    	}
    	else
    	{
    		LED = 1;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    5.直流电机调速

    在原代码的基础上改个IO口就行(根据上述分析,Motor=1旋转)

    #include 
    #include "Delay.h"
    #include "Key.h"
    #include "Nixie.h"
    #include "Timer0.h"
    
    sbit Motor=P1^0;
    
    unsigned char Counter,Compare;	//计数值和比较值,用于输出PWM
    unsigned char KeyNum,Speed;
    
    void main()
    {
    	Timer0_Init();
    	while(1)
    	{
    		KeyNum=Key();
    		if(KeyNum==1)
    		{
    			Speed++;
    			Speed%=4;
    			if(Speed==0){Compare=0;}	//设置比较值,改变PWM占空比
    			if(Speed==1){Compare=50;}
    			if(Speed==2){Compare=75;}
    			if(Speed==3){Compare=100;}
    		}
    		Nixie(1,Speed);
    	}
    }
    
    void Timer0_Routine() interrupt 1
    {
    	TL0 = 0x9C;		//设置定时初值
    	TH0 = 0xFF;		//设置定时初值
    	Counter++;
    	Counter%=100;	//计数值变化范围限制在0~99
    	if(Counter<Compare)	//计数值小于比较值
    	{
    		Motor=1;		//输出1
    	}
    	else				//计数值大于比较值
    	{
    		Motor=0;		//输出0
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    分布式.幂等性
    树状数组模板2【区间修改,单点询问】(线段树)
    希望六月:参加阿里云 PolarDB 与「函数计算」动手活动,送博客园T恤
    【linux基础(六)】Linux中的开发工具(中)--gcc/g++
    我的创作纪念日
    leetcode-218.天际线问题
    14天刷爆LeetCode算法学习计划——Day02双指针(1)
    angular 在vscode 下的hello world
    判断一个数是否是回文(python和c#)
    开仓风险计算器.xlsx(可计算:名义价值、最大资金亏损、开仓所需保证金、开仓资金杠杆、最小逐仓保证金、U本位需开张数、币本位需开张数)
  • 原文地址:https://blog.csdn.net/2302_80796399/article/details/136110982