中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

有做瀏覽單的網站/百度小說風云榜2022

有做瀏覽單的網站,百度小說風云榜2022,蛋糕店網站建設模版,群暉打開wordpress4.9.8目錄 1.電機模塊開發(fā) 1.1 讓小車動起來 1.2 串口控制小車方向 1.3 如何進行小車PWM調速 1.4 PWM方式實現小車轉向 2.循跡小車 2.1 循跡模塊使用 2.2 循跡小車原理 2.3 循跡小車核心代碼 3.跟隨/避障小車 3.1 紅外壁障模塊分析?編輯 3.2 跟隨小車的原理 3.3 跟隨小…

目錄

1.電機模塊開發(fā)

1.1 讓小車動起來

1.2 串口控制小車方向

1.3 如何進行小車PWM調速

1.4 PWM方式實現小車轉向

2.循跡小車?

2.1 循跡模塊使用

2.2 循跡小車原理

2.3 循跡小車核心代碼

3.跟隨/避障小車

3.1 紅外壁障模塊分析?編輯

3.2 跟隨小車的原理

3.3 跟隨小車開發(fā)和調試代碼

3.4 超聲波模塊介紹

3.5 搖頭測距小車開發(fā)和調試代碼

4.測速小車

4.1 測速模塊

4.2 測試原理和單位換算

4.3 定時器和中斷實現測速開發(fā)和調試代碼

4.4 小車速度顯示在OLED屏

5.遠程控制小車

5.1 藍牙控制小車

5.2 藍牙控制并測速小車

5.3 wifi控制測速小車

5.4 4g控制小車

6.語音控制小車

6.1語音模塊配置:

6.2 語音控制小車開發(fā)和調試代碼


1.電機模塊開發(fā)

L9110s概述

接通VCC,GND 模塊電源指示燈亮, 以下資料來源官方,具體根據實際調試

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

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

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

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

1.1 讓小車動起來

核心代碼:

#include "reg52.h"
#include "intrins.h"sbit RightCon1A = P3^2;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void Delay1000ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}void goForward()
{LeftCon1A = 0;LeftCon1B = 1;RightCon1A = 0;RightCon1B = 1;
}void goLeft()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 1;
}void goRight()
{LeftCon1A = 0;LeftCon1B = 1;RightCon1A = 0;RightCon1B = 0;
}void goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void main()
{while(1){goForward();Delay1000ms();Delay1000ms();goBack();Delay1000ms();Delay1000ms();goLeft();Delay1000ms();Delay1000ms();goRight();Delay1000ms();Delay1000ms();}
}

1.2 串口控制小車方向

  • 串口分文件編程進行代碼整合——具體過程看課程,主要考驗C語言功底和代碼調試能力,通過現象來改代碼
  • 接入藍牙模塊,通過藍牙控制小車
  • 添加點動控制,如果APP支持按下一直發(fā)數據,松開就停止發(fā)數據(藍牙調試助手的自定義按鍵不 能實現),就能實現前進按鍵按下后小車一直往前走的功能

1.3 如何進行小車PWM調速

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

開發(fā):借用PWM的舵機控制代碼

核心代碼:

#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "time.h"extern char speed;void main()
{Time0Init();//UartInit();while(1){speed = 10;//10份單位時間全速運行,30份停止,所以慢,20ms是40份的500usDelay1000ms();Delay1000ms();speed = 20;Delay1000ms();Delay1000ms();speed = 40;Delay1000ms();Delay1000ms();}
}//time.c
#include "motor.h"
#include "reg52.h"char speed;
char cnt = 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. 打開總中斷EAEA = 1;
}void Time0Handler() interrupt 1
{cnt++;  //統計爆表的次數. cnt=1的時候,報表了1//重新給初值TL0=0x33;TH0=0xFE;//控制PWM波if(cnt < speed){//前進goForward();}else{//停止stop();}if(cnt == 40){//爆表40次,經過了20mscnt = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s}}

1.4 PWM方式實現小車轉向

原理: 左輪定時器0調速,右輪定時器1調速,那么左轉就是右輪速度大于左輪!

核心代碼:

#include "motor.h"
#include "reg52.h"char speedLeft;
char cntLeft = 0;char speedRight;
char cntRight = 0;void Time1Init()
{//1. 配置定時器1工作模式位16位計時TMOD &= 0x0F;TMOD |= 0x1 << 4;//2. 給初值,定一個0.5出來TL1=0x33;TH1=0xFE;//3. 開始計時TR1 = 1;TF1 = 0;//4. 打開定時器1中斷ET1 = 1;//5. 打開總中斷EAEA = 1;
}void Time0Init()
{//1. 配置定時器0工作模式位16位計時TMOD = 0x01;//2. 給初值,定一個0.5出來TL0=0x33;TH0=0xFE;//3. 開始計時TR0 = 1;TF0 = 0;//4. 打開定時器0中斷ET0 = 1;//5. 打開總中斷EAEA = 1;
}void Time1Handler() interrupt 3
{cntRight++;  //統計爆表的次數. cnt=1的時候,報表了1//重新給初值TL1=0x33;TH1=0xFE;//控制PWM波if(cntRight < speedRight){//右前進goForwardRight();}else{//停止stopRight();}if(cntRight == 40){//爆表40次,經過了20mscntRight = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s}}void Time0Handler() interrupt 1
{cntLeft++;  //統計爆表的次數. cnt=1的時候,報表了1//重新給初值TL0=0x33;TH0=0xFE;//控制PWM波if(cntLeft < speedLeft){//左前進goForwardLeft();}else{//停止stopLeft();}if(cntLeft == 40){//爆表40次,經過了20mscntLeft = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s}}

2.循跡小車?

2.1 循跡模塊使用

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

接線方式

  • VCC:接電源正極(3-5V)
  • GND:接電源負極 DO:TTL開關信號輸出0、1
  • AO:模擬信號輸出(不同距離輸出不同的電壓,此腳一般可以不接)

2.2 循跡小車原理

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

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

2.3 循跡小車核心代碼

//main.c
#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "time.h"
#include "reg52.h"
extern char speedLeft;
extern char speedRight;sbit leftSensor = P2^7;
sbit rightSensor = P2^6;void main()
{Time0Init();Time1Init();//UartInit();while(1){if(leftSensor == 0 && rightSensor == 0){speedLeft = 32;speedRight = 40;}if(leftSensor == 1 && rightSensor == 0){speedLeft = 12;//10份單位時間全速運行,30份停止,所以慢,20ms是40份的500usspeedRight = 40;}if(leftSensor == 0 && rightSensor == 1){speedLeft = 32;speedRight = 20;}if(leftSensor == 1 && rightSensor == 1){//停speedLeft = 0;speedRight = 0;}}
}//motor.c
#include "reg52.h"sbit RightCon1A = P3^2;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void goForwardLeft()
{LeftCon1A = 0;LeftCon1B = 1;
}void stopLeft()
{LeftCon1A = 0;LeftCon1B = 0;
}void goForwardRight()
{RightCon1A = 0;RightCon1B = 1;
}
void stopRight()
{RightCon1A = 0;RightCon1B = 0;
}void goForward()
{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 goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void stop()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 0;
}//delay.c
#include "intrins.h"void Delay1000ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}//time.c
#include "motor.h"
#include "reg52.h"char speedLeft;
char cntLeft = 0;char speedRight;
char cntRight = 0;void Time1Init()
{//1. 配置定時器1工作模式位16位計時TMOD &= 0x0F;TMOD |= 0x1 << 4;//2. 給初值,定一個0.5出來TL1=0x33;TH1=0xFE;//3. 開始計時TR1 = 1;TF1 = 0;//4. 打開定時器1中斷ET1 = 1;//5. 打開總中斷EAEA = 1;
}void Time0Init()
{//1. 配置定時器0工作模式位16位計時TMOD = 0x01;//2. 給初值,定一個0.5出來TL0=0x33;TH0=0xFE;//3. 開始計時TR0 = 1;TF0 = 0;//4. 打開定時器0中斷ET0 = 1;//5. 打開總中斷EAEA = 1;
}void Time1Handler() interrupt 3
{cntRight++;  //統計爆表的次數. cnt=1的時候,報表了1//重新給初值TL1=0x33;TH1=0xFE;//控制PWM波if(cntRight < speedRight){//右前進goForwardRight();}else{//停止stopRight();}if(cntRight == 40){//爆表40次,經過了20mscntRight = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s}}void Time0Handler() interrupt 1
{cntLeft++;  //統計爆表的次數. cnt=1的時候,報表了1//重新給初值TL0=0x33;TH0=0xFE;//控制PWM波if(cntLeft < speedLeft){//左前進goForwardLeft();}else{//停止stopLeft();}if(cntLeft == 40){//爆表40次,經過了20mscntLeft = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s}}

3.跟隨/避障小車

3.1 紅外壁障模塊分析

原理和循跡是一樣的,循跡紅外觀朝下,跟隨朝前

3.2 跟隨小車的原理

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

3.3 跟隨小車開發(fā)和調試代碼

//main.c
#include "motor.h"
#include "delay.h"
#include "reg52.h"//sbit leftSensor = P2^7;
//sbit rightSensor = P2^6;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();}}
}//motor.c
#include "reg52.h"sbit RightCon1A = P3^2;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void goForward()
{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 goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void stop()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 0;
}//delay.c#include "intrins.h"void Delay1000ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}

3.4 超聲波模塊介紹

使用超聲波模塊,型號:HC-SR04

  • 怎么讓它發(fā)送波 Trig ,給Trig端口至少10us的高電平
  • 怎么知道它開始發(fā)了 Echo信號,由低電平跳轉到高電平,表示開始發(fā)送波
  • 怎么知道接收了返回波 Echo,由高電平跳轉回低電平,表示波回來了
  • 怎么算時間 Echo引腳維持高電平的時間! 波發(fā)出去的那一下,開始啟動定時器 波回來的拿一下,我們開始停止定時器,計算出中間經過多少時間
  • 怎么算距離 距離 = 速度 (340m/s)* 時間/2

時序圖:

3.5 搖頭測距小車開發(fā)和調試代碼

//main.c
#include "reg52.h"
#include "hc04.h"
#include "delay.h"
#include "sg90.h"
#include "motor.h"#define MIDDLE 0
#define LEFT 1
#define RIGHT 2void main()
{char dir;double disMiddle;double disLeft;double disRight;Time0Init();Time1Init();//舵機的初始位置sgMiddle();Delay300ms();Delay300ms();dir = MIDDLE;while(1){if(dir != MIDDLE){sgMiddle();dir = MIDDLE;Delay300ms();}disMiddle = get_distance();if(disMiddle > 35){//前進goForward();}else if(disMiddle < 10){goBack();}else{//停止stop();//測左邊距離sgLeft();Delay300ms();disLeft = get_distance();sgMiddle();Delay300ms();sgRight();dir = RIGHT;Delay300ms();disRight = get_distance();if(disLeft < disRight){goRight();Delay150ms();stop();}if(disRight < disLeft){goLeft();Delay150ms();stop();}}}
}//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()
{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)* 時間/2return  (time * 0.017);
}//delay.c
#include "intrins.h"void Delay2000ms()		//@11.0592MHz
{unsigned char i, j, k;i = 15;j = 2;k = 235;do{do{while (--k);} while (--j);} while (--i);
}void Delay10us()		//@11.0592MHz
{unsigned char i;i = 2;while (--i);
}void Delay300ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 3;j = 26;k = 223;do{do{while (--k);} while (--j);} while (--i);
}void Delay150ms()		//@11.0592MHz
{unsigned char i, j, k;i = 2;j = 13;k = 237;do{do{while (--k);} while (--j);} while (--i);
}void Delay450ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 4;j = 39;k = 209;do{do{while (--k);} while (--j);} while (--i);
}//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. 打開總中斷EAEA = 1;
}void sgMiddle()
{//中間位置jd = 3; //90度 1.5ms高電平cnt = 0;
}void sgLeft()
{//左邊位置jd = 5; //135度 1.5ms高電平cnt = 0;
}void sgRight()
{//右邊位置jd = 1; //0度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次,經過了20mscnt = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1ssg90_con = 1;}}//motor.c
#include "reg52.h"sbit RightCon1A = P3^2;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void goForward()
{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 goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void stop()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 0;
}

4.測速小車

4.1 測速模塊

  • 用途:廣泛用于電機轉速檢測,脈沖計數,位置限位等。
  • 有遮擋,輸出高電平;無遮擋,輸出低電平
  • 接線 :VCC 接電源正極3.3-5V
  • GND 接電源負極 DO TTL開關信號輸出
  • AO 此模塊不起作用

4.2 測試原理和單位換算

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

4.3 定時器和中斷實現測速開發(fā)和調試代碼

測試數據通過串口發(fā)送到上位機

//main.c
#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "reg52.h"
#include "time.h"
#include "stdio.h"sbit speedIO = P3^2;//外部中斷0
unsigned int speedCnt = 0; //統計格子,脈沖次數
extern unsigned int speed;//速度
extern char signal; //主程序發(fā)速度數據的通知
char speedMes[24];  //主程序發(fā)送速度數據的字符串緩沖區(qū)void Ex0Init()
{EX0 = 1;//允許中斷//EA = 1;在串口初始化函數中已經打開了總中斷IT0 = 1;//外部中斷的下降沿觸發(fā)
}void main()
{Time0Init();//定時器0初始化UartInit();//串口相關初始化//外部中斷初始化Ex0Init();while(1){if(signal){//定時器1s到點,把signal置一,主程序發(fā)送速度sprintf(speedMes,"speed:%d cm/s",speed);//串口數據的字符串拼裝,speed是格子,每個格子1cmSendString(speedMes);//速度發(fā)出去signal = 0;//清0speed,下次由定時器1s后的中斷處理中再置一}}
}void speedHandler() interrupt 0 //外部中斷處理函數
{speedCnt++;//碼盤轉動了一個格子
}//uart.c
#include "reg52.h"
#include "motor.h"
#include "string.h"
sbit D5 = P3^7;
#define SIZE 12sfr AUXR = 0x8E;
char buffer[SIZE];void UartInit(void)		//9600bps@11.0592MHz
{AUXR = 0x01;SCON = 0x50; //配置串口工作方式1,REN使能接收TMOD &= 0x0F;TMOD |= 0x20;//定時器1工作方式位8位自動重裝TH1 = 0xFD;TL1 = 0xFD;//9600波特率的初值TR1 = 1;//啟動定時器EA = 1;//開啟總中斷ES = 1;//開啟串口中斷
}void SendByte(char mydata)
{SBUF = mydata;while(!TI);TI = 0;
}void SendString(char *str)
{while(*str != '\0'){SendByte(*str);str++;}
}//M1qian  M2 hou M3 zuo  M4 you
void Uart_Handler() interrupt 4
{static int i = 0;//靜態(tài)變量,被初始化一次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;default:stop();break;}}if(i == 12) {memset(buffer, '\0', SIZE);i = 0;}}}//motor.c
#include "reg52.h"sbit RightCon1A = P3^7;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void goForward()
{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 goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void stop()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 0;
}//time.c
#include "motor.h"
#include "reg52.h"extern unsigned int speedCnt;
unsigned int speed;
char signal = 0;
unsigned int cnt = 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. 打開總中斷EAEA = 1;
}void Time0Handler() interrupt 1
{cnt++;  //統計爆表的次數. cnt=1的時候,報表了1//重新給初值TL0=0x33;TH0=0xFE;if(cnt == 2000){//爆表2000次,經過了1ssignal = 1;cnt = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s//計算小車的速度,也就是拿到speedCnt的值speed = speedCnt;speedCnt = 0;//1秒后拿到speedCnt個格子,就能算出這1s的速度,格子清零}}

4.4 小車速度顯示在OLED屏

使用oled模塊

//main.c
#include "reg52.h"
#include "intrins.h"
#include "Oled.h"void main()
{//1. OLED初始化Oled_Init();Oled_Clear();Oled_Show_Str(2,2,"speed:35cm/s");while(1);
}//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 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據IIC_Send_Byte(0x00);//	5. ACKIIC_ACK();//6. 寫入指令/數據IIC_Send_Byte(dataCmd);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Write_Data(char dataData)
{//	1. start()IIC_Start();//		//	2. 寫入從機地址  b0111 1000 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據IIC_Send_Byte(0x40);//	5. ACKIIC_ACK();///6. 寫入指令/數據IIC_Send_Byte(dataData);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Init(void){Oled_Write_Cmd(0xAE);//--display offOled_Write_Cmd(0x00);//---set low column addressOled_Write_Cmd(0x10);//---set high column addressOled_Write_Cmd(0x40);//--set start line address  Oled_Write_Cmd(0xB0);//--set page addressOled_Write_Cmd(0x81); // contract controlOled_Write_Cmd(0xFF);//--128   Oled_Write_Cmd(0xA1);//set segment remap Oled_Write_Cmd(0xA6);//--normal / reverseOled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)Oled_Write_Cmd(0x3F);//--1/32 dutyOled_Write_Cmd(0xC8);//Com scan directionOled_Write_Cmd(0xD3);//-set display offsetOled_Write_Cmd(0x00);//Oled_Write_Cmd(0xD5);//set osc divisionOled_Write_Cmd(0x80);//Oled_Write_Cmd(0xD8);//set area color mode offOled_Write_Cmd(0x05);//Oled_Write_Cmd(0xD9);//Set Pre-Charge PeriodOled_Write_Cmd(0xF1);//Oled_Write_Cmd(0xDA);//set com pin configuartionOled_Write_Cmd(0x12);//Oled_Write_Cmd(0xDB);//set VcomhOled_Write_Cmd(0x30);//Oled_Write_Cmd(0x8D);//set charge pump enableOled_Write_Cmd(0x14);//Oled_Write_Cmd(0xAF);//--turn on oled panel		
}void Oled_Clear()
{unsigned char i,j; //-128 --- 127for(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-2unsigned int  i;Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_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 1Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_Write_Cmd(0x10+(col>>4));                            //highfor(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;	}		
}

5.遠程控制小車

5.1 藍牙控制小車

  • 使用藍牙模塊,串口透傳
  • 藍牙模塊,又叫做藍牙串口模塊

串口透傳技術:

  • 透傳即透明傳送,是指在數據的傳輸過程中,通過無線的方式這組數據不發(fā)生任何形式的改變,仿 佛傳輸過程是透明的一樣,同時保證傳輸的質量,原封不動地到了最終接收者手里。
  • 以太網,藍牙,Zigbee, GPRS 等模塊玩法一樣,對嵌入式程序員來說,不需要關心通訊模塊內部數據 及協議棧工作原理,只要通過串口編程獲得數據即可

代碼實現:

//main.c
#include "motor.h"
#include "delay.h"
#include "uart.h"void main()
{UartInit();while(1){stop();}
}//uart.c
#include "reg52.h"
#include "motor.h"
#include "string.h"
#include "delay.h"
sbit D5 = P3^7;
#define SIZE 12sfr AUXR = 0x8E;
char buffer[SIZE];void UartInit(void)		//9600bps@11.0592MHz
{AUXR = 0x01;SCON = 0x50; //配置串口工作方式1,REN使能接收TMOD &= 0x0F;TMOD |= 0x20;//定時器1工作方式位8位自動重裝TH1 = 0xFD;TL1 = 0xFD;//9600波特率的初值TR1 = 1;//啟動定時器EA = 1;//開啟總中斷ES = 1;//開啟串口中斷
}//M1qian  M2 hou M3 zuo  M4 you
void Uart_Handler() interrupt 4
{static int i = 0;//靜態(tài)變量,被初始化一次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();Delay10ms();break;case '2':goBack();Delay10ms();break;case '3':goLeft();Delay10ms();break;case '4':goRight();Delay10ms();break;default:stop();break;}}if(i == 12) {memset(buffer, '\0', SIZE);i = 0;}}}//motor.c
#include "reg52.h"sbit RightCon1A = P3^2;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void goForward()
{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 goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void stop()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 0;
}//delay.c#include "intrins.h"void Delay10ms()		//@11.0592MHz
{unsigned char i, j;i = 18;j = 235;do{while (--j);} while (--i);
}void Delay1000ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}

5.2 藍牙控制并測速小車

原理:運用上面講到的藍牙模塊和測速模塊

代碼實現:

//main.c
#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "reg52.h"
#include "time.h"
#include "stdio.h"
#include "Oled.h"sbit speedIO = P3^2;//外部中斷0
unsigned int speedCnt = 0; //統計格子,脈沖次數
extern unsigned int speed;//速度
extern char signal; //主程序發(fā)速度數據的通知
char speedMes[24];  //主程序發(fā)送速度數據的字符串緩沖區(qū)void Ex0Init()
{EX0 = 1;//允許中斷//EA = 1;在串口初始化函數中已經打開了總中斷IT0 = 1;//外部中斷的下降沿觸發(fā)
}void main()
{Time0Init();//定時器0初始化UartInit();//串口相關初始化//外部中斷初始化Ex0Init();Oled_Init();Oled_Clear();while(1){if(signal){//定時器1s到點,把signal置一,主程序發(fā)送速度sprintf(speedMes,"speed:%d cm/s",speed);//串口數據的字符串拼裝,speed是格子,每個格子1cmSendString(speedMes);//速度發(fā)出去signal = 0;//清0speed,下次由定時器1s后的中斷處理中再置一}Oled_Show_Str(2,2,speedMes);}
}void speedHandler() interrupt 0 //外部中斷處理函數
{speedCnt++;//碼盤轉動了一個格子
}//uart.c
#include "reg52.h"
#include "motor.h"
#include "string.h"
sbit D5 = P3^7;
#define SIZE 12sfr AUXR = 0x8E;
char buffer[SIZE];void UartInit(void)		//9600bps@11.0592MHz
{AUXR = 0x01;SCON = 0x50; //配置串口工作方式1,REN使能接收TMOD &= 0x0F;TMOD |= 0x20;//定時器1工作方式位8位自動重裝TH1 = 0xFD;TL1 = 0xFD;//9600波特率的初值TR1 = 1;//啟動定時器EA = 1;//開啟總中斷ES = 1;//開啟串口中斷
}void SendByte(char mydata)
{SBUF = mydata;while(!TI);TI = 0;
}void SendString(char *str)
{while(*str != '\0'){SendByte(*str);str++;}
}//M1qian  M2 hou M3 zuo  M4 you
void Uart_Handler() interrupt 4
{static int i = 0;//靜態(tài)變量,被初始化一次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;default:stop();break;}}if(i == 12) {memset(buffer, '\0', SIZE);i = 0;}}}//motor.c
#include "reg52.h"sbit RightCon1A = P3^7;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void goForward()
{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 goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void stop()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 0;
}//time.c
#include "motor.h"
#include "reg52.h"extern unsigned int speedCnt;
unsigned int speed;
char signal = 0;
unsigned int cnt = 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. 打開總中斷EAEA = 1;
}void Time0Handler() interrupt 1
{cnt++;  //統計爆表的次數. cnt=1的時候,報表了1//重新給初值TL0=0x33;TH0=0xFE;if(cnt == 2000){//爆表2000次,經過了1ssignal = 1;cnt = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s//計算小車的速度,也就是拿到speedCnt的值speed = speedCnt;speedCnt = 0;//1秒后拿到speedCnt個格子,就能算出這1s的速度,格子清零}}//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 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據IIC_Send_Byte(0x00);//	5. ACKIIC_ACK();//6. 寫入指令/數據IIC_Send_Byte(dataCmd);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Write_Data(char dataData)
{//	1. start()IIC_Start();//		//	2. 寫入從機地址  b0111 1000 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據IIC_Send_Byte(0x40);//	5. ACKIIC_ACK();///6. 寫入指令/數據IIC_Send_Byte(dataData);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Init(void){Oled_Write_Cmd(0xAE);//--display offOled_Write_Cmd(0x00);//---set low column addressOled_Write_Cmd(0x10);//---set high column addressOled_Write_Cmd(0x40);//--set start line address  Oled_Write_Cmd(0xB0);//--set page addressOled_Write_Cmd(0x81); // contract controlOled_Write_Cmd(0xFF);//--128   Oled_Write_Cmd(0xA1);//set segment remap Oled_Write_Cmd(0xA6);//--normal / reverseOled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)Oled_Write_Cmd(0x3F);//--1/32 dutyOled_Write_Cmd(0xC8);//Com scan directionOled_Write_Cmd(0xD3);//-set display offsetOled_Write_Cmd(0x00);//Oled_Write_Cmd(0xD5);//set osc divisionOled_Write_Cmd(0x80);//Oled_Write_Cmd(0xD8);//set area color mode offOled_Write_Cmd(0x05);//Oled_Write_Cmd(0xD9);//Set Pre-Charge PeriodOled_Write_Cmd(0xF1);//Oled_Write_Cmd(0xDA);//set com pin configuartionOled_Write_Cmd(0x12);//Oled_Write_Cmd(0xDB);//set VcomhOled_Write_Cmd(0x30);//Oled_Write_Cmd(0x8D);//set charge pump enableOled_Write_Cmd(0x14);//Oled_Write_Cmd(0xAF);//--turn on oled panel		
}void Oled_Clear()
{unsigned char i,j; //-128 --- 127for(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-2unsigned int  i;Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_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 1Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_Write_Cmd(0x10+(col>>4));                            //highfor(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;	}		
}

5.3 wifi控制測速小車

  • Wifi模塊-ESP-01s
  • 藍牙,ESP-01s,Zigbee, NB-Iot等通信模塊都是基于AT指令的設計

AT指令介紹:

  • AT指令集是從終端設備(Terminal Equipment,TE)或數據終端設備(Data Terminal Equipment,DTE)向終端適配器(Terminal Adapter,TA)或數據電路終端設備(Data Circuit Terminal Equipment,DCE)發(fā)送的。
  • 其對所傳輸的數據包大小有定義:即對于AT指令的發(fā)送,除AT兩個字符外,最多可以接收1056個 字符的長度(包括最后的空字符)。
  • 每個AT命令行中只能包含一條AT指令;對于由終端設備主動向PC端報告的URC指示或者response 響應,也要求一行最多有一個,不允許上報的一行中有多條指示或者響應。AT指令以回車作為結 尾,響應或上報以回車換行為結尾。

代碼實現:

//main.c
#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "reg52.h"
#include "time.h"
#include "stdio.h"
#include "Oled.h"
#include "esp8266.h"sbit speedIO = P3^2;//外部中斷0
unsigned int speedCnt = 0; //統計格子,脈沖次數
extern unsigned int speed;//速度
extern char signal; //主程序發(fā)速度數據的通知
char speedMes[24];  //主程序發(fā)送速度數據的字符串緩沖區(qū)
//發(fā)送數據
char FSSJ[] = "AT+CIPSEND=0,5\r\n";void Ex0Init()
{EX0 = 1;//允許中斷//EA = 1;在串口初始化函數中已經打開了總中斷IT0 = 1;//外部中斷的下降沿觸發(fā)
}void main()
{Time0Init();//定時器0初始化UartInit();//串口相關初始化Delay1000ms();//給espwifi模塊上電時間initWifi_AP(); //初始化wifi工作在ap模式waitConnect(); //等待客戶端的連接//外部中斷初始化Ex0Init();Oled_Init();Oled_Clear();while(1){if(signal){//定時器1s到點,把signal置一,主程序發(fā)送速度SendString(FSSJ);Delay1000ms();sprintf(speedMes,"%dcms",speed);//串口數據的字符串拼裝,speed是格子,每個格子1cmSendString(speedMes);//速度發(fā)出去signal = 0;//清0speed,下次由定時器1s后的中斷處理中再置一}Oled_Show_Str(2,2,speedMes);}
}void speedHandler() interrupt 0 //外部中斷處理函數
{speedCnt++;//碼盤轉動了一個格子
}//uart.c
#include "reg52.h"
#include "motor.h"
#include "string.h"
sbit D5 = P3^7;
#define SIZE 12sfr AUXR = 0x8E;
char buffer[SIZE];extern char AT_OK_Flag;				//OK返回值的標志位
extern char Client_Connect_Flag;void UartInit(void)		//9600bps@11.0592MHz
{AUXR = 0x01;SCON = 0x50; //配置串口工作方式1,REN使能接收TMOD &= 0x0F;TMOD |= 0x20;//定時器1工作方式位8位自動重裝TH1 = 0xFD;TL1 = 0xFD;//9600波特率的初值TR1 = 1;//啟動定時器EA = 1;//開啟總中斷ES = 1;//開啟串口中斷
}void SendByte(char mydata)
{SBUF = mydata;while(!TI);TI = 0;
}void SendString(char *str)
{while(*str != '\0'){SendByte(*str);str++;}
}//M1qian  M2 hou M3 zuo  M4 you
void Uart_Handler() interrupt 4
{static int i = 0;//靜態(tài)變量,被初始化一次char tmp;if(RI)//中斷處理函數中,對于接收中斷的響應{RI = 0;//清除接收中斷標志位tmp = SBUF;if(tmp == 'M' || tmp == 'O' || tmp == '0'){i = 0;}buffer[i++] = tmp;//連接服務器等OK返回值指令的判斷if(buffer[0] == 'O' && buffer[1] == 'K'){AT_OK_Flag	= 1;memset(buffer, '\0', SIZE);}if(buffer[0] == '0' && buffer[2] == 'C'){Client_Connect_Flag	= 1;memset(buffer, '\0', SIZE);}//燈控指令if(buffer[0] == 'M'){switch(buffer[1]){case '1':goForward();break;case '2':goBack();break;case '3':goLeft();break;case '4':goRight();break;default:stop();break;}}if(i == 12) {memset(buffer, '\0', SIZE);i = 0;}}}//motor.c
#include "reg52.h"sbit RightCon1A = P3^7;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void goForward()
{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 goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void stop()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 0;
}//time.c
#include "motor.h"
#include "reg52.h"extern unsigned int speedCnt;
unsigned int speed;
char signal = 0;
unsigned int cnt = 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. 打開總中斷EAEA = 1;
}void Time0Handler() interrupt 1
{cnt++;  //統計爆表的次數. cnt=1的時候,報表了1//重新給初值TL0=0x33;TH0=0xFE;if(cnt == 2000){//爆表2000次,經過了1ssignal = 1;cnt = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1s//計算小車的速度,也就是拿到speedCnt的值speed = speedCnt;speedCnt = 0;//1秒后拿到speedCnt個格子,就能算出這1s的速度,格子清零}}//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 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據IIC_Send_Byte(0x00);//	5. ACKIIC_ACK();//6. 寫入指令/數據IIC_Send_Byte(dataCmd);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Write_Data(char dataData)
{//	1. start()IIC_Start();//		//	2. 寫入從機地址  b0111 1000 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據IIC_Send_Byte(0x40);//	5. ACKIIC_ACK();///6. 寫入指令/數據IIC_Send_Byte(dataData);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Init(void){Oled_Write_Cmd(0xAE);//--display offOled_Write_Cmd(0x00);//---set low column addressOled_Write_Cmd(0x10);//---set high column addressOled_Write_Cmd(0x40);//--set start line address  Oled_Write_Cmd(0xB0);//--set page addressOled_Write_Cmd(0x81); // contract controlOled_Write_Cmd(0xFF);//--128   Oled_Write_Cmd(0xA1);//set segment remap Oled_Write_Cmd(0xA6);//--normal / reverseOled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)Oled_Write_Cmd(0x3F);//--1/32 dutyOled_Write_Cmd(0xC8);//Com scan directionOled_Write_Cmd(0xD3);//-set display offsetOled_Write_Cmd(0x00);//Oled_Write_Cmd(0xD5);//set osc divisionOled_Write_Cmd(0x80);//Oled_Write_Cmd(0xD8);//set area color mode offOled_Write_Cmd(0x05);//Oled_Write_Cmd(0xD9);//Set Pre-Charge PeriodOled_Write_Cmd(0xF1);//Oled_Write_Cmd(0xDA);//set com pin configuartionOled_Write_Cmd(0x12);//Oled_Write_Cmd(0xDB);//set VcomhOled_Write_Cmd(0x30);//Oled_Write_Cmd(0x8D);//set charge pump enableOled_Write_Cmd(0x14);//Oled_Write_Cmd(0xAF);//--turn on oled panel		
}void Oled_Clear()
{unsigned char i,j; //-128 --- 127for(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-2unsigned int  i;Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_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 1Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_Write_Cmd(0x10+(col>>4));                            //highfor(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;	}		
}//esp8266.c
#include "uart.h"//1 工作在路由模式
code char LYMO[] = "AT+CWMODE=2\r\n";
//2 使能多鏈接
code char DLJ[] = "AT+CIPMUX=1\r\n"; 
//3 建立TCPServer
code char JLFW[] = "AT+CIPSERVER=1\r\n"; // default port = 333 char AT_OK_Flag = 0;				//OK返回值的標志位
char Client_Connect_Flag = 0;void initWifi_AP()
{SendString(LYMO);while(!AT_OK_Flag);AT_OK_Flag = 0;SendString(DLJ);while(!AT_OK_Flag);AT_OK_Flag = 0;
}void waitConnect()
{SendString(JLFW);while(!Client_Connect_Flag);AT_OK_Flag = 0;	
}//delay.c
#include "intrins.h"void Delay1000ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}

5.4 4g控制小車

原理:運用EC03-DNC4G通信模塊

模塊介紹:

  • 基于串口AT指令的開發(fā)方式
  • 有兩種工作模式,默認是透傳模式,通過其他方式進入AT指令模式
  • 注意插卡不要出錯,下圖紅色位置為SIM卡狀態(tài)燈,亮才是正常

代碼不做修改,直接基于藍牙小車整合,?4g模塊只要做好外網透傳就可以了

6.語音控制小車

6.1語音模塊配置

使用SU-03T / LD3320

具體介紹看我之前寫過的博客:https://blog.csdn.net/m0_74712453/article/details/13171085

6.2 語音控制小車開發(fā)和調試代碼

代碼示例:

//main.c
#include "reg52.h"
#include "hc04.h"
#include "delay.h"
#include "sg90.h"
#include "Oled.h"
#include "motor.h"#define MIDDLE 0
#define LEFT 1
#define RIGHT 2#define BZ 1
#define XJ 2
#define GS 3sbit A25 = P1^5;
sbit A26 = P1^6;
sbit A27 = P1^7;sbit leftSensorX = P2^7;
sbit rightSensorX = P2^6;sbit leftSensorG = P2^5;
sbit rightSensorG = P2^4;char dir;double disMiddle;
double disLeft;
double disRight;void xunjiMode()
{if(leftSensorX == 0 && rightSensorX == 0){goForward();}if(leftSensorX == 1 && rightSensorX == 0){goLeft();}if(leftSensorX == 0 && rightSensorX == 1){goRight();}if(leftSensorX == 1 && rightSensorX == 1){//停stop();}
}void gensuiMode()
{if(leftSensorG == 0 && rightSensorG == 0){goForward();}if(leftSensorG == 1 && rightSensorG == 0){goRight();}if(leftSensorG == 0 && rightSensorG == 1){goLeft();}if(leftSensorG == 1 && rightSensorG == 1){//停stop();}
}void bizhangMode()
{if(dir != MIDDLE){sgMiddle();dir = MIDDLE;Delay300ms();}disMiddle = get_distance();if(disMiddle > 35){//前進goForward();}else if(disMiddle < 10){goBack();}else{//停止stop();//測左邊距離sgLeft();Delay300ms();disLeft = get_distance();sgMiddle();Delay300ms();sgRight();dir = RIGHT;Delay300ms();disRight = get_distance();if(disLeft < disRight){goRight();Delay150ms();stop();}if(disRight < disLeft){goLeft();Delay150ms();stop();}}}void main()
{int mark = 0;Time0Init();Time1Init();//舵機的初始位置sgMiddle();Delay300ms();Delay300ms();dir = MIDDLE;Oled_Init();Oled_Clear();Oled_Show_Str(2,2,"-----Ready----");while(1){//滿足尋跡模式的條件if(A25 == 0 && A26 == 1 && A27 == 1){if(mark != XJ){Oled_Clear();Oled_Show_Str(2,2,"-----XunJi----");}mark = XJ;xunjiMode();}//滿足跟隨模式的條件if(A25 == 1 && A26 == 0 && A27 == 1){if(mark != GS){Oled_Clear();Oled_Show_Str(2,2,"-----GenSui----");}mark = GS;gensuiMode();}//滿足避障模式的條件if(A25 == 1 && A26 == 1 && A27 == 0){if(mark != BZ){Oled_Clear();Oled_Show_Str(2,2,"-----BiZhang----");}mark = BZ;bizhangMode();}}
}//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()
{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)* 時間/2return  (time * 0.017);
}//delay.c
#include "intrins.h"void Delay2000ms()		//@11.0592MHz
{unsigned char i, j, k;i = 15;j = 2;k = 235;do{do{while (--k);} while (--j);} while (--i);
}void Delay10us()		//@11.0592MHz
{unsigned char i;i = 2;while (--i);
}void Delay300ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 3;j = 26;k = 223;do{do{while (--k);} while (--j);} while (--i);
}void Delay150ms()		//@11.0592MHz
{unsigned char i, j, k;i = 2;j = 13;k = 237;do{do{while (--k);} while (--j);} while (--i);
}void Delay450ms()		//@11.0592MHz
{unsigned char i, j, k;_nop_();i = 4;j = 39;k = 209;do{do{while (--k);} while (--j);} while (--i);
}//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. 打開總中斷EAEA = 1;
}void sgMiddle()
{//中間位置jd = 3; //90度 1.5ms高電平cnt = 0;
}void sgLeft()
{//左邊位置jd = 5; //135度 1.5ms高電平cnt = 0;
}void sgRight()
{//右邊位置jd = 1; //0度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次,經過了20mscnt = 0;  //當100次表示1s,重新讓cnt從0開始,計算下一次的1ssg90_con = 1;}}//motor.c
#include "reg52.h"sbit RightCon1A = P3^7;
sbit RightCon1B = P3^3;sbit LeftCon1A = P3^4;
sbit LeftCon1B = P3^5;void goForward()
{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 goBack()
{LeftCon1A = 1;LeftCon1B = 0;RightCon1A = 1;RightCon1B = 0;
}void stop()
{LeftCon1A = 0;LeftCon1B = 0;RightCon1A = 0;RightCon1B = 0;
}//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 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據IIC_Send_Byte(0x00);//	5. ACKIIC_ACK();//6. 寫入指令/數據IIC_Send_Byte(dataCmd);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Write_Data(char dataData)
{//	1. start()IIC_Start();//		//	2. 寫入從機地址  b0111 1000 0x78IIC_Send_Byte(0x78);//	3. ACKIIC_ACK();//	4. cotrol byte: (0)(0)000000 寫入命令   (0)(1)000000寫入數據IIC_Send_Byte(0x40);//	5. ACKIIC_ACK();///6. 寫入指令/數據IIC_Send_Byte(dataData);//7. ACKIIC_ACK();//8. STOPIIC_Stop();
}void Oled_Init(void){Oled_Write_Cmd(0xAE);//--display offOled_Write_Cmd(0x00);//---set low column addressOled_Write_Cmd(0x10);//---set high column addressOled_Write_Cmd(0x40);//--set start line address  Oled_Write_Cmd(0xB0);//--set page addressOled_Write_Cmd(0x81); // contract controlOled_Write_Cmd(0xFF);//--128   Oled_Write_Cmd(0xA1);//set segment remap Oled_Write_Cmd(0xA6);//--normal / reverseOled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)Oled_Write_Cmd(0x3F);//--1/32 dutyOled_Write_Cmd(0xC8);//Com scan directionOled_Write_Cmd(0xD3);//-set display offsetOled_Write_Cmd(0x00);//Oled_Write_Cmd(0xD5);//set osc divisionOled_Write_Cmd(0x80);//Oled_Write_Cmd(0xD8);//set area color mode offOled_Write_Cmd(0x05);//Oled_Write_Cmd(0xD9);//Set Pre-Charge PeriodOled_Write_Cmd(0xF1);//Oled_Write_Cmd(0xDA);//set com pin configuartionOled_Write_Cmd(0x12);//Oled_Write_Cmd(0xDB);//set VcomhOled_Write_Cmd(0x30);//Oled_Write_Cmd(0x8D);//set charge pump enableOled_Write_Cmd(0x14);//Oled_Write_Cmd(0xAF);//--turn on oled panel		
}void Oled_Clear()
{unsigned char i,j; //-128 --- 127for(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-2unsigned int  i;Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_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 1Oled_Write_Cmd(0x00+(col&0x0f));                          //lowOled_Write_Cmd(0x10+(col>>4));                            //highfor(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;	}		
}

???????

http://www.risenshineclean.com/news/28.html

相關文章:

  • 如何建設英文網站/淘寶店鋪買賣交易平臺
  • 開一個網站建設公司/it培訓四個月騙局
  • 廊坊市做網站/贛州seo排名
  • 手機商城網站開發(fā)/seo流量的提升的軟件
  • 做澳洲外貿的網站有哪些/港港網app下載最新版
  • 不懂代碼用cms做網站/h5制作
  • 好的做網站公司/營銷網站做的好的公司
  • 什么做網站/學生網頁制作成品
  • 福建建筑人才服務中心檔案/熱狗seo顧問
  • 做網站困難嗎/優(yōu)秀網站設計欣賞
  • 做貨到付款的購物網站/seo的中文含義是什么
  • 網站后臺是怎樣制作/經典軟文案例100例簡短
  • 2021年有沒有人給個網站/全網營銷系統
  • 長江設計公司/網絡優(yōu)化報告
  • 萬網網站備案多久/免費優(yōu)化網站
  • 上海網站排名優(yōu)化公司/谷歌seo快速排名軟件首頁
  • 網站建設開發(fā)平臺/網絡服務器的作用
  • 做平面什么網站好用/百度禁止seo推廣
  • 中國平面設計網站/廣告營銷案例分析
  • 網站建設橙子/百度教育app
  • 蘇省住房和城鄉(xiāng)建設廳網站首頁/百度應用市場app下載安裝
  • 做網站需要源碼/河南做網站優(yōu)化