> 文档中心 > 51单片机蓝牙遥控小车 定时器 中断 PWM L298N调速控制

51单片机蓝牙遥控小车 定时器 中断 PWM L298N调速控制


闲时偷学51一周 完成蓝牙小车定时器中断PWM调速控制

关键问题: 51蓝牙串口通信、定时器、中断、L298N、PWM调速

  • 先把我学习过程中的问题摆出来:89C52仅有的两个定时器在使用串口时的干扰问题,PWM产生
  • 一开始找资料看别人51控制L298N的例子,PWM调速的比较少,有的自己试了结果不太理想;
  • 还有就是 初来乍到,哪里有不对的地方 欢迎指正!

操作说明:

  • 打开蓝牙调试器,对应设置好控制字符按键名
  • 打开小车电源并将手机连接到蓝牙模块进行控制

一、前期硬件准备

  1. TT电机小车底板套件,随便买一个两个电机的在这里插入图片描述

  2. 蓝牙模块(我是在淘宝找便宜便买的,啊?买HC-06毕竟咱穷呀~)默认波特率9600一定要对应单片机串口通信波特率在这里插入图片描述
    单片机-----蓝牙模块连线:

  • RXD/P3.0----TXD * GND----GND
  • TXD/P3.1----RXD * VCC/5V/3V- -VCC/5V/3V
  • 用到的蓝牙软件:蓝牙调试器 一般手机应用商店可下载,我的按键设置在这里插入图片描述
  1. STC89C52或者STC89C52RC最小系统板在这里插入图片描述

  2. L298N电机驱动、杜邦线等。本次只用到298N的四个逻辑引脚,其与单片机具体连接看程序定义在这里插入图片描述

  3. 5-12V电池,注意与298N正确连接,通过L298N的板载5V使能输出(插上跳线帽时5V输入端有5V输出)给单片机和蓝牙模块供电。

  4. 其他,还需要用到USB转TTL给单片机下载程序;TTL如图:在这里插入图片描述

    最后就是编程环境 arm Keil了 。

二、51C语言程序编写

  • 废话不多说,看看怎么用当今官方都不建议使用的STC89C52这块单片机来实现蓝牙通信,定时器中断PWM调速小车的主体程序吧。
这里掏出我第一版的部分代码://就是为了举个例子,写的什么玩意? 后来的自己都看不下去了
/*  * * 反面教材,大家笑笑就行了 ~ ~  * * 用延时函数模拟PWM输出,但后面实验发现这玩意太LOW了~*运行下去都是个问题/#include <reg52.h> #define uchar unsigned char#define uint  unsigned intsbit ENA=P1^0;//使能端口A和Bsbit ENB=P1^5;sbit IN1=P1^1;//以下四个逻辑端口sbit IN2=P1^2;sbit IN3=P1^3;sbit IN4=P1^4;void delay(uint n)//延时函数{ uint x,y; for(x=n;x>0;x--) for(y=114;y>0;y--);}void Speed1(uint b) // 定义一个速度函数模拟PWM输出 形参b{  ENB=1; // ENB使能或给高电平 delay(b); //  延时  ENB=0;   //  ENB失能或给低电平 delay(100-b);}void Speed(uint a)  // 定义一个速度函数模拟PWM输出 形参{  ENA=1; // ENA使能或给高电平 delay(a);     //  延时  ENA=0;      //  ENA失能或给低电平 delay(100-a);}//L298N逻辑函数,控制电机正反转以及速度大小void stop()//小车停止函数{IN1=0;IN2=0;IN3=0;IN4=0;}void forward()//小车前进函数{IN1=1;IN2=0;IN3=1;IN4=0;  Speed(30);Speed1(30);}void back()   //小车后退函数{IN1=0;IN2=1;IN3=0;IN4=1;Speed(30);Speed1(30);}void left()  //小车左转函数{IN1=0;IN2=1;IN3=1;IN4=0;Speed(30);Speed1(30);}void right() //小车左转函数{IN1=1;IN2=0;IN3=0;IN4=1;Speed(30);Speed1(30);}void UsartConfiguration()//串口初始化{SCON=0X50;//SCON 是一个特殊功能寄存器,用以设定串行口的工作方式TMOD=0X20;//和接收/发送控制以及设置状态标志PCON=0X00;TH1=0Xfd;    TL1=0Xfd;   //波特率为9600,计算所得TR1= 1;ES = 1;  //开启串口中断    EA = 1;     //开启总中断    }void Com_Int() interrupt 4{uchar receive_data;//EA = 0;if(RI == 1) //一次数据接收完成后RI由硬件自动置1,作接收完成的标志{ //初始设置电机停止ENA=0;//PWM使能端口失能,电机停转ENB=0;receive_data = SBUF;//将收/发数据缓存器SBUF中的数据存入变量/*电机逻辑判断函数*/switch(receive_data){case ('F'): forward();break;case ('B'): back(); break;case ('L'): left();  break;case ('R'): right(); break;case ('S'): stop();    break;}}RI=0;EA = 1;//开启总中断}void main()   //主函数{ UsartConfiguration();while(1);}
  • 由于我头一回的草率,后面又专门在学习网站~哔哩哔哩找了51定时器、中断系统的课看了几遍,哎枯燥难耐的我竟然还认真地做了笔记—但后面自己试验的多了,又觉得那些笔记记得都是废话,因为你永远不会在了解它之前觉得某个问题产生的几率有多大。
  • 关于51 89系列的芯片仅有的两个定时器不能同时工作的问题 :也许不知道是我看的教程有问题还是,为了考验学习者,如果某些教程书里有,当我没说。
    解决办法来源:当两个定时器只有一个工作另一个罢工时、当我实在没辙的时候,低头之际突然想到了来CSDN瞧瞧。在浏览了众多关于定时器的文章里,哎~~ 我TM终于找到了原因—两个定时器同时使用,在中断时会产生干扰,关键就在定时器中断控制寄存器这,程序里会提到。哎~~说多了都是泪啊,硬用时间换来的呢!?!!

以下 直接掏出我呕心沥血的最终代码

/*用定时器中断实现PWM输出控制L298N的蓝牙小车/51两个定时器同时使用冲突问题*单 片 机:STC89C52/STC89C52RC*作   者 :GUard_Byte*   *   *   *   *   *   *   单片机与蓝牙模块连线:*RXD----TXD GND----GND*TXD----RXD  VCC/5V/3V--VCC/5V/3V  关键问题:中断系统优先级TMOD|与串口中断的设置,或运算使得后面中断时前面赋值不被改变*  保证两个定时器不干扰,同时工作*/#include <reg52.h> typedef unsigned int uint;typedef unsigned char uchar;// PWM输出I/O口定义与298N连接,注意我使用的最小系统P0有上拉电阻可置高,若无上拉电阻请换至其他sbit PWM1 = P0^1;sbit PWM2 = P0^2;sbit PWM3 = P0^3;sbit PWM4 = P0^4;uchar receive_data;//储存串口接收的数据uint count0 = 0;// 定时器T0中的计时uint count1 = 0;// 定时器T1中的计时uint  flag1 = 0;// 电机1正反转的标志位uint  flag2 = 0;// 电机2正反转的标志位uint  rate1;// 电机速度等级, 共10级uint  rate2;// 电机速度等级, 共10级/函数名:void Time0_Int()*功  能:定时器0初始化,设定定时器0工作方式和初值*/void Time0_Int(){    EA = 1;   // 开启总中断EX0 = 1;   // 允许外部中断0中断IT0 = 1;   // 下降沿触发中断ET0 = 1;   // 定时器0中断TH0 = (65536 - 10) / 256;// 赋初值, 10usTL0 = (65536 - 10) % 256;TMOD|= 0x01;      // 选择方式一TR0 = 1;  // 打开定时器0中断}/函数名:void T0_inter() ;中断号  1*功  能:定时器0中断服务,及计数 PWM产生*+++++ PWM产生的部分思路借鉴网络 本来想贴链接,啊~后来找不到原文了*    求原谅!++++++*/void T0_inter() interrupt 1{ TR0 = 0;TH0 = (65536 - 10)/256;TL0 = (65536 - 10)%256;TR0 = 1;count0 ++;if (count0 >= 100){count0 = 0;}if (count0 < ( rate1 * 10)){if ( flag1 == 0){PWM1 = 1;PWM2 = 0;}else{PWM1 = 0;PWM2 = 1;}}else{PWM1 = 1;PWM2 = 1;}if (count0 < ( rate2 * 10)){if (flag2 == 0){PWM3 = 1;PWM4 = 0;}else{PWM3 = 0;PWM4 = 1;}}else{PWM3 = 1;PWM4 = 1;}}// 小车前进函数, 速率为3void forward(){ rate1 = rate2 = 2;flag1 = flag2 = 1;}// 小车后退函数, 速率为3  void back(){rate1 = rate2 = 2;flag1 = flag2 = 0;}//小车右急转弯函数, 左边电机正转, 右边电机反转,行进过程有效void turn_left(){flag1 = 1;flag2 = 0;}// 小车左急转弯函数, 右边电机正转, 左边电机反转,行进过程有效void turn_right(){flag1 = 0;flag2 = 1;}// 右边电机加速,实现左转void right_add(){if (rate1 == 5){rate1 = 3;}   rate1++; }// 左边电机加速,实现右转void left_add(){if (rate2 == 5){rate2 = 3;}rate2++; }// 电机加速,最大10,此处限制到5级void moter_add(){if ((rate1==5)&&(rate2 == 5)){rate1 = 2;rate2 = 2;}   rate1++;  rate2++;}// 电机减速,最小为2void moter_less(){if ((rate1==1)&&(rate2 == 1)){rate1 = 5;rate2 = 5;}   rate1--;  rate2--;}// 小车停止函数void stop(){rate1 = rate2 = 0;}/函数名:void Com_init()*功  能:串口初始化,设置串口和定时器1工作模式*/ void Com_init()      {   ES=0;// 关串口中断 SCON = 0x50;// REN=1允许串行接受状态,串口工作模式1,波特率可变 TMOD|=0x20; // 定时器1工作于方式2,8位自动重载模式, 用于产生波特率     TH1=TL1=0xFD;     // 波特率9600 (晶振为11.0592)     PCON &= 0x7f;     // 波特率不倍增      TR1 = 1;// 定时器1开始工作,产生波特率  RI = 0;    // 接收标志位置0    EA=0;//关总中断  ES=1;      // 开启串口中断 }/* * 函数名:void Datectr() * 功  能:用以处理串口将接收到的数据*/void DateCtrl(){switch(receive_data){case ('F'): forward();break;  case ('B'):back(); break;  case ('L'): left_add();      //leftbreak;    case ('l'): turn_left();break;case ('R'): right_add();  //right break;  case ('r'): turn_right();break;case ('u'): moter_add();  break;case ('d'): moter_less();  break;case ('S'): stop();   break;}}void main()      //主函数     { Com_init(); //串口初始化和定时器初始化Time0_Int();while(1){   if(RI==1){ // 判断是否有数据到来receive_data = SBUF; //将收/发数据缓存器SBUF中的数据存入变量    DateCtrl(); //调用数据处理函数    RI = 0;   }      } }//欧克,收工;
  • 现在就可以愉快的玩耍自己亲手制作的蓝牙遥控小车了!最后别忘了给自己比个耶 ✌!哈哈~
  • 最后来张成品图圆满结束:在这里插入图片描述