当前位置:   article > 正文

51单片机红外遥控小车_51单片机智能小车红外遥控器

51单片机智能小车红外遥控器

出遥控小车是一个比较经典的51单片机项目,适合用来作为新手的毕业项目,考察的比较综合。

先放代码:

这是引脚调用和全局变量定义,代码经过多轮调试确定可行,如果复制后运行得不到预期效果,多半是问题出在这个部分,可以更具原理图和开发手册进行修改。

  1. #include <REGX52.H>
  2. #include <intrins.h>
  3. sbit SIO = P3^4; //串行数据输入
  4. sbit IN_CLK = P3^5; //串输入时钟
  5. sbit OUT_CLK = P3^6; //并行输出时钟
  6. sbit beep=P2^3; //蜂鸣器
  7. int code table[5][8]={{0xE7,0xF3,0xF9,0x00,0x00,0xF9,0xF3,0xE7},//前进
  8. {0xE7,0xCF,0x9F,0x00,0x00,0x9F,0xCF,0xE7},//后退
  9. {0xE7,0xE7,0xE7,0x66,0x24,0x81,0xC3,0xE7},//左转
  10. {0xE7,0xC3,0x81,0x24,0x66,0xE7,0xE7,0xE7},//右转
  11. {0x7E,0xBD,0xDB,0xE7,0xE7,0xDB,0xBD,0x7E}//待机
  12. };
  13. unsigned int AllTimer; // 定时器记录时间
  14. unsigned int timer33[33];// 用来存放每个脉冲的时间
  15. unsigned int timer4[4]; //把32位转换成4个字节
  16. unsigned char isok=0; //33位接收完则为1
  17. unsigned char Allok=0;//把32位转换成了4字节完成则为1
  18. sbit IN1=P1^2; //左反
  19. sbit IN2=P1^3; //左正
  20. sbit EN1=P1^4; //左电机
  21. sbit EN2=P1^5; //右电机
  22. sbit IN3=P1^6; //右正
  23. sbit IN4=P1^7; // 右反
  24. int pwm_t=0; //调速的计数变量
  25. int speed; //调速变量
  26. int n=4; //切换点阵模式,初始显示待机

 初始化定时器,TH和TL分别为高八位和低八位,如果是在8位模式下,两者相同,关键地方已加注释,不多做赘述,定时器中断是51单片机中非常重要的一个模块,必须掌握。调用定时器0来解码计时,定时器1则用来给电机调速。

  1. void init()
  2. {
  3. //设置定时器中断
  4. EA=1;
  5. ET1=1;//设置定时器0,用来计算一个脉冲的时间
  6. ET0=1;//用来处理pwm脉宽调制用
  7. //设置外部中断
  8. EX0=1; //设置外部中断0允许
  9. IT0=1;//设置下降沿触发
  10. //启动定时器
  11. TR1=1;
  12. TR0=1;
  13. //设置定时器模式
  14. TMOD=0X22;
  15. //设置定时器起始时间
  16. TH1=238;
  17. TL1=238;
  18. TH0=56;
  19. TL0=56;
  20. }

PWM电机调速,定时器1触发中断一次,执行一次pwm,在0~speed区间,小车电机使能,speed~255区间,电机非使能,调整speed数值大小即可调节小车速度的快慢。

  1. void PWM()interrupt 3
  2. {
  3. pwm_t++;
  4. if(pwm_t>=255)
  5. {
  6. pwm_t=0;
  7. }
  8. if(pwm_t<=speed)
  9. {
  10. EN1=EN2=1;
  11. }else
  12. {
  13. EN1=EN2=0;
  14. }
  15. }

以下是简单的控制方向和加速减速的代码。

  1. void speed_up() //加速
  2. {
  3. if(speed<=245)
  4. speed+=10;
  5. }
  6. void speed_down() //减速
  7. {
  8. if(speed>=10)
  9. speed-=10;
  10. }
  11. //直行
  12. void move()
  13. {
  14. IN1=0;
  15. IN2=1;
  16. IN3=1;
  17. IN4=0;
  18. }
  19. //停止
  20. void stop()
  21. {
  22. IN1=0;
  23. IN2=0;
  24. IN3=0;
  25. IN4=0;
  26. }
  27. //后退
  28. void back()
  29. {
  30. IN1=1;
  31. IN2=0;
  32. IN3=0;
  33. IN4=1;
  34. }
  35. //左转
  36. void leftmove()
  37. {
  38. IN1=0;
  39. IN2=0;
  40. IN3=1;
  41. IN4=0;
  42. }
  43. //右转
  44. void rightmove()
  45. {
  46. IN1=0;
  47. IN2=1;
  48. IN3=0;
  49. IN4=0;
  50. }

 定时器0初始值设置位56,从56到255,再发射一次脉冲后才把中断标志置为1,计数次数为255-56+1=200,stc51晶振一般都为11.0592MHz,计数一次为1.085us,如晶振不同,还需要进行调整。

out函数将不同的AllTimer值存入timer33数组

  1. // 217us=200*1.085us
  2. void timer() interrupt 1
  3. {
  4. AllTimer++;//加1实际加了217us 65535*217us=14.2s
  5. }
  6. //外部0中断函数0
  7. //每一个下降沿会触发一次中断
  8. //每次中断都是一个波形 13.5ms 1.125ms 2.25ms
  9. void out() interrupt 0
  10. {
  11. static int flag=0; //设置判断是否第一次进入
  12. static int i=0;//表示数组下标i=0;
  13. if(flag) //第二次中断 第一个波形下降沿到了
  14. { //AllTimer 加一次 277.76us
  15. if(AllTimer>55 && AllTimer<65) //如果是引导码62.2
  16. {
  17. i=0;//如果是引导码 存在数组的第一个位置
  18. }
  19. timer33[i]=AllTimer;
  20. i++;//存下一个数据
  21. AllTimer=0;//下一次脉冲从0开始
  22. if(i==33) //防止数组越界,最大下标是32
  23. {
  24. i = 0;
  25. isok=1; //用来标识33位已经解析完了
  26. flag=0;// 33位接收完成后,下次按键从else开始
  27. }
  28. }
  29. else //第一次中断
  30. {
  31. flag=1;
  32. AllTimer=0;
  33. }
  34. }

 codebyte函数中,根据不同的AllTimer值(AllTimer表示为不同的时间长度),来进行解码,讲脉冲信号转换为数字信号,引导码为13.5ms,逻辑1为2.25ms,逻辑0为1.125ms,此为红外通信相关知识,不多做赘述,实际上也不难。

再将32位,4个8位转换成四个字节存入timer4,(实际解码有33位,第一位引导码,不进行解析)

  1. void codeByte()
  2. {
  3. //总共33位
  4. unsigned char i,j,k,value;
  5. unsigned char OneTime;
  6. k=1;// 引导码不处理 从下标1开始
  7. for(i=0;i<4;i++)//4个字节
  8. {
  9. for(j=0;j<8;j++)//4个字节中每个字节的8位
  10. {
  11. OneTime=timer33[k];//每一个脉冲时间
  12. if(OneTime >7)//0--1.125ms--5.18 1--2.25ms--10.3
  13. {
  14. //数据是先收到低位,再收到高位
  15. value=value|0x80;
  16. //0000 0000 | 1000 0000
  17. }
  18. if(j<7)
  19. {
  20. value=value>>1;//0100 0000
  21. }
  22. k++;
  23. }//当前for循环结束 则8位处理完
  24. timer4[i]=value;//存8位数据
  25. value=0;
  26. }//此循环结束 说明32位处理完毕
  27. Allok=1;//4字节处理完毕标志
  28. }

点阵显示是动态显示,一次只能显示一行(一列),显示间隔较短,造成视觉残留,使得外面可以在点阵上看到多行(多列)的图案。

  1. void display()
  2. {
  3. int i;
  4. char da = 0x80;
  5. int j;
  6. for(j=10;j>0;j--)
  7. {
  8. for(i = 0; i < 8;i++) //显示每一行数据,总共8行
  9. {
  10. OUT_CLK =0;
  11. SendBit(table[n][i]);
  12. SendBit(da); //0100 0000
  13. da = _cror_(da,1); //循环右移
  14. OUT_CLK =1;
  15. }
  16. }
  17. }
  18. void SendBit(unsigned char SendData) //0xfe
  19. {
  20. //发送行0100 0000 0x40
  21. unsigned char i = 0;
  22. for(i = 0; i < 8;i++)
  23. {
  24. IN_CLK = 0;
  25. if(SendData & 0x01) SIO = 1;
  26. else SIO = 0;
  27. SendData = SendData >>1;
  28. IN_CLK = 1;
  29. }
  30. }

初始时速度为180,8位的数据码(键值) ,解码后存在timer[2],对照遥控器的键值表,不同的按键来实现不同的功能,当加速使得速度超过200后,蜂鸣器开始警报,速度低于200后,蜂鸣器也停止警报。

全局变量n对应多维数组tabler中不同的八位,每一个8位对于一种显示模式,前进显示前进的箭头,转向显示转向的箭头,车辆初始时或者车辆停止时会显示X待机画面。

此处可以优化,我是在主函数体内的while循环内调用display显示函数,一次闪过八位,但是由于51单片机的性能过低,被其他代码拖累运行速度后,diplay的显示间隔较长,肉眼看起来会很闪,可以采用高性能的51芯片,或者使用定时器来显示,进行优化后图像显示会更好。

  1. void main()
  2. {
  3. init();
  4. speed=180;
  5. while(1)
  6. {
  7. display();
  8. if(speed>200)
  9. beep=0;
  10. else
  11. beep=1;
  12. if(isok==1)
  13. {
  14. codeByte();//解析32位
  15. isok=0;
  16. if(Allok==1)
  17. {
  18. switch(timer4[2])
  19. {
  20. case 0x18:{move();n=0;}break;
  21. case 0x1c: {stop();n=4;}break;
  22. case 0x08: {leftmove();n=2;} break;
  23. case 0x5a:{ rightmove();n=3;} break;
  24. case 0x52: {back();n=1;} break;
  25. case 0x15: speed_up();break;
  26. case 0x07: speed_down();break;
  27. default: break;
  28. }
  29. }
  30. }
  31. }
  32. }

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号