@ 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-1000 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,三、四分别控制电机; 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
;
//开总中断
}