完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
基于stm32的红外巡线小车(基础版)
前两天做了一个红外巡线小车,想记录一下整个过程,也让自己掌握的更牢固,同时也分享给大家看看。在此要特别感谢实验室的学长,帮我解决一些问题到晚上一点多,同时帮我优化了控制的逻辑。这个小车比较基础,主要是分享给新手,同时我自己学的也不是很深入,如果文章有错的地方,还请多指正。那么话不多说,我们来看制作过程。
1.stmf103c8t6最小系统板 2.l298n电机驱动模块 将控制电机的4个io口接到L298N的逻辑输入接口,输出A和输出B分别连接两个电机。12V供电接电源正极,5V供电接单片机5V供电,gnd接电源负极和单片机gnd。 3.两个红外传感器 红外传感器有三个接口,一个vcc一个gnd,另一个是返回数据。 4.锂电池(7.4V~12V) 5.小车底盘(两个电机) 相关的io口接线在函数中都有配置,在这就不写了 二、软件篇 制作红外巡线小车主要需要红外传感器的函数和电机pwm驱动的函数,另外还需要添加正点原子的delay文件和sys文件。 1红外传感器 首先我们要明白红外传感器的原理,当红外灯检测到黑线时返回给io口的值是0,检测到黑线外(亮光位置)时,返回的值是1。知道了这些,我们就只需要读取io口的值,就可以判断小车的巡线情况。 我在头文件中定义了#define DO1 PAin(1) #define DO2 PAin(2) 这两句代码就是读取PA1,PA2两个io口的值,这种定义是基于sys库函数的,比较方便。 red.c #include "red.h" u8 redray1_findblack; u8 redray2_findblack; void REDRAY_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } void REDRAY_Scan(void) { if(DO1==0)redray1_findblack=1; else redray1_findblack=0; if(DO2==0)redray2_findblack=1; else redray2_findblack=0; } 2.电机驱动(pwm) 首先配置电机的io口,然后配置这些io口的pwm。pwm的配置这里就不降讲了,可以看一下网上的stm32的基础教程,这里讲一下怎么计算pwm的占空比和频率: 首先我们看motor.c中的TIM_SetCompare1(TIM4,pwm1);其中pwm1是捕获比较寄存器值,TIM4_PWM_Init(u16 arr,u16 psc)函数中arr是自动重装载寄存器周期的值,psc是时钟频率除数的预分频值。 知道了这些我们就可以计算占空比和频率, 占空比:pwm1/arr100% 频率:72M / ((arr+1)(psc+1))(单位:Hz)这里主频是72MHz motor.c #include "motor.h" #include "stm32f10x.h" void MOTOR_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9; //两个输出端 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); } void TIM4_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //GPIO_PinRemapConfig(GPIO_Remap_TIM4, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO //初始化TIM4 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(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 //初始化TIM4 Channel1 PWM模式 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 TIM_OCInitStructure.TIM_Pulse = 0; TIM_OC1Init(TIM4, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM4 OC1 TIM_OCInitStructure.TIM_Pulse = 0; TIM_OC2Init(TIM4, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM4 OC2 TIM_OCInitStructure.TIM_Pulse = 0; TIM_OC3Init(TIM4, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM4 OC3 TIM_OCInitStructure.TIM_Pulse = 0; TIM_OC4Init(TIM4, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM4 OC4 TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable); //使能TIM4在CCR1上的预装载寄存器 TIM_Cmd(TIM4, ENABLE); //使能TIM4 } void motor_control(u16 pwm1,u16 pwm2,u16 pwm3,u16 pwm4) { TIM_SetCompare1(TIM4,pwm1); TIM_SetCompare2(TIM4,pwm2); TIM_SetCompare3(TIM4,pwm3); TIM_SetCompare4(TIM4,pwm4); } 3.主函数 main.c 小车行进时大致有4种情况,两个红外灯都检测到光亮(直走或者超出黑线范围),左光亮右黑线(前方右转),右光亮左黑线(前方左转),都是黑线(这种情况一般不会出现)。通过if else就可以将小车的基本逻辑表示出来,但是注意上面提到两个红外灯都检测到光亮还可能是超出黑线范围,也就是要拐弯时拐不过来,小车冲过了,所以我们还要考虑这种情况。 我们可以设置一个记录上一次拐弯情况的功能,当超出了黑线范围,但是记录了上一刻的转弯情况,让小车继续转弯,这样就可以回到黑线上。 #include "sys.h" #include #include "red.h" #include "motor.h" #include "stm32f10x.h" #include "delay.h" extern u8 redray1_findblack; extern u8 redray2_findblack; int main(void) { u8 stat = 0; REDRAY_Init();//利用红外对管来检测黑线 delay_init(72); //延时函数初始化 TIM4_PWM_Init(1000-1,720-1); while(1) { REDRAY_Scan(); if(redray1_findblack ==1&&redray2_findblack==0) { stat = 0; motor_control(0,0,0,1000); } else if(redray1_findblack ==0&&redray2_findblack==1) { stat = 1; motor_control(1000,0,0,0); } else if(redray1_findblack ==1&&redray2_findblack==1) { if(stat == 0) { motor_control(0,0,0,1000); } else { motor_control(1000,0,0,0); } } else { motor_control(1000,0,0,1000); } } } 另外还有delay函数和sys函数,在网上一搜就能收到,我就不写了。 以上是比较基础的控制逻辑,如果想要更好的控制,可以考虑一下下面这个图 如果能实现小车的每一个状态之间的变换逻辑,那么这个小车就很强大了。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1617 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1543 浏览 1 评论
977 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
683 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1595 浏览 2 评论
1863浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
645浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
516浏览 3评论
532浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
505浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 09:43 , Processed in 0.889074 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号