国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

基于51單片機的多功能智能語音循跡避障小車

這篇具有很好參考價值的文章主要介紹了基于51單片機的多功能智能語音循跡避障小車。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

一.功能介紹及硬件準備

二.電機控制及調速

三.小車循跡方案

四.跟隨功能實現

五.測速功能實現

六.OLED顯示車速

七.搖頭避障功能實現

八.SU-03T語音模塊介紹

九.語音切換小車模式+OLED顯示模式


一.功能介紹及硬件準備

這是一款基于51單片機開發(fā)的智能小車,通過這篇文章我會記錄下來開發(fā)這款小車的全部過程。這款小車集成了循跡,避障,跟隨,語音切換模式選擇,并且將可以將車速顯示到OLED屏幕上,也可以通過手機app藍牙操控小車。(注:全文的代碼采取分文件編程的寫法)

硬件準備

小車底盤一個(兩驅),5號4節(jié)電池盒一個,51單片機最小系統一個,HC04超聲波模塊一個,SG90舵機一個,紅外避障模塊傳感器兩個,紅外光電反射傳感器兩個,L9110S電機驅動模塊(L298n也可以使用),測速傳感器一個,SU-03T離線語音模塊一個,HC-08藍牙模塊一個,DC-DC電壓轉換模塊兩個,0.96寸OLED屏幕一個,杜邦線若干,熱熔膠槍一個,也可以再準備一個面包板。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件


二.電機控制及調速

關于電機控制選用的是L9110s電機驅動模塊,在淘寶里也很容易買到,也才不到2塊錢,比l298n偏移很,但缺點就是容易發(fā)燙。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

接線說明:

我們以L9110s電機驅動模塊為新手小白講一下這些模塊怎么接線,后面就不多贅述模塊如何接線了。模塊通常的引腳就是VCC,GND,以及其他的控制或信號引腳。VCC就是模塊的電源正極(大多數的模塊都是5V供電,具體的參考模塊說明書),接到單片機最小系統的VCC引腳上。GND就是模塊的負極,接到單片機最小系統的GND引腳上。VCC或GND也可接到通過面包板引出的正負極上。剩下的引腳就接到單片機的IO口上即可。


控制小車前后左右:

控制小車的前后左右運動說白了就是控制兩個電機的正反轉,兩個電機同時正轉小車前進,同時反轉小車后退,電機一個轉一個不轉小車實現轉向。邏輯非常簡單,下面就是L9110s電機驅動模塊的真值表,并且該模塊可同時控制兩個電機。將兩個電機的兩根線

接入端子中就可以寫代碼控制了。

IA1輸入高電平,IA1輸入低電平,【OA1 OB1】電機正轉;

IA1輸入低電平,IA1輸入高電平,【OA1 OB1】電機反轉;

IA2輸入高電平,IA2輸入低電平,【OA2 OB2】電機正轉;

IA2輸入低電平,IA2輸入高電平,【OA2 OB2】電機反轉;

motor.c

#include "reg52.h"

sbit RightCon1A = P3^2; //電機A由P3.2,P3.3控制
sbit RightCon1B = P3^3;
 
sbit LeftCon1A = P3^4;  //電機B由P3.4,P3.5控制
sbit LeftCon1B = P3^5;

void goBack() //后退
{
    LeftCon1A = 0;
    LeftCon1B = 1;
     
    RightCon1A = 0;
    RightCon1B = 1;
}
 
void goRight() //右轉
{
    LeftCon1A = 0;
    LeftCon1B = 1;
     
    RightCon1A = 0;
    RightCon1B = 0;
}
 
 
void goLeft() //左轉
{
    LeftCon1A = 0;
    LeftCon1B = 0;
     
    RightCon1A = 0;
    RightCon1B = 1;
}
  
void goForward() //前進
{
    LeftCon1A = 1;
    LeftCon1B = 0;
     
    RightCon1A = 1;
    RightCon1B = 0;
}

void stop()  //停車
{
	LeftCon1A = 0;
    LeftCon1B = 0;
     
    RightCon1A = 0;
    RightCon1B = 0;	
}

藍牙控制小車

藍牙控制小車的核心思想就是采用串口中斷,用手機app給藍牙模塊發(fā)送不同的字符串,單片機接收到字符串后進入串口中斷,通過判斷字符串內容來控制小車的前后左右。換句話說,藍牙控制小車不需要配置任何藍牙模塊的相關代碼,只需寫好串口中斷的控制即可實現藍牙控制。

usart.c

#include "reg52.h"
#include "intrins.h"
#include <string.h>
#include "motor.h"

#define SIZE 12
sfr AUXR = 0x8E;
char buffer[SIZE];

void UartInit(void)	//9600bps@11.0592MHz
{
	AUXR=0X01;
	SCON = 0x50;    //配置串口工作方式1,REN使能(REN:串行使能接收位)
	TMOD &= 0xF0;		
	TMOD |=0X20;    //設定定時器1工作方式位,8位自動重裝載
	TL1 = 0xFD;		//設定定時器初值
	TH1 = 0xFD;		//設定定時器初值(波特率9600初值)
	ET1 = 0;		//緊止定時器1中斷
	TR1 = 1;		//啟動定時器1
	
	EA=1;       //開啟總中斷
	ES=1;       //開始串口中斷
}

//發(fā)送M1-前進,發(fā)送M2-后退,發(fā)送M3-左轉,發(fā)送M4-右轉

void Usart_Handler() interrupt 4
{
	static int i=0;
	char tmp;
	
	if(RI)//接收中斷處理
	{
		RI=0;//清除中斷標志位
		tmp=SBUF;
		
		if(tmp=='M'){
			i=0;
		}
		buffer[i++]=tmp;
		if(buffer[0]=='M'){
			switch(buffer[1]){
				case'1':
				goForward();	
				break;
				case'2':
				goBack();	
				break;
				case'3':
				goLeft();	
				break;			
				case'4':
				goRight();	
				break;			
			}
		}		
		if(i==12){
		memset(buffer,'\0',SIZE);  //清空串口接收區(qū)
		i=0;
		}	
	}
}

小車調速

前面的代碼實現的小車的前進都是讓小車全速前進,電池的功率有多大小車前進的速度就有多快,6節(jié)干電池供電肯定會比四節(jié)干電池快的多。那么我們用單片機如何給小車調速,我們用PWM給小車進行調速。?

調速原理:全速前進是LeftCon1A = 0; LeftCon1B = 1;完全停止是LeftCon1A = 0;LeftCon1B = 0;那么單位時間內,比如20ms, 有15ms是全速前進,5ms是完全停止, 速度就會比5ms全速前進,15ms完全停止獲得的功率多,相應的速度更快!這就是PWM通過改變占空比調速的原理。

為了更好控制兩個電機的不同狀態(tài)打開兩個定時器中斷,定時器0控制左邊電機,定時器2控制右邊電機。使用兩組定時器中斷調速,這樣就可以通過差速的方式控制小車的轉向。左輪定時器0調速,右輪定時器1調速,那么左轉就是右輪速度大于左輪!

time.c

#include "reg52.h"
#include "motor.h"

char leftspeed;
char cntLeft=0;

char rightspeed;
char cntRight=0;

void Time0Init()
{
	//1. 配置定時器0工作模式位16位計時
	TMOD = 0x01;
	//2. 給初值,定一個0.5出來
	TL0=0x33;
	TH0=0xFE;
	//3. 開始計時
	TR0 = 1;
	TF0 = 0;
	//4. 打開定時器0中斷
	ET0 = 1;
	//5. 打開總中斷EA
	EA = 1;
}

void Time1Init()
{
	//1. 配置定時器1工作模式位16位計時
	TMOD &= 0x0F;
	TMOD |= 0X1 <<4;
	//2. 給初值,定一個0.5出來
	TL1=0x33;
	TH1=0xFE;
	//3. 開始計時
	TR1 = 1;
	TF1 = 0;
	//4. 打開定時器0中斷
	ET1 = 1;
	//5. 打開總中斷EA
	EA = 1;
}

void Time0Handler() interrupt 1
{
	cntLeft++;  //統計爆表的次數. cnt=1的時候,報表了1
	//重新給初值
	TL0=0x33;
	TH0=0xFE;
	
	//控制PWM波
	if(cntLeft < leftspeed){
    goForwardLeft();
	}else{
		   stopLeft();
	}
	
	if(cntLeft == 40){//爆表40次,經過了20ms
		 cntLeft = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s
	}		
}

void Time1Handler() interrupt 3
{
	cntRight++;  //統計爆表的次數. cnt=1的時候,報表了1
	//重新給初值
	TL1=0x33;
	TH1=0xFE;
	
	//控制PWM波
	if(cntRight < rightspeed){
		//右前進
		goForwardRight();
	}else{
		//停止
		stopRight();
	}
	
	if(cntRight == 40){//爆表40次,經過了20ms
		cntRight = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s
	}		
}

三.小車循跡方案

循跡模塊介紹:

我們選用的是TCRT5000傳感器,傳感器的紅外發(fā)射二極管不斷發(fā)射紅外線,當發(fā)射出的紅外線沒有被反射回來或被反射回來但強度不夠大時, 紅外接收管一直處于關斷狀態(tài),此時模塊的輸出端為高電平,指示二極管一直處于熄滅狀態(tài) 被檢測物體出現在檢測范圍內時,紅外線被反射回來且強度足夠大,紅外接收管飽和, 此時模塊的輸出端為低電平,指示二極管被點亮。

(注:該模塊有一個數字信號輸出DO和一個模擬信號輸出AO,我們只使用了數字信號DO引腳,AO懸空即可)

總結就是一句話,沒反射回來,D0輸出高電平,滅燈!

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

循跡原理:

小車循跡是沿著黑色的線走,由于黑色具有較強的吸收能力,當循跡模塊發(fā)射的紅外線照射到黑線時,紅外線將會被黑線吸收,導致循跡模塊上光敏三極管處于關閉狀態(tài),此時模塊上一個LED熄滅。在沒有檢測到黑線時,模塊上兩個LED 常亮。

總結就是一句話,有感應到黑線,D0輸出高電平 ,滅燈!

小車行駛在直線賽道的時候,兩個循跡模塊分別是在黑線的兩側,不會吸收發(fā)射出的紅外線。行駛在圓形賽道的時候,某一側的循跡模塊必然會接觸到黑線部分,因此會給單片機一個高電平信號,單片機通過判斷是那一側的循跡模塊發(fā)出的高電平從而控制小車往那個方向轉向。

總結:

走直線時:兩個循跡模塊都是低電平。

左轉時:左模塊輸出高電平,右模塊輸出低電平。

右轉時:右模塊輸出高電平,左模塊輸出低電平。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

還需注意的就是這個循跡模塊的電壓輸入是3v-5v,而我們的電池盒提供的電壓是6v,雖然不會燒壞模塊,但實測的效果會大打折扣,所以使用DC-DC電壓模塊給循跡模塊提供5v的電壓。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

?

根據上面講的原理,開始寫一個測試代碼。

#include <reg52.h>
#include "motor.h"

sbit leftSensor = P2^7;  //左循跡模塊
sbit rightSensor = P2^6; //右循跡模塊

void main()
{		
	while(1){
		if(leftSensor == 0 && rightSensor == 0){
			goForward();
		}
		if(leftSensor == 1 && rightSensor == 0){
			goLeft();
		}
		if(leftSensor == 0 && rightSensor == 1){
			goRight();
		}
		if(leftSensor == 1 && rightSensor == 1){
			stop();
		}		
    }
}

循跡模塊電位器調節(jié):

經過測試這段代碼就可以實現循跡的功能,但是把代碼燒錄進去之后還需要根據實際情況調節(jié)循跡模塊上的電位器改變循跡模塊的靈敏度。要是發(fā)現小車一放下就轉圈圈,或者不按照黑線循跡,那么很有可能就是電位器的靈敏度的問題。比如家里地板顏色偏灰,這個時候就要把靈敏度調高。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

PWM調速加入實現小車絲滑轉彎:

上面的代碼雖然已經可以實現循跡的功能,但是在實際測試中發(fā)現在轉彎的時候一抽一抽?,F在就改進一下小車“抽抽” 的這個問題。

上面的代碼實現小車轉彎的時候,相當于是一種急剎車式的轉彎,小車在轉彎前絲毫不減速。那么想要讓小車絲滑轉彎,那么就必須兩個輪子都要有速度,而不是通過一個輪子轉另一個輪子不轉這種方式實現轉彎。我們把之前寫過的PWM調速的代碼加入到循跡的代碼中即可實現絲滑轉彎。

#include "motor.h"
#include "usart.h"
#include "time.h"
#include <reg52.h>

/*
	leftspeed,rightspeed這兩個參數具體給多大
	根據小車跑動情況來隨時修改
*/
sbit leftSensor = P2^7; //左循跡模塊
sbit rightSensor = P2^6;//右循跡模塊

extern char leftspeed;
extern char rightspeed;

void main()
{
		Time0Init();
		Time1Init();		

		while(1){
		if(leftSensor == 0 && rightSensor == 0){
			leftspeed = 40; 
			rightspeed = 40;	
		}
		if(leftSensor == 1 && rightSensor == 0){
			leftspeed = 15;
			rightspeed = 40; //右輪速度大于左輪,右轉
		}
		if(leftSensor == 0 && rightSensor == 1){
			leftspeed = 40;  //左輪速度大于右輪,右轉
			rightspeed = 15;
		}
		if(leftSensor == 1 && rightSensor == 1){
			leftspeed = 0; 
			rightspeed = 0;	
		}		
     }
}

實測可能會遇到的問題:

1.直線跑不直:在跑直線的時候可能跑著跑著就越來越斜的這種情況,這種情況的原因就是兩個電機的速度不一致導致的。解決方法就是把轉的快的那一邊的電機速度一點一點給它調慢,直到小車徹底跑直為止。

2.轉彎時跑出賽道:這個情況的出現就是轉彎的時候電機轉速不夠,提高相應的電機轉速即可。


四.跟隨功能實現

原理和尋線是一樣的,尋線紅外觀朝下,跟隨朝前。用到的也是兩個紅外模塊只不過發(fā)射管的位置不一樣而已。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

跟隨小車的原理:

左邊跟隨模塊能返回紅外,輸出低電平,右邊不能返回,輸出高電平,說明物體在左邊,需要左轉 右邊跟隨模塊能返回紅外,輸出低電平,左邊不能返回,輸出高電平,說明物體在右邊,需要右轉

跟隨代碼如下:

#include "motor.h"
#include "reg52.h"

sbit leftSensor = P2^5;
sbit rightSensor = P2^4;

void main()
{
	while(1){
		if(leftSensor == 0 && rightSensor == 0){
			goForward();
		}
		if(leftSensor == 1 && rightSensor == 0){
			goRight();
		}
		
		if(leftSensor == 0 && rightSensor == 1){
			
			goLeft();
		}
		
		if(leftSensor == 1 && rightSensor == 1){
			stop();
		}
	}
}

五.測速功能實現

模塊介紹:

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

用途:廣泛用于電機轉速檢測,脈沖計數,位置限位等。

有遮擋,輸出高電平;無遮擋,輸出低電平

接線 VCC 接電源正極3.3-5V

GND 接電源負極

DO TTL開關信號輸出

AO 此模塊不起作用

安裝位置如圖所示:

??基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

測速原理:

輪子走一圈,經過一個周長,C = 2x3.14x半徑= 3.14 x 輪子直徑(6.5cm),對應的碼盤也轉一圈,碼盤有20個格子,每經過一個格子,會遮擋(高電平)和不遮擋(低電平),那么碼盤一小格就是對應走了 3.14 * 6.5 cm /20 = 1.0205CM。換句話說就是一個脈沖就是走了1.0205CM。定時器可以設計成一秒,統計脈沖數,假設一秒有80脈沖,那么就是80cm/s。

代碼邏輯:

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

接下來我們編程實現將車速通過串口發(fā)送給串口助手,也可以使用藍牙模塊發(fā)送到手機app上。我們先發(fā)送到串口助手上看看效果。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

time.c

#include <REGX52.H>

unsigned int cnt = 0;
extern unsigned int rightspeedCnt;
extern unsigned int leftspeedCnt; 
unsigned int speedleft;
unsigned int speedright;
char singal;

void Time0Init()
{
	//1. 配置定時器0工作模式位16位計時
	TMOD = 0x01;
	//2. 給初值,定一個0.5ms出來
	TL0=0x33;
	TH0=0xFE;
	//3. 開始計時
	TR0 = 1;
	TF0 = 0;
	//4. 打開定時器0中斷
	ET0 = 1;
	//5. 打開總中斷EA
	EA = 1;
}

void Time0Handler() interrupt 1
{
	cnt++;  //統計爆表的次數. cnt=1的時候,報表了1
	//重新給初值
	TL0=0x33;
	TH0=0xFE;
	
	if(cnt == 2000){//爆表2000次,經過了1s
	{
		cnt=0;
		singal=1;
		speedright = rightspeedCnt;	//計算小車的速度,也就是拿到speedCnt的值
		speedleft = leftspeedCnt;
		rightspeedCnt=0;
		leftspeedCnt=0;//1秒后拿到speedCnt個格子,就能算出這1s的速度,格子清零
	}	
  }
}

usart.c

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


void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50; //配置串口工作方式1,REN使能接收
	TMOD &= 0x0F;
	TMOD |= 0x20;//定時器1工作方式位8位自動重裝
	
	TH1 = 0xFD;
	TL1 = 0xFD;//9600波特率的初值
	TR1 = 1;//啟動定時器
	
	EA = 1;//開啟總中斷
}

void SendByte(char mydata)//發(fā)送字符
{
	SBUF = mydata;
	while(!TI);
	TI=0;
}

void SendString(char *str)//發(fā)送字符串
{
	while(*str != '\0'){
		SendByte(*str);
		str++;
	}
}

main.c

#include "motor.h"
#include "usart.h"
#include "reg52.h"
#include "time.h"
#include "stdio.h"

sbit speedIO1 = P3^2;//外部中斷0
sbit speedIO2 = P3^3;//外部中斷1
unsigned int leftspeedCnt = 0;  //統計左輪格子,脈沖次數
unsigned int rightspeedCnt = 0; //統計右輪格子,脈沖次數
extern unsigned int speedleft;  //左輪速度
extern unsigned int speedright; //右輪速度
extern char singal;    //發(fā)送速度的信號
char SpeedMes_R[24];  //主程序發(fā)送右輪速度數據的字符串緩沖區(qū)
char SpeedMes_L[24];  //主程序發(fā)送左輪速度數據的字符串緩沖區(qū)

void Ex0Init()
{
	EX0 = 1;//允外部中斷
	IT0 = 1;//外部中斷的下降沿觸發(fā)
}

void Ex1Init()
{
	EX1 = 1;//允外部中斷
	IT1 = 1;//外部中斷的下降沿觸發(fā)
}

void main()
{
	Time0Init();//定時器0初始化
	UartInit();//串口相關初始化
	Ex0Init();//外部中斷初始化
	Ex1Init();
	
    while(1){
      if(singal){
		sprintf(SpeedMes_R,"rightspeed:%d cm/s",speedright);//串口數據的字符串拼裝,speed是格子,每個格子1cm
		SendString(SpeedMes_R);//速度發(fā)出去
		SendString("\r\n");	
				
		sprintf(SpeedMes_L,"leftspeed:%d cm/s",speedleft);//串口數據的字符串拼裝,speed是格子,每個格子1cm
		SendString(SpeedMes_L);//速度發(fā)出去
		SendString("\r\n");	
				
		singal = 0;//清0speed,下次由定時器1s后的中斷處理中再置一 	  
		}
    }
}

void rightspeedHandler() interrupt 0 //外部中斷處理函數
{
	rightspeedCnt++; //每經過一共格子,加一
}
	
void leftspeedHandler() interrupt 2 //外部中斷處理函數
{
	leftspeedCnt++; //每經過一共格子,加一
}

六.OLED顯示車速

車速可以再上位機中顯示了,接下來我們將車速顯示到OLED屏幕上。使用OLED屏幕需要先了解IIC或者SPI的協議,我使用的0.96寸IIC協議的OLED屏幕。這里就不多贅述OLED屏幕的使用和IIC協議了,我之前也寫過有關IIC和OLED屏幕相關的文章,感興趣的小伙伴可以去看一下。不想深究OLED原理的也可以直接拿廠家提供的代碼直接使用。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

由于OLED相關的代碼過于冗長,就不在文章里展示了,我主頁里的資源有這個小車的完整代碼,我們主要展示主函數代碼以及漢字取模軟件的使用。

取模軟件使用:

輸入顯示的文字

?基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

?按下Ctrl+Enter,選擇C51格式

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

文字的代碼隨即生成

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

本來是想用漢字顯示到屏幕中,但是16*16的漢字顯示的話屏幕太小了,后面的車速的內容就放不下了,所以最后決定用英文顯示。這樣的話就用不上取模軟件了,直接在程序里面包含廠家提供的英文字模庫即可。

main.c

#include "motor.h"
#include "usart.h"
#include "reg52.h"
#include "time.h"
#include "stdio.h"
#include "OLED.h"

sbit speedIO1 = P3^2;//外部中斷0
sbit speedIO2 = P3^3;//外部中斷1
unsigned int leftspeedCnt = 0;  //統計左輪格子,脈沖次數
unsigned int rightspeedCnt = 0; //統計右輪格子,脈沖次數
extern unsigned int speedleft;  //左輪速度
extern unsigned int speedright; //右輪速度
extern char singal;    //發(fā)送速度的信號
char SpeedMes_R[24];  //主程序發(fā)送右輪速度數據的字符串緩沖區(qū)
char SpeedMes_L[24];  //主程序發(fā)送左輪速度數據的字符串緩沖區(qū)

void Ex0Init()
{
	EX0 = 1;//允外部中斷
	IT0 = 1;//外部中斷的下降沿觸發(fā)
}

void Ex1Init()
{
	EX1 = 1;//允外部中斷
	IT1 = 1;//外部中斷的下降沿觸發(fā)
}

void main()
{
	Time0Init();//定時器0初始化
	UartInit();//串口相關初始化
	Ex0Init();//外部中斷0初始化
	Ex1Init();//外部中斷1初始化
	Oled_Init();//OLED初始化
	Oled_Clear();//清屏
	
    while(1){
      if(singal){
		sprintf(SpeedMes_R,"R-speed:%d cm/s",speedright);//串口數據的字符串拼裝,speed是格子,每個格子1cm
		SendString(SpeedMes_R);//速度發(fā)出去
		SendString("\r\n");	
				
		sprintf(SpeedMes_L,"L-speed:%d cm/s",speedleft);//串口數據的字符串拼裝,speed是格子,每個格子1cm
		SendString(SpeedMes_L);//速度發(fā)出去
		SendString("\r\n");	
			
		singal = 0;//清0speed,下次由定時器1s后的中斷處理中再置一 	  
		}
		Oled_Show_Str(1,1,SpeedMes_L); //顯示左輪速度
		Oled_Show_Str(2,1,SpeedMes_R); //顯示右輪速度
    }
}

void rightspeedHandler() interrupt 0 //外部中斷處理函數
{
	rightspeedCnt++; //每經過一共格子,加一
}
	
void leftspeedHandler() interrupt 2 //外部中斷處理函數
{
	leftspeedCnt++; //每經過一共格子,加一
}	

七.搖頭避障功能實現

避障功能是實現用的是超聲波模塊,其原理是通過發(fā)送和收超聲波,利用時間差和聲音傳播速度, 計算出模塊到前方障礙物的距離。當檢測到小于指定距離時,小車停止。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

怎么讓它發(fā)送波:Trig給Trig端口至少10us的高電平

怎么知道它開始發(fā)了 Echo信號:由低電平跳轉到高電平,表示開始發(fā)送波

怎么知道接收了返回波 Echo:由高電平跳轉回低電平,表示波回來了

怎么算時間:Echo引腳維持高電平的時間! 波發(fā)出去的那一下,開始啟動定時器 波回來的拿一下,我們開始停止定時器,計算出中間經過多少時間

怎么算距離:距離 = 速度 (340m/s)* 時間/2

Hc04.c

#include "reg52.h"
#include "delay.h"

sbit Trig = P2^3;
sbit Echo = P2^2;

void Time1Init()
{	
	TMOD &= 0x0F;		//設置定時器模式
	TMOD |= 0x10;
	TH1 = 0;
	TL1 = 0;
	//設置定時器0工作模式1,初始值設定0開始數數,不著急啟動定時器
}

void startHC()   //發(fā)送超聲波
{
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}

double get_distance()  //獲取距離
{
		double time;
		//定時器數據清零,以便下一次測距
		TH1 = 0;
		TL1 = 0;
	//1. Trig ,給Trig端口至少10us的高電平
		startHC();
		//2. echo由低電平跳轉到高電平,表示開始發(fā)送波
		while(Echo == 0);
		//波發(fā)出去的那一下,開始啟動定時器
		TR1 = 1;
		//3. 由高電平跳轉回低電平,表示波回來了
		while(Echo == 1);
		//波回來的那一下,我們開始停止定時器
		TR1 = 0;
		//4. 計算出中間經過多少時間
		time = (TH1 * 256 + TL1)*1.085;//us為單位
		//5. 距離 = 速度 (340m/s)* 時間/2
		return  (time * 0.017);
}

搖頭功能使用舵機實現

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

怎么控制舵機

向黃色信號線“灌入”PWM信號,PWM波的頻率不能太高,大約50HZ,即周期=1/頻率=1/50=0.02s,20ms左右

0.5ms-------------0度; 2.5% 對應函數中占空比為250

1.0ms------------45度; 5.0% 對應函數中占空比為500

1.5ms------------90度; 7.5% 對應函數中占空比為750

2.0ms-----------135度; 10.0% 對應函數中占空比為1000

2.5ms-----------180度; 12.5% 對應函數中占空比為125

SG90.c

#include "reg52.h"
#include "delay.h"

sbit sg90_con = P1^1;

int jd;  //定義角度
int cnt = 0;

void Time0Init()
{
	//1. 配置定時器0工作模式位16位計時
	TMOD &= 0xF0;		//設置定時器模式
	TMOD |= 0x01;
	//2. 給初值,定一個0.5出來
	TL0=0x33;
	TH0=0xFE;
	//3. 開始計時
	TR0 = 1;
	TF0 = 0;
	//4. 打開定時器0中斷
	ET0 = 1;
	//5. 打開總中斷EA
	EA = 1;
}


void SG90_Middle()
{
	//中間位置
	jd = 3; //90度 1.5ms高電平
	cnt = 0;
}


void SG90_Right()
{
	//右邊位置
	jd = 1; //0度
	cnt = 0;
}

void SG90_Left()
{
	//左邊位置
	jd = 5; //135度
	cnt = 0;
}

void Time0Handler() interrupt 1
{
	cnt++;  //統計爆表的次數. cnt=1的時候,報表了1
	//重新給初值
	TL0=0x33;
	TH0=0xFE;
	
	//控制PWM波
	if(cnt < jd){
		sg90_con = 1;
	}else{
		sg90_con = 0;
	}
	
	if(cnt == 40){//爆表40次,經過了20ms
		cnt = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s
		sg90_con = 1;
	}		
}

注意:如果舵機電壓低于額定電壓時,舵機可能會瘋狂地不受控制的搖頭,供電正常后這個問題就可以解決。(一開始我還以為是舵機壞了)

八.SU-03T語音模塊介紹

接下來進入小車的最后一個階段,語音控制。選用的是SU-03T這款語音模塊,這款模塊對小白特別友好,無需編程,不需要二次開發(fā),通過廠家給的網站配置后即可使用,傻瓜式操作。而且這款模塊的識別還是非常靈敏的,前端的界面設計的也非常好用。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

?SU-03T語音模塊配置:
智能公元/AIOT快速產品化平臺??????http://www.smartpi.cn/#/

登錄廠家所提供的開發(fā)平臺,點擊創(chuàng)建產品->其它產品基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

選擇純離線 方案

?基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

?選擇我們使用的SU-03T

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

?填寫好產品名稱,語言選擇中文,如何點擊保存。基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

接下來就進入了我們的配置界面,我們選擇三個IO口分別切換我們的循跡模式,跟隨模式,避障模式。把語音模塊的三個IO口都設置為高電平

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

接著配置語音模塊的喚醒詞,這里可以多配置幾條,并且可以設置靈敏度。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件接著再定義應答語,根據自己的功能定義。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件接著再設置每種詞條的命令,我設置的是當說出某種詞條的時候指定的IO口輸出低電平。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

然后其余的設置都比較簡單,根據自己的愛好選擇音調,語速之類的。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

點擊生成后就等待生成,大約半個小時左右。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

生成完之后點擊下載SDK,后續(xù)燒錄的過程參考廠家提供的資料即可,我都會跟這個項目的源代碼放在一起。

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件

九.語音切換小車模式+OLED顯示模式

語音模塊的加入是我們實現的最后一個功能,也是我們之前所有功能的一個大匯總,所有的功能都是基于我們前面寫過的代碼。但是在實現這個功能之前我有一點需要強調。由于51單片機只有兩組定時器,而我們的許多功能都用到了定時器,比如測速,電機調速,舵機,超聲波避障。因此我們沒有多余的定時器去分配給這么多功能,因此最后這個“大雜燴”小車我們選擇拋棄測速,電機調速這兩個功能。倘若選用更強大的MCU比如STM32就不存在這種取舍問題。

小車總體功能:當說出“進入循跡模式”,小車會進入循跡模式。說出“進入跟隨模式”,小車會進入跟隨模式。說出“進入避障模式”,小車會進入避障模式。并且OLED屏幕上會顯示小車的模式。

OLED.c

#include "reg52.h"
#include "intrins.h"
#include "Oledfont.h"

sbit scl = P1^2;
sbit sda = P1^3;

void IIC_Start()
{
	scl = 0;
	sda = 1;
	scl = 1;
	_nop_();
	sda = 0;
	_nop_();
}

void IIC_Stop()
{
	scl = 0;
	sda = 0;
	scl = 1;
	_nop_();
	sda = 1;
	_nop_();
}

char IIC_ACK()
{
	char flag;
	sda = 1;//就在時鐘脈沖9期間釋放數據線
	_nop_();
	scl = 1;
	_nop_();
	flag = sda;
	_nop_();
	scl = 0;
	_nop_();
	
	return flag;
}

void IIC_Send_Byte(char dataSend)
{
	int i;
	
	for(i = 0;i<8;i++){
		scl = 0;//scl拉低,讓sda做好數據準備
		sda = dataSend & 0x80;//1000 0000獲得dataSend的最高位,給sda
		_nop_();//發(fā)送數據建立時間
		scl = 1;//scl拉高開始發(fā)送
		_nop_();//數據發(fā)送時間
		scl = 0;//發(fā)送完畢拉低
		_nop_();//
		dataSend = dataSend << 1;
	}
}

void Oled_Write_Cmd(char dataCmd)
{
	//	1. start()
	IIC_Start();
	//		
	//	2. 寫入從機地址  b0111 1000 0x78
	IIC_Send_Byte(0x78);
	//	3. ACK
	IIC_ACK();
	//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據
	IIC_Send_Byte(0x00);
	//	5. ACK
	IIC_ACK();
	//6. 寫入指令/數據
	IIC_Send_Byte(dataCmd);
	//7. ACK
	IIC_ACK();
	//8. STOP
	IIC_Stop();
}

void Oled_Write_Data(char dataData)
{
	//	1. start()
	IIC_Start();
	//		
	//	2. 寫入從機地址  b0111 1000 0x78
	IIC_Send_Byte(0x78);
	//	3. ACK
	IIC_ACK();
	//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據
	IIC_Send_Byte(0x40);
	//	5. ACK
	IIC_ACK();
	///6. 寫入指令/數據
	IIC_Send_Byte(dataData);
	//7. ACK
	IIC_ACK();
	//8. STOP
	IIC_Stop();
}


void Oled_Init(void){
	Oled_Write_Cmd(0xAE);//--display off
	Oled_Write_Cmd(0x00);//---set low column address
	Oled_Write_Cmd(0x10);//---set high column address
	Oled_Write_Cmd(0x40);//--set start line address  
	Oled_Write_Cmd(0xB0);//--set page address
	Oled_Write_Cmd(0x81); // contract control
	Oled_Write_Cmd(0xFF);//--128   
	Oled_Write_Cmd(0xA1);//set segment remap 
	Oled_Write_Cmd(0xA6);//--normal / reverse
	Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
	Oled_Write_Cmd(0x3F);//--1/32 duty
	Oled_Write_Cmd(0xC8);//Com scan direction
	Oled_Write_Cmd(0xD3);//-set display offset
	Oled_Write_Cmd(0x00);//
	
	Oled_Write_Cmd(0xD5);//set osc division
	Oled_Write_Cmd(0x80);//
	
	Oled_Write_Cmd(0xD8);//set area color mode off
	Oled_Write_Cmd(0x05);//
	
	Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
	Oled_Write_Cmd(0xF1);//
	
	Oled_Write_Cmd(0xDA);//set com pin configuartion
	Oled_Write_Cmd(0x12);//
	
	Oled_Write_Cmd(0xDB);//set Vcomh
	Oled_Write_Cmd(0x30);//
	
	Oled_Write_Cmd(0x8D);//set charge pump enable
	Oled_Write_Cmd(0x14);//
	
	Oled_Write_Cmd(0xAF);//--turn on oled panel		
}

void Oled_Clear()
{
	unsigned char i,j; //-128 --- 127
	
	for(i=0;i<8;i++){
		Oled_Write_Cmd(0xB0 + i);//page0--page7
		//每個page從0列
		Oled_Write_Cmd(0x00);
		Oled_Write_Cmd(0x10);
		//0到127列,依次寫入0,每寫入數據,列地址自動偏移
		for(j = 0;j<128;j++){
			Oled_Write_Data(0);
		}
	}
}

void Oled_Show_Char(char row,char col,char oledChar){ //row*2-2
	unsigned int  i;
	Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0
	Oled_Write_Cmd(0x00+(col&0x0f));                          //low
	Oled_Write_Cmd(0x10+(col>>4));                            //high	
	for(i=((oledChar-32)*16);i<((oledChar-32)*16+8);i++){
		Oled_Write_Data(F8X16[i]);                            //寫數據oledTable1
	}

	Oled_Write_Cmd(0xb0+(row*2-1));                           //page 1
	Oled_Write_Cmd(0x00+(col&0x0f));                          //low
	Oled_Write_Cmd(0x10+(col>>4));                            //high
	for(i=((oledChar-32)*16+8);i<((oledChar-32)*16+8+8);i++){
		Oled_Write_Data(F8X16[i]);                            //寫數據oledTable1
	}		
}


/******************************************************************************/
// 函數名稱:Oled_Show_Char 
// 輸入參數:oledChar 
// 輸出參數:無 
// 函數功能:OLED顯示單個字符
/******************************************************************************/
void Oled_Show_Str(char row,char col,char *str){
	while(*str!=0){
		Oled_Show_Char(row,col,*str);
		str++;
		col += 8;	
	}		
}

main.c

#include "reg52.h"
#include "hc04.h"
#include "delay.h"
#include "sg90.h"
#include "motor.h"
#include "oled.h"

#define Middle 0 //定義舵機狀態(tài)標志位
#define Left   1
#define Right  2

#define Following 1
#define Tracking  2
#define Avioding  3 //定義模式狀態(tài)標志位

//語音模塊引腳定義
sbit A25 = P1^5;   //跟隨模式
sbit A26 = P1^6;   //避障模式
sbit A27 = P1^7;   //循跡模式

//跟隨紅外模塊引腳定義
sbit Fol_leftSensor  = P2^5;
sbit Fol_rightSensor = P2^4;

//循跡模塊引腳定義
sbit Tra_leftSensor  = P0^1;
sbit Tra_rightSensor = P0^2;

char dir;
double M_distance; //正前方距離
double L_distance; //左側距離
double R_distance; //右側距離

//跟隨模式
void Following_Mode()
{
		if(Fol_leftSensor == 0 && Fol_rightSensor == 0){
				goForward();	
		}
		if(Fol_leftSensor == 1 && Fol_rightSensor == 0){
				goRight();
		}
		if(Fol_leftSensor == 0 && Fol_rightSensor == 1){
				goLeft();
		}
		if(Fol_leftSensor == 1 && Fol_rightSensor == 1){
				stop();
		}	
}

//循跡模式
void Tracking_Mode()
{
		if(Tra_leftSensor == 0 && Tra_rightSensor == 0){
			goForward();
		}
		if(Tra_leftSensor == 1 && Tra_rightSensor == 0){
			goLeft();
		}
		
		if(Tra_leftSensor == 0 && Tra_rightSensor == 1){
			goRight();
		}
		
		if(Tra_leftSensor == 1 && Tra_rightSensor == 1){
			stop();
		}		
}

//避障模式
void Avioding_Mode()
{
			if(dir != Middle){
			SG90_Middle();		
			dir = Middle;
			Delay300ms();	
		}
		
		M_distance = get_distance();
		if(M_distance > 25){
			goForward();//前進
		}else if(M_distance < 10){
			goBack();//距離過小時后退
		}
		else{
			stop();
			SG90_Left();
			Delay300ms();
			L_distance = get_distance();
						
			SG90_Middle();
			Delay300ms();
			
			SG90_Right();
			Delay300ms();	
			R_distance = get_distance();
			dir = Right;
			
			if(L_distance < R_distance){
				goRight();
			}
			
			if(L_distance > R_distance){
				goLeft();
			}			
		}
}

void main()
{
	int mark = 0;
	
	Time0Init();
	Time1Init();
	//舵機的初始位置
	SG90_Middle();
	Delay300ms();		
	Oled_Init();//OLED初始化
	Oled_Clear();//清屏
	Oled_Show_Str(2,2,"-----Ready----");
	
	while(1){
		//滿足避障模式的條件
		if(A26 == 0 && A25 == 1 && A27 == 1){
				if(mark!=Avioding){
				Oled_Clear();
				Oled_Show_Str(2,2,"Avioding_Mode");
				}
				mark = Avioding;  
				Avioding_Mode();
		}
		//滿足跟隨模式的條件
		if(A26 == 1 && A25 == 0 && A27 == 1){
				if(mark!=Following){
				Oled_Clear();
				Oled_Show_Str(2,2,"Following_Mode");
				}
				mark = Following;
				Following_Mode();
		}
		//滿足循跡模式的條件
		if(A26 == 1 && A25 == 1 && A27 == 0){
				if(mark!=Tracking){
				Oled_Clear();
				Oled_Show_Str(2,2,"Tracking_Mode");
				}
				mark = Tracking;
				Tracking_Mode();		
		}		
	}
}

基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件?基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件基于單片機的智能避障小車設計,51單片機,51單片機,單片機,嵌入式硬件文章來源地址http://www.zghlxwxcb.cn/news/detail-778750.html

到了這里,關于基于51單片機的多功能智能語音循跡避障小車的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 單片機原理及應用:獨立式鍵盤控制LED與多功能按鍵識別

    單片機原理及應用:獨立式鍵盤控制LED與多功能按鍵識別

    今天來介紹另一個外設——按鍵與LED的配合工作,與開關不同,按鍵需要注意消除抖動帶來的影響,代碼邏輯也會更復雜一寫,下面先為大家介紹獨立式鍵盤的相關知識。 單片機的獨立式鍵盤指的是一種不依賴于計算機或其他外部設備的鍵盤輸入方式,由若干按鍵按照一定的

    2024年01月21日
    瀏覽(17)
  • 【單片機畢業(yè)設計】【mcuclub-dz-147】多功能醫(yī)療健康監(jiān)測設備

    【單片機畢業(yè)設計】【mcuclub-dz-147】多功能醫(yī)療健康監(jiān)測設備

    項目名:基于單片機的多功能醫(yī)療健康監(jiān)測設備設計與實現 項目名:血壓脈搏體溫檢測儀 項目編號:mcuclub-dz-147 單片機類型:STC12C5A60S2 具體功能: 1、通過血壓計檢測血壓值(一個按鍵控制控制啟動及切換) 2、通過脈搏檢測脈搏值(一個按鍵控制控制啟動1分鐘) 3、通過非

    2024年01月22日
    瀏覽(96)
  • 基于51單片機智能小車循跡功能的實現

    基于51單片機智能小車循跡功能的實現

    本實驗采用兩路紅外循跡模塊單黑線循跡的方法。當紅外循跡模塊未檢測到黑線,則前進;若一邊檢測到黑線,則實現轉彎;若兩邊均檢測到黑線,則停止。利用兩路紅外循跡模塊接收到的信號控制電機的運動,實現小車的前進,轉彎等運動。 背面 正面 --------------------( 黃

    2023年04月08日
    瀏覽(21)
  • 基于51單片機的智能教室系統

    基于51單片機的智能教室系統

    功能: 1.通過LCD實時溫度、光照強度、人數以及手自動模式 2.溫度過高且有人的情況下打開空調 3.光強過弱的時候且有人的情況下打開照明燈 4.通過兩個運放電路模擬進人出人 5.通過按鍵調整手自動模式,手動模式可以手動打開照明燈和空調 嗶哩嗶哩視頻演示鏈接跳轉,請直

    2024年02月11日
    瀏覽(26)
  • 單片機設計基于51單片機的智能風扇控制系統設計與實現

    單片機設計基于51單片機的智能風扇控制系統設計與實現

    ??我們常見的電風扇一般只有四、五個風速檔,用的是人工開關,而且并不是每個人家里都會有空調,或者在一些小型的工廠或者一些小型加工廠,這些地方都可能沒有配備大型的中央空調系統這些東西,所以這些東西往往都會采用風扇這種小成本的東西來代替,但是不清楚

    2024年02月03日
    瀏覽(27)
  • 單片機課設———基于51單片機的智能風扇控制器(匯編語言)

    說明:單片機芯片為AT89C52,使用普中開發(fā)板,用匯編語言編程。 系統實現了對風扇的控制: (1)控制器面板包括:啟/停鍵、模式選擇鍵、風速鍵和類型選擇鍵。 (2)模式分為:手動模式和自動溫控模式。在溫控模式下,風速鍵和類型選擇鍵無效。 (3)風速分為:強、中

    2024年02月11日
    瀏覽(32)
  • 基于51單片機的智能嬰兒看護床設計

    基于51單片機的智能嬰兒看護床設計

    需要源碼及原理圖文件請私信?。。?! 人們對智能化的生活越來越向往,隨著時代的快速發(fā)展單片機在我們日常生活中應用的也越來越廣泛。單片機完成了由模擬電路和數字電路的傳統設計模式過渡到以軟件設計為主體的微控制技術時代。使得單片機在各種各樣的生活場景中

    2023年04月18日
    瀏覽(39)
  • 基于51單片機的智能小車(循跡、避障、藍牙控制)

    基于51單片機的智能小車(循跡、避障、藍牙控制)

    文章目錄 前言 一、功能 二、主要模塊 1.L298N模塊 2.循跡模塊 3.紅外避障模塊 4.超聲波避障模塊 5..藍牙模塊 代碼 三、其余模塊 四、總結 ? 本項目可實現小車紅外循跡,L298N電機驅動,紅外避障,超聲波避障,藍牙控制等功能的切換。 ? 紅外循跡,L298N電機驅動,PWM電機調速

    2024年02月04日
    瀏覽(25)
  • 基于51單片機汽車智能燈光控制系統設計

    基于51單片機汽車智能燈光控制系統設計

    (protues仿真+程序+原理圖+PCB+設計說明書) 仿真圖proteus 7.8 程序編譯器:keil 4/keil 5 編程語言:C語言 設計編號:C0049 硬件構成: 51單片機 LCD1602液晶 光敏電阻 超聲波 ADC0832 LED燈 1.按鍵說明:從左邊第一個起,減鍵、加鍵、設置鍵。單獨一個控制為復位按鍵。 2.LCD1602液晶第一行

    2024年02月08日
    瀏覽(24)
  • 基于STM32的智能門鎖/智能門禁多功能系統

    基于STM32的智能門鎖/智能門禁多功能系統

    本次設計是基于STM32F103C8T6(以下C8T6等同)開發(fā)的智能鎖,支持多種方式對系統進行操作:藍牙、指紋、RFID刷卡、4x4鍵盤輸入,擁有友好的藍牙收發(fā)界面和LCD交互界面。 藍牙:作為總系統的管理員,有主管理和次管理,主管理只能有一個,副管理員可以有多個。主管理員擁有

    2024年02月08日
    瀏覽(31)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包