【Protues仿真】基于AT89C52单片机的舵机和直流电机控制

目录

[1 PWM信号](#1 PWM信号)

[1.1 三个最基本的量](#1.1 三个最基本的量)

[1.1.1 周期 T(Period)](#1.1.1 周期 T(Period))

[1.1.2脉冲宽度 Th(High Time)](#1.1.2脉冲宽度 Th(High Time))

[1.1.3占空比 D(Duty Cycle)](#1.1.3占空比 D(Duty Cycle))

[1.2 为什么要用 PWM](#1.2 为什么要用 PWM)

[1.3 关键参数对照表](#1.3 关键参数对照表)

[1.4单片机里产生 PWM 的四种套路](#1.4单片机里产生 PWM 的四种套路)

[1.4.1 纯软件延时](#1.4.1 纯软件延时)

[1.4.2 定时器中断计数](#1.4.2 定时器中断计数)

[1.4.3 定时器硬件 PWM 模块](#1.4.3 定时器硬件 PWM 模块)

[1.4.4 专用 PWM IC 或驱动板](#1.4.4 专用 PWM IC 或驱动板)

[1.5 计算示例(AT89C52,12 MHz,定时器 0 模式 1)](#1.5 计算示例(AT89C52,12 MHz,定时器 0 模式 1))

[1.6 常见踩坑提醒](#1.6 常见踩坑提醒)

[1.7 一句话总结](#1.7 一句话总结)

[2 AT89C52单片机实现舵机控制](#2 AT89C52单片机实现舵机控制)

[2.1 舵机专用 PWM(50 Hz)](#2.1 舵机专用 PWM(50 Hz))

[2.2 电路原理图](#2.2 电路原理图)

[2.3 控制程序](#2.3 控制程序)

[3 AT89C52单片机实现直流电机控制](#3 AT89C52单片机实现直流电机控制)

3.1L298N电机驱动

3.1.1它到底是什么

3.1.2引脚速记

[3.1.3控制逻辑真值表(电机 A 为例)](#3.1.3控制逻辑真值表(电机 A 为例))

[3.1.4 AT89C52 示例代码(定时器 0 产生 1 kHz PWM)](#3.1.4 AT89C52 示例代码(定时器 0 产生 1 kHz PWM))

[3.1.5 常见坑 & 快速排查](#3.1.5 常见坑 & 快速排查)

[3.2 单片机实现直流电机控制电路原理图](#3.2 单片机实现直流电机控制电路原理图)

[3.3 单片机实现直流电机控制控制程序](#3.3 单片机实现直流电机控制控制程序)


**摘要:**本文系统介绍了PWM技术原理及其在舵机和直流电机控制中的应用。PWM通过调节脉冲宽度实现模拟量控制,关键参数包括周期T、高电平时间Th和占空比D。文中详细阐述了AT89C52单片机实现PWM的四种方法,重点展示了50Hz舵机控制(0.5-2.5ms脉宽对应-90°至+90°)和L298N驱动直流电机的具体实现方案,包含完整的电路原理图和C语言程序代码。特别指出应用中需注意的周期选择、驱动能力、电平匹配等常见问题,并提供了参数计算示例和调试建议。

1 PWM信号

PWM(Pulse Width Modulation,脉冲宽度调制)是一种用「数字脉冲」去等效「模拟量」的技术。

1.1 三个最基本的量

1.1.1 周期 T(Period)

一个完整脉冲循环的时间,单位 μs 或 ms。

例:舵机 50 Hz → T = 20 ms。

1.1.2脉冲宽度 Th(High Time)

一个周期内输出高电平的时间。

例:舵机 1.5 ms。

1.1.3占空比 D(Duty Cycle)

D = Th / T × 100 %

例:1.5 ms / 20 ms = 7.5 %。

1.2 为什么要用 PWM

1 数字口只有 0/1,无法直接输出 3.3 V 的一半电压。

2 通过高速开关,让「平均电压」等于目标值:

Vavg = Vhigh × D

例:5 V、占空比 50 % → 等效 2.5 V(电机速度减半、LED 半亮)。

1.3 关键参数对照表

|------------|--------------|----------------------|------------|------------------|
| 应用 | 周期 T | 常用 Th 范围 | 分辨率要求 | 备注 |
| LED 调光 | 1~5 kHz | 0~100 % | 8 bit | 频率太低会闪 |
| 直流电机调速 | 10~20 kHz | 0~100 % | 8~10 bit | 频率>20 kHz 避人耳噪声 |
| 舵机控制 | 20 ms | 0.5~2.5 ms | 1 μs | 50 Hz 固定 |
| 开关电源(Buck) | 50 k~2 MHz | 根据拓扑 | 10~12 bit | MOSFET 驱动 |

1.4单片机里产生 PWM 的四种套路

1.4.1 纯软件延时

for/while + delay → 最简单、最不准、CPU 100 % 占用。

1.4.2 定时器中断计数

每 x μs 进一次中断,累加变量 → 精度高,可做多通道。

1.4.3 定时器硬件 PWM 模块

51 系列没有,AVR/STM32 有 OCR/ARR 寄存器,直接硬件输出。

1.4.4 专用 PWM IC 或驱动板

PCA9685(I²C 16 路)、DRV8833 等,省 IO,精度高。

1.5 计算示例(AT89C52,12 MHz,定时器 0 模式 1)

目标:50 Hz,1 μs 分辨率

计数频率:12 MHz / 12 = 1 MHz → 1 μs/次

20 ms 对应计数:20 000 次

16 位定时器最大 65 536,够用。

步骤:

设 TH0 = (65536-20000)/256,TL0 = ... 先装 20 ms 周期。

再开一个「比较寄存器」存放 Th(如 1500)。

中断里计数到 Th 翻转 IO,到 20 000 再翻转 IO,循环即可。

1.6 常见踩坑提醒

周期太低 → LED/电机肉眼可见抖动或蜂鸣。

Th 精度太差 → 舵机抖动、稳速电机转速漂移。

IO 驱动能力不足 → 加三极管/MOSFET 做缓冲。

舵机高电平 5 V,STM32 单片机 3.3 V 输出时,最好加 NPN 或电平转换。

1.7 一句话总结

PWM = 「固定周期 + 可变高电平」,用数字开关把平均电压/角度/速度「模拟化」。掌握 T、Th、D 三要素,再挑合适的「生成套路」,任何 PWM 场景都能秒拆。

2 AT89C52单片机实现舵机控制

2.1 舵机专用 PWM(50 Hz)

周期:T = 20 ms(50 Hz)

有效高电平:0.5 ms ~ 2.5 ms(有些舵机 0.4 ms ~ 2.6 ms)

角度映射:

0.5 ms → −90°

1.5 ms → 0°

2.5 ms → +90°

分辨率:舵机内部一般 1 µs 对应 0.09°,所以 10 µs 步进肉眼基本看不出抖动。

2.2 电路原理图

如上图所示,AT89C52单片机实现舵机控制电路由AT89C52单片机、晶振及复位电路、舵机、控制开关和示波器组成。通过PWM信号实现舵机转角的控制,不同开关导通情况下P2.5控制信号的占空比不同,从而实现舵机转角的控制。

2.3 控制程序

objectivec 复制代码
//头文件与为位定义
#include <reg52.h>
#define uint  unsigned int
#define uchar unsigned char
 
uchar Compare=200;//50HZ 抑芷?0ms
uint ZHK;//PWM信号占空比

sbit k2=P2^0;//-90度
sbit k3=P2^1;//0度
sbit k4=P2^2;//90度
sbit k1=P2^5;//舵机控制信号

//定时器T0产生 100μs 中断
void Timer0_init()//100us
{

	TMOD= 0x01;		//设置定时器模式
	TL0 = 0x9B;		//设置定时初值低位
	TH0 = 0xFF;		//设置定时初值高位 差值表示中断周期
	ET0=1;
	EA=1;	
	TR0=1;//启动定时器
}

//定时器延时函数
void Delay(unsigned int ms)
{
    unsigned int i;
    for (i = 0; i < ms; i++)
    {
        while (!TF0);  // 等待定时器T0溢出
        TF0 = 0;       // 清除溢出标志
    }
}

 //定时器T0中断服务函数
void Timer0() interrupt 1
{
	TL0 = 0x9B;		//设置定时初值低位
	TH0 = 0xFF;		//设置定时初值高位

}
//舵机转到-90度
void chushi()
{
      ZHK=196;
      k1=0;
			Delay(ZHK);

      k1=1;
			Delay(Compare-ZHK);
}
//舵机转到0度
void zhongjian()
{
      ZHK=186;
      k1=0;
			Delay(ZHK);

      k1=1;
			Delay(Compare-ZHK);
}
//舵机转到90度
void zuizhong()
{
      ZHK=175;
      k1=0;
			Delay(ZHK);

      k1=1;
			Delay(Compare-ZHK);
}
//主函数
void main()
{

	Timer0_init();
	while(1)
	{
     if(k2==0)
		 {
		 chushi();
		 }
		else if(k3==0)
		 {
		 zhongjian();
		 }
		 else if(k4==0)
		 {
		 zuizhong();
		 }
	}
}

3 AT89C52单片机实现直流电机控制

3.1L298N电机驱动

3.1.1它到底是什么

一块"双H-桥"功率芯片(ST 原装 L298N)+ 外围电路做成的驱动板。

可同时驱动:

两台直流有刷电机,或一台四线两相步进电机。

极限参数:逻辑 5 V 供电,驱动端 5-35 V(建议 ≤24 V 长期工作),连续 2 A/桥,峰值 3 A。

3.1.2引脚速记

Power 区域
VS→ 外接 7-24 V 电机电源
GND→ 与单片机共地

VCC→ 三种用法
① 板上跳线帽插上:内部线性稳压给逻辑 5 V(仅当 VIN ≤12 V 时可用);
② 拔掉跳线帽:由外部单独 5 V 供逻辑;
③ 反向输出:板上稳压 5 V 可引出来给单片机供电(仍要求 VIN ≤12 V)。

Motor 区域
OUT1/OUT2→ 电机 A
OUT3/OUT4→ 电机 B

Logic 区域
IN1/IN2/ENA→ 控制电机 A 的方向与使能
IN3/IN4/ENB→ 控制电机 B
(ENA/ENB 接 PWM 即可调速)

3.1.3控制逻辑真值表(电机 A 为例)

|---------|---------|---------|--------|
| ENA | IN1 | IN2 | 结果 |
| 0 | X | X | 刹车(自由) |
| 1 | 1 | 0 | 正转 |
| 1 | 0 | 1 | 反转 |
| 1 | 1 | 1 | 快速刹车 |
| PWM | 1/0 | 0/1 | 调速+方向 |

3.1.4 AT89C52 示例代码(定时器 0 产生 1 kHz PWM)

objectivec 复制代码
#include <reg52.h>
sbit IN1 = P1^0;
sbit IN2 = P1^1;
sbit ENA = P1^2;    // 接 L298N 的 ENA
bit pwm_out = 0;
unsigned char high = 200;   // 占空比 200/255 ≈ 78 %
void Timer0_Init()
{
    TMOD &= 0xF0;   // 模式 2,8 位自动重装
    TH0 = 256-100;  // 100*1us = 100 us → 10 kHz
    TL0 = 256-100;
    ET0 = 1; EA = 1;
    TR0 = 1;
}
void Timer0_ISR() interrupt 1
{
    static unsigned char cnt = 0;
    cnt++;
    if(cnt == 0)        pwm_out = 1;       // 周期起点
    if(cnt == high)     pwm_out = 0;
    ENA = pwm_out;
}
void main()
{
    IN1 = 1; IN2 = 0;   // 方向:正转
    Timer0_Init();
    while(1)
    {
        /* 可在此修改 high 值调速,或改 IN1/IN2 换向 */
    }
}

3.1.5 常见坑 & 快速排查

|------------|--------------------------------|
| 现象 | 90 % 原因与对策 |
| 电机不转,指示灯不亮 | 没给 +12V;跳线帽错;共地问题 |
| 电机抖动、咔咔响 | 电源功率不足;PWM 频率太低 |
| 芯片过热、保护 | 电流 >2 A;散热片没装;占空比 100 % 长时间堵转 |
| 逻辑失控 | 单片机 5 V 与驱动板 5 V 没共地;ENA 悬空 |

3.2 单片机实现直流电机控制电路原理图

如上图所示,AT89C52单片机实现直流电机控制电路由AT89C52单片机、L298N电机驱动、开关控制电路、晶振及复位电路、输出电压显示、示波器和直流电机组成。通过软件设置不同占空比的PWM信号实现直流电机转速的控制,再通过L298N电机驱动的驱动可以实现直流电机正转、反转、停止、加速和减速的控制。

3.3 单片机实现直流电机控制控制程序

objectivec 复制代码
//头文件与为位定义
#include <reg52.h>
#define uint  unsigned int
#define uchar unsigned char
 
uchar Compare=20;//50HZ 一周期20ms
uint ZHK1;//正转占空比
uint ZHK2;//反转占空比

sbit IN1=P1^0;
sbit IN2=P1^1;
sbit ENA=P1^2; 

sbit k0=P2^0;//正转
sbit k1=P2^1;//反转
sbit k2=P2^2;//停止
sbit k3=P2^3;//正传加速
sbit k4=P2^4;//正传减速
sbit k5=P2^5;//反转加速
sbit k6=P2^6;//反转减速

//定时器T0产生 1000μs 中断
void Timer0_init()//1000us
{

	TMOD= 0x01;		//设置定时器模式
	TL0 = 0x17;		//设置定时初值低位
	TH0 = 0xFC;		//设置定时初值高位 差值表示中断周期
	ET0=1;
	EA=1;	
	TR0=1;//启动定时器
}

//定时器延时函数
void Delay(unsigned int ms)
{
    unsigned int i;
    for (i = 0; i < ms; i++)
    {
        while (!TF0);  // 等待定时器T0溢出
        TF0 = 0;       // 清除溢出标志
    }
}

 //定时器T0中断服务函数
void Timer0() interrupt 1
{
	TL0 = 0x17;		//设置定时初值低位
	TH0 = 0xFC;		//设置定时初值高位

}
//电机正转
void DJZHZH()
{
      ENA=1;
      ZHK1=10;
			IN1=1;
		  IN2=0;
			Delay(ZHK1);

			IN1=0;
		  IN2=0;
			Delay(Compare-ZHK1);
}
//电机反转
void DJFZH()
{
      ENA=1;
      ZHK2=10;
			IN1=0;
		  IN2=1;
			Delay(ZHK2);

			IN1=0;
		  IN2=0;
			Delay(Compare-ZHK2);
}
//停
void DJT()
{
			ENA=0;
			TR0=0;
			IN1=0;
			IN2=0;
}
//正转加速
void DJZHZH1()
{
      ENA=1;
      ZHK1=18;
			IN1=1;
		  IN2=0;
			Delay(ZHK1);

			IN1=0;
		  IN2=0;
			Delay(Compare-ZHK1);
}
//电机反转加速
void DJFZH1()
{
      ENA=1;
      ZHK2=18;
			IN1=0;
		  IN2=1;
			Delay(ZHK2);

			IN1=0;
		  IN2=0;
			Delay(Compare-ZHK2);
}
//电机正传减速
void DJZHZH2()
{
      ENA=1;
      ZHK1=2;
			IN1=1;
		  IN2=0;
			Delay(ZHK1);

			IN1=0;
		  IN2=0;
			Delay(Compare-ZHK1);
}
//电机反转减速
void DJFZH2()
{
      ENA=1;
      ZHK2=2;
			IN1=0;
		  IN2=1;
			Delay(ZHK2);

			IN1=0;
		  IN2=0;
			Delay(Compare-ZHK2);
}

void main()
{

  DJT();	
	Timer0_init();

	while(1)
	{
    if(k0==0)//正转
			{
			DJZHZH();
			}
	
			else if(k1==0)//反转
			{
			DJFZH();
			}
		 	else if(k2==0)	//停止
		{

     DJT();							
		} 
			else if(k3==0)//正转加速
		{

     DJZHZH1();					
		} 
					else if(k5==0)//反转加速
		{

    DJFZH1();			
		} 
		else if(k4==0)//正转减速
		{

     DJZHZH2();					
		} 
					else if(k6==0)//反转减速
		{

    DJFZH2();			
		} 
	}
}
相关推荐
灬若宸1 小时前
14、外部中断
stm32·单片机·嵌入式硬件·系统架构
GodKK老神灭3 小时前
STM32 AFIO模块
stm32·单片机·嵌入式硬件
mftang5 小时前
Zephyr 中的 bt_le_per_adv_set_data 函数的介绍和应用方法
嵌入式硬件·nordic·zephyr
滴啦嘟啦哒6 小时前
【项目复盘】【四轴飞行器设计】驱动开发部分
单片机·面试准备
狂奔的sherry6 小时前
一会儿能ping通一会ping不通解决方案
运维·网络·单片机·嵌入式硬件
qq_401700416 小时前
单片机驱动继电器接口
单片机·嵌入式硬件
anghost1501 天前
基于 STM32 的多传感器健康监测系统设计
stm32·单片机·嵌入式硬件
玉~你还好吗1 天前
【嵌入式电机控制#34】FOC:意法电控驱动层源码解析——HALL传感器中断(不在两大中断内,但重要)
单片机·嵌入式系统·电机控制
STC_USB_CAN_80511 天前
所有普通I/O口都支持中断的51单片机@Ai8051U, AiCube 图形化配置
单片机·嵌入式硬件·51单片机