找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3824|回复: 7
打印 上一主题 下一主题
收起左侧

单片机智能小车巡黑线加蓝牙遥控 源程序(双运行模式)

  [复制链接]
跳转到指定楼层
楼主
模式一  自动模式  通过检测地面黑线自动行驶
模式二  手动模式  通过蓝牙模块+手机蓝牙遥控运行(包含加减速,开关灯,舵机角度控制程序)

材料
STC89C52 芯片
蓝牙模块+手机软件
黑线检测传感器
小车底盘+车轮
12V电池
其它配件


程序如下


  1. #include <reg52.h>           //此文件中定义了51的一些特殊功能寄存器
  2. #include <math.h>
  3. #include <stdio.h>
  4. #include <intrins.h>

  5. #define uchar unsigned char
  6. #define uint  unsigned int
  7. #define TH0_TL0 (65536-500)//设定中断的间隔时长

  8. //定义小车驱动模块输入IO口
  9. sbit Left_1_led  = P2^3;         // 左传感器      
  10. sbit Right_1_led = P2^1;         //右传感器
  11. sbit Left_2_led  = P2^4;         // 左传感器      
  12. sbit Right_2_led = P2^0;         //右传感器
  13. sbit midle_1_led = P2^2;         //中间传感器

  14. sbit K1=P2^7;//
  15. sbit K2=P2^6;//
  16. sbit K3=P2^5;//
  17. sbit LED=P3^6;//灯开关
  18. sbit PWM_OUT=P3^5;//舵机控制
  19.         
  20. sbit OUT1=P1^0;//左前    驱动
  21. sbit OUT2=P1^1;//左前    驱动
  22. sbit OUT3=P1^2;//左后    驱动
  23. sbit OUT4=P1^3;//左后    驱动
  24. sbit OUT5=P1^4;//右前        驱动
  25. sbit OUT6=P1^5;//右前        驱动
  26. sbit OUT7=P1^6;//右后        驱动
  27. sbit OUT8=P1^7;//右后        驱动
  28. /***蜂鸣器接线定义*****/
  29. sbit BUZZ=P3^7;

  30. bit  PWM1;  //PWM 通道 1,          左前
  31. bit  PWM2;  //PWM 通道 2,          左后
  32. bit  PWM3;  //PWM 通道 3,          右前
  33. bit  PWM4;  //PWM 通道 4,          右后
  34. bit PWM_Flag = 1;//舵机启动标志位

  35. uint PWM_Value1;                        //定义pwm值
  36. uchar order1=0;

  37. uchar count0 = 50;//低电平的占空比
  38. uchar count1 = 0;//高电平的占空比

  39. uchar count2 = 50;//低电平的占空比
  40. uchar count3 = 0;//高电平的占空比

  41. uchar date;
  42. uchar mode;

  43. LedOut[5];         //舵机位置转换AISCC
  44. LedOut2[5];         //小车速度转换AISCC

  45. void Q0();

  46. /************************************************************************/        
  47. //延时函数
  48. /************************************************************************/
  49. void delay500ms(void)         
  50. {
  51.     unsigned char a,b,c;
  52.     for(c=23;c>0;c--)
  53.         for(b=75;b>0;b--)
  54.             for(a=70;a>0;a--);
  55. }

  56. /************************************************************************/        
  57. //         BUZZ1( )蜂鸣器
  58. /************************************************************************/
  59. void BUZZ1( )
  60. {
  61.         BUZZ=1;        //50次检测K4确认是按下之后,蜂鸣器发出“滴”声响,然后启动小车。
  62.         delay500ms();
  63.         BUZZ=0;//响50ms后关闭蜂鸣器\PPPPP\\P
  64.         delay500ms();
  65.         BUZZ=1;        
  66.         delay500ms();
  67.         BUZZ=0;        
  68.         delay500ms();
  69.         BUZZ=1;
  70.         delay500ms();
  71.         BUZZ=0;
  72.         delay500ms();
  73.         BUZZ=1;
  74.         delay500ms();
  75.         BUZZ=0;        
  76.         delay500ms();               
  77.         BUZZ=1;
  78.         delay500ms();
  79.         BUZZ=0;
  80. }         


  81. /************************************************************************/
  82. //前速前进
  83. void  run(void)                                           //PWM=1表示电机正转有效        PWM=0 表示电机反转有效
  84. {
  85.           PWM1 = 1;         //左前
  86.           PWM2 = 1;         //左后
  87.           PWM3 = 1;         //右前
  88.           PWM4 = 1;         //右后
  89.           TR0 = 1;
  90.           ET0=1;                    //打开定时器0中断发送脉冲
  91. }
  92. /************************************************************************/        
  93. //后退
  94. void  back(void)
  95. {
  96.       PWM1 = 0;         //左前
  97.           PWM2 = 0;         //左后
  98.           PWM3 = 0;         //右前
  99.           PWM4 = 0;         //右后
  100.           TR0 = 1;
  101.           ET0=1;                    //打开定时器0中断发送脉冲
  102. }

  103. /************************************************************************/        
  104. //左转
  105. void  leftrun(void)
  106. {         
  107.       PWM1 = 0;         //左前
  108.           PWM2 = 0;         //左后
  109.           PWM3 = 1;         //右前
  110.           PWM4 = 1;         //右后
  111.           TR0 = 1;
  112.           ET0=1;                    //打开定时器0中断发送脉冲
  113. }
  114. /************************************************************************/        
  115. //右转
  116. void  rightrun(void)
  117. {
  118.           PWM1 = 1;         //左前
  119.           PWM2 = 1;         //左后
  120.           PWM3 = 0;         //右前
  121.           PWM4 = 0;         //右后
  122.           TR0 = 1;
  123.           ET0=1;                    //打开定时器0中断发送脉冲

  124. }
  125. /************************************************************************/           
  126. //停止   
  127. void  stop(void)
  128. {
  129.           OUT1 = 0;   OUT2 = 0;   
  130.           OUT5 = 0;   OUT6 = 0;   
  131.           OUT3 = 0;   OUT4 = 0;
  132.           OUT7 = 0;   OUT8 = 0;
  133. }

  134. //****定时器0初始化****//
  135. void Timer0Init()
  136. {

  137.     TMOD |= 0x01;          //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响               
  138.     TH0 = 0xfE;
  139.     TL0 = 0x33;
  140.     //ET0=1;           //定时器0中断打开   后面打开
  141.     TR0=1;             //定时器0开关打开
  142.     EA=1;              //总中断打开
  143.         PS=1;
  144. }

  145. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  146. 函数:擦除某一扇区(每个扇区512字节)
  147. 入口:addr = 某一扇区首地址                          
  148. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  149. void erase(uint addr)
  150. {      
  151. // 打开 IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间
  152. // 0x83(晶振<5M)   0x82(晶振<10M)   0x81(晶振<20M)   0x80(晶振<40M)
  153.     ISP_CONTR = 0x81;  
  154.     ISP_CMD   = 0x03;           // 用户可以对"Data Flash/EEPROM区"进行扇区擦除
  155.     ISP_ADDRL = addr;           // ISP/IAP操作时的地址寄存器低八位,
  156.     ISP_ADDRH = addr>>8;        // ISP/IAP操作时的地址寄存器高八位。
  157.     EA =0;   
  158.     ISP_TRIG = 0x46;            // 在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,
  159.     ISP_TRIG = 0xB9;            // 再写入B9h,ISP/IAP命令才会生效。
  160.     _nop_();
  161.     Q0();                                            // 关闭ISP/IAP
  162.         EA = 1 ;                                       
  163. }
  164. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  165. 函数:写一字节
  166. 入口:addr = 扇区单元地址 , dat = 待写入数据
  167. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  168. void Write(uint addr,uchar dat)
  169. {
  170.     ISP_CONTR = 0x81;                  
  171.     ISP_CMD   = 0x02;           // 用户可以对"Data Flash/EEPROM区"进行字节编程
  172.     ISP_ADDRL = addr;        
  173.     ISP_ADDRH = addr>>8;      
  174.     ISP_DATA  = dat;            // 数据进ISP_DATA
  175.     EA = 0;                                            // 关闭中断
  176.     ISP_TRIG = 0x46;         
  177.     ISP_TRIG = 0xB9;         
  178.     _nop_();
  179.     Q0();                       // 关闭ISP/IAP
  180.         EA = 1 ;   
  181. }
  182. /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
  183. 函数:读一字节
  184. 入口:addr = 扇区单元地址
  185. 出口:dat  = 读出的数据
  186. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  187. uchar read(uint addr)
  188. {   
  189.     uchar dat;

  190.     ISP_CONTR = 0x81;                  
  191.     ISP_CMD   = 0x01;          // 用户可以对"Data Flash/EEPROM区"进行字节读
  192.     ISP_ADDRL = addr;         
  193.     ISP_ADDRH = addr>>8;      
  194.     EA = 0;
  195.     ISP_TRIG = 0x46;         
  196.     ISP_TRIG = 0xB9;         
  197.     _nop_();
  198.     dat = ISP_DATA;            // 取出数据
  199.     Q0();                      // 关闭ISP/IAP
  200.         EA = 1 ;                     
  201.     return dat;
  202. }

  203. //**************************/
  204. //函数:EEPROM关闭ISP/IAP操作
  205. //**************************/
  206. void Q0()
  207. {
  208.     ISP_CONTR = 0;             // 关闭IAP功能
  209.     ISP_CMD   = 0;             // 待机模式,无ISP操作
  210.     ISP_TRIG  = 0;             // 关闭IAP功能, 清与ISP有关的特殊功能寄存器
  211. }

  212. /********************************************************************
  213. * 名称 : UART_Send_Byte
  214. * 功能 : 串口屏通讯发送字节数
  215. ***********************************************************************/
  216. void UART_Send_Byte(unsigned char mydata)  
  217. {
  218.          ES=0;
  219.         TI=0;
  220.     SBUF=mydata;
  221.     while(!TI);
  222.     TI=0;
  223.     ES=1;
  224. }

  225. /********************************************************************
  226. * 名称 : UART_Send_Str
  227. * 功能 : 串口屏通讯文本串发送
  228. ***********************************************************************/
  229. void UART_Send_Str(char *s)            
  230. {
  231.     int i=0;
  232.     while(s[i]!=0)
  233.     {
  234.            UART_Send_Byte(s[i]);
  235.            i++;
  236.     }

  237. }
  238. /********************************************************************
  239. * 名称 : DisPlay
  240. * 功能 : 当前舵机位置转换函数,显示当前位置
  241. ***********************************************************************/
  242. void DisPlay()
  243. {
  244.     uchar i;
  245.     uchar DisDate;
  246.     DisDate = count2;
  247.     LedOut[0] = DisDate%100000/10000+0X30;
  248.     LedOut[1] = DisDate%10000/1000+0X30;
  249.     LedOut[2] = DisDate%1000/100+0X30;
  250.     LedOut[3] = DisDate%100/10+0X30;
  251.     LedOut[4] = DisDate%10+0X30;
  252.     UART_Send_Str("Pwm_Angel");         
  253.     for(i=0;i<5;i++)                                                   
  254.     {                  
  255.       UART_Send_Byte(LedOut[i]);
  256.     }
  257. }

  258. /********************************************************************
  259. * 名称 : DisPlay
  260. * 功能 : 当前速度转换函数,显示当前速度
  261. ***********************************************************************/
  262. void Spend_DisPlay()
  263. {
  264.     uchar i;
  265.     uchar DisDate;
  266.     DisDate = count0;
  267.     LedOut2[0] = DisDate%100000/10000+0X30;
  268.     LedOut2[1] = DisDate%10000/1000+0X30;
  269.     LedOut2[2] = DisDate%1000/100+0X30;
  270.     LedOut2[3] = DisDate%100/10+0X30;
  271.     LedOut2[4] = DisDate%10+0X30;
  272.     UART_Send_Str("Car Spend");         
  273.     for(i=0;i<5;i++)                                                   
  274.     {                  
  275.       UART_Send_Byte(LedOut2[i]);
  276.     }
  277. }
  278. //****串口初始化****//
  279. void UsartInit()
  280. {
  281.     TMOD = 0x21;
  282.     PCON = 0x00;         //波特率不加倍
  283.     SCON = 0x50;   
  284.     TH1 = 0xFd;      //设置波特率 9600                11.0592M
  285.     TL1 = 0xFd;
  286.     TR1 = 1;         //启动定时器1
  287.         PS=1;
  288.     ES = 1;          //开串口中断
  289.     EA = 1;          //开总中断
  290.     //IT0=0;         //外部中断1触发方式选择位                IT0=0,为电平触发方式,引脚INT1上低电平有效。IT0=1,为跳变沿触发方式,引脚INT1上的电平从高到低的负跳变有效。
  291.     //EX0=1;         //外部中断0中断允许位。            EX0=1,打开外部中断0中断。          EX0=0,关闭外部中断0中断。
  292. }

  293. /*******************************************************************************
  294. * 函数名         : Usart() interrupt 4
  295. * 函数功能                  : 串口通信中断函数
  296. * 输入           : 无
  297. * 输出                  : 无
  298. *******************************************************************************/
  299. void Usart() interrupt 4
  300. {

  301.         ET0 = 0 ;
  302.         ES = 0;
  303.         date=SBUF;//出去接收到的数据
  304.         RI = 0;//清除接收中断标志位
  305.         //SBUF=date;
  306.     //while(!TI);
  307.     //TI=0;
  308.         /******按键处理减pwm占空比,电机加速*****/                         //0-20加减速度
  309.         if(date=='6') //加速
  310.            {
  311.           count0 += 10;
  312.           if(count0 >= 150)
  313.              {
  314.                 count0 = 150;
  315.              }

  316.            }
  317.         /******按键处理减pwm占空比,电机减速*****/
  318.         if(date=='7') //减速
  319.            {
  320.                 count0 -= 10;
  321.         if(count0 <= 0)
  322.             {
  323.                count0 = 0;
  324.             }

  325.            }        
  326.         if(date=='8')        {mode = 1;}         //模式1自动
  327.         if(date=='9')   {mode = 2;}  //模式2手动
  328.         if(date=='A')         {LED=~LED;}  //开关灯

  329.         /******按键处理减pwm占空比,电机减速*****/
  330.         if(date=='E') //舵机上抬
  331.            {
  332.               count2 += 5;
  333.           if(count2 >= 75)
  334.              {
  335.                 count2 = 75;
  336.              }
  337.                   
  338.            }
  339.         
  340.         if(date=='F') //舵机下降
  341.            {
  342.                   count2 -= 5;
  343.          if(count2 <= 20)
  344.             {
  345.                count2 = 20;
  346.             }
  347.                  
  348.            }
  349.    ES = 1;
  350.                                                                                  
  351. }

  352. /********************************************************************
  353. * 名称 : SteeringGear() interrupt 1
  354. * 功能 : 定时器0中断函数        (模式选择控制)
  355. ***********************************************************************/
  356. void SteeringGear() interrupt 1
  357. {

  358.         TR0 = 0;
  359.     TL0 = TH0_TL0 % 256;
  360.     TH0 = TH0_TL0 / 256 ;//定时器装初值

  361.     if(++count1 < count0)
  362.        {
  363.                   if(PWM1==1)  {OUT1=1;OUT2=0;}        else   {OUT2=1;OUT1=0;} //PWM=1表示电机正转有效        PWM=0 表示电机反转有效
  364.                   if(PWM2==1)  {OUT3=1;OUT4=0;}        else   {OUT4=1;OUT3=0;}
  365.                   if(PWM3==1)  {OUT5=1;OUT6=0;}        else   {OUT6=1;OUT5=0;}
  366.                   if(PWM4==1)  {OUT7=1;OUT8=0;}        else   {OUT8=1;OUT7=0;}
  367.        }
  368.     else
  369.            {
  370.                   if(PWM1==1)  {OUT1=0;OUT2=0;} else   {OUT2=0;OUT1=0;}
  371.                   if(PWM2==1)  {OUT3=0;OUT4=0;} else   {OUT4=0;OUT3=0;}
  372.                   if(PWM3==1)  {OUT5=0;OUT6=0;}        else   {OUT6=0;OUT5=0;}
  373.                   if(PWM4==1)  {OUT7=0;OUT8=0;}        else   {OUT8=0;OUT7=0;}
  374.            }
  375.     if(count1 >= 100)
  376.        {
  377.           count1=0;
  378.        }

  379. }


  380. //主函数
  381.         void main(void)
  382. {        
  383.     uchar a;
  384.     UsartInit();  
  385.         Timer0Init();
  386.         DisPlay();;
  387.         BUZZ1( );   
  388.         ET0 = 0;        
  389.         BUZZ=0;         
  390.         mode=0;
  391.     P1=0X00;  
  392.         LED = 0;
  393.         Spend_DisPlay() ;

  394.     while(1)
  395.           {
  396.             
  397.               while(mode==1)                  //自动程序
  398.                     {
  399.                           BUZZ=1;
  400.                   delay500ms();
  401.                   BUZZ=0;
  402.                   delay500ms();
  403.                   while(mode==1)   //有信号为0  没有信号为1
  404.                         {

  405.                                    //WDT_CONTR=0x35;           //喂狗
  406.                            if(Left_1_led==1&&Right_1_led==1)          {   run();                    Spend_DisPlay() ; }           //调用前进函数                                 
  407.                                    else
  408.                                      {                          
  409.                                        if(Left_1_led==0&&Right_1_led==1)  {  leftrun();           Spend_DisPlay() ;}            //左边检测到黑线        调用小车左转  函数                  
  410.                                        if(Right_1_led==0&&Left_1_led==1)  { rightrun();           Spend_DisPlay() ;}                //右边检测到黑线  调用小车右转        函数
  411.                                     }
  412.                         }
  413.                      }
  414.              while(mode==2)                  //手动程序
  415.                         {
  416.                            BUZZ=0;
  417.                    delay500ms();
  418.                    BUZZ=1;
  419.                    delay500ms();
  420.                    BUZZ=0;        
  421.                    delay500ms();               
  422.                    BUZZ=1;
  423.                    delay500ms();
  424.                    BUZZ=0;
  425.                    while(mode==2)
  426.                          {
  427.                                    a = 1;
  428.                                                             
  429.                                while(date=='1')                //调用前进函数
  430.                                       {  
  431.                                          run();   
  432.                                          if(a == 1)  {UART_Send_Str("Car Run" );   Spend_DisPlay() ;}
  433.                                                  a = 0;
  434.                                       }                 

  435.                                while(date=='2')            //调用小车左转
  436.                                       {  
  437.                                          leftrun();  
  438.                                          if(a == 1)  {UART_Send_Str("left run" );  Spend_DisPlay() ;}
  439.                                                  a = 0;
  440.                                       }                 
  441.                            
  442.                                while(date=='4')                  //调用小车右转
  443.                                               {  
  444.                                          rightrun();  
  445.                                          if(a == 1) { UART_Send_Str("right run" );  Spend_DisPlay() ;}
  446.                                                  a = 0;
  447.                                       }        
  448.         
  449.                                while(date=='5')                   //调用小车后退
  450.                                       {  
  451.                                          back();  
  452.                                          if(a == 1)  {UART_Send_Str("back" );            Spend_DisPlay() ;  }
  453.                                                  a = 0;
  454.                                       }         
  455.         
  456.                                while(date=='0')                           //调用停止
  457.                                        {
  458.                                              
  459.                                          stop();
  460.                                                  if(a == 1) DisPlay();
  461.                                                  a = 0;
  462.                                                                                              
  463.                                                  if(++count3 < count2)         PWM_OUT=1;
  464.                                              else
  465.                                                            {
  466.                                                               PWM_OUT=0;
  467.                                                           }
  468.                                             if(count3 >= 100)
  469.                                                      {
  470.                                                     count3=0;
  471.                                                    }
  472.                                                    //WDT_CONTR=0x35;                                                   
  473.                                            }               
  474.                                 }
  475.                    }
  476.         }               
  477. }
复制代码


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏11 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:913639 发表于 2021-4-28 16:51 | 只看该作者
老哥,代码是全的吗
回复

使用道具 举报

板凳
ID:1531 发表于 2021-9-23 11:21 | 只看该作者
同问,代码全吗?
回复

使用道具 举报

地板
ID:365834 发表于 2021-10-18 21:13 | 只看该作者
zbjllq 发表于 2021-9-23 11:21
同问,代码全吗?

全的,直接编译就可以用(Keil4编写)。
回复

使用道具 举报

5#
ID:365834 发表于 2021-10-18 21:17 | 只看该作者
晚安可否 发表于 2021-4-28 16:51
老哥,代码是全的吗

全的,直接复制就可以。
回复

使用道具 举报

6#
ID:979801 发表于 2021-11-10 16:11 | 只看该作者
远方zjm 发表于 2021-10-18 21:13
全的,直接编译就可以用(Keil4编写)。

请问可以用Keil5运行吗
回复

使用道具 举报

7#
ID:783404 发表于 2021-11-12 11:10 | 只看该作者
有没有ad原理图啊
回复

使用道具 举报

8#
ID:65956 发表于 2021-11-30 09:38 | 只看该作者
蓝牙APP都没发出来共享一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表