话不多说先来看视频,时长00:44


处理器电路设计


单片机是系统的CPU,是系统稳定、正常运行的重要前提,以下为单片机选型的两种方案:

(1)传统的8位单片机,是通过超大规模集成电路对其进行集成为一个独立芯片的控制器。内部组件包括CPU、随机存储器、只读存储器、I/O接口、中断系统、计时器、串口通讯、数模转换等。STC89C52单片机是最常见的51单片机,但是资源较少,精确度低,处理速度相比STM32单片机差很多。

(2)使用目前市面上最常见的STM32单片机,STM32系列单片机可分为ARMCortex-M3内核体系结构的不同应用领域。它可分为STM32F1系列和STM32F4系列,STM32F1系列单片机时钟频率最高可达72米,在同一产品中性能最好。单片机的基本处理速度为36米,16位单片机的性能也很好。微晶片的内建快闪记忆体相当大,范围从32kb到512kb,可视需要选择。单个设备的功耗非常低,仅360mA,32位单片机产品的功耗最低,每兆赫只有0.5安培。特别值得一提的是,内接单晶片汇流排是一种Harvard架构,可执行速度高达1.25 DMIPS/MHz的指令。此芯片越来越多地被用作主要控制器。

通过对单片机的资源和处理时间的速度我们采用选择STM32103C8T6为本系统主控芯片,程序下载是只需要一个JLINK就可以轻松完成。控制器模块电路如下所示:

基于stm32的循迹小车的系统框图(基于STM32超声波避障小车)(1)


电源模块设计


本设计采用锂电池供电, 模块的供电电压一般都为5V,同时超声波模块需要较大的电流才能正常工作,所以在降压的基础上也要保证足够大的输出电流。本设计采用可调输出版本,模块的输入电压范围广,输出电压在1.25V-35V内可调,电压转换效率高,输出纹波小。降压电路如下所示:

基于stm32的循迹小车的系统框图(基于STM32超声波避障小车)(2)


电机驱动模块设计


要完成转向是能够利用单片机实现的,然而单片机I0的带负载能力弱,因此我们选择了大功率放大器件TB6612FNG。TB6612FNG是采用MOSFET-H桥结构的双通道大电流电路输出,可以控制2个电机的驱动。相比普通的电机驱动,外围电路非常简单,只需要一个芯片和一个钽电容进行PWM输出滤波,系统尺寸小。PWM信号输入频率范围广,轻松满足本设计的需求。

电机驱动引脚表

1控制芯片:TB6612 2控制芯片数量:2 3 1号TB6612引脚分配: 4 VM PWMA--------->TIM1_CH1(PA8) 5 VCC AIN2--------->GPIOB_12 6 GND AIN1--------->GPIOB_13 7 AO1 STBY--------->GPIOB_14 8 AO2 BIN1--------->GPIOB_15 9 BO2 BIN2--------->GPIOA_12 10 BO1 PWMB--------->TIM1_CH2(PA9) 11 GND GND 12 2号TB6612引脚分配: 13 VM PWMA--------->TIM1_CH3(PA10) 14 VCC AIN2--------->GPIOB_5 15 GND AIN1--------->GPIOB_6 16 AO1 STBY--------->GPIOB_7 17 AO2 BIN1--------->GPIOB_8 18 BO2 BIN2--------->GPIOA_9 19 BO1 PWMB--------->TIM1_CH4(PA11) 20 GND GND 21真值表 22 AIN1 0 1 0 1 23 AIN2 0 0 1 1 24 BIN1 0 1 0 1 25 BIN2 0 0 1 1 26 停止 正转 反转 刹车

电机所用到的定时器配置

1//初始化TIMX,设置TIMx的ARR,PSC 2//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期 3//定时器选择TIM1 4static void TB6612_ADVANCE_TIM1_Mode_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty) 5{ 6 //-----------------时基结构体初始化-------------------------/ 7 TIM_TimeBaseInitTypeDef TIM_TimeStructure; 8 /*开启定时器1时钟,即内部时钟CK_INT=72M*/ 9 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); 10 TIM_DeInit(TIMx); 11 /*内部时钟作为计数器时钟,72MHZ*/ 12 TIM_InternalClockConfig(TIMx); 13 /*自动重装载寄存器的值,累计TIM_Period 1个频率后产生一个更新或者中断*/ 14 TIM_TimeStructure.TIM_Period=arr; 15 /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(71 1)=1MHZ*/ 16 TIM_TimeStructure.TIM_Prescaler=psc-1; 17 /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/ 18 TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1; 19 /*向上计数模式*/ 20 TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up; 21 /*重复计数器*/ 22 TIM_TimeStructure.TIM_RepetitionCounter=0; 23 /*初始化定时器*/ 24 TIM_TimeBaseInit(TIMx,&TIM_TimeStructure); 25 /*使能ARR预装载寄存器(影子寄存器)*/ 26 TIM_ARRPreloadConfig(TIMx,ENABLE); 27 //-----------------输出比较结构体初始化-----------------------/ 28 TIM_OCInitTypeDef TIM_OCInitStructure; 29 /*PWM模式设置,设置为PWM模式1*/ 30 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; 31 /*PWM输出使能相应的IO口输出信号*/ 32 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; 33 /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/ 34 TIM_OCInitStructure.TIM_Pulse=duty; 35 /*输出通道电平极性设置*/ 36 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; 37 /*初始化输出比较参数*/ 38 TIM_OC1Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道1 39 TIM_OC2Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道2 40 TIM_OC3Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道3 41 TIM_OC4Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道4 42 /*自动重装载*/ 43 TIM_OC1PreloadConfig(TIMx,TIM_OCPreload_Enable); 44 TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable); 45 TIM_OC3PreloadConfig(TIMx,TIM_OCPreload_Enable); 46 TIM_OC4PreloadConfig(TIMx,TIM_OCPreload_Enable); 47 /*使能计数器*/ 48 TIM_Cmd(TIMx,ENABLE); 49 /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/ 50 TIM_CtrlPWMOutputs(TIMx,ENABLE); 51} 52//高级定时器输出通道初始化函数 53static void TB6612_ADVANCE_TIM_Gpio_Config() 54{ 55 GPIO_InitTypeDef GPIO_InitStruct; 56 /*----------通道1配置--------------*/ 57 /*定时器1输出比较通道*/ 58 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 59 /*配置为复用推挽输出*/ 60 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; 61 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8; 62 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; 63 GPIO_Init(GPIOA,&GPIO_InitStruct); 64 /*-----------通道二配置-------------*/ 65 /*定时器1输出比较通道*/ 66 /*配置为复用推挽输出*/ 67 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; 68 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11; 69 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; 70 GPIO_Init(GPIOA,&GPIO_InitStruct); 71 /*-----------通道三配置-------------*/ 72 /*定时器1输出比较通道*/ 73 /*配置为复用推挽输出*/ 74 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; 75 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9; 76 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; 77 GPIO_Init(GPIOA,&GPIO_InitStruct); 78 /*-----------通道四配置-------------*/ 79 /*定时器1输出比较通道*/ 80 /*配置为复用推挽输出*/ 81 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; 82 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10; 83 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; 84 GPIO_Init(GPIOA,&GPIO_InitStruct); 85}


超声波模块


采用HC-SR04超声波模块,该芯片具有较高的集成度以及良好的稳定性,测度距离十分精确,十分稳定。供电电压为DC5V供电电流小于10mA,探测距离为0.010m-3.5m一共有四个引脚VCC(DC5V)、Triger(发射端)、Echo(接收端)、GND(地)。HC-SR04实物图如下:

基于stm32的循迹小车的系统框图(基于STM32超声波避障小车)(3)

3年嵌入式物联网学习资源整理分享:C语言、Linux开发、数据结构;软件开发,STM32单片机、ARM硬件开发、物联网通信开发、综合项目开发教程资料;笔试面试真题。点击下方插件免费领取↓↓↓嵌入式物联网学习资料(头条)

基于stm32的循迹小车的系统框图(基于STM32超声波避障小车)(4)

该模块是利用单片机的IO触发电平测距,单片机内部利用普通定时器产生一个高电平信号之后,超声波就可以自主发送频率为40khz的方波,然后等待信号的返回;若有信号返回,单片机IO口就立刻输出一高电平,利用高电平产生的时间可以计算小车与障碍物的距离。最终距离就是高电平持续时间乘以声音在空气中传播的速度再除以2,可以反复测量距离。

在程序开始首先初始化超声波,利用定时器并设置时基的自动重装载初值1000,psc为预分频值72,这样的话我们产生一次中断的时间是1ms,并设置抢占优先级0,子优先级3。HC_SR04_Echo引脚接收到高电平,打开定时器,且每1ms进入一次中断。在测量时首先让Trig发送一个大于10us的高电平,然后拉高HC_SR04_Trig,当Echo为0时打开定时器计时,当Echo为1时关闭定时器,通过公式计算距离。

模块工作原理:(1)单片机触发引脚,输出高电平信号;(2)模块发送端自动发送特定频率的方波;(3)如果有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波的发射时长;(4)测试距离=(高电平时间*声速(340M/S))/2。

注意:在硬件操作上需要首先让模块地端先连接,否则会影响模块工作。测距时,被测物体的摆放不能太过于杂乱,否则会影响测试结果。

基于stm32的循迹小车的系统框图(基于STM32超声波避障小车)(5)

超声波重要代码(可参考)

1/* 获取接收到的高电平的时间(us*/ 2uint32_t Get_HC_SR04_Time(void) 3{ 4 uint32_t t=0; 5 t=Acoustic_Distance_Count*1000;//us 6 t =TIM_GetCounter(TIM2);//获取us 7 TIM2->CNT =0; 8 Acoustic_Distance_Count=0; 9 Systic_Delay_us(100); 10 return t; 11} 12/*获取距离*/ 13void Get_HC_SR04_Distance(void) 14{ 15 static uint16_t count=0; 16 switch(count) 17 { 18 case 1: 19 { 20 GPIO_SetBits(Acoustic_Port,HC_SR04_Trig);//Trig发送一个大于10us的高电平 21 }break; 22 23 case 15: 24 { 25 count=0; 26 GPIO_ResetBits(Acoustic_Port,HC_SR04_Trig); 27 while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==0);//当Echo为0时打开定时器 计时 28 Open_Tim2(); 29 while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==1);//当Echo为0时打开定时器 计时 30 Close_Tim2(); 31 HC_SR04_Distance=(float)(Get_HC_SR04_Time()/5.78); 32 33 }break; 34 default:break; 35 } 36 count ; 37}


舵机模块


本系统使用的是SG90型号的舵机,舵机是一种常见的角度驱动器,本系统需要判断不同位置的障碍物可以且对转向的力度小。舵机可以理解为方向盘称,方向盘是一个常见的名字。它实际上是一个伺服马达。舵机实物图如下:

基于stm32的循迹小车的系统框图(基于STM32超声波避障小车)(6)

舵机模块接口简单,舵机模块只有三个引脚。分别引引出了三根线左右两边是电源正负接口线,中间一根是PWM信号线直接连接单片机的控制引脚。通过控制单片机的引脚输出的脉冲宽度进而控制舵机旋转的角度。舵机每增加0.1ms 舵机对应增加9度。

0.5ms---------0

1.0ms---------45

1.5ms---------90

2.0ms---------135

2.5ms-----------180

20ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平持续时间为1.5ms,周期为20ms的方波,duty=1.5/20=7.5%。在这里设置定时器自动重装载寄存器arr的值为1000,所以当占空比为百分之75是,在程序中就要设置占空比为75/1000=7.5%, 这就是具体的算法。

舵机重要代码(可参考)

1/**PWM引脚初始化*/ 2static void SERVO_Gpio_Init(void) 3{ 4 GPIO_InitTypeDef GPIO_InitStruct; 5 /*----------通道2配置--------------*/ 6 /*定时器3输出比较通道*/ 7 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 8 /*配置为复用推挽输出*/ 9 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; 10 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7; 11 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; 12 GPIO_Init(GPIOA,&GPIO_InitStruct); 13} 14//定时器3初始化,设置TIMx的ARR,PSC 15//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期 16static void SERVO_TIM_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty) 17{ 18 //-----------------时基结构体初始化-------------------------/ 19 TIM_TimeBaseInitTypeDef TIM_TimeStructure; 20 /*开启定时器3时钟,即内部时钟CK_INT=72M*/ 21 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); 22 TIM_DeInit(TIMx); 23 /*内部时钟作为计数器时钟,72MHZ*/ 24 TIM_InternalClockConfig(TIMx); 25 /*自动重装载寄存器的值,累计TIM_Period 1个频率后产生一个更新或者中断*/ 26 TIM_TimeStructure.TIM_Period=arr;//1000 当定时器从0计数到999,即1000次,为一个定时周期 27 /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(1440-1 1)=0.05MHZ*/ 28 TIM_TimeStructure.TIM_Prescaler=psc-1;;//1400 //即定时器的频率为5KHZ 29 /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/ 30 TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1; 31 /*向上计数模式*/ 32 TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up; 33 /*重复计数器*/ 34 TIM_TimeStructure.TIM_RepetitionCounter=0; 35 /*初始化定时器*/ 36 TIM_TimeBaseInit(TIMx,&TIM_TimeStructure); 37 /*使能ARR预装载寄存器(影子寄存器)*/ 38 TIM_ARRPreloadConfig(TIMx,ENABLE); 39 //-----------------输出比较结构体初始化 开始-----------------------/ 40 TIM_OCInitTypeDef TIM_OCInitStructure; 41 /*PWM模式设置,设置为PWM模式1*/ 42 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; 43 /*PWM输出使能相应的IO口输出信号*/ 44 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; 45 /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/ 46 TIM_OCInitStructure.TIM_Pulse=duty; //占空比大小 47 /*输出通道电平极性设置*/ 48 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; 49 /*初始化输出比较参数*/ 50 TIM_OC2Init(TIMx,&TIM_OCInitStructure); 51 //-----------------输出比较结构体初始化 结束-----------------------/ 52 /*自动重装载*/ 53 TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable); 54 /*使能计数器*/ 55 TIM_Cmd(TIMx,ENABLE); 56 /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/ 57 TIM_CtrlPWMOutputs(TIMx,ENABLE); 58} 59/*舵机PWM初始化 60 每增加0.1ms 舵机对应增加9度 610.5ms---------0 621.0ms---------45 631.5ms---------90 642.0ms---------135 652.5ms-----------180 662.1ms turn_left=150 670.8ms turn_right=25 681.3ms turn_front=75 6920ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平为1.5ms,周期为20ms的方波,duty=1.5/20=7.5% ,而定时器自动重装载寄存器arr的值为 1000 ,所以duty=75,时占空比为75/1000=7.5%. 70*/ 71void SERVO_Init(void) 72{ 73 SERVO_Gpio_Init(); 74 SERVO_TIM_Config(TIM3,1000,1440,turn_front); 75/** 我们把定时器设置自动重装载寄存器 arr 的值为 1000,设置时钟预分频器为 1440,则 76驱动计数器的时钟:CK_CNT = CK_INT / (1440-1 1)=0.05M,则计数器计数一次的时间等于: 771/CK_CNT=20us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间 78为:1/CK_CNT*ARR=20ms。 79PWM 信号的频率 f = TIM_CLK/{(ARR 1)*(PSC 1)} TIM_CLK=72MHZ 80 = 72 000 000/(1000*1440)=5KHZ 81*/ 82} 83/*舵机角度控制*/ 84void SERVO_Angle_Control(uint16_t Compare2) 85{ 86 TIM_SetCompare2(TIM3,Compare2); 87}


编码器模块


调节小车前进的速度和避障快慢我们采用EC11旋转式编码器,可以用于光度、湿度、音量调节等参数的调节。EC11编码器的形状类似于电位器,中心有一个旋钮可以调节PWM信号,光电码盘利用光电转换原理输出三组方波脉冲。EC11编码器的实物图如下:

基于stm32的循迹小车的系统框图(基于STM32超声波避障小车)(7)


OLED显示模块


用来显示小车转速,以及左右编码器数值和电池电压等参数所用的是OLED显示模块,分辨率较高,而且功耗低,正常显示时仅0.06W,供电电压范围在3.3V-5V,有IIC和SPI两种通信协议可供选择。显示模块的亮度和对比度可以通过程序设置。由于它使用寿命长以及其他的优点,OLED更加适合小系统,本系统由于单片机引脚有限,不适合利用简单的LCD1602或者12864来显示,在多方对比之下OLED效果更好。OLED显示部分相对比较简单,大家参考中景园的例程就可以实现。

原文作者:果果小师弟

原文标题:【项目分享】基于STM32超声波避障小车

原文链接:https://mp.weixin.qq.com/s/Z_Dlx_OnNw2s0lTIFUm5_A

,