当前位置: 首页 > news >正文

Proteus仿真51单片机控制L298N PWM电机调速

51单片机概述

51单片机是指Intel公司开发的MCS-51系列单片机及其兼容产品,是应用最广泛的8位单片机系列之一。其名称来源于该系列的第一款芯片8051。

主要特点:

  • 8位CPU:处理数据宽度为8位

  • 哈佛结构:程序存储器和数据存储器分开

  • 40引脚DIP封装:标准双列直插式封装

  • 4KB ROM:早期型号,现代兼容型号容量更大

  • 128B RAM:内部数据存储器

  • 32个I/O口:4个8位并行I/O端口

  • 2个16位定时器/计数器

  • 1个全双工串行通信口

  • 5个中断源:2个外部中断,2个定时器中断,1个串口中断

常见51单片机型号

型号主要特性
8051原始型号,4KB ROM,128B RAM
8031无片内ROM
89C51Atmel公司产品,Flash ROM
89S51支持ISP在线编程
STC89C52宏晶科技产品,8KB Flash,512B RAM
STC12C5A60S2增强型51,1T周期,60KB Flash,1280B RAM

51单片机内部结构

1. CPU结构

  • 算术逻辑单元(ALU):执行算术和逻辑运算

  • 累加器(ACC):主要寄存器,用于运算和数据传输

  • B寄存器:用于乘除法运算

  • 程序状态字(PSW):包含各种状态标志位

  • 程序计数器(PC):16位,指向下一条要执行的指令

2. 存储器结构

  • 程序存储器(ROM/Flash):存储程序代码

  • 内部数据存储器(RAM):128字节(52系列为256字节)

  • 特殊功能寄存器(SFR):控制各功能模块

  • 外部扩展存储器:可扩展至64KB

3. 输入输出端口

  • P0口:8位开漏双向I/O口,兼作地址/数据总线

  • P1口:8位准双向I/O口

  • P2口:8位准双向I/O口,兼作高8位地址总线

  • P3口:8位准双向I/O口,具有第二功能

51单片机最小系统

一个能工作的51单片机最小系统需要:

  1. 单片机芯片(如STC89C52)

  2. 时钟电路:通常11.0592MHz晶振+两个30pF电容

  3. 复位电路:10kΩ电阻+10μF电容构成上电复位

  4. 电源电路:5V稳定电源,加滤波电容

L298N介绍

L298N是一种双H桥电机驱动芯片,能够驱动两个直流电机或一个步进电机,广泛应用于机器人、智能小车等项目中。

主要特性

  • 工作电压:5V-35V

  • 最大电流:2A(单桥)

  • 逻辑电压:5V(兼容TTL电平)

  • 驱动方式:双H桥驱动

  • 可同时控制:2个直流电机或1个两相/四相步进电机

模块引脚说明

电源部分

  • +12V/VCC:电机驱动电源输入(5-35V)

  • GND:电源地

  • +5V:输出5V(当使能跳线帽接通时)或5V输入(当断开跳线帽时)

控制部分

  • ENA/ENB:PWM使能端(A/B通道)

  • IN1/IN2:A通道控制输入端

  • IN3/IN4:B通道控制输入端

与51单片机的连接方式

51单片机引脚连接L298N: 
- P1.0 → L298N ENA (PWM输入A) 
- P1.1 → L298N IN1 
- P1.2 → L298N IN2
- (如果需要控制第二个电机)  
- P1.3 → L298N ENB (PWM输入B)   
- P1.4 → L298N IN3   
- P1.5 → L298N IN4

电机控制逻辑

单个直流电机控制

IN1IN2ENA电机状态
00X停止
10PWM正转(PWM调速)
01PWM反转(PWM调速)
11X刹车

PWM调速原理

通过改变ENA/ENB引脚PWM信号的占空比来调节电机速度:

  • 占空比高 → 平均电压高 → 转速快

  • 占空比低 → 平均电压低 → 转速慢

典型应用电路

  1. 电源部分

    • 电机电源与单片机电源共地

    • 建议电机电源与逻辑电源分开供电

    • 大容量滤波电容靠近L298N电源引脚

  2. 保护电路

    • 电机两端并联续流二极管

    • 必要时添加散热片

proteus仿真图 

代码实现 

主函数 

#include <REGX52.H>
#include <intrins.h>
#include "LCD1602.h"
#include "public.h"
#include "stdio.h"
char war[32];sbit IN1 = P1^1;
sbit IN2 = P1^2;
sbit ENA = P1^0;  // PWM输出引脚unsigned char PWM = 0;  // PWM占空比 0-100
bit DIR = 0;            // 方向 0或1void Timer0Init()  // 100us@11.0592MHz
{TMOD &= 0xF0;  // 设置定时器模式TMOD |= 0x02;  // 8位自动重装模式TH0 = 0xA4;    // 重装值TL0 = 0xA4;    // 初始值TR0 = 1;       // 启动定时器ET0 = 1;       // 使能定时器中断EA = 1;        // 开启总中断
}void main()
{Timer0Init();LCD_Init();LCD_Clear();IN1 = 1;IN2 = 0;  // 初始方向PWM =20;	while(1){// 这里可以添加按键扫描或其他控制逻辑来改变PWM值// 例如:// if(按键加按下) PWM++;// if(按键减按下) PWM--;// if(按键方向按下) DIR = !DIR;if(P1_4 ==0){Delay_ms(100);if(P1_4 ==0) { PWM++; }}if(P1_5 ==0){Delay_ms(100);if(P1_5 ==0) { PWM--; }}if(P1_6 ==0){Delay_ms(100);if(P1_6 ==0) { DIR = !DIR; }}// 限制PWM范围if(PWM > 100) PWM = 100;if(PWM < 0) PWM = 0;// 设置方向if(DIR){IN1 = 1;IN2 = 0;}else{IN1 = 0;IN2 = 1;}sprintf(war,"PWM:%03d DIR:%d",(int)PWM,(int)DIR);LCD_ShowString(2,1,war);	}
}void Timer0_ISR() interrupt 1
{static unsigned char count = 0;count++;if(count >= 100){count = 0;}if(count < PWM){ENA = 1;  // 高电平期间电机通电}else{ENA = 0;  // 低电平期间电机断电}
}

LCD1602.c

#include <REGX52.H>//引脚配置:
//sbit LCD_RS=P1^2;
//sbit LCD_RW=P1^3;
//sbit LCD_EN=P1^4;sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0//函数定义:
/*** @brief  LCD1602延时函数,12MHz调用可延时1ms* @param  无* @retval 无*/
void LCD_Delay()
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}/*** @brief  LCD1602写命令* @param  Command 要写入的命令* @retval 无*/
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602写数据* @param  Data 要写入的数据* @retval 无*/
void LCD_WriteData(unsigned char Data)
{LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602设置光标位置* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @retval 无*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));}
}/*** @brief  LCD1602初始化函数* @param  无* @retval 无*/
void LCD_Init()
{LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动LCD_WriteCommand(0x01);//光标复位,清屏
}void LCD_Clear()
{LCD_WriteCommand(0x01);//光标复位,清屏
}
/*** @brief  在LCD1602指定位置上显示一个字符* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @param  Char 要显示的字符* @retval 无*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}/*** @brief  在LCD1602指定位置开始显示所给字符串* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  String 要显示的字符串* @retval 无*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);}
}///**
//  * @brief  返回值=X的Y次方
//  */
//int LCD_Pow(int X,int Y)
//{
//	unsigned char i;
//	int Result=1;
//	for(i=0;i<Y;i++)
//	{
//		Result*=X;
//	}
//	return Result;
//}///**
//  * @brief  在LCD1602指定位置开始显示所给数字
//  * @param  Line 起始行位置,范围:1~2
//  * @param  Column 起始列位置,范围:1~16
//  * @param  Number 要显示的数字,范围:0~65535
//  * @param  Length 要显示数字的长度,范围:1~5
//  * @retval 无
//  */
//void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
//{
//	unsigned char i;
//	LCD_SetCursor(Line,Column);
//	for(i=Length;i>0;i--)
//	{
//		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
//	}
//}///**
//  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
//  * @param  Line 起始行位置,范围:1~2
//  * @param  Column 起始列位置,范围:1~16
//  * @param  Number 要显示的数字,范围:-32768~32767
//  * @param  Length 要显示数字的长度,范围:1~5
//  * @retval 无
//  */
//void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
//{
//	unsigned char i;
//	unsigned int Number1;
//	LCD_SetCursor(Line,Column);
//	if(Number>=0)
//	{
//		LCD_WriteData('+');
//		Number1=Number;
//	}
//	else
//	{
//		LCD_WriteData('-');
//		Number1=-Number;
//	}
//	for(i=Length;i>0;i--)
//	{
//		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
//	}
//}///**
//  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
//  * @param  Line 起始行位置,范围:1~2
//  * @param  Column 起始列位置,范围:1~16
//  * @param  Number 要显示的数字,范围:0~0xFFFF
//  * @param  Length 要显示数字的长度,范围:1~4
//  * @retval 无
//  */
//void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
//{
//	unsigned char i,SingleNumber;
//	LCD_SetCursor(Line,Column);
//	for(i=Length;i>0;i--)
//	{
//		SingleNumber=Number/LCD_Pow(16,i-1)%16;
//		if(SingleNumber<10)
//		{
//			LCD_WriteData(SingleNumber+'0');
//		}
//		else
//		{
//			LCD_WriteData(SingleNumber-10+'A');
//		}
//	}
//}///**
//  * @brief  在LCD1602指定位置开始以二进制显示所给数字
//  * @param  Line 起始行位置,范围:1~2
//  * @param  Column 起始列位置,范围:1~16
//  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
//  * @param  Length 要显示数字的长度,范围:1~16
//  * @retval 无
//  */
//void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
//{
//	unsigned char i;
//	LCD_SetCursor(Line,Column);
//	for(i=Length;i>0;i--)
//	{
//		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
//	}
//}

lcd1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__//用户调用函数:
void LCD_Init();
void LCD_Clear();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
//void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
//void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
//void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
//void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endif

#ifndef _public_H
#define _public_H#include "REGX52.h"		 #define  u16 unsigned int 	//对系统默认数据类型进行重定义
#define u8 unsigned char void Delay_us(u16 ten_us);
void Delay_ms(u16 ms);#endif
#include "public.h"/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void Delay_us(u16 ten_us)
{while(ten_us--);	
}/*******************************************************************************
* 函 数 名       : delay_ms
* 函数功能		 : ms延时函数,ms=1时,大约延时1ms
* 输    入       : ms:ms延时时间
* 输    出    	 : 无
*******************************************************************************/
void Delay_ms(u16 ms)
{u16 i,j;for(i=ms;i>0;i--)for(j=110;j>0;j--);
}

效果演示 

相关文章:

  • 帮公司做网站运营今天全国31个省疫情最新消息
  • 贸易公司注册需要什么条件排名seo怎么样
  • 263企业邮箱设置西安百度首页优化
  • 中药材天地网做中药零售网站搜索引擎营销的特点是什么
  • wordpress与phpmyadminseo综合查询 站长工具
  • 财务管理软件唐山百度提升优化
  • 深入GPU编程:从硬件架构到内核优化
  • Gated CNN Block,抑制背景噪声、强化边缘特征,更好地融合不同尺度的特征信息
  • python的智慧养老院管理系统
  • 深入解析RS485通信:从原理到Linux驱动开发实践
  • 图像处理解决方案
  • Promptify与ReActAgent
  • Docker、Docker composer与Docker desktop
  • 【Elasticsearch】es初识,在项目架构中的用途,与mysql和kafka的配合使用,
  • .NET 7.0 EF Core:一、创建Web API 项目基础框架和用户表的增删改查
  • C++ 第二阶段项目三:图形绘制库
  • PDF24 Creator(PDF工具箱)
  • 中文PDF解析准确率排名
  • 设计模式:揭秘Java原型模式——让复杂对象的创建不再复杂
  • 使用pyflink编写demo并将任务提交到yarn集群
  • 【启发式算法】RRT*算法详细介绍(Python)
  • 一篇文章了解XML
  • LeetCode 3298.统计重新排列后包含另一个字符串的子字符串数目2
  • aspose.word在IIS后端DLL中高并发运行,线程安全隔离
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | BackgroundSlider(背景滑块)
  • Web项目开发中Tomcat10+所需的jar包