赞
踩
前言:我巡线小车代码是分割赛道的思想写的(从标志位上得知已经跑到那里了)
以下是材料选择与代码展示
1:光敏板(协会自己做的),原理是和红外检测差不多,是当其中一个光敏LED灯碰到白线会给GPIO的引脚输出低电平,此处低电平用0表示,高电平用1表示。相信有一定单片机知识的小伙伴会get到我的点。这里传感器可以用红外传感器,这个需要对应场地找对应效果最好的传感器,这里选择如果不好,可以在学校问一问做这方面比赛的学长,这里不做过多解释。
2:L298N的直流电机驱动
这里注意需要12V供电,自身在供电可以产生5V电压,用于某一类单片机或一些模块供电。左右分别有OUT1,OUT2,OUT3,OUT4,四路输出,其对应着四路输入,这里这个模块简单来说就是将单片机产生的对应引脚的PWM做放大处理输出在电机上,要不靠单片机GPIO产生的电压怎么驱动小车前进呢。这里是IN1=1,IN2=0,左轮正传,如果颠倒IN1与IN2的值,就会电机反转,如果IN1与IN2都为0或者都为1,电机会瞬间停止。IN3与IN4亦然。这里我们玩过51的固有的思维是用时钟中断来调节PWM(也就是速度),但是STM32却可以硬件产生精准的PWM,但只针对对应自己设定的引脚,这里用STM32就要换一种思维了,要知道PWM=0,其实就是给这个输入引脚置0了,如果PWM为最大值其实就是对应输入引脚置1了。要转变一下思维。
3.小车的车身和所选用的轮子
对于车身,由于我比较喜欢合金的觉得更结实,这个就看个人想法了。但是重要的一点是最好买双层的车身,因为可以把驱动等放在最底上一层,把STM32放在最上层,这样显得条理清晰,还可以使小车更稳定。轮子建议选择麦克纳姆轮,这样可以保证小车跑起来不会那么容易失控。这里可以去网上搜巡线小车套件。此处要注意,我是l298n一路控制一边的两个马达,还要注意马达接线,不要误以为是同向的两根线接在一起,不要忘了,轮子安装可是反方向安装的呦,这里很容易出错。
4.电池
电池的话采用18650电池,最好买三节或四节11V到12V左右的电池组,这里我当时就犯了错误,我买的就是单个电池最后充电还要一节一节冲,十分麻烦,而且有很多时候不仅充电效率低而且有很多时候单个充电会充不上,所以这边建议买可充电的电池组。然后别忘了买搭配使用的充电器
5.以下是自己的代码段
其中使用STM32的定时器3产生PWM的
PA.6和PA.7分别对应l298n的IN1和IN2
PB.0与PB.1分别对应l298n的IN3和IN4
子函数 .h文件
- #ifndef __Timer3_H__
- #define __Timer3_H__
-
- #include <stm32f10x.h>
-
- void TIM3_PWM_Init(u16 arr,u16 psc);
- void Led_Init(void);
- void up(void);
- void left(void);
- void right(void);
- void surrounding(void);
-
- #endif
子函数.c文件
- #include "stm32f10x.h" // Device header
- #include "Delay.h"
-
- #define L1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_3)
- #define L2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)
- #define L3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)
- #define L4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)
- #define L5 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)
- #define L6 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)
- #define L7 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)
- #define L8 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)
-
-
- extern int arr1,arr2,arr3,arr4;
- extern int flag;
- extern int flag1;
- extern int counter;
- extern int flag2;
- extern int i;
-
- void left(void);
-
-
- void TIM3_PWM_Init(u16 arr,u16 psc)
- {
-
-
- GPIO_InitTypeDef GPIO_InitStructure;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
-
-
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO
-
- //设置引脚为复用输出功能,输出TIM3 CH的PWM脉冲波形 GPIOA.6 GPIOA.7 GPIOB.0 GPIOB.1
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //通道3 TIM_CH3 通道4 TIM_CH4
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //通道1 TIM_CH1 通道2 TIM_CH2
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA
-
- //初始化TIM3定时器,我的4个pwm是用的定时器3的四个pwm通道
- 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 Channel 1 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_OC1Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC1
- TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR1上的预装载寄存器
-
- //初始化TIM3 Channel 2 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上的预装载寄存器
-
- //初始化TIM3 Channel 3 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_OC3Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC3
- TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR3上的预装载寄存器
-
- //初始化TIM3 Channel 4 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_OC4Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC4
- TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR4上的预装载寄存器
-
- TIM_Cmd(TIM3, ENABLE); //使能TIM3
-
-
- }
-
-
-
- void Led_Init()
- {
-
- GPIO_InitTypeDef GPIO_InitStruct1;
-
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
-
-
-
- GPIO_InitStruct1.GPIO_Mode= GPIO_Mode_IPD;
- GPIO_InitStruct1.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;
- GPIO_InitStruct1.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOB,&GPIO_InitStruct1);
-
-
-
- }
-
-
- void up()
- {
-
- while(1)
- {
-
-
- if(L3==1&&L4==0&&L5==0&&L6==1)//4,5中间两灯遇见白线
- {
- arr1=800;
- arr2=0;
- arr3=810;
- arr4=0;
- flag2=0;
-
- }
-
-
- else if((flag1==4&&L3==0&&L4==0&&L5==0&&L6==0)&&flag2==0)//遇见一条横白线,且标志位flag2为0
-
- {
-
-
- counter++;//经过的横白线次数累计
- flag2=1;//立即将标志位flag2变为1,防止下回在此进入此判断条件下由于stm32运算速度较快而造成多次counter累加
-
-
- if(counter==3)//经过第三次横白线
- {
-
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,800);
- TIM_SetCompare3(TIM3,0);;
- TIM_SetCompare4(TIM3,800); //运用反冲速度减速1.89秒
-
-
- Delay(1890);
-
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,899);
- TIM_SetCompare3(TIM3,899);;
- TIM_SetCompare4(TIM3,0); //辅助左转,此处可将左轮PWM变小,此处由于我硬件问题左轮反转有问题,所以改高PWM
-
- Delay(2000);//左转2秒
-
- flag1=5;//改变标志位的值,使主函数完成调用左转子函数操作
- break;
-
-
- }
-
-
- }
-
-
-
-
- else if(((L1==0&&L2==0&&L3==0&&L7==1)||(L1==0&&L3==0&&L7==0))&&flag==1)//遇见需要左转的情况,改为左转标志位
- {
-
- flag1=1;
- break;
-
-
- }
-
-
- else if((L8==0&&L7==0&&L2==1)&&flag1==2)//遇见需要右转的情况,改为右转标志位
- {
-
-
- flag1=3;
-
- break;
-
-
-
-
- }
-
- else if(L3==1&&L4==0&&L5==1&&L6==1)//4灯遇白线
- {
- arr1=770;
- arr2=0;
- arr3=800;
- arr4=0;
-
- flag2=0;
-
- }
-
- else if(L3==1&&L4==1&&L5==0&&L6==1)//5灯遇白线
- {
-
- arr1=800;
- arr2=0;
- arr3=780;
- arr4=0;
- flag2=0;
-
-
- }
-
-
-
- else if(L3==0&&L4==0&&L5==1&&L6==1)//3,4灯遇白线
- {
-
- arr1=760;
- arr2=0;
- arr3=800;
- arr4=0;
-
-
-
-
-
- }
-
- else if(L3==1&&L4==1&&L5==0&&L6==0)//5,6灯遇白线
- {
-
- arr1=800;
- arr2=0;
- arr3=770;
- arr4=0;
-
- flag2=0;
-
-
-
- }
-
-
- else if(L3==0&&L4==1&&L5==1&&L6==1)//3灯遇白线
- {
-
- arr1=750;
- arr2=0;
- arr3=800;
- arr4=0;
-
- flag2=0;
-
-
-
- }
-
-
-
-
- else if(L3==1&&L4==1&&L5==1&&L6==0)//6灯遇白线
- {
-
- arr1=800;
- arr2=0;
- arr3=760;
- arr4=0;
-
-
-
-
-
- }
-
-
- else if(L2==0&&L5==1)//2灯遇白线,加5灯为了增加判断准确性
- {
-
- arr1=740;
- arr2=0;
- arr3=800;
- arr4=0;
- flag2=0;
-
-
- }
-
-
- else if(L7==0&&L3==1)//7灯遇白线,加3灯为了增加判断准确性
- {
-
- arr1=800;
- arr2=0;
- arr3=750;
- arr4=0;
- flag2=0;
-
- }
-
-
-
-
- TIM_SetCompare1(TIM3,arr1);
- TIM_SetCompare2(TIM3,arr2);
- TIM_SetCompare3(TIM3,arr3);
- TIM_SetCompare4(TIM3,arr4); //赋pwm值的,以下同理
-
-
-
-
-
-
- }
-
-
- }
-
-
-
-
-
- void left()
- {
-
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,0);
- TIM_SetCompare4(TIM3,0);
-
- Delay(1500);
-
-
-
-
-
-
- while(1)
- {
-
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,750);
- TIM_SetCompare3(TIM3,490); //左转
- TIM_SetCompare4(TIM3,0);
-
-
-
- if(flag1==1)
- {
- if(L2==0||L3==0||(L4==0&&L5==1)||(L4==0&&L5==0)||(L4==1&&L5==0))//左转停止的判断
- {
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,0);
- TIM_SetCompare4(TIM3,0);
- Delay(500);
- flag1=2;
- break;
-
- }
- }
-
-
-
-
- else if(flag1==5)//为了增加执行准确性
- {
-
- if(L5==0||(L5==0&&L6==1))//s弯左转准备开始标志
- {
- flag1=6;
- break;
-
- }
-
-
-
-
- }
-
-
-
- }
-
- }
-
-
-
-
- void right()//右转
- {
-
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,0);
- TIM_SetCompare4(TIM3,0);
-
-
-
- Delay(1500);
-
-
-
-
- while(1)
- {
-
- TIM_SetCompare1(TIM3,520);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,0);
- TIM_SetCompare4(TIM3,500);
- if(flag1==3)
- {
-
- if(L6==0||L5==0||(L4==0&&L5==1)||L4==0)//右转结束标志
- {
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,0);
- TIM_SetCompare4(TIM3,0);
-
- Delay(500);
- flag1=4;
- break;
-
- }
-
-
-
-
- }
- }
-
-
-
-
- }
-
-
-
- void surrounding()//转S弯的函数
- {
-
- while(1)
- {
-
- if(L3==1&&L4==0&&L5==0&&L6==1)
- {
-
- arr1=720;
- arr2=0;
- arr3=750;
- arr4=0;
-
-
-
- }
-
-
-
- else if(L2==0&&L3==0&&L4==0&&L5==0)//最后遇见横白线,意味着跑到终点,直行7秒左右停止
- {
-
-
-
- while(1)
- {
- if(i==0)
- {
-
- TIM_SetCompare1(TIM3,500);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,500);;
- TIM_SetCompare4(TIM3,0);
- Delay(7000);
- i=1;
-
- }
-
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,0);;
- TIM_SetCompare4(TIM3,0);
-
-
-
-
-
- }
-
- }
-
- else if(L4==0)
- {
- arr1=510;
- arr2=0;
- arr3=780;
- arr4=0;
-
-
-
- }
-
-
- else if(L5==0)
- {
- arr1=899;
- arr2=0;
- arr3=0;
- arr4=450;
-
-
-
- }
-
-
- else if(L3==0)
- {
-
- arr1=440;
- arr2=0;
- arr3=780;
- arr4=0;
-
-
-
- }
-
-
- else if(L6==0)
- {
-
- arr1=800;
- arr2=0;
- arr3=0;
- arr4=430;
-
-
-
- }
-
-
- else if(L2==0)
- {
-
- arr1=430;
- arr2=0;
- arr3=780;
- arr4=0;
-
-
-
-
- }
-
- else if(L7==0)
- {
- arr1=840;
- arr2=0;
- arr3=380;
- arr4=0;
-
-
-
-
- }
-
- else if(L1==0)
- {
-
- arr1=420;
- arr2=0;
- arr3=780;
- arr4=0;
-
-
-
- }
-
-
- else if(L8==0)
- {
-
- arr1=840;
- arr2=0;
- arr3=380;
- arr4=0;
-
-
-
- }
-
-
-
- TIM_SetCompare1(TIM3,arr1);
- TIM_SetCompare2(TIM3,arr2);
- TIM_SetCompare3(TIM3,arr3);
- TIM_SetCompare4(TIM3,arr4);
-
-
-
- }
-
-
-
-
-
-
-
- }
-
-
-
-
-
主函数
- #include "stm32f10x.h" // Device header
- #include "Timer3.h"
- #include "Delay.h"
-
- #define L1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_3)
- #define L2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)
- #define L3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)
- #define L4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)
- #define L5 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)
- #define L6 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)
- #define L7 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)
- #define L8 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)
-
-
-
- int arr1,arr2,arr3,arr4;//对左右两轮输出占空比,我是左两轮共接一路输出
- int counter;//记横白线数量
- int flag;
- int flag1;//记转弯等的标志位
- int flag2;//十字路口标志位,将要过S弯之前的横白线与直线当作十字路口
- int i;//最后停止时用的变量
-
-
-
- int main()
- {
-
- TIM3_PWM_Init(899,0);
- Led_Init();
-
- if(L1==0&&L2==0&&L3==0&&L4==0&&L5==0&&L6==0&&L7==0&&L8==0)//开始小车在起跑线准备开跑
- {
-
-
- TIM_SetCompare1(TIM3,899);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,899);
- TIM_SetCompare4(TIM3,0);
-
- Delay(2500);
-
- flag=1;
- }
-
- while(1)
- {
-
-
-
-
- if(flag==1)//开始直行遇左转停止
- {
- up();
- flag=0;//标志位为0,下次不进此if判断
-
- }
-
-
- else if(flag1==1)//遇见第一个需要左转的标志位
- {
-
-
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,0);
- TIM_SetCompare4(TIM3,0);//由于速度过快此处相当于减速
- Delay(600);
-
- left();//调用左转子函数
-
-
-
- }
-
- else if(flag1==2)//遇见直走标志位
- {
-
- up();//调用直走子函数
-
-
- }
-
-
- else if(flag1==3)//遇见右转标志位
- {
-
- TIM_SetCompare1(TIM3,0);
- TIM_SetCompare2(TIM3,0);
- TIM_SetCompare3(TIM3,0);
- TIM_SetCompare4(TIM3,0);//此处各轮停止转动相当于减速
-
- Delay(800);
- right();//调用右转子函数
-
-
-
- }
-
- else if(flag1==4)//遇到第二个直行标志位
- {
-
-
-
- up();//调用直行子函数
-
-
- }
-
- else if(flag1==5)//遇到预备过S弯的标志位
- {
-
-
- left();//调用特定左转子函数
-
-
-
-
- }
-
-
- else if(flag1==6)//遇到开始过S弯的标志位
- {
-
-
-
-
-
-
- surrounding(); //调用过S弯的子函数
-
- }
-
-
-
- }
-
-
-
-
- }
延迟函数.h文件
- #ifndef __DELAY_H__
- #define __DELAY_H__
-
- void Delay(unsigned int xms);
-
- #endif
延迟函数.c文件
- void Delay(unsigned int xms)
- {
- unsigned char i, j;
- while(xms--)
- {
- i = 2;
- j = 239;
- do
- {
- while (--j);
- } while (--i);
- }
- }
-
如果代码有问题欢迎各位大佬批评指正,后续也会分享一些其他学习的东西,如果大家觉得对你有帮助欢迎关注我呦~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。