[Proteus仿真]基于51单片机的汽车电动助力转向系统(包括代码讲解视频)

目录

一、主要功能

二、硬件资源

三、程序编程

四、实现现象


一、主要功能

基于51单片机,三个电阻传感器链接ADC0832数模转换器分别代表扭矩、车速、电流。
如果扭矩不变,车速变小,L298N驱动电机速度加快,PWM调速
如果车速不变,扭矩越大,L298N驱动电机速度加快,PWM调速
如果扭矩方向发生变化,则电机方向发生改变
如果扭矩小于1N或车速大于90,电机不转
如果电流超过程序设置好的额定值,电机不转蜂鸣器报警
同时,扭矩,车速和电流通过LCD12864显示屏实时显示

仿真图:

二、硬件资源

基于KEIL5编写C++代码,PROTEUS8.15进行仿真,全部资源在页尾,提供安装包。

本系统由51单片机、电流传感器、车速传感器、扭矩传感器、报警系统、L298N驱动电机模块、按键模块、LCD12864显示模块组成。

51单片机是一种非常常用的单片机系列,其主要硬件组成如下:

1. 中央处理器(CPU):51单片机的CPU采用哈佛架构,包括一个8位的ALU(算术逻辑单元)、8位的寄存器、PC(程序计数器)以及其他控制逻辑。它能够执行单片机上的指令和进行算术和逻辑运算。

2. 存储器:51单片机通常包含两种主要的存储器,即ROM(只读存储器)和RAM(随机访问存储器)。ROM用于存储程序代码和常量数据,它是只读的,不可修改。RAM用于存储临时数据和变量。

3. 输入输出(I/O)口:51单片机通常包含多个I/O口,用于与外部设备进行数据的输入和输出。每个I/O口都可以配置为输入或输出模式,并且可以通过读写寄存器来控制和访问。

4. 定时器和计数器:51单片机通常包含多个定时器和计数器,用于生成精准的时间延迟和定期中断。这些定时器和计数器可以用于测量时间、计数脉冲和生成脉冲。

5. 中断系统:51单片机通常支持中断功能,用于响应外部事件或特定条件的发生。当中断事件发生时,CPU将会中断当前的执行,转而执行相应的中断服务程序。中断能够提高系统的响应速度和效率。

6. 时钟:51单片机通常需要外部时钟源来提供基本的时钟信号,以驱动CPU执行指令。时钟信号的频率决定了单片机的工作速度和性能。

以上是51单片机的主要硬件组成,通过这些组件的协作,单片机能够完成各种任务,包括控制和处理数据、驱动外部设备、读写存储器等。

三、程序编程

/*全部代码看页尾*/
#include <REGX52.H>
#include<intrins.h>
#include<stdio.h>
#include < character.h >
#include < lcd.h >
#define uchar unsigned char
#define uint unsigned  int
typedef unsigned char u8;
typedef unsigned int  u16;
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
sbit CS  = P1^0;        //扭矩
sbit CLK = P1^1;
sbit DIO = P1^2;
sbit CS1  = P3^5;        //电流
sbit CLK1 = P3^6;
sbit DIO1 = P3^7;
sbit CS2  = P1^3;        //车速
sbit CLK2 = P1^4;
sbit DIO2 = P1^5;
sbit Motor1_EN  = P0^3;
sbit Motor1_IN1 = P0^0;
sbit Motor1_IN2 = P0^1;
sbit BEEP = P0^3;
sbit key = P1^6;

/*变量定义*/
static int number= 0 ,fz=0,flag=0,flag1=0;				
static 	char dl,cs;
static signed int nj;
uchar count,a=0,b,c;

/*函数定义*/
void dlpd();
void cspd();
void njpd();
void ajpd();
/*
扭矩:
车速
电流
*/


void jiemian1(void)			  
{				   
  Lcd_Character_16X16( 1, 0, 0 , function_logo[0]);  // 扭
	Lcd_Character_16X16( 1, 0, 16 ,function_logo[1]);  // 矩
	Lcd_Character_16X8 ( 1, 0,32,letter_logo[nj/100]);
	Lcd_Character_16X8 ( 1, 0,40,letter_logo[(nj/10)%10]);
	Lcd_Character_16X8 ( 1, 0,48,letter_logo[nj%10]);
	Lcd_Character_16X16( 1, 2, 0 , function_logo[2]);  // 车
	Lcd_Character_16X16( 1, 2, 16, function_logo[3]);  //速
	Lcd_Character_16X8 ( 1, 2,32,letter_logo[cs/100]);
	Lcd_Character_16X8 ( 1, 2,40,letter_logo[(cs/10)%10]);
	Lcd_Character_16X8 ( 1, 2,48,letter_logo[cs%10]);
	
	Lcd_Character_16X16( 1, 4, 0 , function_logo[4]);  // 电
	Lcd_Character_16X16( 1, 4, 16, function_logo[5]); // 流
	Lcd_Character_16X8 ( 1, 4,32,letter_logo[dl/100]);
	Lcd_Character_16X8 ( 1, 4,40,letter_logo[(dl/10)%10]);
	Lcd_Character_16X8 ( 1, 4,48,letter_logo[dl%10]);
}

void Timer0_Init(void)		//200微秒@11.0592MHz
{
	//AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x48;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
}

void Car_Move(uchar speed)	 //电机转动
{
	uchar Car_Speed = speed;
	count++;	
	if(count <= Car_Speed)
	{
		Motor1_IN1 = 1;
	}
	else
	{
	 	Motor1_IN1 = 0;
	}
	if(count >= 100)
	{
	 	count = 0;
	}	
}

void Car_Move1(uchar speed)	 //电机转动
{
	uchar Car_Speed = speed;
	count++;	
	if(count <= Car_Speed)
	{
		Motor1_IN2 = 1;
	}
	else
	{
	 	Motor1_IN2 = 0;
	}
	if(count >= 100)
	{
	 	count = 0;
	}	
}

void Timer0_isr(void) interrupt 1
{
  TL0 = 0x48;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	if(flag1 == 0)
	{
	switch(a)
	{
		case 0:Motor1_IN1 = 0;break;
		case 1:Car_Move(30);break;	 	 //电机低速前进
		case 2:Car_Move(60);break;	 	 //电机高速前进
		case 3:Car_Move(90);break;	 	 //电机高速前进
		case 4:Car_Move(120);break;	 	 //电机高速前进
		case 5:Car_Move(150);break;	 	 //电机高速前进
		case 6:Car_Move(180);break;	 	 //电机高速前进
		default:break;
	}
 } 
	else if(flag1 == 1)
	{
		switch(a)
	{
		case 0:Motor1_IN2 = 0;break;
		case 1:Car_Move1(30);break;	 	 //电机低速前进
		case 2:Car_Move1(60);break;	 	 //电机高速前进
		case 3:Car_Move1(90);break;	 	 //电机高速前进
		case 4:Car_Move1(120);break;	 	 //电机高速前进
		case 5:Car_Move1(150);break;	 	 //电机高速前进
		case 6:Car_Move1(180);break;	 	 //电机高速前进
		default:break;
	}
	}
}

uchar get_AD_Res()          //ADC0832启动读取扭矩的值
{
	uchar i, data1=0, data2=0;
	CS=0;
	
	CLK=0;DIO=1;_nop_();
	CLK=1;_nop_();
	
	CLK=0;DIO=1;_nop_(); 
	CLK=1;_nop_();
	
	CLK=0;DIO=0;_nop_();
	CLK=1;_nop_();
	
	CLK=0;DIO=1;_nop_(); 
	
	for(i=0; i<8; i++)
	{
		CLK=1;_nop_();
		CLK=0;_nop_();
		data1=(data1<<1)|(uchar)DIO; 
	}
	
	for(i=0; i<8; i++)
	{
		data2=data2|(uchar)DIO<<i;
		CLK=1;_nop_();
		CLK=0;_nop_();
	}
	CS=1;
	
	return(data1 == data2)?data1:0;
}

uchar get_AD_Res1()          //ADC0832启动读取电流值
{
	uchar i, data1=0, data2=0;
	CS1=0;
	
	CLK1=0;DIO1=1;_nop_();
	CLK1=1;_nop_();
	
	CLK1=0;DIO1=1;_nop_(); 
	CLK1=1;_nop_();
	
	CLK1=0;DIO1=0;_nop_();
	CLK1=1;_nop_();
	
	CLK1=0;DIO1=1;_nop_(); 
	
	for(i=0; i<8; i++)
	{
		CLK1=1;_nop_();
		CLK1=0;_nop_();
		data1=(data1<<1)|(uchar)DIO1; 
	}
	
	for(i=0; i<8; i++)
	{
		data2=data2|(uchar)DIO1<<i;
		CLK1=1;_nop_();
		CLK1=0;_nop_();
	}
	CS1=1;
	
	return(data1 == data2)?data1:0;
}

uchar get_AD_Res2()          //ADC0832启动读取车速值
{
	uchar i, data1=0, data2=0;
	CS2=0;
	
	CLK2=0;DIO2=1;_nop_();
	CLK2=1;_nop_();
	
	CLK2=0;DIO2=1;_nop_(); 
	CLK2=1;_nop_();
	
	CLK2=0;DIO2=0;_nop_();
	CLK2=1;_nop_();
	
	CLK2=0;DIO2=1;_nop_(); 
	
	for(i=0; i<8; i++)
	{
		CLK2=1;_nop_();
		CLK2=0;_nop_();
		data1=(data1<<1)|(uchar)DIO2; 
	}
	
	for(i=0; i<8; i++)
	{
		data2=data2|(uchar)DIO2<<i;
		CLK2=1;_nop_();
		CLK2=0;_nop_();
	}
	CS2=1;
	
	return(data1 == data2)?data1:0;
}

void Time1Init()
{
	TMOD |= 0x10;
	TH1   = (65536-57567)/256;
	TL1   = (65536-57567)%256;
	EA    = 1;
	ET1   = 1;
	TR1   = 1;
}

void Time1Start() interrupt 3
{
    static	u16 count1 = 0;      //定义计数变量
	TH1   = (65536-57567)/256;
	TL1   = (65536-57567)%256;
	count1++;
	if(count1 == 1)//达到1s
	{
		count1 = 0; 
		ajpd();
	}
}
        
void main()					  //主函数
{	
	Timer0_Init();
	Time1Init();        //定时器1初始化
	Lcd_Initial();     //LCD初始化
	Lcd_Display_On();	//启动屏幕
	jiemian1();
	Motor1_IN1=0;
	Motor1_IN2=0;
	while(1)
	{
	  nj=get_AD_Res();	
		dl=get_AD_Res1();	
		cs=get_AD_Res2();	
		nj-=26;
		nj=nj/4;
		if( nj<1)
		{
			nj=0;
		}
		dlpd(); //电流判断
		cspd();//车速判断
		njpd(); //扭矩判断
		jiemian1();	
	
		if(flag == 0)
		{
		a=b*c;
		}

	}
	
}

void dlpd()
{
	if(dl>100)
	{
		BEEP = 1;
		a= 0;
		flag = 1;
	}
	else 
	{
		BEEP = 0;
		flag = 0;
	}
}

void cspd()
{
	if(cs>90)
	{
		b=0;
	}
	else if(cs>0 && cs <30)
	{
		b=3;
	}
	else if(cs>30 && cs <60)
	{
		b=2;
	}
	else if(cs>60 && cs <90)
	{
		b=1;
	}
	
	
}

void njpd()
{

  if(nj==0)
	{
		c=0;
	
			
	}
	else if(nj>=1 && nj <15)
	{
		c=1;
			
	}
	else if(nj>15 && nj <25)
	{
		c=2;
	
	}
}

void ajpd()
{
	if(key==0)
	{
		Delay(50);
		if(key == 0)
		{
			flag1++;
			if(flag1>1)
			{
				flag1 = 0;
			}
		}
	}
}

四、实现现象

具体动态效果看B站演示视频:

基于51单片机的汽车电动助力转向系统_哔哩哔哩_bilibili

全部资料(源程序、仿真文件、安装包、演示视频、流程图、代码讲解):

链接:https://pan.baidu.com/s/1AFNrIABmiHdw1RSl5rGisg 
提取码:ms6z 
--来自百度网盘超级会员V4的分享

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
自动控制节水灌溉技术的高低代表着农业现代化的发展状况,灌溉系统自动化水平较低是制约我国高效农业发展的主要原因。本文就此问题研究了单片机控制的滴灌节水灌溉系统,该系统可对不同土壤的湿度进行监控,并按照作物对土壤湿度的要求进行适时、适量灌水,其核心是单片机和PC机构成的控制部分,主要对土壤湿度与灌水量之间的关系、灌溉控制技术及设备系统的硬件、软件编程各个部分进行了深入的研究。 单片机控制部分采用上下位机的形式。下位机硬件部分选用AT89C51单片机为核心,主要由土壤湿度传感器,信号处理电路,显示电路,输出控制电路,故障报警电路等组成,软件选用汇编语言编程。上位机选用586型以上PC机,通过MAX232芯片实现同下位机的电平转换功能,上下位机之间通过串行通信方式进行数据的双向传输,软件选用VB高级编程语言以建立友好的人机界面。系统主要具有以下功能:可在PC机提供的人机对话界面上设置作物要求的土壤湿度相关参数;单片机可将土壤湿度传感器检测到的土壤湿度模拟量转换成数字量,显示于LED显示器上,同时单片机可采用串行通信方式将此湿度值传输到PC机上;PC机通过其内设程序计算出所需的灌水量和灌水时间,且显示于界面上,并将有关的灌水信息反馈给单片机,若需灌水,则单片机系统启动鸣音报警,发出灌水信号,并经放大驱动设备,开启电磁阀进行倒计时定时灌水,若不需灌水,即PC机上显示的灌水量和灌水时间均为0,系统不进行灌水。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

夜间去看海

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

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

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

打赏作者

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

抵扣说明:

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

余额充值