@ 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;//开总中断
}