基于STM32F103C8T6的循迹避障小车完整制作过程(详细) 您所在的位置:网站首页 智能循迹小车原理图解 基于STM32F103C8T6的循迹避障小车完整制作过程(详细)

基于STM32F103C8T6的循迹避障小车完整制作过程(详细)

2023-09-26 18:30| 来源: 网络整理| 查看: 265

接上篇

链接:基于STM32F103C8T6的循迹避障小车完整制作过程(详细)----上篇(第123点)

其实上篇就是一些基础的东西,本篇讲一下如何让小车循迹 四,如何通过pwm调整电机的转速(调节小车的快慢) 1,为何pwm能调速度?

我的理解是,对于直流电机来讲,一上高平电机就会转动,如果改变了高电平占有的比例,就是让电机在单位时间内接到的高电平时间减少,它的速度就会减小。 注意这里的pwm是由单片机输出到电机驱动的IN1-IN4端的,所以我们要进行软件设置,以输出想要的高电平,这里主要就是软件方面的事啦。

2,如何连接stm32和电机驱动?

stm32没有单独的pwm模块,它是利用定时器来输出pwm的,每个定时器有4个通道,我们需要找到定时器这4个通道所接的引脚,再将这4个引脚接到电机驱动的输入端上就好了。先简单回顾一下stm32定时器的相关知识。首先我查看了stm3210x系列的技术手册 在这里插入图片描述 可以看到的是,我们手上的这块STM32F103C8T6有3个通用定时器(我的工程中把这三个定时器都用完了),再往下,每个定时器有4个通道,我们需要找到这4个通道分别对应的引脚。比如我给电机所使用的定时器为TIM3,查看数据手册对引脚的定义后发现如下: 在这里插入图片描述 所以定时器3的通道1-4分别对应的是PA6,PA7,PB0,PB1,我将这4个引脚分别接到电机驱动的IN1-IN4,如此一来,关于电机调速的硬件电路我们已经搭好了。

3,如何设置定时器输出4路可调pwm?

这是最关键的地方了,先贴一下我的电机设置的代码吧,下面是moter.c程序

#include "moter.h" void CarGo(void) { TIM_SetCompare1(TIM3 , 400); //数值越大速度越慢 TIM_SetCompare2(TIM3 , 900); TIM_SetCompare3(TIM3 , 400); TIM_SetCompare4(TIM3 , 900); } void CarStop(void) { TIM_SetCompare1(TIM3 , 900); TIM_SetCompare2(TIM3 , 900); TIM_SetCompare3(TIM3 , 900); TIM_SetCompare4(TIM3 , 900); } void CarBack(void) { TIM_SetCompare1(TIM3 , 900); TIM_SetCompare2(TIM3 , 300); TIM_SetCompare3(TIM3 , 900); TIM_SetCompare4(TIM3 , 300); } void CarLeft(void) { TIM_SetCompare1(TIM3 , 900); TIM_SetCompare2(TIM3 , 300); TIM_SetCompare3(TIM3 , 300); TIM_SetCompare4(TIM3 , 900); } void CarBigLeft(void) { TIM_SetCompare1(TIM3 , 900); TIM_SetCompare2(TIM3 , 100); TIM_SetCompare3(TIM3 , 100); TIM_SetCompare4(TIM3 , 900); } void CarRight(void) { TIM_SetCompare1(TIM3 , 300); TIM_SetCompare2(TIM3 , 900); TIM_SetCompare3(TIM3 , 900); TIM_SetCompare4(TIM3 , 300); } void CarBigRight(void) { TIM_SetCompare1(TIM3 , 100); TIM_SetCompare2(TIM3 , 900); TIM_SetCompare3(TIM3 , 900); TIM_SetCompare4(TIM3 , 100); } void TIM3_PWM_Init(void) //TIM3的pwm设置和相应的引脚设置 { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); TIM_TimeBaseStructure.TIM_Period = 899; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseInit(TIM3 , &TIM_TimeBaseStructure); //端口复用 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //初始化要用的A6/A7口 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; //初始化要用的B0/B1口 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); //PWM通道1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_Pulse = 900; TIM_OC1Init(TIM3 , &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3 , TIM_OCPreload_Enable); //PWM通道2 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_Pulse = 900; TIM_OC2Init(TIM3 , &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM3 , TIM_OCPreload_Enable); //PWM通道3 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_Pulse = 900; TIM_OC3Init(TIM3 , &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM3 , TIM_OCPreload_Enable); //PWM通道4 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_Pulse = 900; TIM_OC4Init(TIM3 , &TIM_OCInitStructure); TIM_OC4PreloadConfig(TIM3 , TIM_OCPreload_Enable); TIM_Cmd(TIM3 , ENABLE); }

下面是moter.h文件内容

#ifndef __MOTER_H #define __MOTER_H #include "stm32f10x.h" void TIM3_PWM_Init(void); void CarGo(void); void CarStop(void); void CarBack(void); void CarLeft(void); void CarBigLeft(void); //大右转 void CarRight(void); void CarBigRight(void); //大左转 #endif

这些代码也很好用,在main函数前调用TIM3_PWM_Init()这一个函数就可以完成引脚和定时器的初始化了,在后面直接用前进后退转弯这些函数就可以了。

下面介绍一下这个函数的一些关键参数:

TIM_TimeBaseStructure.TIM_Period = 899; TIM_TimeBaseStructure.TIM_Prescaler = 0; 根据定时器的周期计算公式:周期=(arr+1)*(psc+1)/CLK=900/72000000, 所以就是设置定时器基准频率为80KHZ

再看每个pwm口的设置基本是一样的,主要参数是这几个:

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_Pulse = 900;//脉宽设置

1,TIM_OCMode_PWM2的意思是什么? 当计时器值小于比较器设定值时则TIMX输出脚此时输出有效低电位。 当计时器值大于或等于比较器设定值时则TIMX输出脚此时输出高电位。 2,TIM_OCPolarity_High表示起始波形为高电位 3,TIM_Pulse = 900表示总的脉宽值为900 由于计数器的值为899+1,则此时的占空比是1,我们通过下面这个SetCompare函数再来设置比较值从而设置占空比。 4,最后我们用TIM_SetCompare1(TIM3 , 400)这个函数来设置比较值 比如说,我们这里设置比较值为400,总脉宽为900,初始电位为高电平,且设置的是PWM2模式,那么在0-400里为低电平,在400-900里为高电平。也就是说,设置的比较值越大,高电平占有的时间越短。 比如我的前进函数:

void CarGo(void) { TIM_SetCompare1(TIM3 , 400); //数值越大速度越慢 TIM_SetCompare2(TIM3 , 900); TIM_SetCompare3(TIM3 , 400); TIM_SetCompare4(TIM3 , 900); }

这样的设置就相当于是将CH1和CH3通道的pwm高电平设置在400-900这个时间里,将CH2和CH4这两个通道拉低,这样一来,改变通道1和通道3的比较值就可以改变电机的转速了。 好了 电机调速我们已经设置完成了。

五,如何设置IO口读取循迹模块的信号(检测黑线)

这个比较简单,就是读取io口的高低电平。 我们先看一下TCRT5000循迹模块怎么用, 在这里插入图片描述 它有4个IO接口,我们只需要用3个即可,就是VCC,GND,D0其中D0就是用来返回信号的,它有两个状态,就是高电平和低电平。 就我用的模块来讲,正常情况下,D0返回低电平,当模块检测到黑线的时候,返回高电平,以此,我们就可以进行相关的程序编写了。 下面是我的xunji.c文件内容:

#include "xunji.h" void xunji_config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); // 使能PC端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; //选择对应的引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PC端口 } void Read_xunji_Date(void) { xunji_1; xunji_2; xunji_3; xunji_4; }

下面是xunji.h文件内容:

#ifndef __XUNJI_H #define __XUNJI_H #include "stm32f10x.h" #define xunji_1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4) #define xunji_2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5) #define xunji_3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6) #define xunji_4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7) void xunji_config(void); void Read_xunji_Date(void); //读循迹模块返回的值 #endif

可以看到,我所用的是引脚B4,B5,B6,B7,这4个引脚分别接到4个循迹模块的D0口上,这里将它们初始化,再调用GPIO_ReadInputDataBit读取引脚电平即可。

用法:在主函数中先调用xunji_config()进行引脚初始化,在循环的最前面调用Read_xunji_Date(void)函数读取4个循迹模块的电平值后就可以进行相关的循迹程序编写了。

六,完成循迹小车的制作(编写循迹主函数)

前面已经完成了调速和循迹模块函数的编写,这里可以直接编写主函数了:

int main(void) { float length_res[5]; //用来存放测距结果 SystemInit(); // 配置系统时钟为72M delay_init(); //延时初始化 xunji_config(); //循迹初始化 TIM3_PWM_Init(); //电机pwm TIM3 SG90_pwm_init(); //舵机pwm TIM2 CH_SR04_Init(); //超声波定时器 TIM4 OLED_Init(); //oled显示初始化 while(1) { Read_xunji_Date(); //读循迹线值 //车前4个循迹模块从左到右分别是xunji_1,xunji_2,xunji_3,xunji_4 if(xunji_1==0&&xunji_2==0&&xunji_3==0&&xunji_4==0)//0000 { CarGo(); //如果都没有读取到黑线,直走 delay_ms(10); } if(xunji_1==0&&xunji_2==1&&xunji_3==1&&xunji_4==0)//0110 { CarGo(); //如果中间两个读取到黑线,直走 delay_ms(10); } if(xunji_1==0&&xunji_2==1&&xunji_3==0&&xunji_4==0)//0100 { CarBigLeft(); //如果第二个读取到黑线,左转 delay_ms(10); } if(xunji_1==0&&xunji_2==0&&xunji_3==1&&xunji_4==0)//0010 { CarBigRight(); //如果第三个读取到黑线,右转 delay_ms(10); } if(xunji_1==1&&xunji_2==0&&xunji_3==0&&xunji_4==0)//1000 { CarBigLeft(); //如果第一个读取到黑线,左转 delay_ms(10); } if(xunji_1==0&&xunji_2==0&&xunji_3==0&&xunji_4==1)//0001 { CarBigRight(); //如果第四个读取到黑线,左转 delay_ms(10); } } }

主函数前面是一些初始化的配置,while(1)里就是循迹的循环了,代码里我已经写了很多注释了,这里就不再多解释了,就是一堆if函数,也很容易看懂。 本篇就到此为止了。

下面是我写的已经测试完成了的工程,主函数里有两个循环,分别是循迹和避障循环,他们是单独工作的,引用掉一个再打开另一个就行。 https://download.csdn.net/download/weixin_43924857/11650617 当然循迹和避障的策略都是我自己为了完成任务写的,比较简单,能够实现循迹避障功能,到后面你已经会操作各个模块后,自己写个更好的循迹避障策略是完全没有问题的,或者是用我的工程,里面的各模块函数也都写好了,直接调用就行。

整个完整过程会分为上中下三篇,还剩一篇(下篇)过两天慢慢码完再发。

下面是下篇的地址:

基于STM32F103C8T6的循迹避障小车完整制作过程(详细)----下篇(第789点)

工程文件已经放到百度网盘: 链接:https://pan.baidu.com/s/1VSRC418Tz8uLCF8cjrIY1g 提取码:7m9y



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有