51单片机教程51蓝牙PID循迹超声波急停避障小车
流水鱼实现功能:
- 能够实现自动识别黑线,完成5路循迹。
- 能够通过蓝牙于89C52系列芯片串口通信控制小车
- 能够自动感应障碍物实现自动刹停。
准备材料:
- 89C52芯片及最小系统板 ,
- L298n模块,
- 模拟量5路循迹模块,
- 稳压模块,
- HC-06模块,
- 超声波模块,
- 亚巧克力板,
- 4个电机,
- 12vDC电源,
- DC转接母头
普通小车使能实现原理:
利用51单片机IO口控制L298n模块引脚供电实现对电机触发。再通过EN使能端进行PWM调速,实现转弯,漂移,转圈等特殊转速。
IN为L298N模块控制引脚
EN为L298N模块使能引脚
L298N模块单边IN为0,0时,电机停止转动,为1,0 、0,1时正转、反转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #include <REGX52.H> unsigned char Duty_left,Duty_right,j=0,i=0;
sbit IN11=P0^2; sbit IN12=P0^1;
sbit IN13=P0^3; sbit IN14=P0^4;
sbit IN21=P1^1; sbit IN22=P1^2;
sbit IN23=P1^4; sbit IN24=P1^3;
sbit EN1A=P0^0; sbit EN1B=P0^5; sbit EN2A=P1^6; sbit EN2B=P1^7; void Timer0_Init() { TMOD|=0x01; TH0=0xff; TL0=0x9c; EA=1; ET0=1; TR0=1; }
void Timer0_Routine() interrupt 1 { TH0=0xff; TL0=0x9c; i++; j++;
if(i<=Duty_left) { EN1A=1; EN2A=1; } else { EN1A=0; EN2A=0; } if(j<=Duty_right) { EN1B=1; EN2B=1; } else { EN1B=0; EN2B=0; } if(i==100) { i=0; } if(j==100) { j=0; }
}
|
蓝牙小车原理:
通过将蓝牙模块的TX 与RX 与单片机交叉相接进行串口通信,实现收发数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
| #include <REGX52.H>
sbit IN11=P0^2; sbit IN12=P0^1;
sbit IN13=P0^3; sbit IN14=P0^4;
sbit IN21=P1^1; sbit IN22=P1^2;
sbit IN23=P1^4; sbit IN24=P1^3;
char i; unsigned char ReceiveData;
void correct_left() { IN11=0; IN12=0; IN21=0; IN22=0; IN13=1; IN14=0; IN23=1; IN24=0;
}
void correct_right() { IN11=1; IN12=0; IN21=1; IN22=0; IN13=0; IN14=0; IN23=0; IN24=0;
}
void Left_turning() {
IN11=0; IN12=1; IN21=0; IN22=1; IN13=1; IN14=0; IN23=1; IN24=0; }
void Right_turning() {
IN11=1; IN12=0; IN21=1; IN22=0; IN13=0; IN14=1; IN23=0; IN24=1; }
void forward_move() { IN11=1; IN12=0; IN21=1; IN22=0; IN13=1; IN14=0; IN23=1; IN24=0; }
void back() { IN11=0; IN12=1; IN21=0; IN22=1; IN13=0; IN14=1; IN23=0; IN24=1; }
void stop() { IN11=0; IN12=0; IN21=0; IN22=0; IN13=0; IN14=0; IN23=0; IN24=0; }
void receive(unsigned char m) { switch(m) { case '8':forward_move();break; case '5':stop();break; } }
void Uart_Init() { PCON = 0x00; SCON = 0x50; TMOD = 0x20; TL1 = 0xFD; TH1 = 0xFD; ET1 = 0; TR1 = 1; EA=1; ES=1; }
void Uart_Routine() interrupt 4 { stop(); RI=0; ReceiveData=SBUF; receive(ReceiveData); }
void main() { Uart_Init(); while(1); }
|
超声波急停避障小车原理:
1.采用 IO 口 TRIG 触发测距,给一个 10us 的高电平信号;
2.模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
3.有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
4.测试距离=(高电平时间*声速(340M/S))/2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <REGX52.H> #include "delay.h" sbit Trig=P3^3; sbit Echo=P3^2; unsigned int a,distance;
int csb() {
TMOD &= 0x0F; TL1 = 0; TH1 = 0; Trig=1; Delay10us(2); Trig=0; while(!Echo); TR1=1; while(!Echo); TR1=0; a=TH1*256+TL1; TH1=0; TL1=0; distance= a*1.7/100; Trig=0; Echo=0; return distance; }
|
5路PID循迹小车原理:
简单的循迹就是通过循迹模块反馈给单片机的高低电平信号进行不断判断和迭代,列出全部情况,这里就不做赘述。在此分享和学习关于PID算法循迹。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include <REGX52.H>
float Kp = 0.5; float Ki = 0.2; float Kd = 0.1;
int error = 0; int lastError = 0; int integral = 0; int derivative = 0;
void CalculatePID() { int sensorValues = (left1 << 4) | (left2 << 3) | (mid3 << 2) | (right4 << 1) | right5;
switch(sensorValues) { case 0b00000: case 0b11111: break; case 0b00100: error = 0; break; }
integral = integral + error; derivative = error - lastError; int turn = (int)(Kp * error + Ki * integral + Kd * derivative); lastError = error;
Duty_left = 26 + turn; Duty_right = 26 - turn;
Duty_left = Duty_left < 0 ? 0 : (Duty_left > 100 ? 100 : Duty_left); Duty_right = Duty_right < 0 ? 0 : (Duty_right > 100 ? 100 : Duty_right); }
void Timer0_Routine() interrupt 1 { }
void main() { Timer0_Init(); while(1) { CalculatePID(); } }
|