基于stm32的智能小车设计
摘要
本次试验主要分析了基于STM32F103微处理器的智能小车控制系统的系统设计过程。此智能系统的组成主要包括STM32F103控制器、电机驱动电路、红外探测电路、超声波避障电路。本次试验采用STM32F103微处理器为核心芯片,利用PWM技术对速度以及舵机转向进行控制,循迹模块进行黑白检测,避障模块进行障碍物检测并避障功能,其他外围扩展电路实现系统整体功能。小车在运动时,避障程序优先于循迹程序,用超声波避障电路进行测距并避障,在超声波模块下我们使用舵机来控制超声波的发射方向,用红外探测电路实现小车循迹功能。在硬件设计的基础上提出了实现电机控制功能、智能小车简单循迹和避障功能的软件设计方案,并在STM32集成开发环境Keil下编写了相应的控制程序,并使用mcuisp软件进行程序下载。
关键词:stm32;红外探测;超声波避障;PWM;电机控制
- 1 -
基于stm32的智能小车设计
Abstract
This experiment mainly analyzes the control system of smart car based on microprocessor STM32F103 system design process. The composition of the intelligent system mainly including STM32F103 controller, motor drive circuit, infrared detection circuit, circuit of ultrasonic obstacle avoidance. This experiment adopts STM32F103 microprocessor as the core chip, using PWM technique to control speed and steering gear steering, tracking module is used to detect the black and white, obstacle avoidance module for obstacle detection and obstacle avoidance function, other peripheral extended circuit to realize the whole system function. When the car is moving, obstacle avoidance program prior to tracking, using ultrasonic ranging and obstacle avoidance obstacle avoidance circuit, we use steering gear under ultrasonic module to control the emission direction of ultrasonic, infrared detection circuit is used to implement the car tracking function. On the basis of the hardware design is proposed for motor control function, simple intelligent car tracking and obstacle avoidance function of software design, and in the STM32 integrated development environment under the Keil. Write the corresponding control program, and use McUisp program download software.
Keywords:STM32;Infrared detection;Ultrasonic obstacle avoidance;PWM;Motor control
- 2 -
基于stm32的智能小车设计
目录
1.绪论.......................................................... - 4 - 1.1研究概况 .................................................. - 4 - 1.2研究思路 .................................................. - 4 - 2.软硬件设计.................................................... - 5 - 2.1中央处理模块 .............................................. - 5 - 2.1.1 stm32f103内部结构 .................................... - 6 - 2.1.2 stm32最小系统电路设计 ................................ - 7 - 2.1.3 stm32软件设计的基本思路 .............................. - 9 - 2.1.4 stm32中断介绍 ........................................ - 9 - 2.1.5 stm32定时/计数器介绍 ................................ - 11 - 2.1.6 主程序设计流程图 ..................................... - 12 - 2.2 电机驱动模块 ............................................. - 13 - 2.2.1 驱动模块结构及其原理 ................................. - 13 - 2.2.2 驱动模块电路设计 ..................................... - 14 - 2.2.3驱动软件程序设计 ..................................... - 14 - 2.3 避障模块设计 ............................................. - 18 - 2.3.1 避障模块器件结构及其原理 ............................. - 19 - 2.3.2 HC-SR04模块硬件电路设计 ............................. - 21 - 2.3.3 HC-SR04模块程序设计 ................................. - 21 - 2.4循迹模块设计 ............................................. - 28 - 2.4.1 循迹模块结构及其原理 ................................. - 28 - 2.4.2 循迹模块电路设计 ..................................... - 30 - 2.4.3 红外循迹模块程序设计 ................................. - 30 - 3.软件调试..................................................... - 33 - 3.1 程序仿真 ................................................ - 33 - 3.2 程序下载 ................................................. - 34 - 4.系统测试..................................................... - 35 - 5.总结......................................................... - 37 - 致谢........................................................... - 39 -
- 3 -
基于stm32的智能小车设计
参考文献....................................................... - 40 - 附录........................................................... - 41 -
1.绪论
智能小车通过各种感应器获得外部环境信息和内部运动状态,实现在复杂环境背景下的自主运动,从而完成具有特定功能的机器人系统。而随着智能化电器时代的到来,它们在为人们提供的舒适的生活环境的同时,也提高了制造智能化电器对于人才要求的门槛。智能小车是集成了多种高新技术,它不仅融合了电子、传感器、计算机硬件、软件等许多学科的知识,而且还涉及到当今许多前沿领域的技术,它是一个国家高科技技术水平的重要体现。通过建立起简易智能小车的设计,引导学生从理论走向实践,培养同学们的动手能力,使同学们在了解智能化电器的工作原理的基础上,还使同学们获得完成整体项目的能力,并掌握了Stm32开发板的编程原理,为同学们进入ARM领域提供了基础。另外,本次课程设计,使同学们了解自己的不足之处,从而使同学们有目标的提升自己的能力。
1.1研究概况
国外研究概况:上世纪50年代初,国外就有智能车辆的研究,从90年代开始,智能车辆的研究就进入了系统化、大规模的研究阶段。尤其突出的是美国卡内基-梅陇大学机器人研究所已经完成了Navlab系列的自主车辆的研究,这一研究成果代表了国外智能车辆的主要研究方向。国内研究概况:我国对于智能车辆的研究较晚,始于上世纪80年代,而且现在大部分还是使用入门级别的51单片机进行设计与研究的,为了弥补与国外研究的差距,开设了全国大学生电子设计竞赛。
1.2研究思路
系统将采集的传感器信号送入stm32微控制器中,stm32微控制器根据采集的信号做出不同的判断,从而控制电机运动方向和运动速度。系统以stm32微控制器为核心,通过传感器采集不同的信号做出判断,继而改变电机的运动方向和运动速度。实验系统结构如图1.1所示:
- 4 -
基于stm32的智能小车设计
传感器传感器采样传感器电路STM32主控制器电机驱动电路 图1.1 实验系统结构图
2.软硬件设计
智能小车控制系统具备了障碍物检测、自主避障、自主循迹等功能。相应的控制系统主要由以下四个模块组成:避障模块、循迹模块、电机驱动模块、中央处理模块四个模块组成,系统总体框架如图2.1所示:
图2.1 系统框架图
我们本节主要任务是了解各个模块的功能,掌握各个模块所使用的器件的使用方法,并能够编写相应的程序代码。掌握各个模块的功能。
2.1中央处理模块
在人类身体结构中,大脑可以根据各个器官所传输的信息做出相应的行为动作用以保证人体所必须的生理原料,而stm32处理器之于智能小车就相当于大脑之于人类,它可以从各个模块之间获得数据,并对所传输的数据进行实时处理,来驱使电机模块做出相应的行为动作。
由ARM公司设计的基于ARMv7架构的Cortex系列的标准体系结构在2006年推出,此结构是用来满足日渐复杂的不同性能要求的软件设计,根据所面向的领域,Cortex系列可以分为A、R、M三个分工明确的系列[1]。Stm32处理器的出现为微控制系统、工业控制系统、汽车车身系统和无线网络等对功耗和成本敏感的嵌入式应用领域实现高系统性能系统提供了基础,使编程的复杂性,集高性能、低功耗、低成本大大简化,并使它们融为于一体[2]。意法半导体ST公司作为一个半导体制造厂商,是ARM公司Cortex-M3内核开发项目一个主要合作方。2007年6
- 5 -
基于stm32的智能小车设计
月11日由ST公司率先推出的基于Cortex-M3内核的STM32系列微控处理器研发而出。此中,A系列是面向复杂的尖端应用程序,用于运行开放式的复杂操作系统;R是Real的首字母缩写,是面向实时系统开发的;M是Mirco的首字母缩写,专门面向低成本的微控制领域开发研究。因此,Cortex-M3处理器是由ARM公司设计的首款基于ARMv7-M体系结构的32位标准处理器,它不仅具有低功耗、少门数等优点,而且还具有短中断延迟、低调试成本等众多优点,使它在众多的处理器中脱颖而出。目前为止,STM32系列处理器暂分为2个系列。其中,STM32F101系列是标准型系列,工作频率设定在36MHZ;STM32F103系列是增强型系列,工作频率设定在72MHZ,其带有更多片内RAM和更丰富的外设资源。这两个系列的产品在软件和引脚封装方面具有兼容性,并且拥有相同的片内Flash资源,使软件的开发和升级更加方便。本次试验,我们使用的是stm32f103处理器。 2.1.1 stm32f103内部结构
STM32F103系列微处理器是首款基于ARMv7-M体系结构的32位标准RISC (精简指令集)处理器,具有执行代码效率高,外设资源丰富等众多优点。该系列微处理器工作频率设定在72MHz,高达128K 字节的内置Flash存储器和20K 字节的SRAM,方便程序编写,而且具有丰富的通用I/O 端口。其内部结构图如图2.2所示:
图2.2内部结构图
- 6 -
基于stm32的智能小车设计
Stm32处理器主系统主要由4个被动单元和4个驱动单元构成。4个驱动单元是:通用DMA1,通用DMA2,内核DCode总线和系统总线。4个被动单元由APB桥,APB设备,内部Flash闪存,内部SRAM、FSMC。我们实验所采用的芯片具有64KBSRAM、512KBFLASH、2个基本定时器,4个通用定时器,2个高级定时器,3个SPI,2个IIC,5个串口,1个USB,1个CAN,3个12位的ADC,1个12位DAC、1个SDIO接口,1个FSMC接口以及112个通用I/O口。 2.1.2 stm32最小系统电路设计
Stm32的最小系统电路主要由系统时钟电路、实时时钟电路、JTAG调试接口电路,复位电路和启动模式选择电路组成。最小系统电路原理图如图2-1-3所示:
图2.3 最小系统电路原理图
主要电路原理图的设计及功能如下所示: 1.系统时钟电路
系统时钟电路主要作用是提供节拍,就相当于人类的心脏跳动,随着心脏的跳动,血液就会到达全身部位,所以系统时钟的重要性就不言而喻啦。系统时钟的电路设计如图2.4所示:
- 7 -
基于stm32的智能小车设计
图2.4 系统时钟电路图
在时钟电路中,我们选用8M的晶振。 2.复位电路
复位电路的设计如图2.5所示:
图2.5 复位电路图
本次试验所采用的开发板为低电平复位。如图所示,当按键悬空时RST输入为高电平,当按键按下时,RST脚输入为低电平,从而电路复位。 3.JTAG电路
JTAG电路原理图如图2.6所示:
图2.6 JAG电路原理图 JTAG的主要功能是使目标文件烧到核处理器中。 4.启动模式电路
启动模式电路原理图如图2.7所示:
- 8 -
基于stm32的智能小车设计
图2.7 启动模式电路原理图
通过设置BOOT[1:0]引脚可以选择三种不同启动模式,启动模式如表2-1所示:
表2-1 启动模式表
启动模式选择引脚 BOOT1 X 0 1
BOOT0 0 1 1
启动模式
说明
主闪存存储器 主闪存存储器被选为启动区域 系统存储器 内置SRAM
系统存储器被选为启动区域 内置SRAM被选为启动区域
2.1.3 stm32软件设计的基本思路
在对其他模块设计之前,我们必须了解stm32的编程规则。任何处理器,包括stm32处理器,想要处理器完成某项相应的动作,就必须对处理器的寄存器进行操作。比如,我们在单片机C51中,同样,我们在stmM32的开发中过程中,我们同样可以对寄存器直接操作:
GPIOx->BRR=0x0011。 (x可以是A,B,C,D,E…比如GPIOA就是端口A) 但是,对于stm32这种级别的处理器,几百个寄存器记起来谈何容易。所以,ST(意法半导体)提出了固件库的概念,利用固件库进行编程。固件库的本质就是函数的集合,固件库将那些寄存器的底层操作都封装起来,提供一整套API供开发者使用。比如,上面通过控制BRR寄存器来控制电平的变化,官方库封装了一个函数:
Void GPIO_ResetBits(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin) {GPIOx->BRR = GPIO_Pin;} (x可以是A,B,C,D,E…比如GPIO_A就是端口A)
通过使用GPIO_ResetBits()函数就可以直接对寄存器进行操作啦。 2.1.4 stm32中断介绍
- 9 -
基于stm32的智能小车设计
本方案中,我们要使用stm32的中断,在程序设计中,我们要开启各个管道的中断,打开各个中断通道,配置中断方式,我们先来讲述下stm32单片机的中断机制。结构图如下所示:
图2.32 stm32外部中断/事件控制器结构图
图中的实线箭头,为外部中断信号的传输路径。 首先外部信号从编号为1的输入线进入。
其次这个外部信号通过编号2的边沿检测电路,这个边沿检测电路受到“上升沿选择寄存器”、“下降沿选择寄存器”的控制,我们可以控制这两个寄存器来选择中断的触发方式。我们可以在程序中进行设置,比如
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;设置为上升沿触发中断
然后该外部信号进入编号为3或门,或门另一端是软件中断寄存器,如果,软件中断/事件寄存器的对应位置1,编号3的输出总是为有效信号1。之后进入“中断挂起请求寄存器”,该寄存器记录了外部信号的电平变化。
最后经过编号为4的与门进入NVIC中断控制器,如果 “中断屏蔽寄存器”的对应位置0,外部的中断请求信号不能传输到NVIC中断控制器,从而实现中断的屏蔽。由于我们采用的是外部信号触发中断,所以我们只需了解外部中断的请求机制,对于事件的中断请求机制,我们在这里不做介绍。 我们以PE1为例,介绍下外部中断的一般步骤。步骤如下: ? 开启I/O的复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO
- 10 -
基于stm32的智能小车设计
,ENABLE); ? 初始化I/O为输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOE, &GPIO_InitStructure); ? 初始化线上中断,设置触发条件
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource1); EXTI_InitStructure.EXTI_Line=EXTI_Line1;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); ? 配置中断分组NVIC,并使能中断
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x06;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); ? 编写中断服务函数
void EXTI1_IRQHandler(void){}主要代码详见附录2. 2.1.5 stm32定时/计数器介绍
Stm32系列的单片机一般包含8个计数/定时器,TIM1、TIM8分别为高级控制定时器,TIM2~TIM5为通用定时器,TIM6以及TIM7为基本定时器。对于定时器的详细内容,我们不在这里一一介绍。
然后我们介绍一下本实验采用了那些定时器,以及这些定时器所要完成的功能有哪些。本实验所采用的定时器以及功能如下表所示:
表2-2定时器介绍表
定时器名称
定时器配置模式
- 11 -
主要功能
基于stm32的智能小车设计
TIM2 定时器中断模式 通过定时器中断,控制超
声波的扫描周期
TIM3 PWM复用输出模式 控制小车速度及舵机转
向
TIM5 输入捕获模式 采集超声波发射到接受的高电平持续时间t
2.1.6 主程序设计流程图
在本节实验中,循迹模块以及避障模块都是采用中断方式进行工作的,因此其主程序流程图如下图所示:
开始系统初始化前进 图1.2 主程序流程图
根据程序设计图,主程序设计如下: int main(void) {
u8 TIM5CH1_CAPTURE_STA=0; //输入捕获状态 u16 TIM5CH1_CAPTURE_VAL; //输入捕获值 delay_init(); //延时函数初始化 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
LED_Init();
GPIO_Configuration(); //端口初始化 EXTIX_Init(); //扫描轨迹
TIM2_Int_Init(4999,7199); //控制超声波扫描周期 TIM3_PWM_Init(1999,719); //控制舵机方向
TIM5_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 while(1)
- 12 -
基于stm32的智能小车设计
{ farward_Low();delay_ms(10);} }
2.2 电机驱动模块
Stm32对小车的控制,就是对电机的控制,通过控制电机的转向,小车的运动状态就会发生改变。电机驱动模块的主要器件为LM293N,我们下面就详细讲解下电机驱动模块。
2.2.1 驱动模块结构及其原理
电机驱动模块的实物图如图2.8所示:
图2.8 驱动电路实物图
电机驱动模块的主要器件是芯片LM293D,内部原理图如图2.9所示:
K1
K4
K3
K2
图2.9 电机驱动内部原理图
全桥式驱动电路的4只开关管都工作在斩波状态,如图1.2所示,K1、K2为一组,K3、K4 为另一组,两组的状态互补,一组导通则另一组必定关断。当K1、K2导通时,K3、K4关断,电机两端加正向电压,电机实现正转或反转制动;当K3、K4导通时,K1、K2关断,电机两端为反向电压,电机实现反转或正转制动。
- 13 -
基于stm32的智能小车设计
2.2.2 驱动模块电路设计
电机驱动模块的电路原理如图2.10所示:
图2.10 驱动模块电路原理图
表2-2是各个端口状态与运动方向的关系,其关系如下表所示:
表2-2 端口与运动方向关系表
电机M1 停止 正转 反转 -
IN1 0 1 0 1
IN2 0 0 1 1
电机M2 停止 正转 反转 -
IN3 0 1 0 1
IN4 0 0 1 1
2.2.3驱动软件程序设计
车轮电机的动作由GPIO口的输出实现,本节主要配置运动方向和运动速度,对于运动速度的控制,我们必须使用PWM,通过改变PWM的占空比来调节速度的大小,其主要代码设计如下所示:
void TIM3_PWM_Init(u16 arr,u16 psc){ ….}
要想使stm32的通用定时器TIMx产生PWM输出,需要用到的寄存器有:预分频寄存器(TIMx_PSC)、自动重装载寄存器(TIMx_ARR)、捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。我们先介绍这几个寄存器,然后介绍如何使用库函数产生PWM输出。下面我们就简单介绍下这些寄存器:
首先是预分频寄存器(TIMx_PSC),该寄存器可以用设置对时钟进行分频,然后在提供给计数器作为计数器的时钟。该寄存器的各位功能如图所示:
- 14 -
基于stm32的智能小车设计
图2.11 TIMx_PSC寄存器各位描述
接下来介绍自动重装载寄存器(TIMx_ARR),该寄存器的各位描述如下图所示:
图2.12TIMx_ARR寄存器各位描述
通过设置这两个寄存器,我们就可以算出PWM的输出周期,计算公式为: Tout=((arr+1)*(psc+1))/Tclk。其中Tclk为系统时钟周期。
其次我们介绍捕获/比较模式寄存器(TIMx_CCMR1/2),总共有两个,TIMx_CCMR1和
TIMx_CCMR2,TIMx_CCMR1控制通道CH1和CH2,TIMx_CCMR2控制CH3和CH4。因为这2个寄存器差不多,我们仅以通道CH1为例,介绍其中的TIMx_CCMR1为例,该寄存器的各位描述如下图所示:
图2.13TIMx_CCMR1/2寄存器各位描述
这里我们只介绍该寄存器的OCxM位,我们就以TIMx_CCMR1中的OC1M(控制通道CH1)为例,该位功能如下图所示:
- 15 -
基于stm32的智能小车设计
图2.14 OC1M功能描述
我们使用的是PWM输出模式,所以OC1M必须设置为110/111。OC2M(控制通道CH2)各位描述与OC1M相同,我们这要不在叙述。
然后我们介绍捕获/比较使能寄存器(TIMx_CCER),该寄存器控制着各个输入/输出通道
的开关,对于该寄存器,各位描述如下图所示:
图2.15TIMx_CCER寄存器描述
该寄存器比较简单,因为我们只介绍通道1,所以我们只讲CC1E位。如果我们想使能输入/捕获1,我们只需使用CC1E位。要想使PWM从I/O口输出,此位必须设置为1。
最后介绍捕获/比较寄存器(TIMx_CCR1~4),总共有4个,分别对应CH1~4,因为这4个寄存器相似,我们仅以TIMx_CCR1为例,该寄存器的给位介绍如下图所示:
图2.16TIMx_CCR1寄存器各位描述
- 16 -
基于stm32的智能小车设计
在输出模式下,该寄存器的值与CNT中的值进行比较,根据结果,实现电平的翻转。至此,我们把用到的几个寄存器都介绍完毕,下面我们就介绍如何通过库函数来配置实现PWM三路输出。
? 开启TIM3时钟以及复用功能输出。使能GPIO和端口复用功能时钟。库函
数使能TIM3、GPIO以及复用功能时钟的方法是: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
? 初始化TIM3,设置TIM3的PSC和ARR。在开启了TIM3的时钟之后,我们
要设置PSC和ARR寄存器的值来控制PWM的输出周期。调用的格式如下: TIM_TimeBaseStructure.TIM_Period=arr; TIM_TimeBaseStructure.TIM_Prescaler=psc; TIM_TimeBaseStructure.TIM_ClockDivision=0;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
? 设置TIM3_CH1、CH2、CH3的PWM模式,使能TIM3的CH1、CH2、CH3输出。
在库函数中PWM通道设置是通过TIM_OC1Init~TIM_OC4Init来设置的,这里我们需要3路PWM输出,所以我们需要使用函数TIM_OC1Init、TIM_OC2Init、TIM_OC3Init。库函数的调用格式如下: TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3, &TIM_OCInitStructure); TIM_OC1Init(TIM3, &TIM_OCInitStructure); TIM_OC3Init(TIM3, &TIM_OCInitStructure);
? 使能TIM3。完成以上配置后,我们要使能定时器TIM3。库函数调用格式
如下: TIM_Cmd(TIM3, ENABLE);
? 通过修改TIM3_CCRx(x为1,2,3)来控制占空比。库函数格式如下:
- 17 -
基于stm32的智能小车设计
Void TIM_SetComparex(TIM3,uint16_t Compare2);
我们可以知道,通过定时器3控制PWM波的占空比,从而实现速度方面的控制。其中arr和psc可以控制PWM波的周期,TIM3_CCRx可以控制PWM波的占空比。我们只需要调用此函数就可以实现不同的速度控制。
对于运动方向控制的代码我们就以后退为例,由于端口寄存器过于简单,我们不在此介绍端口的寄存器。我们仅介绍如何通过库函数进行端口配置。对各个I/O端口配置的过程相似,我们仅以PD8为例:主要过程如下所示: ? 使能I/O口时钟,调用格式如下所示:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC, ENABLE);
? 初始化I/O参数,调用格式如下所示:
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure); ? 操作I/0口
GPIO_SetBits(GPIOD,GPIO_Pin_8);PD8置1 GPIO_ResetBits(GPIOD,GPIO_Pin_8);PD8置0
我们知道了如何对端口进行操作之后就可以随意的控制小车的运动啦,运动方向的程序设计,其基本函数单元如下所示: void Left_Low(void);…
我们调用这些函数,就可以实现不同运动方向的控制。主要代码详见附录3.
2.3避障模块设计
在人类身体构造系统中,眼睛可以使我们非常方便的采集到外界环境的信息,然后把信息及时的传输到大脑,并对外界环境信息的变化做出相应的处理。而对智能小车来说,避障模块之于小车就相当于眼睛之于人类。避障模块可以采集外部地形数据,然后把所采集的地形数据传输到中央处理模块,从而实现躲避障碍的功能。避障模块所采用的器件在市场中有许多类型,比如红外检测,光位移检测,超声波检测等。本次试验我们使用的是HC-SR04超声波检测,超声波由于具
- 18 -
基于stm32的智能小车设计
有检测能力强,传播路径宽,因此我们决定使用HC-SR04器件。
在使用HC-SR04模块进行超声波测距的同时,我们可以使用舵机进行辅助。舵机的主要作用是改变HC-SR04模块的照射方向,从而控制超声波的发射方向。在程序编写过程中,如果小车前方遇见障碍时,我们可以直接控制舵机的转向,而小车的车身可以保持不变,在测量结束后,小车再做相应的动作。 2.3.1 避障模块器件结构及其原理
HC-SR04超声波测距模块测量范围在2cm-400cm之间,可以实现无接触式测距功能。HC-SR04超声波测距模块由一个超声波发射器、一个超声波接收器和控制电路组成,避障模块的实物结构图如图2.17所示:
图2.17实物正反面结构图
如结构图所示VCC提供5v电源,GND为接地线,TRIG为触发信号线,ECHO为回向信号输出线。基本原理如下:采用IO口TRIG触发测距,给至少10us的高电平信号,在TRIG触发沿到来后,超声波发射器会自动发出8个40KHz的方波,并且检测是否有信号返回,当超声波接收器接收到超声波时,表明有信号返回,通过IO口ECHO输出一高电平,高电平持续的时间就是超声波从发射到返回的时间。因此测量距离=(高电平持续时间*340m/s)/2。测量时序图如图2.18所示:
- 19 -
基于stm32的智能小车设计
图2.18 超声波时序图
我们根据时序图,可以编写相应的程序代码。为了防止发射信号对回向信号的影响,我们的测量周期不易过小。并且由于HC-SR04的感应角度不大于15°,所以测距时,为了防止发射信号丢失,我们要求被测物体的面积不应小于0.5平方米,否则可能导致测量结果不准确。
舵机在避障模块的主要作用前面已经提到,本节主要讲解舵机的工作特性。舵机的实物图如图2.19所示:
图2.19 舵机实物图
舵机的工作工作原理是stm32微处理器发出数据给舵机,舵机内部有一个基准电路,它会产生周期为20ms,宽度为1.5ms的基准信号,它将微处理器传输的直流偏置电压与电位器的电压数据进行比较,获得电压差输出。经由电路板上的IC 判断转动方向,再驱动无核心马达开始转动,透过减速齿轮将动力传至摆臂,同时由位置检测器送回反馈信号。舵机的转动角度与stm32所提供的PWM信号相关。标准信号PWM周期为20ms,理论上来讲脉宽为1~2ms,实际我们的脉宽为0.5~2.5ms,脉宽与所转的角度一一对应。角度与脉宽的对应图如图2.20所示:
- 20 -
基于stm32的智能小车设计
图2.20 舵机角度与脉宽对应图
2.3.2 HC-SR04模块硬件电路设计 超声波模块硬件原理图如下图所示:
图2.21 超声波硬件原理图
HC-SR04模块主要由发射器、接收器和部分电路组成。在此试验中,我们只需简单了解电路的设计,对于其基本原理可以不用过多涉猎,我们只需明白它们的工作原理,并且能够简单运用即可。 2.3.3 HC-SR04模块程序设计
根据硬件电路的设计,我们对避障子程序进行设计,程序流程图如图2.22所示:
- 21 -
基于stm32的智能小车设计
开始系统初始化前进否前方是否有障碍是舵机左转否小车左转小车左方是否有障碍是舵机右转否小车右方是否有障碍小车右转小车后转避障子程序结束 图2.22 避障程序流程图
避障模块在程序设计中,我们的工作主要是: 1、控制超声波的扫描周期
2、采集超声波发射到接受的高电平持续时间t
3、对采集的高电平持续时间t进行处理,判断前方是否有障碍 下面我们就详细介绍我们是怎么通过软件设计来完成这几个步骤的: 1、控制超声波的扫描周期
根据表2-2,我们采用的是TIM2来控制超声波的扫描周期。首先我们把TIM2设置为定时器中断模式,代码格式为void TIM2_Int_Init(u16 arr,u16 psc); 由于配置定时器中断模式十分简单,我们就不在详细介绍,其详细代码见附录4.定时器TIM2的中断周期计算公式为T=((arr+1)*(psc+1))/Tclk。Tclk为系统周期,一般为72Mhz.我们在中断服务程序中控制超声波的发射,我们采用PC7作为触发信号,根据超声波时序图,我们需要在中断程序中给PC7一个持续10ms的高电平,中断服务程序如下:
- 22 -
基于stm32的智能小车设计
void TIM2_IRQHandler(void) //TIM2中断 {
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update );
GPIO_SetBits(GPIOC,GPIO_Pin_7);
delay_ms(10);
GPIO_ResetBits(GPIOC,GPIO_Pin_7);
} }
2、采集超声波发射到接受的持续时间t
在本节试验中,我们使用了通用定时器TIM5的输入捕获功能,输入捕获模式具有测量频率或者测量脉冲的宽度的功能。我们开启TIM5通道CH1(定时器5)的输入捕获模式,采集ECHO端口的高电平持续时间。配置定时器5代码格式为: void TIM5_Cap_Init(u16 arr,u16 psc){…}
下面我们就详细讲解一下,如何开启并使用通用定时器的输入捕获功能。 输入捕获的原理,简单的讲就是通过检测TIM5(定时器)通道CH1的边沿信号,当边沿信号发生变化时,当前寄存器的值TIM1_CNT存放到通道的捕获/比较寄存器(TIM5_CCR1)里面。我们的实验就是采集捕获/比较寄存器(TIM5_CCR1)中的值并进行处理,完成相应的动作。为了使TIM5通道CH1具有捕获功能,我们需要用到TIM5_PSC、TIM5_ARR、捕获/比较模式寄存器(TIM5_CCMR1)、捕获/比较使能寄存器(TIM5_CCER)、捕获/比较寄存器(TIM5_CCR1)、DMA/中断使能寄存器(TIM5_DIER)、控制寄存器(TIM5_CR1)。我们下面就简单介绍下下这几个寄存器。
TIM5_PSC、TIM5_ARR、TIM5_CCR1这3个寄存器用法与前节中相同,我们就不在赘述,而在本实验中,捕获/比较寄存器TIM5_CCMR1非常重要,该寄存器的各位描述如下图所示:
- 23 -
基于stm32的智能小车设计
图2.23 TIMx_CCMR1各位描述
我们使用的是TIM5捕获/比较通道CH1,所以图中只介绍[7:0]位。本次试验我们设置CC1S[1:0]=01,IC1PSC[1:0]=00,IC1F[3:0]=0000。
接着我们再来看看捕获/比较使能寄存器TIMx_CCER,本节用到了CC1E和CC1P两位,描述如下图所示:
图2.24 TIMx_CCER最低两位描述
- 24 -
基于stm32的智能小车设计
所以要使能通道CH1输入捕获,CC1E必须设置为1,而CC1P则可以根据实际情况设置。
其次,我们再看看DMA/中断使能寄存器(TIM5_DIER),因为我们使用的是通道CH1,所以我们仅介绍控制通道CH1的位,如下图所示:
图2.25 TIMx_DIER各位描述
通过此图我们知道,我们需要设置CC1IE为1即可。
然后,我们再看看控制寄存器TIMx_CR1,我们只用到了最低位,所以我们仅介绍位0的功能,TIMx_CR1寄存器各位描述及位0功能描述如下如所示:
图2.26 TIMx_CR1寄存器各位描述及位0功能描述
我们要使能计数器,所以位0设置为1。至此,我们所使用的寄存器一一介绍完毕,下面介绍怎么配置输入/捕获步骤:
? 开启TIM5时钟以及GPIOA时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); ? 初始化TIM5,设置TIM5的psc和arr。
TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler =psc; TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
- 25 -
基于stm32的智能小车设计
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); ? 设置TIM5的输入比较参数,开启捕获模式。
TIM5_ICInitStructure.TIM_Channel=TIM_Channel_1;
TIM5_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising; TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 TIM_ICInit(TIM5, &TIM5_ICInitStructure); ? 设置TIM5的DIER寄存器,使能捕获和更新中断功能。
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE); ? 设置中断分组并编写中断服务函数
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); ? 使能定时器
TIM_Cmd(TIM5,ENABLE );
我们知道了如何设置TIM5的CH1为输入捕获模式,我们是在TIM5的中断服务函数中采集持续时间t的,TIM5CH1_CAPTURE_STA为输入捕获状态,
TIM5CH1_CAPTURE_VAL为输入捕获值,中断服务函数如下所示: if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
{ if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{ if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
{ if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{ TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else TIM5CH1_CAPTURE_STA++;}}
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
- 26 -
基于stm32的智能小车设计
{ if(TIM5CH1_CAPTURE_STA&0X40)
{ TIM5CH1_CAPTURE_STA|=0X80;
//捕获到一个下降沿
//标记成功捕获到一次上升沿
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设
置为上升沿捕获
}else
//还未开始,第一次捕获上升沿
//清空
{ TIM5CH1_CAPTURE_STA=0;
TIM5CH1_CAPTURE_VAL=0; TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);
//CC1P=1 设置为下降沿捕获}}}
3、对采集的时间t进行处理,判断前方是否有障碍
我们对采集时间t的处理也是在TIM5的中断服务函数中的,我们根据因测量距离=(高电平持续时间t*340m/s)/2,得出只要高电平持续时间t<1500us,距离就小于25cm,就会判定前方有障碍,其详细代码如下:
if(t==2){Leftstate=temp;
- 27 -
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿
{
temp=TIM5CH1_CAPTURE_STA&0X3F; temp*=65536;//溢出时间总和
temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间 TIM_Cmd(TIM2, DISABLE); if(temp<1500)
{ stopward();t++;flag++; if(t==1)
{ Midstate=temp;
TIM_SetCompare2(TIM3,60);//舵机右转}
基于stm32的智能小车设计
}
TIM_SetCompare2(TIM3,250); //舵机左转
if(t==3) {t=0;
Rightstate=temp;
TIM_SetCompare2(TIM3,150);
rotate_Left();}} {
else
if(flag==0){farward_Low();} if(flag==1) {turn_Left();} if(flag==2) {turn_Right();} if(flag>=3)
{flag=0;rotate_Left();}
TIM_SetCompare2(TIM3,150);t=0;flag=0; } TIM_Cmd(TIM2, ENABLE);
TIM5CH1_CAPTURE_STA=0;//开启下一次捕获}}
2.4循迹模块设计
这节要完成的任务是使小车沿着黑带运动。要想使小车沿着黑带运动,必须使小车感应到黑迹在什么地方,然后让小车的中央处理单元驱动硬件电路完成相应的行为动作。循迹模块的设计就是使小车能准确的识别黑带的轨迹。小车的中央处理模块从循迹模块获得数据,然后中央处理模块根据采集的数据驱动电机模块完成相应的动作。考虑到成本和操作,本实验使用的红外探测器。 2.4.1 循迹模块结构及其原理
红外探测器(IR)是由红外发射管、红外接收管和部分电路组成。要做到4路循迹,需要使用4个独立的红外探测器器件。我们使用的IR5是一个集成模块,这个集成模块由5个红外探测器组成。其中中间的1个IR探测器在本实验中并未使用。红外循迹模块实物图如图2.27所示:
- 28 -
基于stm32的智能小车设计
图2.27 红外模块正反面
本实验使用的IR5集成模块是由5个相同的IR探测器电路组成的,所以我们只需要了解一个IR探测器的工作原理即可。我们知道IR探测器是由红外发射管、红外接收管和部分电路组成。基本原理是红外发射管发射红外光经地面反射,在黑色区域红外光被吸收,在非黑色区域红外光被反射,红外接收管根据反射光的强度为比较器提供模拟量,从而输出相应的电平量。其单个IR探测器电路原理图如图2.28所示:
图2.28 IR探测器电路原理图
根据原理图详解下IR探测器的工作原理:VCC为模块提供电源,是IR探测器工作的前提条件,红外发射管DF2发射红外光到达“地面”,经反射后红外光会到达DS2红外接收管,由于不同颜色的地面会对光的吸收有着不同的效果,所以发射后的光的强度也会不同,反射强度不同,LM339的5脚会输入一个变化的电压量,LM339是一个电压较器,当LM339的“+”端输入信号大于“-”端的比较信号后,LM339的输出端截止,在外部的上拉电源的作用下,使IR探测器的输出端输出+5v的电压。同理,在“+”端电压小于“—”端电压时,LM339输出端电压饱和使IR探测器输出为低电压。因此可以通过调节R2的电阻值,改变比较电压的大小即“—”端电压的大小,从而控制探测的距离。R4是整个正反馈电路的重要组成部分,由于“+”输入端电压会经常发生在比较电压附近扰动的现象,这些微小的扰动都会造成输出端的巨大变化,因此,我们采用正反馈的方式避免这种现象的发生。加入R4电阻,就成为人们所说的“施密特触发器”,其特
- 29 -
基于stm32的智能小车设计
性图如图2.29所示:
图2.29 施密特触发器特性图
当输入端的电压发生转化时,只要在比较电压值附近的干扰不超过du之值,输出的电压就不会改变。R4正反馈的引入,不仅提高了电路的处理速度,而且可以免除由于寄生电路耦合而产生的自己震荡。但是,在提升电路的处理速度的同时,带来的缺点就是分辨率降低,因为只要在du附近输出的电压值就不会改变。
2.4.2 循迹模块电路设计
IR5探测器的集成模块的电路原理图如图2.30所示:
图2.30 红外循迹模块电路图
2.4.3 红外循迹模块程序设计
根据电路原理图,我们对循迹子程序进行设计,循迹子程序流程图如图2.31所示:
- 30 -
基于stm32的智能小车设计
开始系统初始化前进否检测是否出界是是小车右转是否左侧出界否小车右转循迹子程序结束
图2.31 循迹子程序流程图
我们在循迹程序设计中,主要工作为: 1、配置管脚与红外探测器的对应关系
当红外探测器模块在黑带上方时,输出为0。当红外探测器模块在白色上方时,输出为1。因此我们采用中断的方式进行循迹,因为采用的是4路循迹,所以我们需要4个管脚与其一一对应,对应关系如下表:
表2-3管脚与红外探测器位置对应关系表 管脚名称 PE1 PE2 PE3 PE4
红外探测器位置
左 最左 右 最右
在配置好管脚与红外位置关系之后,我们就需要进行中断初始化,中断程序上文2.1.4节中已经讲过,我们在这里就不做介绍。 2、编写中断服务函数
我们在中断初始化之后,就需要写中断服务函数啦,我们就以PE1为例,当
- 31 -
基于stm32的智能小车设计
PE1的值发生变化时,我们就进入中断服务函数,在中断服务函数中判断红外探测器是否在黑带上方,如果在,此时我们需要使小车向左转,如果不在黑带上方,小车就继续前进。其中断服务函数代码如下:
#define KEY3 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_1) void EXTI1_IRQHandler(void) {if(KEY3==0)
{Right_Low();}
EXTI_ClearITPendingBit(EXTI_Line1);} //清除LINE2上的中断标志位
- 32 -
基于stm32的智能小车设计
3.软件调试
上文提到了各个模块的电路设计及其程序设计,本章就根据各个模块的电路设计进行相应的编程。我们使用keil3软件进行程序仿真,然后使用mcuscip软件把我们得到的目标文件烧到处理器中,即程序下载。 3.1 程序仿真
RVMDK源自德国的KEIL公司,是RealView MDK的简称。支持ARM7,ARM9,和最新的Cortrx-M3核处理器,自动配置启动代码,具有强大的软件仿真功能,而且具有启动代码小,性能高的优点,软件keil3的操作主界面如图3.1所示:
图3.1 Keil主界面
在程序仿真中,我们只能观察PC7脚位的电平变化,来判断是否满足超声波的发射条件,而对于超声波发射到接受的高电平持续时间t,我们在程序仿真中是无法观测到的。因此我们只能通过对硬件进行测试,来完成对整个产品设计的考核。PC7的软件仿真结果如下图所示:
图3.2 PC7脚电平仿真图
- 33 -
基于stm32的智能小车设计
3.2程序下载
串口下载软件使用mcuisp,该软件属于第三方软件,由单片机在线编程网提供,该软件启动界面如图3.2所示:
图3.2 mcuisp启动界面
我们使用mcuisp软件进行程序下载,程序下载图如下所示:
图3.3 mcuisp程序下载图
- 34 -
基于stm32的智能小车设计
4.系统测试
在程序调试中,我们知道PC7的电平变化已经满足了超声波的发射条件,我们本节就是对硬件进行测试,验证本次方案是否成功。小车实物图如下所示
图4.1 智能小车实物图
当小车前方遇到障碍时,小车舵机左转,观测左侧是否有障碍物,测试图如下:
图4.2 智能小车检测障碍图
小车检测到前方有障碍时,舵机左转,检测小车左方是否有障碍,如果无,则小车左转,测试图如下图所示:
图4.3 智能小车避障图
循迹模块采用的是中断的方式工作的, stm32微处理器通过采集红外探测器
- 35 -
基于stm32的智能小车设计
的数据,对电机发出不同的命令,下图为智能小车在循迹过程中所拍摄的画面:
- 36 -
基于stm32的智能小车设计
5.总结
本文根据毕业设计开题报告书所布置的任务,制定了详细的设计方案,并按照此方案逐步完成了电路原理图的设计以及软件程序的设计。本文的重点是基于stm32微处理器为核心,添加其他外围电路为辅助,并且加载必要的程序设计,使小车智能化行动。整个智能小车系统以stm32微处理器为核心,外围电路包括避障电路、循迹电路、电机驱动电路等,这些外围电路通过stm32微处理器结合起来,使得各个模块在保证工作准确性的同时,提高了小车的智能化。 论文首先分析了研究智能小车的研究意义,对于此次研究的必要性进行了可行性分析。然后分析了国内外的研究概况,最后再此基础上提出了设计思路与程序流程,对于设计思路进行了可行性的分析。接着分别介绍了各个模块的硬件设计方案以及软件设计方案。在硬件设计方案中包括对各个硬件电路所采用的器件进行分析和对硬件电路的设计分析,从而决定器件的使用方案,以及硬件电路图的设计。而在软件设计方案中,我们只分析软流程件设计,以确定对应的程序编码。最后我们对软件、硬件进行测试,对于软件测试,我们使用keil软件进行程序仿真,而对于硬件测试,我们使用mcuisp硬件调试工具进行程序下载,验证了系统的稳定性和实用性。
在本方案中,由于受到所采购的硬件模块尺寸的影响,循迹模块在进行工作的时候,受到外部影响的因素很大。在本次试验设计中,由于循迹探头的安装距离小车车轮很近,当循迹探头采集数据传输到CPU时,小车已经向前行驶了一段时间。假设小车的转弯时间为T,小车的转弯时的速度为V,我们要保证小车转弯的路程不超过额定值S,那么就有公式VT<=S。要解决此问题,有两种方案可供选择。
? 减小转弯时间T
小车的转弯时间T与小车的转弯灵敏度成反比。在保证小车速度适当的情况下,我们只有减少小车的转弯时间来完成相应的行为动作,即提高小车的转弯灵敏度。小车的转弯灵敏度与小车的车轮直径有关,具体来讲就是:在车轮角速度一定的情况下,车轮直径越大,有公式V=ωR,车轮的线速度就越大,那么在单位时间内有,小车的行驶距离就会变大。所以,小车的车轮直径与转弯灵敏度成反比,车轮直径越大,灵敏度就越小,相
- 37 -
基于stm32的智能小车设计
反车轮直径越小,灵敏度就越高。在本次试验中我们采用的车轮直径稍大,从而导致小车转弯的灵敏度大大下降。因此,我们可以通过减少小车车轮的直径大小来解决此问题。 ? 增加转弯额定值S
在本次试验中,循迹探头距小车的车轮距离太近,导致小车的额定值S过小,进而导致小车在循迹工作时误差较大。解决此问题,我们可以拉大车轮与循迹探头的距离。
上文提到的两种方法,又受到所采购的器件的物理尺寸的影响。在本次试验中,器件的物理尺寸限制了小车转弯灵敏度的最大值,所以本实验的循迹模块不是很理想,但是只要我们采用上述的两种方法,一定可以提高循迹模块的执行效率。总的来说,设计方案是完善的,基本上达到了设计所要求的目标。
- 38 -
基于stm32的智能小车设计
致谢
一个学期的学习和锻炼,使我的毕业论文设计基本完成。在这期间,我在所学的基础知识之上,去接触stm32,在接触之初,我不断的遇到问题,而我也知道不经一番寒彻骨,哪的梅香扑鼻来的道理,最终我克服了种种困难,不仅使自己的知识更加牢固,而且也锻炼了自己的心性。
当然以上所有成绩的取得都离不开老师和同学的帮助。我首先要感谢的是我的母校,它为我提供了一个良好的学习环境,非常感谢学院领导对我们毕业设计相关工作精心合理的安排。当然,我的指导老师张健,我非常感谢他在我毕业设计的整个过程中始终予以的热情指导和督促,对我提出的疑惑耐心地指点,他的指点是我克服困难、完成设计的重要因素,对我一个月的实习也产生了鼓励和支持的作用。同时我还要感谢汤飞同学、柳晓峰同学的真诚指点,以及其他各位老师和同学的不吝指教,使我度过了紧张而又充实的三个月。毕业设计的这三个月,我不仅收获了知识、能力,也深刻的体会到了师情和友情的珍贵,这段时光将成为我人生中少有的美好回忆,路漫漫其修远兮,吾将上下而求索,我会以此激励自己继续努力,争取使自己的人生对社会产生些许积极的价值!
- 39 -
基于stm32的智能小车设计
参考文献
[1] 杜春雷.ARM体系结构与编程[M].北京:清华大学出版社,2003-02-01 [2] 姚文详,宋岩.ARM Cortex-M3权威指南[M].北京:北京航空航天大学出版
社,2009-07
[3] 范书瑞.Cortex-M3嵌入式处理器原理与应用[M].北京:电子工业出版社,
2011-01-01
[4]李宁.基于MDK的STM32处理器开发应用[M].北京:北京航空航天大学出版社,2008:1-260.
[5] 刘军,张洋.原子教你玩STM32[M].北京:北京航空航天大学出版社,2013-05-01
[6] 彭刚,秦志强.基于ARM Cortex-M3的STM32系列[M].北京:电子工业出版社,2011-01
[7] 张自强,晏英俊.基于stm32的步进电机转速控制实验设计[J].实验室科学,2010-12,13(6):59-61
[8] 周柱,孟文,田环宇.基于stm32智能小车设计[J].技术与市场,2011-06,18(6):1-2
[9] 李亚巨,樊东.基于stm32f103zet6的智能小车的制作[J].电子制作,2013-11,(19):52-53
[10] 赵志昊.智能小车的制作 [J].科技传播,2011-11,(21):202-203 [11] 李婕.基于STM32的智能小车的制无线视频监控智能小车设计[D].兰州:兰州理工大学出版社,2014-4:1-56
- 40 -
基于stm32的智能小车设计
附录
附录1
void TIM5_Cap_Init(u16 arr,u16 psc) {
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能TIM5时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 清除之前设置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入 GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉
//初始化定时器5 TIM5
TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
//初始化TIM5输入捕获参数
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波 TIM_ICInit(TIM5, &TIM5_ICInitStructure);
//中断分组初始化
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM5中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级2级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
- 41 -
基于stm32的智能小车设计
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
TIM_Cmd(TIM5,ENABLE ); //使能定时器5 }
附录2
void EXTIX_Init(void) {
EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
//GPIOD.2 中断线以及中断初始化配置 下降沿触发
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource1);
EXTI_InitStructure.EXTI_Line=EXTI_Line1; //左1 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);
EXTI_InitStructure.EXTI_Line=EXTI_Line2; //最左 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
//GPIOD.3 中断线以及中断初始化配置 下降沿触发 //右
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3); EXTI_InitStructure.EXTI_Line=EXTI_Line3;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始
- 42 -
基于stm32的智能小车设计
化外设EXTI寄存器
//GPIOD.4 中断线以及中断初始化配置 下降沿触发 //最右 GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4); EXTI_InitStructure.EXTI_Line=EXTI_Line4;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //使能左1所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x06; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能最左所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x04; //子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //使能右1所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x07; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //使能最右所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; //抢占优先
- 43 -
基于stm32的智能小车设计
级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x05; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
EXTI_ClearITPendingBit(EXTI_Line1); //清除LINE1上的中断标志位 EXTI_ClearITPendingBit(EXTI_Line2); //清除LINE1上的中断标志位 EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE1上的中断标志位 EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE1上的中断标志位 } 附录3
void farward_Low(void) {
GPIO_SetBits(GPIOD,GPIO_Pin_8); GPIO_ResetBits(GPIOD,GPIO_Pin_9);
GPIO_SetBits(GPIOD,GPIO_Pin_10); GPIO_ResetBits(GPIOD,GPIO_Pin_11);
TIM_SetCompare1(TIM3,1000); TIM_SetCompare3(TIM3,1000); }
void Left_Low(void)
{
GPIO_SetBits(GPIOD,GPIO_Pin_8); GPIO_ResetBits(GPIOD,GPIO_Pin_9);
GPIO_SetBits(GPIOD,GPIO_Pin_10); GPIO_ResetBits(GPIOD,GPIO_Pin_11);
TIM_SetCompare1(TIM3,1000); TIM_SetCompare3(TIM3,400); }
void Right_Low(void) {
GPIO_SetBits(GPIOD,GPIO_Pin_8); GPIO_ResetBits(GPIOD,GPIO_Pin_9);
GPIO_SetBits(GPIOD,GPIO_Pin_10); GPIO_ResetBits(GPIOD,GPIO_Pin_11);
TIM_SetCompare1(TIM3,400); TIM_SetCompare3(TIM3,1000); }
void backward(void)
{
GPIO_ResetBits(GPIOD,GPIO_Pin_8); GPIO_SetBits(GPIOD,GPIO_Pin_9);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
- 44 -
基于stm32的智能小车设计
GPIO_SetBits(GPIOD,GPIO_Pin_11);
TIM_SetCompare1(TIM3,2000); TIM_SetCompare3(TIM3,2000); }
void stopward(void)
{
GPIO_SetBits(GPIOD,GPIO_Pin_8); GPIO_SetBits(GPIOD,GPIO_Pin_9);
GPIO_SetBits(GPIOD,GPIO_Pin_10); TIM_SetCompare3(TIM3,2000); GPIO_SetBits(GPIOD,GPIO_Pin_11); TIM_SetCompare1(TIM3,2000);} 附录4
void TIM2_Int_Init(u16 arr,u16 psc) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动
重装载寄存器周期的值 计数到5000为500ms
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的
预分频值 10Khz的计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数
模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据
TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_ITConfig( //使能或者失能指定的TIM中断 TIM2, //TIM2
TIM_IT_Update | //TIM 中断源
TIM_IT_Trigger, //TIM 触发中断源 ENABLE //使能 );
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外
设NVIC寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIMx外设 }
- 45 -
基于stm32的智能小车设计
第一章 绪论,描述你为什么要做这个课题,以及本课题的国内外研究现状;
第二章 题目任拟,描述基本的理论及技术基础,比如对STM32的性能及原理描述,这部分
可以参考各种资料,但是要注意查重的问题; 第三章:硬件系统设计(如果有),描述你的作品硬件系统的各个部分;
第四章 软件设计,用流程图+语言+少量代码对你的软件各个部分进行描述,不允许将大段
代码黏贴在这里或者用一张流程图占一页的方式凑页数;
第五章 测试,用语言和图片描述你的测试方法、测试过程以及测试结果,重点是要让答辩
老师能从这里看到你的设计确实成功了。
第六章 总结,综合测试的结果,对你的设计做出结论,是否满足任务书要求,并对其存在
的问题或者需要进行的改进做出展望。 致谢
参考文献 所有列出的文献必须在正文中标注引用 附录 代码及重要图片
- 46 -