当前位置:   article > 正文

【51单片机篇】项目:智能小车_寻迹小车项目概述

寻迹小车项目概述

一、项目概述

该智能小车具有循迹、跟随、避障三种模式,可以通过语音识别实现三种模式的切换,并且在oled显示屏显示当前模式。在循迹模式下,小车可以通过循迹模块跟随赛道中的黑线位置实时改变方向,并沿赛道前行;在跟随模式下,小车可以通过跟随模块实时跟随前方物体而移动;在避障模式下,小车利用超声波模块检测前方距离,并根据距离判断障碍物位置,并及时躲避前方障碍。

二、硬件部分 

1.小车底盘套件

2.51开发板

3.电池盒(4节)

4.面包板

5.L9110s电机驱动模块

6.循迹模块(2个)

7.红外跟随模块(2个)

8.SU-03语音模块

9.OLED显示屏

10.超声波

11.sg-90舵机

12.杜邦线若干

•循迹模块介绍 

当发射出的红外线没有被反射回来或被反射回来但强度不够大时,红外接收管一直处于关断状态,此时模块的输出端为高电平,指示二极管一直处于熄灭状态被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管饱和,此时模块的输出端为低电平,指示二极管被点亮。

总结就是一句话,有感应到黑线,D0输出高电平 ,灭灯。
•跟随模块介绍

左边跟随模块能返回红外,输出低电平,右边不能返回,输出高电平,物体在左边,需要左转;

右边跟随模块能返回红外,输出低电平,左边不能返回,输出高电平,物体在右边,需要右转。
•语音模块介绍 

 语音模块配置网址如下: 

 智能公元/AI产品零代码平台 (smartpi.cn)

配置好以后先连接USB转TTL进行固件烧录 测试(SU-03T 的RX是B6  TX是B7 ),测试无误后即可接入开发板使用。

三、软件部分 

main.c

  1. #include "reg52.h"
  2. #include "hc04.h"
  3. #include "delay.h"
  4. #include "sg90.h"
  5. #include "motor.h"
  6. #include "Oled.h"
  7. #define MIDDLE 0
  8. #define LEFT 1
  9. #define RIGHT 2
  10. #define BZ 1
  11. #define XJ 2
  12. #define GS 3
  13. #define ST 4
  14. sbit A25 = P1^5;
  15. sbit A26 = P1^6;
  16. sbit A27 = P1^7;
  17. sbit leftSensoXJ = P2^7;
  18. sbit rightSensorXJ = P2^6;
  19. sbit leftSensorGS = P2^5;
  20. sbit rightSensorGS = P2^4;
  21. char dir;
  22. double disMiddle;
  23. double disLeft;
  24. double disRight;
  25. void xunjiMode()
  26. {
  27. if(leftSensoXJ == 0 && rightSensorXJ == 0){
  28. goForward();//前进
  29. }
  30. if(leftSensoXJ == 1 && rightSensorXJ == 0){
  31. goLeft();//左转
  32. }
  33. if(leftSensoXJ == 0 && rightSensorXJ == 1){
  34. goRight();//右转
  35. }
  36. if(leftSensoXJ == 1 && rightSensorXJ == 1){
  37. stop();//停止
  38. }
  39. }
  40. void gensuiMode()
  41. {
  42. if(leftSensorGS == 0 && rightSensorGS == 0){
  43. goForward();//前进
  44. }
  45. if(leftSensorGS == 1 && rightSensorGS == 0){
  46. goRight();//右转
  47. }
  48. if(leftSensorGS == 0 && rightSensorGS == 1){
  49. goLeft();//左转
  50. }
  51. if(leftSensorGS == 1 && rightSensorGS == 1){
  52. stop();//停止
  53. }
  54. }
  55. void bizhangMode()
  56. {
  57. if(dir != MIDDLE){
  58. sgMiddle();//中间
  59. dir = MIDDLE;
  60. Delay450ms();
  61. }
  62. disMiddle = get_distance();
  63. if(disMiddle > 35){
  64. //前进
  65. goForward();
  66. }else if(disMiddle < 10){
  67. goBack();
  68. }else{
  69. //停止
  70. stop();
  71. //测左边距离
  72. sgLeft();//左边
  73. Delay450ms();
  74. disLeft = get_distance();
  75. sgMiddle();//中间
  76. Delay450ms();
  77. //测右边距离
  78. sgRight();//右边
  79. dir = RIGHT;
  80. Delay450ms();
  81. disRight = get_distance();
  82. if(disLeft < disRight){
  83. goRight();
  84. Delay150ms();
  85. stop();
  86. }
  87. if(disLeft > disRight){
  88. goLeft();
  89. Delay150ms();
  90. stop();
  91. }
  92. }
  93. }
  94. void main()
  95. {
  96. int mark = 0;
  97. Time0Init();//舵机用
  98. Time1Init();//超声波用
  99. sgMiddle();//中间
  100. Delay450ms();
  101. Delay450ms();
  102. dir = MIDDLE;
  103. OLED_Init();
  104. OLED_Clear();
  105. Oled_Show_Str(2,2,"----Ready----");
  106. while(1){
  107. //循迹模式
  108. if(A25 == 0 && A26 == 1 && A27 == 1){
  109. if(mark != XJ){
  110. OLED_Clear();
  111. Oled_Show_Str(2,2,"----XunJi----");
  112. }
  113. mark = XJ;
  114. xunjiMode();
  115. }
  116. //跟随模式
  117. if(A25 == 1 && A26 == 0 && A27 == 1){
  118. if(mark != GS){
  119. OLED_Clear();
  120. Oled_Show_Str(2,2,"----GenSui----");
  121. }
  122. mark = GS;
  123. gensuiMode();
  124. }
  125. //避障模式
  126. if(A25 == 1 && A26 == 1 && A27 == 0){
  127. if(mark != BZ){
  128. OLED_Clear();
  129. Oled_Show_Str(2,2,"----BiZhang----");
  130. }
  131. mark = BZ;
  132. bizhangMode();
  133. }
  134. //停下
  135. if(A25 == 0 && A26 == 0 && A27 == 0){
  136. if(mark != ST){
  137. OLED_Clear();
  138. Oled_Show_Str(2,2,"----Stop----");
  139. }
  140. mark = ST;
  141. stop();
  142. }
  143. }
  144. }

hc04.c

  1. #include "reg52.h"
  2. #include "delay.h"
  3. sbit Trig = P2^3;
  4. sbit Echo = P2^2;
  5. void Time1Init()
  6. {
  7. TMOD &= 0x0F;
  8. TMOD |= 0x10;
  9. TH1 = 0;
  10. TL1 = 0;
  11. //设置定时器1工作模式1,初始值设定0开始数数,不着急启动定时器
  12. }
  13. void startHC()
  14. {
  15. Trig = 0;
  16. Trig = 1;
  17. Delay10us();
  18. Trig = 0;
  19. }
  20. double get_distance()
  21. {
  22. double time;
  23. //定时器数据清零,以便下一次测距
  24. TH1 = 0;
  25. TL1 = 0;
  26. //1. 给Trig一个至少10us高电平
  27. startHC();
  28. //2. 由低电平跳转到高电平,表示开始发送波
  29. while(Echo == 0);
  30. //波出去的那一下,开启定时器
  31. TR1 = 1;
  32. //3. 由高电平跳转到低电平,表示波回来了
  33. while(Echo == 1);
  34. //波回来的那一下,停止定时器
  35. TR1 = 0;
  36. //4. 计算出中间经过多少时间
  37. time = (TH1 * 256 + TL1)*1.085;//二进制1左移1位,变成10(2),相当于乘以2,左移8位,相当于乘以2的8次方=256
  38. //5. 距离=速度(340m/s)*时间/2
  39. return(time * 0.017);
  40. }

sg90.c

  1. #include "reg52.h"
  2. #include "delay.h"
  3. sbit D5 = P3^7;
  4. sbit D6 = P3^6;
  5. sbit sg90_con = P1^1;
  6. int jd;
  7. int cnt = 0;
  8. void Time0Init()
  9. {
  10. //1. 配置定时器0工作模式16位计时
  11. TMOD &= 0xF0;
  12. TMOD |= 0X01;
  13. //2. 给初值,定一个0.5ms出来
  14. TL0 = 0x33;
  15. TH0 = 0xFE;
  16. //3.打开定时器0中断
  17. ET0 = 1;
  18. //4.打开总中断EA
  19. EA = 1;
  20. //5. 开始计时
  21. TR0 = 1;
  22. TF0 = 0;
  23. }
  24. void sgMiddle()
  25. {
  26. //舵机开盖
  27. jd = 3;//90度,1.5ms高电平
  28. cnt = 0;
  29. }
  30. void sgLeft()
  31. {
  32. //舵机开盖
  33. jd = 5;//135度,2.5ms高电平
  34. cnt = 0;
  35. }
  36. void sgRight()
  37. {
  38. //舵机关盖
  39. jd = 1;//0度,0.5ms高电平
  40. cnt = 0;
  41. }
  42. void Time0Handler() interrupt 1
  43. {
  44. cnt++;//统计爆表次数
  45. TL0 = 0x33;//重新给初值
  46. TH0 = 0xFE;//重新给初值
  47. /*控制PWM波*/
  48. if(cnt < jd){
  49. sg90_con = 1;
  50. }else{
  51. sg90_con = 0;
  52. }
  53. /*统计爆表次数*/
  54. if(cnt == 40){//爆表了40次,经过了20ms
  55. cnt = 0;
  56. sg90_con = 1;
  57. }
  58. }

 motor.c

  1. #include "reg52.h"
  2. sbit RightCon1A = P3^7;
  3. sbit RightCon1B = P3^3;
  4. sbit LeftCon1A = P3^4;
  5. sbit LeftCon1B = P3^5;
  6. void goForward()
  7. {
  8. LeftCon1A = 0;
  9. LeftCon1B = 1;
  10. RightCon1A = 0;
  11. RightCon1B = 1;
  12. }
  13. void goBack()
  14. {
  15. LeftCon1A = 1;
  16. LeftCon1B = 0;
  17. RightCon1A = 1;
  18. RightCon1B = 0;
  19. }
  20. void goLeft()
  21. {
  22. LeftCon1A = 0;
  23. LeftCon1B = 0;
  24. RightCon1A = 0;
  25. RightCon1B = 1;
  26. }
  27. void goRight()
  28. {
  29. LeftCon1A = 0;
  30. LeftCon1B = 1;
  31. RightCon1A = 0;
  32. RightCon1B = 0;
  33. }
  34. void stop()
  35. {
  36. LeftCon1A = 0;
  37. LeftCon1B = 0;
  38. RightCon1A = 0;
  39. RightCon1B = 0;
  40. }

Oled.c

  1. #include "reg52.h"
  2. #include "intrins.h"
  3. #include "Oledfont.h"
  4. sbit scl = P0^1;
  5. sbit sda = P0^3;
  6. void IIC_Start()
  7. {
  8. scl = 0;//防止雪花
  9. sda = 1;
  10. scl = 1;
  11. _nop_();
  12. sda = 0;
  13. }
  14. void IIC_Stop()
  15. {
  16. scl = 0;
  17. sda = 0;
  18. scl = 1;
  19. _nop_();
  20. sda = 1;
  21. _nop_();
  22. }
  23. char IIC_ACK()
  24. {
  25. char flag;
  26. sda = 1;//就在时钟脉冲9期间释放数据线
  27. _nop_();
  28. scl = 1;
  29. _nop_();
  30. flag = sda;
  31. _nop_();
  32. scl = 0;
  33. _nop_();
  34. return flag;
  35. }
  36. void IIC_Send_Byte(char dataSend)
  37. {
  38. int i;
  39. for(i=0;i<8;i++){
  40. scl = 0;//scl拉低,让sda做好数据准备
  41. sda = dataSend & 0x80;//1000 0000获得dataSend的最高位
  42. _nop_();//发送数据建立时间
  43. scl = 1;//scl拉高开始发送
  44. _nop_();
  45. scl = 0;//发送完毕,拉低
  46. _nop_();
  47. dataSend = dataSend << 1;
  48. }
  49. }
  50. void OLED_Write_Cmd(char dataCmd)
  51. {
  52. //1.START
  53. IIC_Start();
  54. //2.写入从机地址 b0111 1000 0x78
  55. IIC_Send_Byte(0x78);
  56. //3.ACK
  57. IIC_ACK();
  58. //4.cotrol byte:(0)(0)000000 写入命令 (0)(1)000000 写入数据
  59. IIC_Send_Byte(0x00);
  60. //5.ACK
  61. IIC_ACK();
  62. //6.写入指令/数据
  63. IIC_Send_Byte(dataCmd);
  64. //7.ACK
  65. IIC_ACK();
  66. //8.STOP
  67. IIC_Stop();
  68. }
  69. void OLED_Write_Data(char dataData)
  70. {
  71. //1.START
  72. IIC_Start();
  73. //2.写入从机地址 b0111 1000 0x78
  74. IIC_Send_Byte(0x78);
  75. //3.ACK
  76. IIC_ACK();
  77. //4.cotrol byte:(0)(0)000000 写入命令 (0)(1)000000 写入数据
  78. IIC_Send_Byte(0x40);
  79. //5.ACK
  80. IIC_ACK();
  81. //6.写入指令/数据
  82. IIC_Send_Byte(dataData);
  83. //7.ACK
  84. IIC_ACK();
  85. //8.STOP
  86. IIC_Stop();
  87. }
  88. void OLED_Init(void)
  89. {
  90. OLED_Write_Cmd(0xAE);//--display off
  91. OLED_Write_Cmd(0x00);//---set low column address
  92. OLED_Write_Cmd(0x10);//---set high column address
  93. OLED_Write_Cmd(0x40);//--set start line address
  94. OLED_Write_Cmd(0xB0);//--set page address
  95. OLED_Write_Cmd(0x81); // contract control
  96. OLED_Write_Cmd(0xFF);//--128
  97. OLED_Write_Cmd(0xA1);//set segment remap
  98. OLED_Write_Cmd(0xA6);//--normal / reverse
  99. OLED_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
  100. OLED_Write_Cmd(0x3F);//--1/32 duty
  101. OLED_Write_Cmd(0xC8);//Com scan direction
  102. OLED_Write_Cmd(0xD3);//-set display offset
  103. OLED_Write_Cmd(0x00);//
  104. OLED_Write_Cmd(0xD5);//set osc division
  105. OLED_Write_Cmd(0x80);//
  106. OLED_Write_Cmd(0xD8);//set area color mode off
  107. OLED_Write_Cmd(0x05);//
  108. OLED_Write_Cmd(0xD9);//Set Pre-Charge Period
  109. OLED_Write_Cmd(0xF1);//
  110. OLED_Write_Cmd(0xDA);//set com pin configuartion
  111. OLED_Write_Cmd(0x12);//
  112. OLED_Write_Cmd(0xDB);//set Vcomh
  113. OLED_Write_Cmd(0x30);//
  114. OLED_Write_Cmd(0x8D);//set charge pump enable
  115. OLED_Write_Cmd(0x14);//
  116. OLED_Write_Cmd(0xAF);//--turn on oled panel
  117. }
  118. void OLED_Clear()
  119. {
  120. int i,j;
  121. for(i=0;i<8;i++){
  122. OLED_Write_Cmd(0xB0 + i);//page0--page7
  123. //每个page从0列
  124. OLED_Write_Data(0x00);
  125. OLED_Write_Data(0x10);
  126. //0到127列,依次写入0,每写入数据,列地址自动偏移
  127. for(j=0;j<128;j++){
  128. OLED_Write_Data(0);
  129. }
  130. }
  131. }
  132. void Oled_Show_Char(char row,char col,char oledChar){ //row*2-2
  133. unsigned int i;
  134. OLED_Write_Cmd(0xb0+(row*2-2)); //page 0
  135. OLED_Write_Cmd(0x00+(col&0x0f)); //low
  136. OLED_Write_Cmd(0x10+(col>>4)); //high
  137. for(i=((oledChar-32)*16);i<((oledChar-32)*16+8);i++){
  138. OLED_Write_Data(F8X16[i]); //写数据oledTable1
  139. }
  140. OLED_Write_Cmd(0xb0+(row*2-1)); //page 1
  141. OLED_Write_Cmd(0x00+(col&0x0f)); //low
  142. OLED_Write_Cmd(0x10+(col>>4)); //high
  143. for(i=((oledChar-32)*16+8);i<((oledChar-32)*16+8+8);i++){
  144. OLED_Write_Data(F8X16[i]); //写数据oledTable1
  145. }
  146. }
  147. /******************************************************************************/
  148. // 函数名称:Oled_Show_Char
  149. // 输入参数:oledChar
  150. // 输出参数:无
  151. // 函数功能:OLED显示单个字符
  152. /******************************************************************************/
  153. void Oled_Show_Str(char row,char col,char *str)
  154. {
  155. while(*str!=0){
  156. Oled_Show_Char(row,col,*str);
  157. str++;
  158. col += 8;
  159. }
  160. }

四、项目实现

语音控制智能小车

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/767762
推荐阅读
相关标签
  

闽ICP备14008679号