找回密码
 立即注册

QQ登录

只需一步,快速开始

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

2.4G遥控小车设计 超声波数据回传 舵机转向 OLED显示 STC8A8K64S4单片机程序+电路

  [复制链接]
跳转到指定楼层
楼主
在上一次用开发板做小车后  继续深入研究  把开发板换成了PCB  遥控器用两个模拟量摇杆,达到了玩小车的乐趣 , 又在原有的基础上增加了超声波数据回传,实现了数据收发,而且程序也有了很大的优化 ,速度变得更快了点,最重要的还是用了PCB ,买一些元器件就可以自己做电路,特别适合学生DIY,我也是用腐刻做板的,所以不用担心很复杂。直接附上图片吧。

制作出来的实物图如下:


Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)


nRF24L01无线发射检测:
1、将nRF24L01模块按照正确方向插到J11端子上;
2、MINI USB连接线给开发板通电下载程序,下载软件中内部IRC时钟选择11.0592MHZ;
3、下载程序后,开发板蓝色指示灯会不停闪烁,表示无线发送正常;
4、此时,如果有下发接收程序的开发板,则可以观察到有表示接收到的红色指示灯闪烁。
注:该实验需要配合接收实验进行。

nRF24L01无线接收实验:
1、将nRF24L01模块按照正确方向插到J11端子上;
2、MINI USB连接线给开发板通电下载程序,下载软件中内部IRC时钟选择11.0592MHZ;
3、下载程序后,开发板红色指示灯会常亮,表示没有接收到无线信号;
4、此时,如果有下发发送程序的开发板,则可以观察到该接收板上的红色指示灯闪烁。
注:该实验需要配合发送实验进行。

单片机源程序如下:
  1. /****************************************Copyright (c)****************************************************
  2. **                                       
  3. **                                 
  4. **
  5. **--------------File Info---------------------------------------------------------------------------------
  6. ** File name:                       
  7. ** Last modified Date:         
  8. ** Last Version:                  
  9. ** Descriptions:                                                       
  10. **--------------------------------------------------------------------------------------------------------
  11. ** Created by:                        FiYu
  12. ** Created date:                2018-2-1
  13. ** Version:                            1.0
  14. ** Descriptions:                nRF24L01无线发射程序(硬件SPI)                                       
  15. **--------------------------------------------------------------------------------------------------------
  16. ** Modified by:                        FiYu
  17. ** Modified date:                               
  18. ** Version:                                  
  19. ** Descriptions:               
  20. ** Rechecked by:                               
  21. **********************************************************************************************************/
  22. /****-----请阅读ReadMe.txt进行实验-----***********/


  23. #include        "STC8.H"
  24. #include "oled.h"
  25. #include  "intrins.h"
  26. #include  "delay.h"
  27. #include  "ADC.h"
  28. #include "NRF24L01.h"
  29. #include "timer.h"
  30.   bit ZF,CJ=0;
  31.         bit kaiqi=0;       
  32.         sbit Rled=P0^7;
  33.         sbit Gled=P0^6;
  34.         sbit Bled=P0^5;
  35. extern bit TIM,JS ;
  36. extern bit LEDK;         
  37. extern uint8  RxPayload[6];   //无线接收缓存
  38. extern uint8  TxPayload[6];   //无线发送缓存
  39. extern uint8 S2;
  40. void moter(uint8 zf,uint8 SD)        ;                                   //  电机驱动函数
  41. void CSZX(uint16 y);
  42. void INT0_init();                //外部中断0的初始化配置       
  43. void INT1_init();
  44. void led(bit x,bit y,bit z);
  45. void OLEDXS(void);
  46. void INT0_int (void) interrupt 0               
  47. {               
  48.      
  49.                 delay_ms(150);
  50.         if(P3^2==0)
  51.                 {
  52.                         kaiqi=~kaiqi;
  53.                 }
  54.        
  55.         }

  56. void INT1_int (void) interrupt 2               
  57. {               
  58.                 delay_ms(150);
  59.           if(P3^3==0){CJ=~CJ;}               
  60. }

  61. /***************************************************************************
  62. * 描  述 : 主函数
  63. * 入  参 : 无
  64. * 返回值 : 无
  65. **************************************************************************/
  66. int main()         
  67. {   
  68.                 uint16 n1=0;
  69.     bit M1=1;       
  70.                 TxPayload[0] = 0x5A;
  71.                 TxPayload[3] = 0xA5;
  72.                 OLED_Init() ;  
  73.                 delay_ms(20);                               
  74.                  OLEDXS();
  75.                 Init_NRF24L01_MA();                  //初始化
  76.                 Set_TxMode_MA();                                                  //配置nRF24L01为发送模式       
  77.           delay_ms(20);
  78.                 INT0_init();
  79.           INT1_init();
  80.     Timer1Init();
  81.                 EA=1;
  82.                 ADC_config();

  83.   while(1)
  84.   {
  85.         if(CJ==0&&kaiqi==0){led(1,1,1); led(0,1,1);Set_TxMode_MA();              //第0模式    发送停止不接受
  86.             while(CJ==0&&kaiqi==0){
  87.                         ADC1();                                //读取AD的值
  88.                         ADC2();               
  89.                         if(kaiqi==0&&LEDK==1)
  90.                         {
  91.                                 Rled=~Rled;                                                
  92.                                 TxPayload[0] = 0x5A;       
  93.                                 TxPayload[1] = 50;       
  94.                                 TxPayload[2] = 50;       
  95.                                 TxPayload[3] = 0xA5;       
  96.                                 TxPayload[4] = 0;       
  97.                                 NRF24L01_TxPacket_MA(TxPayload);            //发送校验码
  98.                                 NRF24L01_TxPacket_MA(TxPayload+1);          //发送数据               
  99.                                 NRF24L01_TxPacket_MA(TxPayload+2);    //发送数据
  100.                                 NRF24L01_TxPacket_MA(TxPayload+3);    //发送校验码
  101.                                 NRF24L01_TxPacket_MA(TxPayload+4);    //发送启动标志位

  102.                                 LEDK=0;
  103.                         }       
  104.                 }
  105.         }
  106.                        
  107. if(kaiqi==0&&CJ==1){led(1,0,1);                 //第1模式  接收和发送停止信号
  108.         while(CJ==1&&kaiqi==0){
  109.                         if(JS==1){Set_TxMode_MA();  
  110.             while(JS){        led(1,0,1);       
  111.                         ADC1();                                //读取AD的值
  112.                         ADC2();               
  113.                         TxPayload[1] = 50;       
  114.                         TxPayload[2] = 50;                               
  115.                         TxPayload[4] = 1;       
  116.           
  117.                         NRF24L01_TxPacket_MA(TxPayload);            //发送校验码
  118.                         NRF24L01_TxPacket_MA(TxPayload+1);          //发送数据               
  119.                         NRF24L01_TxPacket_MA(TxPayload+2);    //发送数据
  120.                         NRF24L01_TxPacket_MA(TxPayload+3);    //发送校验码
  121.                         NRF24L01_TxPacket_MA(TxPayload+4);    //发送启动标志位
  122.                         CSZX(70+20*TxPayload[1]/50);          //使控制超声波的舵机转到中间位置
  123.                                
  124.                                 if(TxPayload[2]<48)moter(0,(49-TxPayload[2])*80/45);   //用OLED显示控制电机的PWM值  这里最大是80,可以修改到90以上,但不能是100,因为AD的波动值会直接超过一百
  125.                                          else if(TxPayload[2]<52)   moter(2,0);              //防止AD波动造成误启动
  126.                                                                 else  moter(1,(TxPayload[2]-52)*80/45);                                //正转PWM值                       
  127.                 }
  128.         }                       
  129.                          if(JS==0){        Set_RxMode_MA();
  130.                         while(!JS){
  131.                   if(NRF24L01_RxPacket_MA(RxPayload) == RX_OK)          //如果接收成功
  132.                         {
  133.                         if(RxPayload[0] == 0x04)                                                                     //检验校验码
  134.                         {                               
  135.                         while( !(NRF24L01_RxPacket_MA(RxPayload+1)==RX_OK));                                //等待接收数据
  136.                          while( !(NRF24L01_RxPacket_MA(RxPayload+2)==RX_OK));                                //等待接收数据
  137.                                 while( !(NRF24L01_RxPacket_MA(RxPayload+3)==RX_OK));                        //检验校验码
  138.                         }
  139.                
  140.                         if(RxPayload[0] == 0x04 && RxPayload[3] == 0x05 )                 //符合校验码的值 ,则中间的数据是正确的,不然乱码,错位的数据就不对
  141.                                 {
  142.                                 n1= RxPayload[1]*256+RxPayload[2];
  143.                                         if(n1>=4000) LCD_P8x16Str(64, 6,"---.-");
  144.                                 if(n1/1000==0) OLED_ShowChar(64,6,' ');
  145.                                          else OLED_ShowChar(64,6,' '+16+n1/1000);
  146.                                                                 OLED_ShowChar(72,6,' '+16+n1%1000/100);
  147.                                                                 OLED_ShowChar(80,6,' '+16+n1%1000%100/10);
  148.                                                                 OLED_ShowChar(88,6,'.');       
  149.                                                                 OLED_ShowChar(96,6,' '+16+n1%1000%100%10);
  150.                                                                 RxPayload[0] = 0;
  151.                                                                 RxPayload[1] = 0;
  152.                                                                 RxPayload[2] = 0;
  153.                                                                 RxPayload[3] = 0;                               
  154.                                                                 }
  155.                                                         }
  156.                                                 }
  157.                                         }
  158.                                 }
  159.                         }
  160.        
  161. if(kaiqi==1&&CJ==0){ led(1,1,1);    led(1,1,0);         //第二模式  只发送不接收
  162.     Set_TxMode_MA();
  163. while(CJ==0&&kaiqi==1){
  164.                         ADC1();                                //读取AD的值
  165.                         ADC2();                    
  166.                         TxPayload[4] =2;          
  167.                         NRF24L01_TxPacket_MA(TxPayload);            //发送校验码
  168.                         NRF24L01_TxPacket_MA(TxPayload+1);          //发送数据               
  169.                         NRF24L01_TxPacket_MA(TxPayload+2);    //发送数据
  170.                         NRF24L01_TxPacket_MA(TxPayload+3);    //发送校验码
  171.                         NRF24L01_TxPacket_MA(TxPayload+4);    //发送启动标志位
  172.        
  173.                         CSZX(70+20*TxPayload[1]/50);          //使控制超声波的舵机转到中间位置               
  174.                                 if(TxPayload[2]<48)moter(0,(49-TxPayload[2])*80/45);   //用OLED显示控制电机的PWM值  这里最大是80,可以修改到90以上,但不能是100,因为AD的波动值会直接超过一百
  175.                                          else if(TxPayload[2]<52)   moter(2,0);              //防止AD波动造成误启动
  176.                                                                 else  moter(1,(TxPayload[2]-52)*80/45);                                //正转PWM值               
  177.                 }
  178.         }

  179. if(kaiqi==1&&CJ==1){led(1,1,1);}
  180. //if(kaiqi==1&&CJ==1){led(1,1,1);                 //第3模式  接收和发送
  181. //        while(CJ==1&&kaiqi==1){       
  182. //               
  183. //                        if(JS==1){Set_TxMode_MA();
  184. //            while(JS){led(0,0,0);
  185. //                        TxPayload[4] = 3;       
  186. //                        ADC1();                                //读取AD的值
  187. //                        ADC2();                            
  188. //                        NRF24L01_TxPacket_MA(TxPayload);            //发送校验码
  189. //                        NRF24L01_TxPacket_MA(TxPayload+1);          //发送数据               
  190. //                        NRF24L01_TxPacket_MA(TxPayload+2);    //发送数据
  191. //                        NRF24L01_TxPacket_MA(TxPayload+3);    //发送校验码
  192. //                        NRF24L01_TxPacket_MA(TxPayload+4);    //发送启动标志位
  193. //                        CSZX(70+20*TxPayload[1]/50);          //使控制超声波的舵机转到中间位置
  194. //                       
  195. //                                if(TxPayload[2]<48)moter(0,(49-TxPayload[2])*80/45);   //用OLED显示控制电机的PWM值  这里最大是80,可以修改到90以上,但不能是100,因为AD的波动值会直接超过一百
  196. //                                         else if(TxPayload[2]<52)   moter(2,0);              //防止AD波动造成误启动
  197. //                                                                else  moter(1,(TxPayload[2]-52)*80/45);                                //正转PWM值               
  198. //                }               
  199. //                       
  200. //                        if(JS==0){        Set_RxMode_MA();        led(1,1,1);
  201. //                        while(!JS){       
  202. //                  if(NRF24L01_RxPacket_MA(RxPayload) == RX_OK)          //如果接收成功
  203. //                        {
  204. //                        if(RxPayload[0] == 0x04)                                                                     //检验校验码
  205. //                        {                               
  206. //                        while( !(NRF24L01_RxPacket_MA(RxPayload+1)==RX_OK));                                //等待接收数据
  207. //                         while( !(NRF24L01_RxPacket_MA(RxPayload+2)==RX_OK));                                //等待接收数据
  208. //                                while( !(NRF24L01_RxPacket_MA(RxPayload+3)==RX_OK));                        //检验校验码
  209. //                        }
  210. //               
  211. //                        if(RxPayload[0] == 0x04 && RxPayload[3] == 0x05 )                 //符合校验码的值 ,则中间的数据是正确的,不然乱码,错位的数据就不对
  212. //                                {
  213. //                                n1= RxPayload[1]*256+RxPayload[2];
  214. //                                        if(n1>=5500) LCD_P8x16Str(56, 6,"---.-");
  215. //                                if(n1/1000==0) OLED_ShowChar(64,6,' ');
  216. //                                         else OLED_ShowChar(64,6,' '+16+n1/1000);
  217. //                                                                OLED_ShowChar(72,6,' '+16+n1%1000/100);
  218. //                                                                OLED_ShowChar(80,6,' '+16+n1%1000%100/10);
  219. //                                                                OLED_ShowChar(88,6,'.');       
  220. //                                                                OLED_ShowChar(96,6,' '+16+n1%1000%100%10);
  221. //                                                                RxPayload[0] = 0;
  222. //                                                                RxPayload[1] = 0;
  223. //                                                                RxPayload[2] = 0;
  224. //                                                                RxPayload[3] = 0;                               
  225. //                                                                }
  226. //                                                        }
  227. //                                                }
  228. //                                        }
  229. //                                }
  230. //                        }
  231. //                }

  232.         }
  233. }



  234. void led(bit x,bit y,bit z)
  235. {
  236.   Rled=x;
  237.         Gled=y;
  238.         Bled=z;
  239. }
  240. void OLEDXS(void)
  241. {                uint8 i;
  242.                 LCD_P8x16Str(56, 2,"X:");       //2.4G模块用了SPI,所以OLED用IIC显示
  243.                 LCD_P8x16Str(0, 2,"Y:");
  244.                 for(i=0;i<8;i++)        //遥控小车——发射
  245.            {
  246.                    LCD_P16x16Ch(i*16,0,i);                   
  247.                  };
  248.                  
  249.                          for(i=8;i<11;i++)
  250.            {
  251.                    LCD_P16x16Ch(i*16-16*8,4,i);        //转向角           控制小车转向的舵机
  252.                  };
  253.                  
  254.                  LCD_P8x16Str(48, 4,":");
  255.                 LCD_P8x16Str(80, 4,"'C");
  256.           LCD_P8x16Str(0, 6,"PWMY:");
  257.                 LCD_P8x16Str(104, 6,"CM");       
  258. }


  259. void moter(uint8 zf,uint8 SD)                                           //  电机驱动函数  
  260. {   uint8 sudu,i;
  261.            sudu=SD;
  262.           ZF=zf;
  263.           
  264.                 OLED_ShowChar(40,6, ' '+16+sudu%100/10);
  265.                 OLED_ShowChar(48,6, ' '+16+sudu%100%10);
  266.        
  267.                         if(zf<1)                           
  268.                         {
  269.                                 for(i=13;i<15;i++)  //反转
  270.                                  {
  271.                                         LCD_P16x16Ch(i*16-16*7,2,i);                   
  272.                                  }           
  273.                         }
  274.                                 else if(zf<2)      //正转
  275.                                         {
  276.                                                 for(i=11;i<13;i++)
  277.                                          {
  278.                                                 LCD_P16x16Ch(i*16-16*5,2,i);                   
  279.                                          };  
  280.                                  }
  281.                                            else {
  282.                                                                          for(i=15;i<17;i++)  //停转
  283.                                                                  {
  284.                                                                         LCD_P16x16Ch(i*16-16*9,2,i);                   
  285.                                                                  }
  286.                                                  }
  287.                                
  288.    
  289.                  
  290. }
  291. void CSZX(uint16 y)                  //超声波初值显示函数  ,没加可屏蔽
  292. {               
  293.                 uint8 yy;
  294.            yy=y;       
  295.             
  296.                 OLED_ShowChar(56,4,' '+16+yy/100);
  297.                 OLED_ShowChar(64,4,' '+16+yy%100/10);
  298.                 OLED_ShowChar(72,4,' '+16+yy%100%10);
  299.                                
  300. }
  301. void INT0_init()                //外部中断0的初始化配置       
  302. {
  303.         IE0  = 0;               //将INT0中断请求标志位清"0"
  304.         EX0 = 1;               //使能INT0中断允许位
  305.         IT0 = 1;                   //选择INT0为上升沿或下降沿触发方式          1为下降沿,0为上升沿

  306. }

  307. void INT1_init()
  308. {
  309.                                                                                 //外部中断1的初始化配置
  310.         IE1  = 0;                //将INT1中断请求标志位清"0"
  311.         EX1 = 1;                //使能INT1中断允许位
  312.         IT1 = 1;                      //选择INT1为下降沿触发方式           1为下降沿,0为上升沿                  
  313. }
复制代码

所有资料51hei提供下载:
PCB 图.zip (55.86 KB, 下载次数: 74)
遥控小车PCB版.zip (4.38 MB, 下载次数: 103)




评分

参与人数 2黑币 +65 收起 理由
shineyunze978 + 15 赞一个!
admin + 50 共享资料的黑币奖励!

查看全部评分

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

使用道具 举报

沙发
ID:243748 发表于 2019-2-24 20:57 来自手机 | 只看该作者
好资料,希望能用得七
回复

使用道具 举报

板凳
ID:260743 发表于 2019-4-28 15:44 | 只看该作者
PCB封装库不全,根本打不开,文件大小才5KB
回复

使用道具 举报

地板
ID:310993 发表于 2021-3-30 01:41 | 只看该作者
15932885***@是高手玩家!编程水平较高!电路板设计也很到位!细节也做的比较到位!只是习惯了51编程,变量名称太随意,说明及关键理解性说明,太少有点可惜了!系统分析师可能会认为,这种习惯不适合做大型程序!但做玩家那是高手!
回复

使用道具 举报

5#
ID:417804 发表于 2021-12-3 16:31 | 只看该作者
请问小车底盘是从哪里弄的啊?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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