当前位置:   article > 正文

智能小车STM32——蓝牙循迹_基于stm32单片机的蓝牙智能小车

基于stm32单片机的蓝牙智能小车
1、功能介绍

蓝牙切换功能:智能小车内置了蓝牙模块,可以通过手机或其他蓝牙设备与之连接。用户可以通过手机发送指令控制小车的运动方向,实现远程控制

循迹功能:智能小车配备了红外线传感器,可以实现循迹功能。通过检测地面上的黑线或白线,小车能够自动沿着线路行驶,实现自动导航功能。

1.硬件准备

小车底盘一个(两驱),5号4节电池盒一个,STM32f103c8t6最小系统板,红外光电反射传感器两个,ST-LINK下载器,HC-05蓝牙模块、CH340模块、L298N电机驱动模块,焊接设备、一些杜邦线、也可以再准备一个面包板。

硬件搭设

硬件及程序

1.电机驱动

1.主电源正极接12v,主电源负极接GND。

 2.先将5V的跳线帽短接,这样不用额外通过5V输入端外加电源在给单片机供电,可直接有5V输入端连接导线直接给单片机供电,如不将跳线帽短接,则5V输入端输出的电压为12V,连接单片机会导致单片机烧毁

3.A相使能,B相使能是对输入1.2.3.4的控制,如果使能A和使能B加上跳线帽的话,则只需要通过控制输入1.2(一个电机),3.4(另外一个电机)分别给两个电机的两端0和1实现正反转,都给0或者都给1则电机不会转,如果使能A和使能B不加上跳线帽的话,当AB为低电平时,输入1.2.3.4都不会工作,所以可以通过控制使能A和使能B的开和关的周期来控制产生PWM波。
 

2.小车运动

  • 当IN1、IN3为高电平,IN2、IN4为低电平时,电机正转
  • 当IN1、IN3为低电平,IN2、IN4为高电平时,电机反转
  • 都为高电平时,电机不转
  • 电机的正转和反转与跟电机的接线不同而不同,注意自己调试

motor.c

  1. #include "stm32f10x.h"
  2. #include "pwm.h"
  3. void motor_init()
  4. {
  5. GPIO_InitTypeDef GPIO_InitStructure;
  6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  7. //2.设置GPIO模式
  8. //PB12~PB15 通用推挽输出
  9. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  10. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 |GPIO_Pin_8 |GPIO_Pin_11;
  11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12. GPIO_Init(GPIOA, &GPIO_InitStructure);
  13. PWM_Init();
  14. }
  15. void car_go()
  16. {
  17. //左轮
  18. GPIO_SetBits( GPIOA, GPIO_Pin_6);
  19. GPIO_ResetBits( GPIOA,GPIO_Pin_7);
  20. TIM_SetCompare3(TIM3, 90 );
  21. //右轮
  22. GPIO_SetBits( GPIOA, GPIO_Pin_8);
  23. GPIO_ResetBits( GPIOA,GPIO_Pin_11);
  24. TIM_SetCompare4(TIM3, 90 );
  25. }
  26. void car_back()
  27. {
  28. //左轮
  29. GPIO_ResetBits( GPIOA, GPIO_Pin_6);
  30. GPIO_SetBits( GPIOA,GPIO_Pin_7);
  31. TIM_SetCompare3(TIM3, 90 );
  32. //右轮
  33. GPIO_ResetBits( GPIOA, GPIO_Pin_8);
  34. GPIO_SetBits( GPIOA,GPIO_Pin_11);
  35. TIM_SetCompare4(TIM3, 90 );
  36. }
  37. void car_right()
  38. {
  39. //左轮
  40. GPIO_ResetBits( GPIOA, GPIO_Pin_6);
  41. GPIO_ResetBits( GPIOA,GPIO_Pin_7);
  42. TIM_SetCompare3(TIM3, 90 );
  43. //右轮
  44. GPIO_SetBits( GPIOA, GPIO_Pin_8);
  45. GPIO_ResetBits( GPIOA,GPIO_Pin_11);
  46. TIM_SetCompare4(TIM3, 75);
  47. }
  48. void car_left ()
  49. {
  50. //左轮
  51. GPIO_SetBits( GPIOA, GPIO_Pin_6);
  52. GPIO_ResetBits( GPIOA,GPIO_Pin_7);
  53. TIM_SetCompare3(TIM3, 75 );
  54. //右轮
  55. GPIO_ResetBits( GPIOA, GPIO_Pin_8);
  56. GPIO_ResetBits( GPIOA,GPIO_Pin_11);
  57. TIM_SetCompare4(TIM3, 90 );
  58. }
  59. void car_stop ()
  60. {
  61. //左轮
  62. GPIO_ResetBits( GPIOA, GPIO_Pin_6);
  63. GPIO_ResetBits( GPIOA,GPIO_Pin_7);
  64. //右轮
  65. GPIO_ResetBits( GPIOA, GPIO_Pin_8);
  66. GPIO_ResetBits( GPIOA,GPIO_Pin_11);
  67. }

pwm.c

  1. #include "stm32f10x.h"
  2. void PWM_Init(void)
  3. {
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  6. TIM_OCInitTypeDef TIM_OCInitStructure;
  7. //1.打开时钟
  8. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  9. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  10. //PB8,PB9 复用推挽输出
  11. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  12. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
  13. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  14. GPIO_Init(GPIOB, &GPIO_InitStructure);
  15. //初始化TIM4 100us
  16. TIM_InternalClockConfig(TIM3);
  17. TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  18. TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  19. TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
  20. TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; //PSC
  21. TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  22. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
  23. //初始化PWM波形
  24. TIM_OCStructInit(&TIM_OCInitStructure);
  25. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  26. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  27. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  28. TIM_OCInitStructure.TIM_Pulse = 0; //CCR
  29. TIM_OC3Init(TIM3, &TIM_OCInitStructure);//初始化右轮
  30. TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  31. TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  32. TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
  33. TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; //PSC
  34. TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  35. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
  36. TIM_OCStructInit(&TIM_OCInitStructure);
  37. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  38. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  39. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  40. TIM_OCInitStructure.TIM_Pulse = 0; //CCR
  41. TIM_OC4Init(TIM3, &TIM_OCInitStructure);//初始化左轮
  42. //使能定时器
  43. TIM_Cmd(TIM3, ENABLE);
  44. }
  45. void PWM_SetCompare3(uint16_t Compare)
  46. {
  47. TIM_SetCompare3(TIM3, Compare);
  48. }
  49. void PWM_SetCompare4(uint16_t Compare)
  50. {
  51. TIM_SetCompare3(TIM3, Compare);
  52. }

2.循迹模块

循迹模块通常具有两个红外传感器,可以通过连接线将其与单片机的GPIO口相连。确保连接正确且稳固。首先,初始化单片机的相关引脚,并设置为输入模式。然后,循迹模块的红外传感器将会输出高低电平信号,根据这些信号判断当前位置是否在黑线上。可以使用if语句或逻辑判断来处理不同的情况,例如当传感器检测到黑线时小车继续前进,当传感器检测到白线时小车停止或转向等。


track.c

  1. #include "stm32f10x.h"
  2. #include "motor.h"
  3. #define track_left GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_6)
  4. #define track_right GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_8)
  5. void track_Init(){
  6. GPIO_InitTypeDef GPIO_InitStructure;
  7. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  8. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_8;
  10. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  11. GPIO_Init(GPIOB, &GPIO_InitStructure);
  12. }
  13. void track(){
  14. if(track_left==0 && track_right==0 ){
  15. car_go();
  16. }
  17. else if(track_left==1 && track_right==0){
  18. car_left();
  19. }
  20. else if(track_left==0 && track_right==1){
  21. car_right();
  22. }
  23. else {
  24. car_stop();
  25. }
  26. }

3.蓝牙模块

蓝牙模块的前期调试,可用usb转ttl模块连接蓝牙模块,RXD-TX TXD-RX VCC-VCC GND-GND。

如果上电了,蓝牙指示灯默认是2s闪烁就是进入了AT指令模式,可通过上位机向蓝牙发送指令。如果上电不是AT指令模式,就摁着蓝牙的按键再上电。

AT指令集(建议改名字就好,密码不要改)

AT+NAME=Bluetooth-Master  蓝牙主机名称为Bluetooth-Master

AT+ROLE=1                蓝牙模式为主模式

AT+CMODE=0               蓝牙连接模式为任意地址连接模式

AT+PSWD=1234             蓝牙配对密码为1234

AT+UART=9600,0,0       蓝牙通信串口波特率为9600,停止位1位,无校验位

AT+RMAAD                 清空配对列表

usart.c

  1. #include "stm32f10x.h"
  2. #include "usart.h"
  3. #include "pwm.h"
  4. #include "motor.h"
  5. #include "track.h"
  6. //
  7. //加入以下代码,支持printf函数,而不需要选择use MicroLIB
  8. #if 1
  9. #pragma import(__use_no_semihosting)
  10. //标准库需要的支持函数
  11. struct __FILE
  12. {
  13. int handle;
  14. };
  15. FILE __stdout;
  16. //定义_sys_exit()以避免使用半主机模式
  17. void _sys_exit(int x)
  18. {
  19. x = x;
  20. }
  21. //重定义fputc函数
  22. int fputc(int ch, FILE *f)
  23. {
  24. while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
  25. USART1->DR = (u8) ch;
  26. return ch;
  27. }
  28. #endif
  29. #if EN_USART1_RX //如果使能了接收
  30. //串口1中断服务程序
  31. //注意,读取USARTx->SR能避免莫名其妙的错误
  32. u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
  33. //接收状态
  34. //bit15, 接收完成标志
  35. //bit14, 接收到0x0d
  36. //bit13~0, 接收到的有效字节数目
  37. u16 USART_RX_STA=0; //接收状态标记
  38. void usart_Init(void)
  39. {
  40. //GPIO端口设置
  41. GPIO_InitTypeDef GPIO_InitStructure;
  42. USART_InitTypeDef USART_InitStructure;
  43. NVIC_InitTypeDef NVIC_InitStructure;
  44. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE); //使能USART1,GPIOA时钟
  45. //USART1_TX GPIOA.9
  46. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  47. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  48. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  49. GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
  50. //USART1_RX GPIOA.10初始化
  51. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  52. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  53. GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
  54. //Usart1 NVIC 配置
  55. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  56. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
  57. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
  58. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
  59. NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
  60. //USART 初始化设置
  61. USART_InitStructure.USART_BaudRate = 9600;//串口波特率
  62. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
  63. USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
  64. USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
  65. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  66. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
  67. USART_Init(USART1, &USART_InitStructure); //初始化串口1
  68. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  69. USART_Cmd(USART1, ENABLE);
  70. }
  71. #endif
  72. void USART1_IRQHandler(void)
  73. {
  74. int res;
  75. if(USART_GetITStatus( USART1, USART_IT_RXNE)==SET)
  76. res=USART_ReceiveData(USART1);
  77. switch(res){
  78. case '1': car_go();break;
  79. case '2': car_back();break;
  80. case '3': car_left();break;
  81. case '4': car_right();break;
  82. case '5': car_stop();break;
  83. USART_ClearITPendingBit( USART1, USART_IT_RXNE);
  84. }
  85. }

usart.h

  1. #ifndef __USART_H
  2. #define __USART_H
  3. #include "stdio.h"
  4. #include "stm32f10x.h"
  5. #define USART_REC_LEN 200 //定义最大接收字节数 200
  6. #define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
  7. extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
  8. extern u16 USART_RX_STA; //接收状态标记
  9. //如果想串口中断接收,请不要注释以下宏定义
  10. void uart_init();
  11. #endif

Delay.c

  1. #include "stm32f10x.h"
  2. /**
  3. * @brief 微秒级延时
  4. * @param xus 延时时长,范围:0~233015
  5. * @retval 无
  6. */
  7. void Delay_us(uint32_t xus)
  8. {
  9. SysTick->LOAD = 72 * xus; //设置定时器重装值
  10. SysTick->VAL = 0x00; //清空当前计数值
  11. SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
  12. while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
  13. SysTick->CTRL = 0x00000004; //关闭定时器
  14. }
  15. /**
  16. * @brief 毫秒级延时
  17. * @param xms 延时时长,范围:0~4294967295
  18. * @retval 无
  19. */
  20. void Delay_ms(uint32_t xms)
  21. {
  22. while(xms--)
  23. {
  24. Delay_us(1000);
  25. }
  26. }
  27. /**
  28. * @brief 秒级延时
  29. * @param xs 延时时长,范围:0~4294967295
  30. * @retval 无
  31. */
  32. void Delay_s(uint32_t xs)
  33. {
  34. while(xs--)
  35. {
  36. Delay_ms(1000);
  37. }
  38. }

main.c

  1. #include "stm32f10x.h"
  2. #include "Delay.h"
  3. #include "motor.h"
  4. #include "pwm.h"
  5. #include "track.h"
  6. #include "usart.h"
  7. #define key GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)
  8. uint8_t Speed;
  9. void delay_s(int s);
  10. void USART1_IRQHandler(void);
  11. void usart_Init();
  12. void delay_s(int s)
  13. {
  14. uint8_t b;
  15. for( b = s;b>0;b--)
  16. {
  17. delay_ms(1000);
  18. }
  19. }
  20. int main(void)
  21. {
  22. motor_init();
  23. usart_Init();
  24. track_Init();
  25. while(1)
  26. {
  27. if(key==0)
  28. {
  29. USART1_IRQHandler();
  30. }
  31. else
  32. {
  33. track();
  34. }
  35. }
  36. }


 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号