基于STC8G2K64S4单片机控制小车循迹 #前言
本文从硬件和软件两方面介绍了使用STC8G2K64S4单片机控制舵机的方法,并使用步进电机和直流电机来举例说明
之前说讲了如何用STC8G2K64S4单片机控制步进电机和直流电机,这次就是说用这两种电机来控制小车结合循迹模块来实现循迹,这也是一个在学习51单片机过程中的一个很基础的例程
硬件方面步进电机和直流电机可参考我写的两外两篇文章,基于STC8G2K64S4单片机控制步进电机和 基于STC8G2K64S4单片机控制直流电机,这里就不多介绍了
要完成小车循迹任务,必不可少的就是光敏传感器,这里我用的是单数字量灰度传感,所以当传感器检测到黑色时输出“1”,检测到白色是输出“0”
黑色 i=1; 白色 i=0;
当检测红黄蓝这些颜色时需要调整电位器来控制输出,电位器的准确度也是很重要的,避免后期出现漏判误判。光敏传感器的高度也有一定的影响,只要在他的高度范围内就可以。高度范围一般在某宝买的时候下面商品详情都有
软件方面这里两种电机控制方法也可以参考基于STC8G2K64S4单片机控制步进电机和 基于STC8G2K64S4单片机控制直流电机这两篇文章
我是用了双路的循迹,也就是两个光敏传感器。对我来说这样足以循迹也相对稳定,如果觉得不稳定的话也可以用四路。双路循迹原理是当两个光敏同时检测到黑色是,小车前进;当左边检测到白色时,意思小车向左偏,则需左边轮子加速或者右边轮子减速即可;当右边检测到白色时,意思小车向右偏,则需右边轮子加速或者左边轮子减速即可
if G1==1&&G2==1 GO if G1==0&&G2==1 turn right if G1==1&&G2==0 turn left
在设计程序时由于地纸是方格所以我就写的按格数行进,给多少变量走几格。记格是通过行进方向两边的光敏传感器实现,当两边传感器检测到黑线时格数加一
#步进电机正常行驶代码:
#include "headfile.h"
//sbit P36 //定义P36为左后电机使能端
//sbit P06 //定义P06为右前电机使能端
//sbit P07 //定义P07为右前电机pwm输出端
//sbit P37 //定义P37为左后电机pwm输出端
//sbit P33 //定义P33为左侧光光敏
//sbit P32 //定义P32为右侧光光敏
void init_all()
{
pwm_init(PWM0_P07, 0, 0);
pwm_init(PWM1_P37, 0, 0);
}
void go()
{
P36=1;
P06=0; //两个电机方向使能
while(1)
{
if(P33==1&&P32==1)
{
pwm_freq(PWM0_P07, 5000, 5000); //右前电机正常速度
pwm_freq(PWM3_P37, 5000, 5000); //左后电机正常速度
}
if(P33==1&&P32==0)
{
pwm_freq(PWM0_P07, 5000, 5000); //右前电机正常速度
pwm_freq(PWM3_P37, 4000, 5000); //左后电机减速
}
if(P33==0&&P32==1)
{
pwm_freq(PWM0_P07, 4000, 5000); //右前电机减速
pwm_freq(PWM3_P37, 5000, 5000); //左后电机正常速度
}
}
}
void main()
{
DisableGlobalIRQ(); //关闭总中断
board_init(); //初始化内部寄存器,勿删除此句代码。
init_all();
EnableGlobalIRQ(); //开启总中断
while(1)
{
go();
}
}
记格数行驶代码:
#include "headfile.h"
unsigned int i,j;
//sbit P36 //定义P36为左后电机使能端
//sbit P06 //定义P06为右前电机使能端
//sbit P07 //定义P07为右前电机pwm输出端
//sbit P37 //定义P37为左后电机pwm输出端
//sbit P20 //定义P20为检测黑线记格数用光敏
//sbit P33 //定义P33为左侧光光敏
//sbit P32 //定义P32为右侧光光敏
void init_all()
{
pwm_init(PWM0_P07, 0, 0);
pwm_init(PWM3_P37, 0, 0);
}
void go_forward(i) //定义变量i为格数
{
j=0;
P36=1;
P06=0; //两个电机方向使能
while(1)
{
if(P20==1&&j!=i) //两边光敏检测黑线并计数
{
j++;
pwm_freq(PWM0_P07, 4000, 5000); //右前电机低速
pwm_freq(PWM3_P37, 4000, 5000); //左后电机低速
pca_delay_ms(500); //延时度过黑线
}
if(P33==1&&P32==1)
{
pwm_freq(PWM0_P07, 5000, 5000); //右前电机正常速度
pwm_freq(PWM3_P37, 5000, 5000); //左后电机正常速度
}
if(P33==1&&P32==0)
{
pwm_freq(PWM0_P07, 5000, 5000); //右前电机正常速度
pwm_freq(PWM3_P37, 4000, 5000); //左后电机减速
}
if(P33==0&&P32==1)
{
pwm_freq(PWM0_P07, 4000, 5000); //右前电机减速
pwm_freq(PWM3_P37, 5000, 5000); //左后电机正常速度
}
if(P20==1&&i==j) break; //当检测到黑线并格数记完退出循环
}
pwm_freq(PWM0_P07, 0, 0); //右前电机停止
pwm_freq(PWM3_P37, 0, 0); //左后电机停止
}
void main()
{
DisableGlobalIRQ(); //关闭总中断
board_init(); //初始化内部寄存器,勿删除此句代码。
init_all();
EnableGlobalIRQ(); //开启总中断
while(1)
{
go_forward(2); //向前前进两格
}
}
#直流电机
正常行驶代码:
#include "headfile.h"
//sbit P15,P16 //定义P15 P16为右前电机方向使能端
//sbit P35,P36 //定义P35 P36为左后电机方向使能端
//sbit P07 //定义P07为右前电机pwm输出端
//sbit P37 //定义P37为左后电机pwm输出端
//sbit P33 //定义P33为左侧光光敏
//sbit P32 //定义P32为右侧光光敏
void init_all()
{
pwm_init(PWM0_P07, 0, 0);
pwm_init(PWM3_P37, 0, 0);
}
void go()
{
P15=1;
P16=0; //右前电机方向使能
P35=1;
P36=0; //左后电机方向使能
while(1)
{
if(P33==1&&P32==1)
{
pwm_duty(PWM0_P07, 5000, 5000); //右前电机正常速度
pwm_duty(PWM3_P37, 5000, 5000); //左后电机正常速度
}
if(P33==1&&P32==0)
{
pwm_duty(PWM0_P07, 5000, 5000); //右前电机正常速度
pwm_duty(PWM3_P37, 4000, 5000); //左后电机减速
}
if(P33==0&&P32==1)
{
pwm_duty(PWM0_P07, 4000, 5000); //右前电机减速
pwm_duty(PWM3_P37, 5000, 5000); //左后电机正常速度
}
}
}
void main()
{
DisableGlobalIRQ(); //关闭总中断
board_init(); //初始化内部寄存器,勿删除此句代码。
init_all();
EnableGlobalIRQ(); //开启总中断
while(1)
{
go();
}
}
记格数行驶代码:
#include "headfile.h"
unsigned int i,j;
//sbit P15,P16 //定义P15 P16为右前电机方向使能端
//sbit P35,P36 //定义P35 P36为左后电机方向使能端
//sbit P07 //定义P07为右前电机pwm输出端
//sbit P37 //定义P37为左后电机pwm输出端
//sbit P20 //定义P20为检测黑线记格数用光敏
//sbit P33 //定义P33为左侧光光敏
//sbit P32 //定义P32为右侧光光敏
void init_all()
{
pwm_init(PWM0_P07, 0, 0);
pwm_init(PWM3_P37, 0, 0);
}
void go_forward(i) //定义变量i为格数
{
j=0;
P15=1;
P16=0; //右前电机方向使能
P35=1;
P36=0; //左后电机方向使能
while(1)
{
if(P20==1&&j!=i) //两边光敏检测黑线并计数
{
j++;
pwm_duty(PWM1_P07, 4000); //右前电机低速
pwm_duty(PWM3_P37, 4000); //左后电机低度
pca_delay_ms(500); //延时度过黑线
}
if(P33==1&&P32==1)
{
pwm_duty(PWM0_P07, 5000, 5000); //右前电机正常速度
pwm_duty(PWM3_P37, 5000, 5000); //左后电机正常速度
}
if(P33==1&&P32==0)
{
pwm_duty(PWM0_P07, 5000, 5000); //右前电机正常速度
pwm_duty(PWM3_P37, 4000, 5000); //左后电机减速
}
if(P33==0&&P32==1)
{
pwm_duty(PWM0_P07, 4000, 5000); //右前电机减速
pwm_duty(PWM3_P37, 5000, 5000); //左后电机正常速度
}
if(P20==1&&i==j) break; //当检测到黑线并格数记完退出循环
}
pwm_duty(PWM1_P07, 0); //右前电机停止
pwm_duty(PWM3_P37, 0); //左后电机停止
}
void main()
{
DisableGlobalIRQ(); //关闭总中断
board_init(); //初始化内部寄存器,勿删除此句代码。
init_all();
EnableGlobalIRQ(); //开启总中断
while(1)
{
go_forward(2); //向前前进两格
}
}
在检测黑线时延迟是为了同一根黑线不检测两次,给一段延时在度过黑线后再继续检测黑线。代码中的库函数为逐飞库函数
本人小白,有问题交流讨论,虚心受教



