找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 14190|回复: 8
收起左侧

STM32两轮智能避障小车制作 含keil工程源码、连线图

  [复制链接]
ID:495511 发表于 2019-3-21 17:08 | 显示全部楼层 |阅读模式
这个项目最主要研究了基于STM32F103微处理器的智能小车控制系统的设计。整个系统主要包括STM32F103控制器、电机驱动电路、红外检测电路、超声波避障电路。我们采用STM32F103芯片,采用脉冲宽度调制信号(PWM)来完成对电机的控制,循迹模块采用红外探测法进行黑白探测,避障模块进行障碍物检测并躲避,超声波模块用来检测小车与障碍物之间的距离,其他外围电路可用于其他功能的拓展。小车在运行过程中,避障程序优先于循迹程序。

1.介绍
1.1项目介绍
1.2研究目的
1.3设想
1.4研究方法及思路
1.5成果
2.软硬件设计
2.1智能小车介绍
2.2智能小车的组成部分
2.2.1微处理器
2.2.2传感器检测部分
2.2.3超声波检测部分
2.2.4机器人的脚
2.3循迹原理
2.3.1红外探测法
2.3.2循迹方法
2.3.3道路现象分析
2.3.4循迹代码
2.4避障原理
2.4.1HC-SR04工作原理
2.4.2自由避障策略
2.4.3自由避障代码
2.5自动驾驶系统总体结构
3.软硬件调试
3.1软件调试
3.2硬件调试
4.结论

1.介绍1.1项目介绍

本项目是一个自动驾驶系统的项目,该项目能够通过提供自动驾驶、对路况智能处理以及其他为行驶系统设计的新功能,根据场景设定完成自动驾驶。该自动驾驶的设备可以是私家汽车, 货车,也可以是卡车等。

1.2研究目的

设计一个自动驾驶系统,可以在特定地方寻找轨迹,并沿着轨迹行走;可以检测到障碍物的距离并进行躲避。

1.3设想

假设在校方提供提供的样机、红外探测器、超声波检测模块功能正常,电池电量充足,源程序思路代码均正确,场地轨迹明显的情况下,我们的小车可以沿着黑色轨迹线持续行走,遇到障碍物时小车停止,移开障碍物后,小车可继续沿着特定的轨迹行走,直至我们要求其结束。

1.4研究方法及思路

本次实验我们采取模拟法,使用HL-1 智能小车模拟真实的汽车,进行实验。实验过程中,我们模拟不同的路况,例如“T型路”、“十字路”、“断头路”等路况,将小车放在相应的位置,观察其红外探测的指示灯的亮灭状况,并记录下来,分析其对应情况时IO口的输入情况,得出循迹伪代码;避障时,我们通过设置障碍物,分析小车遇到障碍物时应做出的回应,得到相应的伪代码。最终进行整体代码的分析撰写。


1.5成果

循迹:小车在特定场景模式下,按照黑色的轨迹行驶;

避障:循迹模式下,小车遇障碍物停止;自由模式下,小车到障碍物的距离大于20cm时直行,小车到障碍物的距离大于10cm小于20cm时右转;小车到障碍物的距离小于10cm时后退;

文档:提交技术报告、会议纪要、进度计划表、任务书组、项目组成员表等文档

2.软硬件设计2.1智能小车介绍
  • 智能小车是轮式机器人。
  • 它是一个集环境感知、规划决策、自动驾驶等功能于一体的综合系统                           
  • 它是集中运用了计算机、传感、信息、通信、导航、人工智能及自动控制等技术的综合体。
图 1 智能小车整体图
2.2智能小车的组成部分2.2.1微处理器
图 2 STM32F103C8主芯片整体图

STM32F103C8主芯片

  •    内核:ARM 32位的Cortex-M3 CPU 工作频率72MHz                           
  •    存储器:64KB闪存程序存储器、20KB的SRAM
  •    电源电压:2.0V~3.6V
  •    数据转换器:2个12位AD转换器(10个输入通道)
  •    调试模式:串行单线调试(SWD)和JTAG接口
2.2.2传感器检测部分
图 3 红外反射传感器整体图

红外反射传感器

  •    检测距离:1mm~8mm
  •    比较器输出数字开关量(0和1)
  •    配多圈可调精密电位器调节灵敏度
  •    工作电压:3.3V~5V

传感器的红外发射二极管不断发射红外线,当发射出的红外线没有被反射回来或被反射回来强度不大时,比较器的输出端为高电平,指示灯熄灭;当红外线被反射回来且强度足够大时,比较器的输出端为低电平,指示灯被点亮。

2.2.3超声波检测部分
图 4 HC-SR04整体图

HC-SR04引脚

  • VCC供5V电源
  • GND为地线
  • TRIG触发控制信号输入
  • ECHO回响信号输出
表 1  HC-SR04电器参数

电气参数

HC-SR04声波模块

工作电压

DC  5V

工作电流

15mA

输入触发信号

10us的TTL脉冲

输出回响

输出TTL电平信号信号,与射程成比例



2.2.4机器人的脚
图 5 LN98N集成电机驱动整体图
  •    机械部分

车轮为三个,前轮是两个主动轮,后轮是一个从动轮

  •    电机部分
  •   两个直流电机
  •   L298N集成电机驱动芯片
  •   工作电压:5V

微控制器产生PWM信号给L298N,通过调节方波的占空比来控制电机的转速。两个电机转速相同时小车前进或后退;转速不同时小车转弯;两个电机反向等速运转时,小车原地转圈。

2.3循迹原理

小车循迹指的是小车在白色地板上循黑线行走,通常采取的方法是红外探测法。

2.3.1红外探测法

利用红外线在不同颜色的物体表面具有不同的反射强度的特点,在小车行驶过程中不断地向地面发射红外光,当红外光遇到白色纸质地板时发生漫反射,反射光被装在小车上的接收管接收;如果遇到黑线则红外光被吸收,小车上的接收管接收不到红外光。单片机就是否收到反射回来的红外光为依据来确定黑线的位置和小车的行走路线。

2.3.2循迹方法

采用与路面颜色有较大差别的线条(白色路面上有条黑色曲线)作引导线,当循迹传感器照到黑线时输出高电平1,照到白色时输出低电平0。

图 6 循迹示意图
2.3.3道路现象分析
路径名称
路径图示
小车操作



循迹直行


寻迹直行,沿着当前黑色路径指示直行

L弯左转

循迹左转90度,沿着当前黑色路径指示直行

L弯右转

循迹右转90度,沿着当前黑色路径指示直行

T型路口按命令转弯

遇到T型路口,根据命令转弯。命令左转,向左转弯;命令右转,向右循迹转弯。

            

              十字路口

遇到十字路口,根据命令行驶。左转,右转直行

断头路

遇到断头路,左转180度调头

图表 1   道路状态模拟

我们采用三路循迹,共8中状态指示,对应状况如下所示

表 2    红外检测状态分析

指示灯A、C、E
代号
回应
000
OUT
掉头(‘u’)
001
R
右转(‘r’)
010
M
执行(‘f’)
011
MR
右转(‘r’)
100
L
左转(‘l’)
101
LR

110
LM
左转(‘l’)
111
LMR
右转(‘r’)

备注:我们设计的线路之间有一定的距离,LR状态不会出现

2.3.4循迹代码
图 7   循迹代码截图
2.4避障原理2.4.1HC-SR04工作原理
  • 给超声波模块接入电源和地。
  • 给脉冲触发引脚(trig)输入一个长为20us的高电平方波。
  • 输入方波后,模块会自动发射8个40KHz的声波,与此同时回波引脚(echo)端的电平会由0变为1;(此时应该启动定时器计时)
  • 当超声波返回被模块接收到时,回波引 脚端的电平会由1变为0;(此时应该停止定时器计数),定时器记下的这个时间即为超声波由发射到返回的总时长。
  •   根据声音在空气中的速度为344米/秒,即可计算出所测的距离
2.4.2自由避障策略
表 3自由避障策略分析
当前距离(curDis)/cm
应答策略/代号
10<curDis <20
掉头(‘u’)
curDis<10
后退(‘b’)
curDis >20
直行(‘f’)

2.4.3自由避障代码
图 8  自由避障程序截图
2.5自动驾驶系统总体结构

图 8  自动驾驶系统总体结构
3.软硬件调试3.1软件调试

系统开发条件:Keil 5.26.2.0

下载工具:J-Link 6.20

3.2硬件调试

小车连线:

·电源

              小车J2 –VCC 接stm32控制板JP2- +5V

              小车J2 –GND接stm32控制板JP2- GN

              小车J2 –VCC接红外控制板VCC

小车J2 –GND接红外控制板GND

·驱动

              小车J3-IN1接stm32控制板JP3-PB10

              小车J3-IN2接stm32控制板JP3-PB11

              小车J3-IN3接stm32控制板JP3-PB12

              小车J3-IN4接stm32控制板JP3-PB13

              小车J3-EN1接stm32控制板JP3-3.3V

              小车J3-EN2接stm32控制板JP3-3.3V

·红外信号输出

              红外控制板D01接stm32控制板J2-PB5

              红外控制板D02接stm32控制板J2-PB6

              红外控制板D03接stm32控制板J2-PB7

·超声波输入输出

              超声波模块接小车J6

              小车J4-P2.0接stm32控制板PA0

              小车J4-P2.1接stm32控制板PA4

4.结论

本次项目设计了中央处理模块、电机驱动模块、避障模块和循迹模块。其中中央处理模块的芯片是stm32f103,电机驱动模块的主要芯片是LM293D,避障模块的主要器件是HC-SR04,循迹模块的主要器件是五个红外探测器(IR)。通过各模块之间的配合以及软件和硬件设计的结合,使得最终设计出的小车具有循迹功能和避障功能,即能沿轨迹黑线前进,不会偏出轨迹,并且当探测到障碍物时可停止前进,且探测距离大于10cm。最终完成了该项目的设想预期。



  1. #include <stdio.h>

  2. extern void CarInit(void);
  3. extern void DebugInit(void);
  4. extern void TimerInit(void);
  5. extern void CheckTimer(void);

  6. int main()
  7. {
  8.   TimerInit();    // 系统任务定时器初始化
  9.   CarInit();      // 小车各模块初始化
  10.   DebugInit();

  11.   while(1)
  12.   {
  13.     CheckTimer(); // 开始执行定时任务
  14.   }
  15. }
  16. timer.c
  17. #include "stm32f10x.h"

  18. void TimerInit()
  19. {
  20.               RCC->APB2ENR |= 1 << 11;

  21.               TIM1->PSC = 36000 - 1;
  22.               TIM1->ARR = 65535;
  23.               TIM1->CR1 = 0x81;
  24. }

  25. static unsigned short TimeGet()
  26. {
  27.   return TIM1->CNT;
  28. }


  29. struct timer
  30. {
  31.   void (*proc)(void);
  32.   int reload;
  33.   unsigned short begin;
  34.   unsigned short duration;
  35. };

  36. #define TIMER_CNT_MAX 8
  37. static struct timer tmr[TIMER_CNT_MAX];
  38. static int tmr_cnt=0;

  39. int SetTimer(unsigned short duration, void (*proc)(void) , int reload)
  40. {
  41.   if (tmr_cnt >= TIMER_CNT_MAX)
  42.   {
  43.     return 0;
  44.   }
  45.   tmr[tmr_cnt].begin = TimeGet();
  46.   tmr[tmr_cnt].duration = duration;
  47.   tmr[tmr_cnt].proc = proc;
  48.   tmr[tmr_cnt].reload = reload;
  49.   tmr_cnt++;
  50.   return 1;
  51. }

  52. // CheckTimer为主程序循环调用函数,执行定时事务
  53. void CheckTimer()
  54. {
  55.   int tmr_idx=0;
  56.   int i=0;
  57.   unsigned short now = TimeGet();

  58.   while (tmr_idx < tmr_cnt)
  59.   {
  60.     if ((unsigned short)(now - tmr[tmr_idx].begin) >= tmr[tmr_idx].duration)
  61.     {
  62.       if (tmr[tmr_idx].proc)
  63.         (*tmr[tmr_idx].proc)();
  64.       if (tmr[tmr_idx].reload)
  65.       {
  66.         tmr[tmr_idx].begin = now;
  67.         tmr_idx++;
  68.       }
  69.       else
  70.       {
  71.         for (i=tmr_idx; i<tmr_cnt-1; i++)
  72.           tmr[i] = tmr[i+1];
  73.         tmr_cnt--;
  74.       }
  75.     }
  76.     else
  77.       tmr_idx++;
  78.   }
  79. }

  80. 3.motor.c

  81. #include "stm32f10x.h"

  82. struct motor
  83. {
  84.   enum {STOP, FORWARD, BACKWARD} state;
  85.   int forward_opcode;
  86.   int backward_opcode;
  87. };

  88. static struct motor left_motor, right_motor;

  89. void MotorInit()
  90. {
  91.   RCC->APB2ENR |= 1 << 3;
  92.   GPIOB->CRH &= 0xff0000ff;
  93.   GPIOB->CRH |= 0x00333300; //PB10              左后退 , PB11              左前进, PB12              右前进, PB13  右后退
  94.   GPIOB->BSRR = ((1 << 10) | (1 << 11) | (1 << 12) | (1 << 13)) << 16;
  95.             
  96.   left_motor.state = STOP;
  97.   left_motor.forward_opcode = 1 << 11;
  98.   left_motor.backward_opcode = 1 << 10;

  99.   right_motor.state = STOP;
  100.   right_motor.forward_opcode = 1 << 12;
  101.   right_motor.backward_opcode = 1 << 13;            
  102. }

  103. //对某电机施加前转驱动电平
  104. static void MotorRotateForward(struct motor *pmotor)
  105. {
  106.               if (pmotor->state != FORWARD)
  107.               {
  108.                 GPIOB->BSRR = (pmotor->backward_opcode << 16) | pmotor->forward_opcode;
  109.                 pmotor->state = FORWARD;
  110.               }
  111. }

  112. //对某电机施加后转驱动电平
  113. static void MotorRotateBackward(struct motor *pmotor)
  114. {
  115.               if(pmotor->state != BACKWARD)
  116.               {
  117.                 GPIOB->BSRR = (pmotor->forward_opcode << 16) | pmotor->backward_opcode;
  118.                 pmotor->state = BACKWARD;
  119.               }
  120. }

  121. //对某电机停止驱动电平
  122. static void MotorStop(struct motor *pmotor)
  123. {
  124.               if (pmotor->state != STOP)
  125.               {
  126.                 GPIOB->BSRR = (pmotor->forward_opcode | pmotor->backward_opcode) << 16;
  127.                 pmotor->state = STOP;
  128.               }
  129. }

  130. //电机控制函数
  131. //输入参数:电机标识字符'r'或’l'(右或左)   操作代码字符'f'、'b'或's'(正转、反转或静止)
  132. void MotorControl(char motor, char op_cmd)
  133. {
  134.   struct motor *pmotor;

  135.   if (motor == 'r')
  136.     pmotor = &right_motor;
  137.   else if (motor == 'l')
  138.     pmotor = &left_motor;
  139.   else
  140.     return;
  141.   if (op_cmd == 'f')
  142.     MotorRotateForward(pmotor);
  143.   if (op_cmd == 'b')
  144.     MotorRotateBackward(pmotor);
  145.   if (op_cmd == 's')
  146.     MotorStop(pmotor);
  147. }
  148. wheel.c
  149. #include "stm32f10x.h"

  150. extern void MotorInit(void);
  151. static void WheelDrive(void);
  152. extern void MotorControl(char motor, char op_cmd);
  153. extern int SetTimer(unsigned short duration, void (*proc)(void) , int reload);

  154. struct wheel
  155. {
  156.   unsigned short period;
  157.   unsigned short duty;
  158.   unsigned short current;
  159.   unsigned char motor;
  160.   unsigned char dir;
  161. };

  162. static struct wheel wheel_left, wheel_right;
  163. static enum{STOP, FORWARD, BACKWARD, LEFT, RIGHT, U_TURN} state;

  164. // WheelInit是对小车的车轮要的外部接口进行初始化。
  165. void WheelInit()
  166. {
  167.               MotorInit();

  168.               wheel_left.period = 50;
  169.               wheel_left.duty = 15;
  170.               wheel_left.current = wheel_left.period;
  171.               wheel_left.dir = 's';
  172.               wheel_left.motor = 'l';
  173.             
  174.               wheel_right.period = 50;
  175.               wheel_right.duty = 15;
  176.               wheel_right.current = wheel_right.period;
  177.               wheel_right.dir = 's';
  178.               wheel_right.motor = 'r';

  179.               state = STOP;
  180.             
  181.               SetTimer(2, WheelDrive, 1); // 每1ms执行一次
  182. }

  183. static void WheelRun(struct wheel *pwheel, char dir)
  184. {
  185.               if((dir != 'f') && (dir != 'b'))
  186.     return;
  187.               pwheel->dir = dir;
  188.               pwheel->current++;
  189.               if (pwheel->current >= pwheel->period)
  190.     pwheel->current = 0;
  191.               if (pwheel->current < pwheel->duty)
  192.     MotorControl(pwheel->motor, pwheel->dir);
  193.               if(pwheel->current >= pwheel->duty)
  194.     MotorControl(pwheel->motor, 's');
  195. }

  196. static void WheelStop (struct wheel *pwheel)
  197. {
  198.               if(pwheel->dir == 's')
  199.   return;
  200.               pwheel->dir = 's';
  201.               pwheel->current = pwheel->period;
  202.               MotorControl(pwheel->motor, 's');
  203. }

  204. // WheelDrive是根据工作状态来设定小车的前进、后退、左转、右转及停止,
  205. // 主要是操控WheelRun和WheelStop两个函数实现所需要的功能。
  206. static void WheelDrive()
  207. {
  208.   switch(state)
  209.   {
  210.                 case FORWARD:
  211.       WheelRun(&wheel_right, 'f');
  212.       WheelRun(&wheel_left, 'f');
  213.     break;
  214.                
  215.     case BACKWARD:
  216.       WheelRun(&wheel_right, 'b');
  217.       WheelRun(&wheel_left, 'b');
  218.     break;

  219.                 case LEFT:
  220.                   WheelRun(&wheel_right, 'f');
  221.       WheelStop(&wheel_left);
  222.     break;

  223.                 case RIGHT:
  224.       WheelStop(&wheel_right);
  225.       WheelRun(&wheel_left, 'f');
  226.     break;

  227.                 case STOP:
  228.       WheelStop(&wheel_right);
  229.       WheelStop(&wheel_left);
  230.     break;

  231.     case U_TURN:
  232.       WheelRun(&wheel_right, 'b');
  233.       WheelRun(&wheel_left, 'f');
  234.     break;
  235.   }
  236. }
  237. // WheelControl外部采用命令方式改变车的工作状态
  238. void WheelControl(char cmd)
  239. {
  240.   switch(cmd)
  241.   {
  242.                 case 'f':
  243.       state = FORWARD;
  244.     break;

  245.                 case 'b':
  246.       state = BACKWARD;
  247.     break;

  248.                 case 'l':
  249.       state = LEFT;
  250.     break;

  251.                 case 'r':
  252.       state = RIGHT;
  253.     break;

  254.                 case 's':
  255.       state = STOP;
  256.     break;

  257.     case 'u':
  258.       state = U_TURN;
  259.     break;
  260.   }            
  261. }

  262. void SpeedChange(unsigned char mode)
  263. {
  264.   if (mode)
  265.   {
  266.     wheel_left.duty = 35;
  267.     wheel_right.duty = 35;
  268.   }
  269.   else
  270.   {
  271.     wheel_left.duty = 15;
  272.     wheel_right.duty = 15;
  273.   }
  274. }
  275. detection.c

  276. #include "stm32f10x.h"
  277. #include <stdio.h>

  278. static void UpdateDistance(void);
  279. extern void SpeedChange(unsigned char mode);
  280. extern int  SetTimer(unsigned short duration, void (*proc)(void) ,int reload);

  281. static unsigned char TIM2CaptureFlag; // 输入捕获状态
  282. unsigned int curDis = 0xffff;         // 当前距离
  283. unsigned char SYSTEM_MODE = 0;        // 模式选择 0--循迹避障,1--自由避障
  284. char InfraredState;

  285. void DetectionInit()
  286. {
  287.   GPIO_InitTypeDef        GPIO_InitStructure;
  288.   NVIC_InitTypeDef        NVIC_InitStructure;
  289.   TIM_ICInitTypeDef       TIM_ICInitStruct;
  290.   TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

  291.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
  292.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  293.   // HC-SR04 Echo PA0 (TIM2_CH1的IC1)
  294.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  295.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  296.   GPIO_Init(GPIOA, &GPIO_InitStructure);
  297.   GPIO_ResetBits(GPIOA, GPIO_Pin_0);

  298.   // HC-SR04 Trig PA4
  299.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  300.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  301.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  302.   GPIO_Init(GPIOA, &GPIO_InitStructure);
  303.   GPIO_ResetBits(GPIOA, GPIO_Pin_4);

  304.   // LED
  305.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  306.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  307.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  308.   GPIO_Init(GPIOC, &GPIO_InitStructure);
  309.   GPIO_ResetBits(GPIOC, GPIO_Pin_13);

  310.   // 左红外 PB5,中红外 PB6,右红外 PB7
  311.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  312.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  313.   GPIO_Init(GPIOB, &GPIO_InitStructure);

  314.   // 功能选择 PB8
  315.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  316.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  317.   GPIO_Init(GPIOB, &GPIO_InitStructure);
  318.   GPIO_ResetBits(GPIOB, GPIO_Pin_8);

  319.   // TIM2
  320.   TIM_TimeBaseStructure.TIM_Period = 0xffff;                  // 重载计数值最大
  321.   TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;               // 计数周期1us
  322.   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     // 不分频
  323.   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
  324.   TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  325.   //TIM2_CH1输入捕获初始化
  326.   TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;               // 使用通道1
  327.   TIM_ICInitStruct.TIM_ICFilter = 0x02;                       // 不滤波
  328.   TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;          // 不分频
  329.   TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;// 直接映射到IC1
  330.   TIM_ICInit(TIM2, &TIM_ICInitStruct);

  331.   // TIM2 NVIC配置
  332.   NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  333.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  334.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  335.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  336.   NVIC_Init(&NVIC_InitStructure);

  337.   TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
  338.   TIM_Cmd(TIM2, ENABLE);

  339.   // 100ms更新一次距离
  340.   SetTimer(200, UpdateDistance, 1);
  341. }

  342. char DetectionGet()
  343. {
  344.   InfraredState = (GPIOB->IDR >> 5) & 0x7; // 低三位分别为PB5、PB6、PB7的值
  345.   return InfraredState;
  346. }

  347. void TIM2_IRQHandler(void)
  348. {
  349.   if((TIM2CaptureFlag & 0x10) == 0)                       // 是否是新的一次捕获
  350.   {
  351.     TIM2CaptureFlag |= 0x10;                              // 捕获到一次上升沿
  352.     TIM_SetCounter(TIM2, 0);
  353.     TIM_OC1PolarityConfig(TIM2, TIM_ICPolarity_Falling);  // 设置为下降沿捕获
  354.   }
  355.   else
  356.     curDis = 0.017 * TIM_GetCapture1(TIM2);
  357.   TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);                // 清除中断标志位
  358. }

  359. static void Delay20Us()
  360. {
  361.   int i = 0;
  362.   for (; i <= 231; i++);
  363. }

  364. static void UpdateDistance()
  365. {
  366.   TIM2CaptureFlag = 0;
  367.   TIM_OC1PolarityConfig(TIM2, TIM_ICPolarity_Rising);

  368.   // Trig
  369.   GPIO_SetBits(GPIOA, GPIO_Pin_4);
  370.   Delay20Us();
  371.   GPIO_ResetBits(GPIOA, GPIO_Pin_4);

  372.   // 系统模式选择
  373.   if (GPIOB->IDR & 0x100)
  374.     SYSTEM_MODE = 1;
  375.   else
  376.     SYSTEM_MODE = 0;
  377.   SpeedChange(SYSTEM_MODE);
  378. }
  379. track.c
  380. #include "stm32f10x.h"
  381. #include <stdio.h>

  382. extern void WheelControl(char cmd);

  383. enum {OUT, R, M, MR, L, LR, LM, LMR};
  384. extern unsigned int curDis; // 当前测距结果
  385. static char lastDetect = M; // 上一次的红外探测结果
  386. static char uTurnFLag = 0;  // 大转弯标记

  387. void TrackRun(char detection)
  388. {
  389.   if (curDis <= 15)
  390.     GPIO_SetBits(GPIOC, GPIO_Pin_13);
  391.   else
  392.     GPIO_ResetBits(GPIOC, GPIO_Pin_13);

  393.   // 当前距离小于15cm,停车
  394.   if (curDis <= 15)
  395.   {
  396.     WheelControl('s');
  397.     return;
  398.   }

  399.   if (detection != OUT)
  400.     uTurnFLag = 0;

  401.   // 直行的case
  402.   if (detection == M)
  403.     WheelControl('f');

  404.   // 右转的case
  405.   if (detection == R || detection == MR || detection == LMR)
  406.     WheelControl('r');

  407.   // 左转的case
  408.   if (detection == L)
  409.     WheelControl('l');

  410.   // 大转弯
  411.   if (uTurnFLag)
  412.     WheelControl('u');

  413.   // other cases
  414.   if (detection == OUT)
  415.     switch (lastDetect)
  416.     {
  417.       case R:
  418.         WheelControl('r');
  419.       break;

  420.       case M:
  421.         uTurnFLag = 1;
  422.       break;

  423.       case MR:
  424.         WheelControl('r');
  425.       break;

  426.       case L:
  427.         WheelControl('l');
  428.       break;

  429.       case LM:
  430.         WheelControl('l');
  431.       break;
  432.     }

  433.   if (detection != OUT)
  434.     lastDetect = detection;
  435. }
  436. avoid.c
  437. #include "stm32f10x.h"

  438. extern void WheelControl(char cmd);

  439. extern unsigned int curDis;

  440. void ObstacleAvoid()
  441. {
  442.   if (curDis <= 20)
  443.     GPIO_SetBits(GPIOC, GPIO_Pin_13);
  444.   else
  445.     GPIO_ResetBits(GPIOC, GPIO_Pin_13);

  446.   if (curDis >= 10 && curDis <= 20) // 满足 10cm <= dist <= 20cm
  447.     WheelControl('u');              // 则右转

  448.   if (curDis < 10)                  // 满足 dist < 10cm
  449.     WheelControl('b');              // 则后退

  450.   if (curDis > 20)
  451.     WheelControl('f');              // 其他case则直行
  452. }
  453. car.c
  454. #include "stm32f10x.h"
  455. #include <stdio.h>

  456. static void CarRun (void);
  457. extern void WheelInit(void);
  458. extern char DetectionGet(void);
  459. extern void DetectionInit(void);
  460. extern void ObstacleAvoid(void);
  461. extern void TrackRun(char detection);
  462. extern int  SetTimer(unsigned short duration, void (*proc)(void) , int reload);

  463. extern unsigned char SYSTEM_MODE;

  464. void CarInit()
  465. {
  466.   WheelInit();               // 车轮初始化
  467.   DetectionInit();           // 传感器初始化(红外和超声波)
  468.   SetTimer(2, CarRun, 1);    // 每1ms执行一次CarRun
  469. }

  470. static void CarRun()
  471. {
  472.   char det = DetectionGet();
  473.   if (SYSTEM_MODE)
  474.     ObstacleAvoid();
  475.   else
  476.     TrackRun(det);
  477. }
复制代码

底板网上购得,技术文档、源码在附件中
全部资料51hei下载地址:
Smart_Car_Lib_Ver.7z (191.29 KB, 下载次数: 203)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:266092 发表于 2019-3-29 10:47 | 显示全部楼层
程序质量很好,学习学习
回复

使用道具 举报

ID:505045 发表于 2019-5-18 18:20 | 显示全部楼层
楼主可以发给我邮箱吗?17382569964@163.COM
回复

使用道具 举报

ID:591784 发表于 2019-7-28 22:08 | 显示全部楼层
RocWang 发表于 2019-5-18 18:20
楼主可以发给我邮箱吗?

你有吗?能不能也发我一份。992163846@qq.com
回复

使用道具 举报

ID:588361 发表于 2019-7-29 10:21 | 显示全部楼层
谢谢楼主分享
回复

使用道具 举报

ID:657560 发表于 2019-12-6 14:45 | 显示全部楼层
RocWang 发表于 2019-5-18 18:20
楼主可以发给我邮箱吗?

你有吗?能不能也发我一份。1610077438@qq.com    谢谢啦
回复

使用道具 举报

ID:826937 发表于 2020-10-8 19:52 | 显示全部楼层
包含proteus的仿真文件么
回复

使用道具 举报

ID:818895 发表于 2020-10-21 20:48 | 显示全部楼层
这么好的案例,要好好学习STM32.
回复

使用道具 举报

ID:889199 发表于 2021-4-15 16:41 | 显示全部楼层
Kvn梦元儿 发表于 2020-10-8 19:52
包含proteus的仿真文件么

不包含proteus文件。——来自已经下载人的评论
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表