Bootstrap

51单片机--小车的情绪表达

在本次任务中,通过小车红外循迹模块的反馈,完成小车四种情绪任务的反馈

(四个情绪的具体实现视频在资源处)

硬件设备:

轮趣科技阿克曼小车(前轮由舵机控制 后轮由两个电机控制) 51单片机 l298n电驱模块

杜邦线 红外模块

软件:采用keil5作为IDE 使用普中科技进行烧录

阿克曼小车相关淘宝链接:【淘宝】https://m.tb.cn/h.gWoFBmqRHmh52o5?tk=lsuzWEfMeUD ZH4920

一:前期准备

由于四个任务都是统一的端口和引脚,只有主函数不同,所以我们前期的定义、函数、初始化和调用都相同,在前面统一给出

在本段代码的设计中,进行了电机的PWM占空比调速,由于51单片机没有32单片机的hal库和cubemx定义引脚 这些都需要我们在代码中去手动定义

在代码中我们定义了引脚和定时器

引脚定义
#include <reg52.h>
#include <intrins.h>
sbit PWM = P3^7;  //设定PWM输出的I/O端口
unsigned char count = 0;
unsigned char timer1 ;
unsigned int Counter_L,Compare_L,Counter_R,Compare_R;
unsigned int i=0;
int t;
sbit HWSM_L=P2^3;  //红外线探测模块//前
sbit HWSM_R=P2^5;    //红外线探测模块//后
//sbit Moter_R=P3^0;  //电机使能
//sbit Moter_L=P3^1;
sbit PWM_L=P3^0;
sbit PWM_R=P3^1;
sbit IN1=P1^1;   //右电机正反转
sbit IN2=P1^0;
sbit IN3=P1^5;   //左电机正反转
sbit IN4=P1^4;
定时器和中断定义
void Timer1_Routine() interrupt 3
{

    t++;
    if(t == 100)
    {t=0;}
    TL1 = 0xA4;        
    TH1 = 0xFF;        
    Counter_L++;
    Counter_R++;
    Counter_L %= 100;
    Counter_R %= 100;
    if(Counter_L<Compare_L)    
    {
        PWM_L=1;
    }
    else
    {
        PWM_L=0;
    }
        
    if(Counter_R<Compare_R)    
    {
        PWM_R=1;
    }
    else
    {
        PWM_R=0;
    }
}
延时函数
void delay1s(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=50;c>0;c--)
        for(b=50;b>0;b--)
            for(a=16;a>0;a--);
    _nop_();  //if Keil,require use intrins.h
}
void delay(unsigned int xms) // xms代表需要延时的毫秒
{
    unsigned int x, y;
    for(x = xms; x > 0; x--)
        {
        for(y = 110; y > 0; y--);
                {
                    
                }
    }
}
在主函数进行之前,我们还需要对定时器和中断进行初始化:
void Timer0_Init()           
{
    TMOD &= 0x00;
    TMOD |= 0x01; //定时器T0设置成方式1
 
    TH0 = 0xff;   //定时常数 0.1ms 晶振为11.0592MHz
    TL0 = 0xa4;
 
    ET0 = 1;      
    TR0 = 1; 
    EA=1; 
    }
    
/*T0中断初始化*/
void Time0_Init() interrupt 1 
{
    TR0 = 0; 
    TH0 = 0xff; // 0.1ms
    TL0 = 0xa4;
    
    if(count <= timer1) //5==0° 15==90°
    { 
        PWM = 1; 
    }
    else 
    { 
        PWM = 0; 
    }
    count++;
    if (count >= 200) //T = 20ms清零
    { 
        count = 0; 
    }
    TR0 = 1; //开启T0
    Counter_L++;  
    Counter_R++;  
 
    
    Counter_L %= 100;   
    Counter_R %= 100;  
    
    
    if(Counter_L < Compare_L)      
    {  
        PWM_L = 1;  
    }  
    else                  
    {  
        PWM_L = 0;  
    }  
  
    if(Counter_R < Compare_R)      
    {  
        PWM_R = 1;  
    }  
    else                  
    {  
        PWM_R = 0;  
    }  
}

这样我们初始化的定义就完成了 

下面我们需要定义一些我们在小车行驶过程中要用到的函数,以便我们调用pwm占空比

void back(int compare_left,int compare_right)//设置占空比
{
    Compare_L=compare_left;
    Compare_R=compare_right;
    IN1 = 1; 
  IN2 = 0;
  IN3 = 1; 
  IN4 = 0;
}
void go(int compare_left,int compare_right)//设置占空比
{
    Compare_L=compare_left;
    Compare_R=compare_right;
    IN1 = 0; 
  IN2 = 1;
  IN3 = 0; 
  IN4 = 1;
}

 这样前期准备工作就做完了,我们可以去实现四个情绪的任务

二:强迫

强迫的实现过程主要为两边的红外模块识别到墙壁后后退,达到在两个墙壁之前往复运动的效果

实现代码如下:

void main()
{ 
    unsigned int def;
    unsigned int f;
    Timer0_Init();
//    Compare_L=10;Compare_R=90;  
  
    while(1)
    {
        
            if(HWSM_L==0)
        {
            f=0;
        }
        if(HWSM_R==0)
        {
                f=1;
        }
        if(f==0)
        {
            back(50,50);
        }
        if(f==1)
        {
            go(25,25);
        }            

        }
}

在本函数中,先调用函数实现了定时器的初始化,在while循环中通过红外模块的返回值进行了小车的pwm调速

三:警惕 

警惕的实现过程主要为小车识别到黑线或墙壁车停下

实现代码如下

void main()
{ unsigned int def;
    unsigned int f;
    Timer0_Init();
//    Compare_L=10;Compare_R=90;  
  
    while(1)
    {
            if(HWSM_L==0)
        { 
                    go(0,0);
        } 
            else
                { 
          go(50,50);
        }                     警惕
    
        }
}

在这段函数里同样先调用函数实现定时器的初始化 ,通过一个红外模块的返回值判断小车的运动状态是否应该停止

四:犹豫

犹豫的实现过程为小车识别到黑线向后退再向前进识别黑线循环往复的过程

实现代码如下

void main()
{ unsigned int def;
    unsigned int f;
    Timer0_Init();
//    Compare_L=10;Compare_R=90;  
  
    while(1)
    {

        if(HWSM_L==0)
        {
            go(15,15);                                    ///犹豫
        } else    
        { 
            back(15,15);
        } 
        
        }
}

定时器初始化完毕后,执行后退,检测不到黑线前进的循环过程

五:偏执

偏执的实现过程为,小车识别到黑线后向后退一段距离,通过舵机和电机差速的方式掉头离开

在51单片机的控制舵机过程中,需要定时器产生计数器来控制小车舵机的转动

void main()
{ unsigned int def;
    Timer0_Init();
//    Compare_L=10;Compare_R=90;  
  
    while(1)
    {
        
            if(HWSM_L==0||HWSM_R==0)
        {
            back(15,15);
            delay(15);
            timer1 =9;
        //    delay1s();
            go(0,50);
            //IN1=1;IN2=0;IN3=1;IN4=0;
        //    for(def=0;def<=10;def++){
            delay(15);//}
    //        IN1=1;IN2=0;IN3=1;IN4=0;//前
        //    delay1s();
        }
        else 
        {
            
            timer1 =9;
        //    delay1s();
        //IN1=0;IN2=1;IN3=0;IN4=1;
            go(15,15);
        }
        //delay1s();
        
    //    timer1 =5;//舵机恢复到0°的位置
        /*count=0;//让定时器重新计数
        delay1s();
        timer1 =15;//舵机旋转90°
        count=0;
        delay1s();*/
    }
}

通过timer的设定值改变舵机转动的不同角度

六:注意

在51单片机的控制之中,保持电池满电或者给51单片机进行单独供电,如果电压不稳定,51会重启void main主函数,电机和舵机都会被重置

(简单来说能用32用32)51真的是太不稳定了。。。。

 

;