• 51单片机 小车 L298N pwm调速 串口控制 按键控制


    难点:1、串口定时器T1,和T0定时器优先级

                2、pwm频率与占空比的设置

    按键控制

    按键1——前进

    按键2——后退

    按键3——加速

    按键4——减速

    (板子上只有四个按键)

    串口控制

    ‘1’——前进

    ‘2’——后退

    ‘3’——加速

    ‘4’——减速

    ‘5’——左转

    ‘6’——右转

    源码:

    #include <reg52.h>

    typedef unsigned char u8;
    typedef unsigned int u16;

    //L298N引脚定义
    sbit ena = P0^0;
    sbit in1 = P0^1;
    sbit in2 = P0^2;
    sbit in3 = P0^3;
    sbit in4 = P0^4;
    sbit enb = P0^5;

    //按键
    sbit key1 = P3^3;    //模拟前进
    sbit key2 = P3^4;         //模拟后退
    sbit key3 = P3^6;         //模拟加速
    sbit key4 = P3^7;   //模拟减速
     
    u16 MA = 0,MB = 0;      //pwm控制用

    u16 SpeedA = 20; //50%占空比
    u16 SpeedB = 20;

    u8 flag;                 //标志,1代表前进,0代表后退
    u8 cmd;         //串口接收的命令sbuf


    void delay(u16 z);        //声明延时函数

    //前进
    void forward()
    {
    flag = 1;                 //代表前进状态
    in1=1;                    //l298n手册
    in2=0;  
    in3=1;  
    in4=0;
    }


    //后退
    void fallback()
    {
    flag = 0;                //代表后退状态
    in1=0;  
    in2=1;  
    in3=0;  
    in4=1;
    }


    //加速
    void quick()
    {
    SpeedA += 1;  //每次加1
    if(SpeedA >= 40)        //最大40
    {
    SpeedA = 40;
    }
    SpeedB += 1;
    if(SpeedB >= 40)
    {
    SpeedB = 40;
    }
    }


    //减速
    void slow()
    {
    SpeedA -= 1;        //每次减1
    if(SpeedA <= 5)//最小5
    {
    SpeedA = 5;
    }
    SpeedB -= 1;
    if(SpeedB <= 5)
    {
    SpeedB = 5;
    }
    }


    //左转
    void move_left()              //只有前进的时候可以左转
    {
    if(flag == 1)            //前进状态
    {
    in1=1;  
    in2=0;  
    in3=0;  
    in4=0;
    delay(50000);
    forward();
    }
    }


    //右转
    void move_right()                 //只有前进的时候可以右转
    {
    if(flag == 1)                //前进状态
    {
    in1=0;  
    in2=0;  
    in3=1;  
    in4=0;
    delay(50000);
    forward();
    }
    }

    //停止
    void stop()
    {
    in1=0;  
    in2=0;  
    in3=0;  
    in4=0;
    }

    void delay(u16 z)
    {  
    u16 x,y;  
    for(x=z;x>0;x--)   
    for(y=125;y>0;y--); 
    }   

    void SendOneByte(u8 c)    //串口发送数据
    {
    SBUF = c;
    while(!TI);
    TI = 0;
    }


    void main()
    {   
    //串口定时器 定时器T0
    TMOD = 0x21;  //T0定时器为工作方式一,T1定时器为工作方式二
    PCON = 0x00;  //串口初始化相关,波特率
    SCON = 0x50;                 //串口初始化相关,串口工作方式一,允许接收
            TH1 = 0xFD;                   //设置初值
            TL1 = 0xFD;                   //设置初值
    TR1 = 1;                          //开启定时器T1
     

    TH0 = 0xF4;                    //设置初值
    TL0 = 0x48;          //设置初值
    TR0 = 1; //开启定时器T0


    ES = 1;//开放串口中断
    //PS = 1;                         //串口中断优先
    PT0 = 1;                 //定时器0中断优先
    ET0 = 1;//开放定时器T0中断
    EA = 1;//开放总中断

    //按键控制小车
    while(1)
    {
    if(key1 == 0)
    {
    delay(10);
    if(key1 == 0)
    {
    forward();
    SendOneByte(1);
    }
    while(key1 == 0);
    }
    if(key2 == 0)
    {
    delay(10);
    if(key2 == 0)
    {
    fallback();
    SendOneByte(2);
    }
    while(key2 == 0);
    }
    if(key3 == 0)
    {
    delay(10);
    if(key3 == 0)
    {
    quick();
    SendOneByte(3);
    }
    while(key3 == 0);
    }
    if(key4 == 0)
    {
    delay(10);
    if(key4 == 0)
    {
    slow();
    SendOneByte(4);
    }
    while(key4 == 0);
    }
    }
    }


    void time0_int() interrupt 1   //T = 3ms * 40 = 120ms
    {  
    TR0 = 0;      
    TH0 = 0xF4; 
    TL0 = 0x48; //3000;  3ms
    MA++;          
    if(MA < SpeedA)  
    {    
    ena = 1;  
    }  
    else 
      ena = 0;  
    if(MA == 40)
    {    
      MA = 0;  
    }  

    MB++;          
    if(MB < SpeedB)  
    {    
    enb = 1;  
    }  
    else 
      enb = 0;  
    if(MB == 40)
    {    
      MB = 0;  
    }  
    TR0 = 1;
    }

    void UARTInterrupt(void) interrupt 4
    {
    if(RI)
    {
    RI = 0;
    //add your code here!
    cmd = SBUF;
    SendOneByte(cmd);

    //串口控制小车
    switch (cmd)
    {
    case 1:
    forward();
    SendOneByte(1);
    break;
    case 2:
    fallback();
    SendOneByte(2);
    break;
    case 3:
    quick();
    SendOneByte(3);
    break;
    case 4:
    slow();
    SendOneByte(4);
    break;
    case 5:
    move_left();
    SendOneByte(5);
    break;
    case 6:
    move_right();
    SendOneByte(6);
    break;
    default:
    SendOneByte(7);
    break;
    }
    }
    }

    结束!

  • 相关阅读:
    【SQL】在含有GROUP BY的SELECT语句中如何显示COUNT()为0的结果
    【SQL】SQL分页查询总结
    开篇
    Android Native Crash 排查思路
    jmeter+ant+jenkins接口自动化测试框架
    为何推荐使用线程池而不是显式创建线程原因之一—至少让线程有范围和限制
    quartz 中的线程池
    select in 查询结果无顺序及解决办法
    Druid 数据库连接池如何根据url加载Driver
    java 线程池参数
  • 原文地址:https://www.cnblogs.com/gundan/p/8118919.html
Copyright © 2020-2023  润新知