当前位置:   article > 正文

STM32超级蓝牙小车——基于STM32F103C8T6的多功能蓝牙小车(PID循迹、跟踪、有源蜂鸣器播放音乐、蓝牙遥控、AD采集+DMA转运等超多元素小车)_stm32f103c8t6蓝牙小车

stm32f103c8t6蓝牙小车

一、项目时间:2023.7.24~11.26

二、实现效果:通过蓝牙控制小车运动与模式转换

                        模式一:循迹模式

                        模式二:跟踪模式

                        模式三:音乐模式

                        模式四:控制运动模式

三、使用模块:

  1. STM32F103C8T6核心板 * 1
  2. L298N电机驱动模块 * 1
  3. TCRT5000L五路红外循迹传感器模块 * 1
  4. DC3V-6V黄色直流减速电机-TT * 4
  5. 锂电池组电源 6V  * 1
  6. OLED屏幕-四针 * 1
  7. DC - DC 12V装3.3v 5v 12v 电源模块
  8. HC-SR04超声波模块
  9. 光敏模块+热敏模块
  10. 八个灯
  11. 蓝牙模块

下面是超级蓝牙小车实物图:

 需要用到的资源如下:

1,车轮:TIM2-CH1,CH2  => PA0,PA1 + PB0,PB1,PB2,PB10,PB11

2,蓝牙:USART-TX,RX => PA9 PA10 

3,超声波:TIM-CH1,CH2 => PA6 PA7

4,OLED:  PB8,PB9

5,ADC+DMA:  PA3,PA4(采集两个数据:温度与光强)

6,舵机:TIM4-CH2  => PB7

7,循迹模块: PA15,PB3~6

8,炫灯

9:蜂鸣器

下面的表格是引脚使用的直观表格

0123456789101112131415
PA11X5593382288//7
PB11/777764411888

8

四、代码

因为使用到的模块很多,一些基础配置的代码就不放出来了,下面是一些重要部分的代码

1,循迹模块代码 Trailing.c

  1. #include "stm32f10x.h" // Device header
  2. #include "delay.h"
  3. #include "Trailing.h"
  4. #include "Motor.h"
  5. #include "PID.h"
  6. int Speed_Begin = 50; //extern 后面需要加上->变量以及变量的类型
  7. /*====================================
  8. 函数 :五路循迹模块加权函数
  9. 参数 :无
  10. 返回值 :返回五路加权的结果
  11. 描述 :通过对五路循迹情况进行加权,输出
  12. 到PID函数作为误差参数,即将数字情
  13. 况转变为误差。
  14. ====================================*/
  15. int Trailing_Speed(void)
  16. {
  17. // int Flag;
  18. int Sum,Speed_1;
  19. Sum = 0;
  20. // Flag = 0;
  21. if(LED1==1) Sum=Sum-20;
  22. if(LED2==1) Sum=Sum-10;
  23. if(LED3==1) Sum=Sum ;
  24. if(LED4==1) Sum=Sum+10;
  25. if(LED5==1) Sum=Sum+20;
  26. Speed_1 = (int)Sum;
  27. return(Speed_1);
  28. // if(LED1==0) Sum=Sum-20,Flag++;
  29. // if(LED2==0) Sum=Sum-10,Flag++;
  30. // if(LED3==0) Sum=Sum ,Flag++;
  31. // if(LED4==0) Sum=Sum+10,Flag++;
  32. // if(LED5==0) Sum=Sum+20,Flag++;
  33. // Speed_1 = (int)Sum / Flag + Speed_Begin;
  34. // return(Speed_1);
  35. }
  36. /*====================================
  37. 函数 :运动轨迹调整函数
  38. 参数 :无
  39. 返回值 :无
  40. 描述 :先通过pid计算出现在的速度值
  41. 如,速度值等于初始值,直走
  42. 速度值小于初始值,左转
  43. 速度值大于初始值,右转
  44. ====================================*/
  45. void Trailing_Adjust(void)
  46. {
  47. int Speed;
  48. Speed = Speed_Begin + Position_PID(Trailing_Speed());
  49. if(Speed == Speed_Begin) //做一个速度的大小判断,进而判断此时对应的转向
  50. {
  51. delay_ms(1);
  52. Motor_Straight(Speed);
  53. }
  54. else if (Speed < Speed_Begin) Motor_Left(Speed - 2 *Position_PID(Trailing_Speed()));
  55. else Motor_Right(Speed);
  56. }
  57. /*====================================
  58. 函数 :五路循迹模块情况汇总函数
  59. 参数 :无
  60. 返回值 :五路循迹情况
  61. 描述 :通过对五路循迹的情况进行计算得到
  62. 一个五位数的数字,便于输出在OLED
  63. 显示屏上,例:00001—最右边一个
  64. 被遮挡
  65. ====================================*/
  66. int Track_State(void)
  67. {
  68. u16 LED;
  69. LED = (LED1 * 10000) + (LED2 * 1000)+ (LED3 * 100) + (LED4 * 10) + LED5;
  70. return (LED);
  71. }
  72. //u8 Trailing_Filter_One(u8 Value,u8 Get_Io) //滤波1
  73. //{
  74. // u8 Count=0;
  75. // u8 New_Value;
  76. // New_Value=Get_Io;
  77. // while(Value!=New_Value)
  78. // {
  79. // Count++;
  80. // if(Count>=5) return New_Value;
  81. // Delay_us(1);
  82. // New_Value=Get_Io;
  83. // }
  84. // return Value;
  85. //}
  86. //int Trailing_Filter_Two(void) //滤波2+角度结算
  87. //{
  88. // int Speed_ori;
  89. // for(i=0;i<16;i++)
  90. // {
  91. // RAY[i]=1;
  92. // RAY_try[i]=1;
  93. // }
  94. // for(i=0;i<200;i++) //800
  95. // {
  96. // RAY_try[0]=Trailing_Filter_One(1,LED1);//滤波
  97. // RAY_try[1]=Trailing_Filter_One(1,LED2);
  98. // RAY_try[2]=Trailing_Filter_One(1,LED3);
  99. // RAY_try[3]=Trailing_Filter_One(1,LED4);
  100. // RAY_try[4]=Trailing_Filter_One(1,LED5);
  101. //
  102. // RAY[0]&=RAY_try[0];
  103. // RAY[1]&=RAY_try[1];
  104. // RAY[2]&=RAY_try[2];
  105. // RAY[3]&=RAY_try[3];
  106. // RAY[4]&=RAY_try[4];
  107. // delay_us(100); //增加稳定性
  108. // }
  109. // Speed_ori=Trailing_Speed();
  110. // return (Speed_ori);
  111. //}

Trailing.h

  1. #ifndef __TRAILING_H
  2. #define __TRAILING_H
  3. #include "sys.h"
  4. #define LED1 PAin(15)
  5. #define LED2 PBin(3)
  6. #define LED3 PBin(4)
  7. #define LED4 PBin(5)
  8. #define LED5 PBin(6)
  9. #define LED2_1(a) if(a) \
  10. GPIO_SetBits(TRAILING_PORT_2,IO4); \
  11. else GPIO_ResetBits(TRAILING_PORT_2,IO4);
  12. #define TRAILING_PORT_1 GPIOA
  13. #define TRAILING_PORT_2 GPIOB
  14. #define TRAILING_CLK_1 RCC_APB2Periph_GPIOA
  15. #define TRAILING_CLK_2 RCC_APB2Periph_GPIOB
  16. #define IO5 GPIO_Pin_15
  17. #define IO4 GPIO_Pin_3
  18. #define IO3 GPIO_Pin_4
  19. #define IO2 GPIO_Pin_5
  20. #define IO1 GPIO_Pin_6
  21. //起始速度值
  22. extern int Speed_Begin;
  23. //#define Ray[0] PAin(8)
  24. //#define Ray[1] PAin(9)
  25. //#define Ray[2] PAin(10)
  26. //#define Ray[3] PAin(11)
  27. //#define Ray[4] PAin(12)
  28. //#define LED1 PAin(8)
  29. //#define LED2 PAin(9)
  30. //#define LED3 PAin(10)
  31. //#define LED4 PAin(11)
  32. //#define LED5 PAin(12)
  33. //循迹模块初始化
  34. void Trailing_Init(void);
  35. //五路循迹模块加权函数
  36. int Trailing_Speed(void);
  37. //五路循迹模块情况汇总函数
  38. int Track_State(void);
  39. //u8 Trailing_Filter_One(u8 Value,u8 Get_Io);
  40. //int Trailing_Filter_Two(void);
  41. //运动轨迹调整函数
  42. void Trailing_Adjust(void);
  43. #endif
  44. //OLED_ShowString(1,1,"NUM:");
  45. //int NUM;
  46. //while(1)
  47. //{
  48. // Trailing_Speed();
  49. // Trailing_Adjust();
  50. // NUM = Track_State();
  51. // OLED_ShowNum(1,6,NUM,5);
  52. //}

2、跟踪模块代码 HCSR04.c

  1. #include "stm32f10x.h" // Device header
  2. #include "sys.h"
  3. #include "delay.h"
  4. #include "PID.h"
  5. #include "Motor.h"
  6. #include "HCSR04.h"
  7. #include "OLED.h"
  8. extern int Speed_Begin;
  9. int Location_Begin = 30;
  10. //超声波计数
  11. u16 msHcCount = 0;
  12. /*====================================
  13. 函数    :打开定时器函数
  14. 参数    :无
  15. 返回值    :无
  16. 描述    :通过使能TIMx
  17. ====================================*/
  18. static void HCSR04_TimerOpen()  
  19. {
  20.    TIM_SetCounter(HCSR04_TIM,0);
  21.    msHcCount = 0;
  22.    TIM_Cmd(HCSR04_TIM, ENABLE); 
  23. }
  24. /*====================================
  25. 函数    :关闭定时器函数
  26. 参数    :无
  27. 返回值    :无
  28. 描述    :通过失能TIMx
  29. ====================================*/
  30. static void HCSR04_TimerClose()
  31. {
  32.    TIM_Cmd(HCSR04_TIM, DISABLE); 
  33. }    
  34. //定时器中断
  35. void TIM3_IRQHandler(void)  
  36. {
  37.    if (TIM_GetITStatus(HCSR04_TIM, TIM_IT_Update) != RESET)  
  38.    {
  39.        TIM_ClearITPendingBit(HCSR04_TIM, TIM_IT_Update); 
  40.        msHcCount++;
  41.    }
  42. }
  43. /*====================================
  44. 函数    :获取定时器计数器值函数
  45. 参数    :无
  46. 返回值    :获取高电平时间
  47. 描述    :通过获取定时器计数器值,
  48.          通过计算得到高电平时间
  49. ====================================*/
  50. u32 HCSR04_GetEchoTimer()
  51. {
  52.    u32 t = 0;
  53.    t = msHcCount * 1000;
  54.    t += TIM_GetCounter(HCSR04_TIM);
  55.    HCSR04_TIM -> CNT = 0;  
  56.    delay_ms(50);
  57. //   msHcCount = 0;
  58.    return t;
  59. }
  60. /*====================================
  61. 函数    :通过定时器3计数器值推算距离函数
  62. 参数    :无
  63. 返回值    :超声波测距的距离
  64. 描述    :通过控制io口的开关与超声波模块的使用
  65.          ,通过计算值得到最终模块的测距
  66. ====================================*/
  67. float Hcsr04_GetLength(void )
  68. {
  69.    u32 t = 0;
  70.    int i = 0;
  71.    float lengthTemp = 0;
  72.    float sum = 0;
  73.    while(i!=2)
  74.    {
  75.       TRIG_Send = 1;      
  76.       delay_us(20);
  77.       TRIG_Send = 0;
  78.       while(ECHO_Reci == 0);      
  79.       HCSR04_TimerOpen();
  80.       i = i + 1;
  81.       while(ECHO_Reci == 1);
  82.       HCSR04_TimerClose();        
  83.       t = HCSR04_GetEchoTimer();        
  84.       lengthTemp = ((float)t / 58.0);//cm
  85.       sum = lengthTemp + sum ;
  86.    }
  87.     lengthTemp = sum/2.0;
  88.     return lengthTemp;
  89. }
  90. /*====================================
  91. 函数    :位置调整函数
  92. 参数    :无
  93. 返回值    :无
  94. 描述    :先通得出现在的距离值(上限~下限),
  95.           然后进行PID计算得出PID距离值 
  96.          如,距离值大于上限值,前进
  97.              距离值小于下限值,后退
  98.                距离值在上下限之间,停止     
  99. ====================================*/
  100. void Location_Adjust(void)
  101. {
  102.     int Speed;
  103.     float Speed_1,Speed_2;
  104.     Speed_1 = Location_PID(Hcsr04_GetLength());
  105.     Speed_2 = (int)Speed_1;
  106.     Speed = Speed_Begin + Speed_2;
  107.     if (Location_Begin >= Hcsr04_GetLength())    Motor_Retreat(Speed - 2 * Speed_2);
  108.     else if(Location_Begin + 5 < Hcsr04_GetLength())    Motor_Straight(Speed);
  109. }

HCSR04.h

  1. #ifndef __HCSR04_H
  2. #define __HCSR04_H
  3. #include "sys.h"
  4. //超声波硬件接口定义
  5. #define HCSR04_TIM TIM3
  6. #define HCSR04_TIMCLK RCC_APB1Periph_TIM3
  7. #define HCSR04_PORT GPIOA
  8. #define HCSR04_CLK RCC_APB2Periph_GPIOA
  9. #define HCSR04_TRIG GPIO_Pin_7 //输出
  10. #define HCSR04_ECHO GPIO_Pin_6 //输入
  11. #define ECHO_Reci PAin(6)
  12. #define TRIG_Send PAout(7)
  13. extern int Speed_Begin;
  14. extern int Location_Begin;
  15. //起始速度值
  16. extern int Speed_Begin;
  17. //起始距离值
  18. extern int Location_Begin;
  19. //配置超声波模块定时器
  20. void HCSR04_NVIC(void);
  21. //超声波模块初始化
  22. void HCSR04_Init(void);
  23. //打开定时器
  24. static void HCSR04_TimerOpen(void);
  25. //关闭定时器
  26. static void HCSR04_TimerClose(void);
  27. //获取定时器计数器值
  28. u32 HCSR04_GetEchoTimer(void);
  29. //推算距离
  30. float Hcsr04_GetLength(void );
  31. //位置调整
  32. void Location_Adjust(void);
  33. #endif
  34. // while(1)
  35. // {
  36. Motor_Retreat(50);
  37. // Location_Adjust();
  38. // delay_ms(10);
  39. // }

3,蜂鸣器音乐模块 Beep.c

  1. #include "stm32f10x.h" // Device header
  2. #include "beep.h"
  3. int melody[] = {50, 50, 50, 50, 200, 200, 200, 400, 400, 500, 500, 500};
  4. /*====================================
  5. 函数 :发声1基本函数
  6. 参数 :
  7. 返回值 :
  8. 描述 :
  9. ====================================*/
  10. void Sound(u16 frq)
  11. {
  12. u32 time;
  13. if(frq != 1000)
  14. {
  15. // time = 500000/((u32)frq);
  16. time = 100000/((u32)frq);
  17. PBeep = 1;
  18. delay_us(time);
  19. PBeep = 0;
  20. delay_us(time);
  21. }
  22. else
  23. delay_us(1000);
  24. }
  25. /*====================================
  26. 函数 :发声2基本函数
  27. 参数 :
  28. 返回值 :
  29. 描述 :
  30. ====================================*/
  31. void Sound2(u16 time)
  32. {
  33. PBeep = 1;
  34. delay_ms(time);
  35. PBeep = 0;
  36. delay_ms(time);
  37. }
  38. /*====================================
  39. 函数 :成功音效(先快后慢)
  40. 参数 :
  41. 返回值 :
  42. 描述 :得得得 得 得 得
  43. ====================================*/
  44. void play_successful(void)
  45. {
  46. int id=0;
  47. for(id = 0 ;id < 5 ;id++)
  48. {
  49. Sound2(melody[id]);
  50. }
  51. }
  52. /*====================================
  53. 函数 :失败音效(先快后慢)
  54. 参数 :
  55. 返回值 :
  56. 描述 :得 得 得 得得得
  57. ====================================*/
  58. void play_failed(void)
  59. {
  60. int id=0;
  61. for(id = 5 ;id >=0 ;id--)
  62. {
  63. Sound2(melody[id]);
  64. }
  65. }
  66. /*====================================
  67. 函数 :播放音乐
  68. 参数 :
  69. 返回值 :
  70. 描述 :音乐库中有:红尘情歌
  71. 小燕子
  72. (注意:music和time前面两版含
  73. 有13这个音,但由于不能正常发音,
  74. 后面的为删除这个音节的版本)
  75. ====================================*/
  76. void play_music(void)
  77. {
  78. // 低7 1 2 3 4 5 6 7 高1 高2 高3 高4 高5 不发音
  79. uc16 tone[] = {247,262,294,330,349,392,440,494,523,587,659,698,784,1000};//音频数据表
  80. // //红尘情歌
  81. // u8 music[]={5,5,6,8,7,6,5,6,13,13,//音调
  82. // 5,5,6,8,7,6,5,3,13,13,
  83. // 2,2,3,5,3,5,6,3,2,1,
  84. // 6,6,5,6,5,3,6,5,13,13,
  85. // 5,5,6,8,7,6,5,6,13,13,
  86. // 5,5,6,8,7,6,5,3,13,13,
  87. // 2,2,3,5,3,5,6,3,2,1,
  88. // 6,6,5,6,5,3,6,1,
  89. // 13,8,9,10,10,9,8,10,9,8,6,
  90. // 13,6,8,9,9,8,6,9,8,6,5,
  91. // 13,2,3,5,5,3,5,5,6,8,7,6,
  92. // 6,10,9,9,8,6,5,6,8};
  93. // u8 time[] = {2,4,2,2,2,2,2,8,4, 4, //时间
  94. // 2,4,2,2,2,2,2,8,4, 4,
  95. // 2,4,2,4,2,2,4,2,2,8,
  96. // 2,4,2,2,2,2,2,8,4 ,4,
  97. // 2,4,2,2,2,2,2,8,4, 4,
  98. // 2,4,2,2,2,2,2,8,4, 4,
  99. // 2,4,2,4,2,2,4,2,2,8,
  100. // 2,4,2,2,2,2,2,8,
  101. // 4, 2,2,2, 4, 2,2,2, 2,2,8,
  102. // 4, 2,2,2,4,2,2,2,2,2,8,
  103. // 4, 2,2,2,4,2,2,5,2,6,2,4,
  104. // 2,2 ,2,4,2,4,2,2,12};
  105. // //小燕子
  106. // u8 music[]={3,5,8,6,5,13,//音调
  107. // 3,5,6,8,5,13,
  108. // 8,10,9,8,9,8,6,8,5,13,
  109. // 3,5,6,5,6,8,9,5,6,13,
  110. // 3,2,1,2,13,
  111. // 2,2,3,5,5,8,2,3,5,13};
  112. // u8 time[] ={2,2,2,2,6,4,//时间
  113. // 2,2,2,2,6,4,
  114. // 6,2,4,4,2,2,2,2,6,4,
  115. // 6,2,4,2,2,4,2,2,6,4,
  116. // 2,2,4,6,4,
  117. // 4,2,2,4,4,4,2,2,6,4};
  118. //删去音节13的两首歌版本
  119. //红尘情歌
  120. u8 music[]={5,5,6,8,7,6,5,6,//音调
  121. 5,5,6,8,7,6,5,3,
  122. 2,2,3,5,3,5,6,3,2,1,
  123. 6,6,5,6,5,3,6,5,
  124. 5,5,6,8,7,6,5,6,
  125. 5,5,6,8,7,6,5,3,
  126. 2,2,3,5,3,5,6,3,2,1,
  127. 6,6,5,6,5,3,6,1,
  128. 8,9,10,10,9,8,10,9,8,6,
  129. 6,8,9,9,8,6,9,8,6,5,
  130. 2,3,5,5,3,5,5,6,8,7,6,
  131. 6,10,9,9,8,6,5,6,8};
  132. u8 time[] = {2,4,2,2,2,2,2,8, //时间
  133. 2,4,2,2,2,2,2,8,
  134. 2,4,2,4,2,2,4,2,2,8,
  135. 2,4,2,2,2,2,2,8,
  136. 2,4,2,2,2,2,2,8,
  137. 2,4,2,2,2,2,2,8,
  138. 2,4,2,4,2,2,4,2,2,8,
  139. 2,4,2,2,2,2,2,8,
  140. 2,2,2, 4, 2,2,2, 2,2,8,
  141. 2,2,2,4,2,2,2,2,2,8,
  142. 2,2,2,4,2,2,5,2,6,2,4,
  143. 2,2 ,2,4,2,4,2,2,12};
  144. // //小燕子
  145. // u8 music[]={3,5,8,6,5,//音调
  146. // 3,5,6,8,5,
  147. // 8,10,9,8,9,8,6,8,5,
  148. // 3,5,6,5,6,8,9,5,6,
  149. // 3,2,1,2,
  150. // 2,2,3,5,5,8,2,3,5};
  151. // u8 time[] ={2,2,2,2,6,//时间
  152. // 2,2,2,2,6,
  153. // 6,2,4,4,2,2,2,2,6,
  154. // 6,2,4,2,2,4,2,2,6,
  155. // 2,2,4,6,
  156. // 4,2,2,4,4,4,2,2,6};
  157. // u8 music[]={13,1,2,3,4,5,6,7,8};//测试基础音
  158. // u8 time[] ={4, 4,4,4,4,4,4,4,4};
  159. u32 yanshi;
  160. u16 i,e;
  161. yanshi = 2;//10 ; 4; 2;
  162. for(i=0;i<sizeof(music)/sizeof(music[0]);i++)
  163. {
  164. for(e=0;e<((u16)time[i])*tone[music[i]]/yanshi;e++)
  165. {
  166. Sound((u32)tone[music[i]]);
  167. }
  168. }
  169. GPIO_ResetBits(BEEP_PORT,BEEP_IO);
  170. }
  171. void play_music2(void)
  172. {
  173. // 低7 1 2 3 4 5 6 7 高1 高2 高3 高4 高5 不发音
  174. uc16 tone[] = {247,262,294,330,349,392,440,494,523,587,659,698,784,1000};//音频数据表
  175. //小燕子
  176. u8 music[]={3,5,8,6,5,//音调
  177. 3,5,6,8,5,
  178. 8,10,9,8,9,8,6,8,5,
  179. 3,5,6,5,6,8,9,5,6,
  180. 3,2,1,2,
  181. 2,2,3,5,5,8,2,3,5};
  182. u8 time[] ={2,2,2,2,6,//时间
  183. 2,2,2,2,6,
  184. 6,2,4,4,2,2,2,2,6,
  185. 6,2,4,2,2,4,2,2,6,
  186. 2,2,4,6,
  187. 4,2,2,4,4,4,2,2,6};
  188. u32 yanshi;
  189. u16 i,e;
  190. yanshi = 2;//10 ; 4; 2;
  191. for(i=0;i<sizeof(music)/sizeof(music[0]);i++)
  192. {
  193. for(e=0;e<((u16)time[i])*tone[music[i]]/yanshi;e++)
  194. {
  195. Sound((u32)tone[music[i]]);
  196. }
  197. }
  198. GPIO_ResetBits(BEEP_PORT,BEEP_IO);
  199. }

音乐模块是学习博客其他优秀博主的写法

Beep.h

  1. #ifndef __BEEP_H
  2. #define __BEEP_H
  3. #include "sys.h"
  4. #include "stdlib.h"
  5. #include "delay.h"
  6. #define BEEP_PORT GPIOA
  7. #define BEEP_CLK RCC_APB2Periph_GPIOA
  8. #define BEEP_IO GPIO_Pin_5 //输出
  9. //定义GPIOB的位地址变量宏,位输入宏,输出宏
  10. #define PBeep PAout(5)
  11. //Beep蜂鸣器初始化
  12. void Beep_Init(void);
  13. //发出声音1
  14. void Sound(u16 frq);
  15. //发出声音2
  16. void Sound2(u16 time);
  17. //放音乐
  18. void play_music(void);
  19. //放音乐2
  20. void play_music2(void);
  21. //播放成功
  22. void play_successful(void);
  23. //播放失败
  24. void play_failed(void);
  25. #endif

4.串口模块代码  Serial.c

这部分代码最多,即讲主函数操作都封装起来了,因为我们是蓝牙小车对吧

  1. #include "stm32f10x.h" // Device header
  2. #include "Serial.h"
  3. uint8_t Serial_RxPacket[4];
  4. uint8_t Serial_TxPacket[4];
  5. char Serial_RxPacket_W[100];
  6. uint8_t Serial_RxFlag;
  7. uint8_t RxData;
  8. int NUM;//A -> 循迹模式:代表此时遮挡情况
  9. float length;//B -> 跟踪模式:代表此时相对遮挡物的距离
  10. void Serial_Pattern(void)
  11. {
  12. // Serial_SendString("OPEN_OK\r\n");
  13. // printf("正在为您播放“程序开始”\r\n");
  14. OLED_ShowString(1,1,"OK1");
  15. if(Serial_RxFlag == 1)
  16. {
  17. OLED_Clear();//OLED清屏
  18. OLED_ShowString(1,1,"OK1");
  19. if (strcmp(Serial_RxPacket_W, "A") == 0)
  20. {
  21. //先停下我们的车
  22. Serial_Stop();
  23. //做好进入模式的准备
  24. Serial_Pattern_into(1);
  25. OLED_ShowString(1,1,"OK 12");
  26. Serial_SendString("Pattern_A_OK\r\n");
  27. //在没有新的指令到来一直保持循迹模式
  28. while(Serial_RxFlag == 0) Serial_PAT_Trailing();
  29. }
  30. else if (strcmp(Serial_RxPacket_W, "B") == 0)
  31. {
  32. Serial_Stop();
  33. Serial_Pattern_into(2);
  34. Serial_SendString("Pattern_B_OK\r\n");
  35. while(Serial_RxFlag == 0) Serial_PAT_Track();
  36. }
  37. else if (strcmp(Serial_RxPacket_W, "C") == 0)
  38. {
  39. Serial_Stop();
  40. // OLED_ShowString(1,1,"OK 10");
  41. Serial_Pattern_into(3);
  42. Serial_SendString("Pattern_C_OK\r\n");
  43. while(Serial_RxFlag == 0) Serial_PAT_Music();
  44. }
  45. else if (strcmp(Serial_RxPacket_W, "w") == 0)
  46. {
  47. Serial_RxFlag = 0;//清空蓝牙接收标志位
  48. Serial_Straight(60);
  49. }
  50. else if (strcmp(Serial_RxPacket_W, "s") == 0)
  51. {
  52. Serial_RxFlag = 0;//清空蓝牙接收标志位
  53. Serial_Retreat(60);
  54. }
  55. else if (strcmp(Serial_RxPacket_W, "a") == 0)
  56. {
  57. Serial_RxFlag = 0;//清空蓝牙接收标志位
  58. Serial_Left(60);
  59. }
  60. else if (strcmp(Serial_RxPacket_W, "d") == 0)
  61. {
  62. Serial_RxFlag = 0;//清空蓝牙接收标志位
  63. Serial_Right(60);
  64. }
  65. else
  66. {
  67. Serial_Stop();
  68. Serial_PAT_XX();
  69. }
  70. }
  71. }
  72. /*====================================
  73. 函数 :进入模式准备
  74. 参数 :无
  75. 返回值 :无
  76. 描述 :
  77. ====================================*/
  78. void Serial_Pattern_into(u8 x)
  79. {
  80. // int i;
  81. Serial_RxFlag = 0;//清空蓝牙接收标志位
  82. // LED_Pattern_1();//灯光效果一 -> 进入模式一循迹模式
  83. // LED_Pattern_1();
  84. // OLED_ShowString(1,1,"Trailing_Mode_OK");//显示正在做的功能
  85. Serial_LEDPx(x);
  86. OLED_ShowString(3,1,"LI:");
  87. OLED_ShowString(4,1,"TI:");
  88. // for(i = 0; i <= 0; i++)
  89. // {
  90. // Servo_SP();
  91. // delay_ms(5);
  92. // }
  93. // i = 0;
  94. play_successful();//成功效果音
  95. GPIO_SetBits(BEEP_PORT,BEEP_IO);//因为蜂鸣器不会自己关
  96. }
  97. /*====================================
  98. 函数 :进入模式的灯光与OLED准备
  99. 参数 :无
  100. 返回值 :无
  101. 描述 :
  102. ====================================*/
  103. void Serial_LEDPx(u8 x)
  104. {
  105. switch(x)
  106. {
  107. case 1: LED_Pattern_1(); LED_Pattern_1(); break;
  108. case 2: LED_Pattern_2(); LED_Pattern_2(); break;
  109. case 3: LED_Pattern_3(); LED_Pattern_3(); break;
  110. }
  111. switch(x)
  112. {
  113. case 1: OLED_ShowString(1,1,"Trailing_Mode_OK"); break;
  114. case 2: OLED_ShowString(1,1,"Track_Mode_OK"); break;
  115. case 3: OLED_ShowString(1,1,"Music_Mode_OK"); break;
  116. }
  117. }
  118. /*====================================
  119. 函数 :循迹模式操作(A)
  120. 参数 :无
  121. 返回值 :无
  122. 描述 :
  123. ====================================*/
  124. void Serial_PAT_Trailing(void)
  125. {
  126. Trailing_Adjust();
  127. NUM = Track_State();
  128. OLED_ShowString(2,1,"NUM:00000");
  129. OLED_ShowNum(2,6,NUM,5);
  130. Serial_PAT_TL();//每次操作的同时都显示一下此时的温度与光强
  131. // printf("遮挡情况:%dcm\n",NUM);
  132. }
  133. /*====================================
  134. 函数 :跟踪模式操作(B)
  135. 参数 :无
  136. 返回值 :无
  137. 描述 :
  138. ====================================*/
  139. void Serial_PAT_Track(void)
  140. {
  141. Location_Adjust();
  142. length = Hcsr04_GetLength();
  143. OLED_ShowString(2,1,"Lo:");
  144. OLED_ShowNum(2,4,length,3);
  145. Serial_PAT_TL();//每次操作的同时都显示一下此时的温度与光强
  146. // printf("距离:%.3fcm\n",length);
  147. }
  148. /*====================================
  149. 函数 :音乐模式操作(C)
  150. 参数 :无
  151. 返回值 :无
  152. 描述 :
  153. ====================================*/
  154. void Serial_PAT_Music(void)
  155. {
  156. int i;
  157. Serial_PAT_TL();//每次操作的同时都显示一下此时的温度与光强
  158. // printf("正在为您播放“红尘情歌”");
  159. OLED_ShowString(2,1,"open'hongchenqingge'");
  160. play_music();
  161. for(i = 0; i <= 0; i++)
  162. {
  163. Servo_SP();//舵机来回转动函数
  164. delay_ms(5);
  165. }
  166. i = 0;
  167. delay_ms(2);
  168. Serial_PAT_TL();//实时显示温度与光强
  169. Serial_PAT_TL();//每次操作的同时都显示一下此时的温度与光强
  170. // printf("正在为您播放“小燕子”");
  171. OLED_ShowString(2,1,"open'xiaoyanzi'");
  172. play_music2();
  173. for(i = 0; i <= 0; i++)//由于串口与定时器的尴尬关系,这里加一个循环可以使舵机转动更加稳定
  174. {
  175. Servo_SP();
  176. delay_ms(5);
  177. }
  178. i = 0;
  179. delay_ms(2);
  180. Serial_PAT_TL();//实时显示温度与光强
  181. }
  182. /*====================================
  183. 函数 :错误指令模式操作(D)
  184. 参数 :无
  185. 返回值 :无
  186. 描述 :
  187. ====================================*/
  188. void Serial_PAT_XX(void)
  189. {
  190. Serial_RxFlag = 0;//清空蓝牙接收标志位
  191. OLED_Clear();//OLED清屏
  192. Serial_SendString("ERROR_COMMAND\r\n");
  193. OLED_ShowString(1, 1, "ERROR_RX");
  194. OLED_ShowString(2, 1, "ERROR_COMMAND");
  195. OLED_ShowString(3,1,"LI:");
  196. OLED_ShowString(4,1,"TI:");
  197. play_failed();//失败效果音
  198. GPIO_SetBits(BEEP_PORT,BEEP_IO);//因为蜂鸣器不会自己关
  199. while(Serial_RxFlag == 0)
  200. {
  201. Servo_SP();//舵机来回摆动一次
  202. delay_ms(2);
  203. Serial_PAT_TL();//实时显示温度与光强
  204. }
  205. }
  206. /*====================================
  207. 函数 :判断此时温度与光强
  208. 参数 :无
  209. 返回值 :无
  210. 描述 :
  211. ====================================*/
  212. void Serial_PAT_TL(void)
  213. {
  214. if(ADValue[0] >= 2000)
  215. {
  216. // OLED_ShowString(3,4,"SO Light");
  217. OLED_ShowNum(3,4,ADValue[0],4);//发送数据包储存数组第一位数据
  218. }
  219. else
  220. {
  221. // OLED_ShowString(3,4,"Not Light");
  222. OLED_ShowNum(3,4,ADValue[0],4);
  223. }
  224. if(ADValue[1] >= 2100)
  225. {
  226. // OLED_ShowString(4,4,"SO hot");
  227. OLED_ShowNum(4,4,ADValue[1],4);//发送数据包储存数组第二位数据
  228. }
  229. else
  230. {
  231. // OLED_ShowString(4,4,"Not hot");
  232. OLED_ShowNum(4,4,ADValue[1],4);
  233. }
  234. }
  235. /*====================================
  236. 函数 :运动控制指令——前进,后退,左转,右转
  237. 参数 :无
  238. 返回值 :无
  239. 描述 :
  240. ====================================*/
  241. void Serial_Straight(u8 x)
  242. {
  243. while(Serial_RxFlag == 0)
  244. {
  245. Motor_Straight(x);
  246. }
  247. }
  248. void Serial_Retreat(u8 x)
  249. {
  250. while(Serial_RxFlag == 0)
  251. {
  252. Motor_Retreat(x);
  253. }
  254. }
  255. void Serial_Right(u8 x)
  256. {
  257. Motor_Right(x);
  258. delay_ms(1500);
  259. while(Serial_RxFlag == 0)
  260. {
  261. Motor_Straight(x);
  262. }
  263. }
  264. void Serial_Left(u8 x)
  265. {
  266. Motor_Left(x);
  267. delay_ms(1200);
  268. while(Serial_RxFlag == 0)
  269. {
  270. Motor_Straight(x);
  271. }
  272. }
  273. void Serial_Stop(void)
  274. {
  275. Motor_Stop();
  276. }

Serial.h

  1. #ifndef __SERIAL_H
  2. #define __SERIAL_H
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include "Key.h"
  6. #include "string.h"
  7. #include "OLED.h"
  8. #include "Motor.h"
  9. #include "Trailing.h"
  10. #include "PID.h"
  11. #include "HCSR04.h"
  12. #include "AD.h"
  13. #include "PWM.h"
  14. #include "led.h"
  15. #include "Beep.h"
  16. #include "Servo.h"
  17. extern uint8_t Serial_RxPacket[4];
  18. extern uint8_t Serial_TxPacket[4];
  19. extern char Serial_RxPacket_W[100];
  20. extern uint8_t Serial_RxFlag;//传输数据标志位
  21. extern uint8_t RxData;
  22. //发送HEX数据包函数
  23. void Serial_SendPacket(uint8_t *ABC,uint8_t Length);
  24. //清除标志位Serial_RxFlag
  25. uint8_t Serial_GetRxFlag(void);
  26. 封装数据函数(接收数据)
  27. //uint8_t Serial_GetRxData(void);
  28. //串口中断
  29. //void USART1_IRQHandler(void);
  30. void USART1_IRQHandler(void);
  31. //串口初始化
  32. void Serial_Init(void);
  33. //串口发送函数
  34. void Serial_SendByte(uint8_t Byte);//一个字节
  35. void Serial_SendArray(uint8_t *Array, uint16_t Length);//一个数组
  36. void Serial_SendString(char *String);//一串字符串(文本)
  37. uint32_t Serial_Pow(uint32_t X,uint32_t Y);//次方函数(与发送数函数结合使用)
  38. void Serial_SendNumber(uint32_t Number,uint8_t Length);//一个十六进制数
  39. //printf的底层函数
  40. int fputc(int ch, FILE *f);
  41. //sprintf封装函数
  42. void Serial_Printf(char *format, ...);
  43. /*====================================
  44. printf打印函数经常乱码解决方案
  45. 1-UTF8不乱码方案
  46. 工程选项(魔术棒) -> C/C++ -> Misc Controles ->填上: --no-multibyte-chars
  47. 2-GB2312编码
  48. 设置 -> Encoding -> 删掉汉字 -> 关闭小文件再打开 -> 再编辑文字 -> 串口选择GBK编码
  49. ====================================*/
  50. extern int NUM;//A -> 循迹模式:代表此时遮挡情况
  51. extern float length;//B -> 跟踪模式:代表此时相对遮挡物的距离
  52. //模式选择
  53. void Serial_Pattern(void);
  54. //进入模式准备
  55. void Serial_Pattern_into(u8 x);
  56. //准备灯光与OLED模式
  57. void Serial_LEDPx(u8 x);
  58. //判断此时温度与光强
  59. void Serial_PAT_TL(void);
  60. //循迹模式操作——A B C D
  61. void Serial_PAT_Trailing(void);//A-循迹模式
  62. void Serial_PAT_Track(void);//B-跟踪模式
  63. void Serial_PAT_Music(void);//C-音乐模式
  64. void Serial_PAT_XX(void);//D-错误指令模式
  65. //运动控制指令——前进,后退,左转,右转
  66. void Serial_Straight(u8 x);//前进
  67. void Serial_Retreat(u8 x);//后退
  68. void Serial_Right(u8 x);//右转
  69. void Serial_Left(u8 x);//左转
  70. void Serial_Stop(void);//停下
  71. #endif

5,PID模块代码 PID.c

  1. #include "stm32f10x.h" // Device header
  2. #include "PID.h"
  3. #include "Trailing.h"
  4. #include "Motor.h"
  5. #include "Delay.h"
  6. #include "HCSR04.h"
  7. #include "usart.h"
  8. #include "OLED.h"
  9. //结构体声明
  10. PIDPara Location;
  11. PIDPara Speed;
  12. extern int Speed_Begin;
  13. extern int Location_Begin;
  14. /*====================================
  15. 函数 :循迹PID函数(位置式)
  16. 参数 :误差
  17. 返回值 :经过PID计算后的量
  18. 描述 :通过pid计算误差,将其加到原有的
  19. 计算中,得到需要的新速度量
  20. ====================================*/
  21. float Position_KP = 1.8;//例:速度80 -> 1.8 大概
  22. // Position_KI = 0.1,
  23. // Position_KD = 0;
  24. int Position_PID(int target)
  25. {
  26. static float Pwm ,
  27. Bias ;
  28. // Interqral_Bias ;
  29. // Last_Bias;
  30. Bias = target;
  31. // Interqral_Bias += Bias;
  32. //
  33. // if(Interqral_Bias > + 6) Interqral_Bias = + 6;
  34. // if(Interqral_Bias < - 6) Interqral_Bias = - 6;
  35. Pwm = Position_KP * Bias ;
  36. // Position_KI * Interqral_Bias ;
  37. // Position_KD * (Bias - Last_Bias);
  38. // Last_Bias = Bias;
  39. return Pwm;
  40. }
  41. /*====================================
  42. 函数 :跟踪PID函数(位置环+速度环)
  43. 参数 :误差
  44. 返回值 :经过PID计算后的量
  45. 描述 :通过pid计算误差,将其加到原有的
  46. 计算中,得到需要的新速度量
  47. ====================================*/
  48. void PID_Init(void)
  49. {
  50. //pid 参数初始化
  51. Location.Kp = 1;
  52. Location.Ki = 0;
  53. Location.Kd = 0;
  54. Location.C0 = 0;
  55. Location.C1 = 0;
  56. Location.Cmin = 0;
  57. Location.Cmax = 0;
  58. Location.E0 = 0;
  59. Location.E1 = 0;
  60. Location.E2 = 0;
  61. Speed.Kp = 1.5;
  62. Speed.Ki = 0;
  63. Speed.Kd = 0;
  64. Speed.C0 = 0;
  65. Speed.C1 = 0;
  66. Speed.Cmin = 0;
  67. Speed.Cmax = 0;
  68. Speed.E0 = 0;
  69. Speed.E1 = 0;
  70. Speed.E2 = 0;
  71. }
  72. /*====================================
  73. 函数 :跟踪PID函数(位置式)
  74. 参数 :误差
  75. 返回值 :经过PID计算后的量
  76. 描述 :通过pid计算误差,将其加到原有的
  77. 计算中,得到需要的新速度量
  78. ====================================*/
  79. int Location_PID(int target)
  80. {
  81. static float Pwm ,
  82. Bias;
  83. // Last_Bias;
  84. Bias = target - Location_Begin;
  85. Pwm = 1 * Bias ;
  86. // 0.3 * (Bias - Last_Bias);
  87. // Last_Bias = Bias;
  88. return Pwm;
  89. }
  90. //int Speed_PID(void)
  91. //{
  92. //
  93. // static float Speed_Pwm ,
  94. // Bias ,
  95. // Last_Bias;
  96. //
  97. // Bias = Location_PID(Hcsr04_GetLength());
  98. // Speed_Pwm = Speed.Kp * Bias +
  99. // Speed.Kd * (Bias - Last_Bias);
  100. //
  101. // Last_Bias = Bias;
  102. //
  103. // return Speed_Pwm;
  104. //}

PID.h

  1. #ifndef __PID_H
  2. #define __PID_H
  3. #include "sys.h"
  4. extern int Speed_Begin;
  5. extern int Location_Begin;
  6. int Position_PID(int target);
  7. //结构体
  8. typedef struct
  9. {
  10. //PID 参数系数K
  11. float Kp;
  12. float Ki;
  13. float Kd;
  14. //PID 控制量C:当前: C0 上一次:C1 范围控制量:Cmin Cmax
  15. float C0;
  16. float C1;
  17. float C2;
  18. float Cmin;
  19. float Cmax;
  20. // //PID 变量:当前: C0 上一次:C1 范围控制量:Cmin Cmax
  21. // static float Pwm;
  22. // static float Bias ;
  23. // static float Interqral_Bias;
  24. // static float Last_Bias;
  25. //PID 误差量E 当前: E0 上一次: E1 上上一次: E2
  26. float E0;
  27. float E1;
  28. float E2;
  29. }PIDPara; //PID 参数
  30. //PID初始化
  31. void PID_Init(void);
  32. //循迹模式PID函数
  33. int Speed_PID(void);
  34. //跟踪模式PID函数
  35. int Location_PID(int target);
  36. #endif

其他还有AD+DMA转运代码,大家在下载中查看吧

五、制作小车需要注意的地方

1,要提早分配好io口,这次制作的过程中就出现了使用PB3的尴尬情况,还要增加释放函数

2,串口与定时器互相影响,我当时原测试模块时初始化互相影响,但是后面将它们初始化放在上下靠近,看教程是定时器见初始化再初始化串口,一次解决,不过在使用串口的同时使用舵机容易造成舵机的抖动,这边偶然增加一个for循环以及delay可以解决这个影响问题,还算是运气很好哈哈

下面是实现的效果展示,我把它做成视频发布在b站:

STM32超级蓝牙小车——基于STM32F103C8T6的多功能蓝牙小车(PID循迹、跟踪、有源蜂鸣器播放音乐、蓝牙遥控、AD采集+DMA转运等超多元素小车)

六、代码源文件

链接:https://pan.baidu.com/s/1WZF10LWIbbE5Mubth__VEQ 
提取码:grcc

这次的程序写了蛮多注释的,也是花了三天时间做的,感觉最大的问题就是串口与定时器关系的问题,程序上可能还存在错误,希望大家多多指正!!!

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

闽ICP备14008679号