C51 小车PWM调速,超声波测距,灰度寻迹代码,实测可用。

该博客分享了一段基于51单片机的代码,实现了PWM调速的小车控制,包括超声波测距功能,用于避障,以及灰度传感器寻迹功能,确保小车能在黑色线条上行驶。通过中断处理超声波回波,计算并判断障碍物距离,同时根据左右灰度传感器的读数调整小车转向。代码详细注释了各个部分的功能,适合初学者理解和实践。
摘要由CSDN通过智能技术生成

@ C51 小车PWM调速,超声波测距,灰度寻迹代码,可直接下载使用

#include<reg52.h>
#include <intrins.h>

#define uint unsigned int
#define uchar unsigned char

float dis;   //超声波距离的缓存
uchar flag;  //超声波中断标志位

uchar Duty_left,Duty_right; //左右占空比标志,取1-100
uchar aa = 0,cc = 0,i = 0;
uchar flag;	                //用于循迹方向的判断

sbit Echo = P3^2;             //超声波模块的回响信号输出,P3^2也是51单片机外部中断0的输入端,利用下降沿来触发中断
sbit Trig = P1^4;             //触发信号脚
//驱动L298N---->
//ENA,ENB为使能端; ENA,1,2和ENB,3,4分别控制一个电机;
sbit IN1 = P1^0;
sbit IN2 = P1^1;
sbit IN3 = P1^2;
sbit IN4 = P1^3;
sbit Light = P1^5;
sbit ENA = P1^6;
sbit ENB = P1^7;

sbit left = P3^0;	     //左右两个灰度传感器
sbit right = P3^1;

//小车直行速度赋值
void forward_move();
//小车停止
void stop();
//小车左转速度赋值(用于左边传感器检测到黑线)
void Left_turning();
//小车右转速度赋值(用于右边传感器检测到黑线)
void Right_turning();
//PWM 定时器初始化
void init_T1(void);
// 延时
void delay__ms(uchar x);
//延时10.9us,每个机器周期约1.09us,在晶振为11.0592MHz时
void nops();
//计算距离的函数
void distance();
//超声波定时器 初始化函数
void init();


void main()//主函数
{
	init();
	init_T1();
	left = 1;
	right = 1;
	while(1)
	{
		distance();  //获取超声波距离
		if(dis < 10)  // 这里改超声波的距离
		{
			stop();     //小车停止
			Light = 0;  //灯亮
		}
		else 
		{
			Light = 1;  //灯灭
			if((left==0)&&(right==1))
			{
				Right_turning();//左边检测到黑线
			}
			else if((left==1)&&(right==0))
			{
				Left_turning();//右边检测到黑线
			}
			else if((left==1)&&(right==1))
			{
				forward_move(); //两边都没检测到黑线
			}
			else
			{
				forward_move();
			}
		}
	}
}



void ex() interrupt 0//外部中断的中断函数
{
	TR0=0;//一旦受到下降沿,立马停止定时器计数
	dis=(TH0*256+TL0)*1.09/58;//先取出定时器里的时间值,之后再将定时器置0
	flag=1;//将标志位置0
	TH0=0;
	TL0=0;
}

void T1_ISR(void) interrupt 3 using 1
{
  TH1 = 0xff;
	TL1 = 0x9c;   //给TH1和TL1重新赋值
	aa++;
  cc++;
  if(aa <= Duty_left)//设置左轮占空比,即左轮速度
		ENA = 1;
  else
		ENA = 0;
  if(cc <= Duty_right)
		ENB = 1;
  else
		ENB = 0;
  if(aa == 100)  //设置pwm周期=0.1ms*100=10ms,这样开头定义的变量正好表示占空比数值
  {
		aa = 0;//加到100后变为0,重新计数
  }
		if(cc == 100)
  {
		cc = 0;
  }
}

//小车直行速度赋值
void forward_move()
{
	
    Duty_left = 18;
    Duty_right = 12;
    IN1 = 1;   	//两个电机均正转
    IN2 = 0;
    IN3 = 1;
    IN4 = 0;
}

//小车停止
void stop()
{   
	Duty_left = 0;
	Duty_right = 0;
  IN1 = 0;
  IN2 = 0;
  IN3 = 0;
  IN4 = 0;
}

//小车左转速度赋值(用于左边传感器检测到黑线)
void Left_turning()
{
  Duty_left = 18;
  Duty_right = 20;
  IN1 = 1;       //两个电机一个正转一个反转(或者一个正转一个不转)
  IN2 = 0;
  IN3 = 0;
  IN4 = 1;
}

//小车右转速度赋值(用于右边传感器检测到黑线)
void Right_turning()
{
  Duty_left = 18;
  Duty_right = 20;
  IN1 = 0;
  IN2 = 1;
  IN3 = 1;
  IN4 = 0 ;
}

//PWM 定时器初始化
void init_T1(void)
{
	TMOD|= 0x10;	   //使用方式1,16位定时器
	TH1 = 0xff;
	TL1 = 0x9c;        //定时 ff 9c  0.1ms
	EA = 1;            //总中断打开
	ET1 = 1;           //定时器中断打开
	TR1 = 1;           //定时器开关打开
}

// ms延时
void delay__ms(uchar x)
{
	uint i,j;
	for(i=0;i<x;i++)
	{
		for(j=0;j<110;j++);
	}
}

//延时10.9us,每个机器周期约1.09us,在晶振为11.0592MHz时
void nops()
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}

//计算距离的函数
void distance()
{
	Trig = 0;//首先将触发拉低
	nops();
	Trig = 1;//给至少10us的高电平,启动模块
	nops();
	nops();
	Trig = 0;//此时已经触发了模块,接下来立刻开启定时器计数
	TR0 = 1;//打开定时器0
	EX0 = 1;//打开外部中断,外部中断输入为P3^2,下降沿有效,触发中断
	delay__ms(1);//等待一下,一个机器周期约为1.09us,如果不等待,可能就错过计算dis,陷入死循环,永远无法得出值
	if(flag == 1)//如果标志位置1,表示Echo输出下降沿,即接收结束
	{
		flag = 0;
	}
}

//超声波定时器 初始化函数
void init()
{
	TMOD = 0x01;//16位计数器,这里不用开启定时器中断,因为定时器中断无事可做,只要定时器里的值就行,因此无需将TF0置1
	TH0 = 0;//全部设为0
	TL0 = 0;
	IT0 = 1;//设置外部中断下降沿有效
	EA = 1;//开总中断
}

  • 18
    点赞
  • 197
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值