【精选】基于stm32的智能小车设计(一)

您所在的位置:网站首页 ai智能小车设计方案怎么做 【精选】基于stm32的智能小车设计(一)

【精选】基于stm32的智能小车设计(一)

2023-11-10 02:11| 来源: 网络整理| 查看: 265

目录

一、原理简述

二、系统硬件设计

1.电机驱动选型

1.1  L298N

1.2  L9110

1.3  DRV8833

1.4 TB6612

2.系统整体硬件设计

3.stm32主控制模块

4.舵机云台

5.超声波模块

三、系统软件设计

1.系统整体软件设计

2.电机驱动及速度的控制

3.舵机云台的控制

4.超声波测距

四、实物展示

五、完整原理图

六、完整代码

        单片机智能小车一直是大家很喜欢的小设计,智能小车的制作虽然难度不高,但是对于初学者来说,由于陌生,因此也总是觉得门槛高。事实上,很多东西都禁不起深挖,当你做完之后才会发现,原来也不过如此。

        我计划在接下来的一段时间里,断断续续地给大家带来智能小车的相关设计,由易到难。涉及蓝牙控、WIFI控、NRF24L01控制,红外遥控控制,红外、超声波避障、寻迹等。每一篇都是一个完整的设计,有着完整的软硬件分析过程,希望可以给你帮助。

        本节将制作一个超声波避障的小车。

一、原理简述

        作为智能小车,最基本的一点肯定是解决电机驱动的问题。

        现在市场上有许多适合小车电机驱动的模块,常见的有L298N、L9110S、DRV8833、TB6612等。这些芯片/模块各有优劣,但是控制原理和方法基本相似。这些芯片/模块的详细介绍可以参照第二章系统硬件设计,将详细地介绍上述几个芯片/模块的重要参数以及使用方法。

        电机驱动解决后,接下来就是超声波模块。超声波配合舵机,可以轻松实现避障,使得小车看上去更加智能。

        本设计主将以stm32为核心,配合电机驱动、舵机和超声波模块,实现小车的自动避障功能。

二、系统硬件设计 1.电机驱动选型 1.1  L298N

工作电压:2.5~46V,

单通道最大输出电流:2A,

逻辑电源(Vss):4.5~7V,

低电平输入范围:-0.3~1.5V,

高电平输入范围:2.3~Vss,

可驱动两路电机。

应用电路图:

                

         上述应用电路为参考电路,VS和VSS都可以使用5V(不建议使用3.3V),IN输入以及PWM可以使用5V或者3.3V单片机,注意PCB板布线适当加粗,且供电电池保持充足电量。

1.2  L9110

工作电压:2.5V~12V,

连续电流输出能力:DIP8  1.0A(8V)

                                SOP8  0.8A(8V),

输入高电平:2.5V~10V

输入低电平:=4.5V

           MAX 0.4A   2.5CNT = 0; //将TIM2计数寄存器的计数值清零 overcount = 0; //中断溢出次数清零 delay_ms(1); return distance; //距离作为函数返回值 } void bubble(unsigned long *a, int n) { int i, j, temp; for (i = 0; i < n - 1; i++) { for (j = i + 1; j < n; j++) { if (a[i] > a[j]) { temp = a[i]; a[i] = a[j]; a[j] = temp; } } } } float get_average_distance(void) { float Distance; unsigned long ultrasonic[5] = {0}; int a,num = 0; int lastDistance; while (num < 5) { Distance = get_ultrasonic_distance(); while(((int)Distance >= 500 || (int)Distance == 0)) { Distance = get_ultrasonic_distance(); } if(Distance >0 || (int)Distance PB5 //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO //初始化TIM3 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 //初始化TIM3 Channel2 PWM模式 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高 TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器 TIM_Cmd(TIM3, ENABLE); //使能TIM3 }

pwm.h

#ifndef __PWM_H #define __PWM_H #include "sys.h" #define TIM3_PWM_SG90_PERIOD (1200-1) #define TIM3_PWM_SG90_PRESCALER (1200-1) /* 频率50HZ 20ms */ #define SG90_PWM_FREQ 72000000/((TIM3_PWM_SG90_PERIOD)*(TIM3_PWM_SG90_PRESCALER)) #define SG90_CENTRE ((int)(1.5/20*TIM3_PWM_SG90_PERIOD)) #define SG90_RIGHT ((int)(0.5/20*TIM3_PWM_SG90_PERIOD)) #define SG90_LEFT ((int)(2.5/20*TIM3_PWM_SG90_PERIOD)) void TIM3_Int_Init(u16 arr,u16 psc); void TIM3_PWM_SG90_Init(u16 arr,u16 psc); #endif

car.c

#include "car.h" void TIM1_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //时钟使能 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE ); //使能指定的TIM1中断,允许更新中断 NVIC_InitStructure.NVIC_IRQChannel = TIM3_UP_IRQn; //TIM3中断 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(TIM1, ENABLE); //使能TIMx外设 } //定时器1中断服务程序 void TIM1_UP_IRQHandler(void) //TIM1中断 { if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 { TIM_ClearITPendingBit(TIM1, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源 PWMA = !PWMA; PWMB = !PWMB; } } void TB6612_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化 GPIO_ResetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_9); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化 GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); } void go_straight(void) { AIN1 = 1; AIN2 = 0; BIN1 = 1; BIN2 = 0; } void go_back(void) { AIN1 = 0; AIN2 = 1; BIN1 = 0; BIN2 = 1; } void ture_right(void) { AIN1 = 1; AIN2 = 0; BIN1 = 0; BIN2 = 1; } void ture_left(void) { AIN1 = 0; AIN2 = 1; BIN1 = 1; BIN2 = 0; } void stop(void) { AIN1 = 0; AIN2 = 0; BIN1 = 0; BIN2 = 0; }

car.h

#ifndef __CAR_H__ #define __CAR_H__ #include "sys.h" #include "delay.h" #define PWMA PBout(6) #define PWMB PBout(9) #define AIN1 PBout(14) #define AIN2 PBout(13) #define BIN1 PBout(15) #define BIN2 PBout(12) void TIM3_Int_Init(u16 arr,u16 psc); void TB6612_GPIO_Init(void); void go_straight(void); void ture_left(void); void go_back(void); void ture_right(void); void stop(void); #endif

ultrasonic.c

#include "ultrasonic.h" /*记录定时器溢出次数*/ unsigned int overcount = 0; void ultrasonic_gpio_init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(TRIG_RCC, ENABLE); RCC_APB2PeriphClockCmd(ECHO_RCC, ENABLE); GPIO_InitStructure.GPIO_Pin = TRIG_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(TRIG_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = ECHO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(ECHO_PORT, &GPIO_InitStructure); } void TIM2_Ultrasonic_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructer; NVIC_InitTypeDef NVIC_InitStructer; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /*定时器TIM2初始化*/ TIM_DeInit(TIM2); TIM_TimeBaseInitStructer.TIM_Period = 999;//定时周期为1000 TIM_TimeBaseInitStructer.TIM_Prescaler = 71; //分频系数72 TIM_TimeBaseInitStructer.TIM_ClockDivision = TIM_CKD_DIV1;//不分频 TIM_TimeBaseInitStructer.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructer); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//开启更新中断 /*定时器中断初始化*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructer.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructer.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructer.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructer.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructer); TIM_Cmd(TIM2, DISABLE);//关闭定时器使能 } void TIM2_IRQHandler(void) //中断,当回响信号很长是,计数值溢出后重复计数,用中断来保存溢出次数 { if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除中断标志 overcount++; } } float get_ultrasonic_distance(void) { float distance = 0; u16 tim; GPIO_SetBits(TRIG_PORT, TRIG_PIN); //拉高信号,作为触发信号 delay_us(20); //高电平信号超过10us GPIO_ResetBits(TRIG_PORT, TRIG_PIN); /*等待回响信号*/ while(GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == RESET); TIM_Cmd(TIM2,ENABLE);//回响信号到来,开启定时器计数 while(GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == SET);//回响信号消失 TIM_Cmd(TIM2, DISABLE);//关闭定时器 tim = TIM_GetCounter(TIM2);//获取计TIM2数寄存器中的计数值,一边计算回响信号时间 distance = (tim + overcount * 1000) / 58.0;//通过回响信号计算距离 TIM2->CNT = 0; //将TIM2计数寄存器的计数值清零 overcount = 0; //中断溢出次数清零 delay_ms(1); return distance; //距离作为函数返回值 } void bubble(unsigned long *a, int n) { int i, j, temp; for (i = 0; i < n - 1; i++) { for (j = i + 1; j < n; j++) { if (a[i] > a[j]) { temp = a[i]; a[i] = a[j]; a[j] = temp; } } } } float get_average_distance(void) { float Distance; unsigned long ultrasonic[5] = {0}; int a,num = 0; int lastDistance; while (num < 5) { Distance = get_ultrasonic_distance(); while(((int)Distance >= 500 || (int)Distance == 0)) { Distance = get_ultrasonic_distance(); } if(Distance >0 || (int)Distance


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3