单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 239|回复: 0
收起左侧

DIY一辆智能电磁循迹小车(提供原理图和PCB STM32程序)

[复制链接]
魔术快斗 发表于 2019-12-1 21:08 | 显示全部楼层 |阅读模式
近期为了迎接校赛,折腾了很久搞了一辆电磁循迹小车,现在决定将小车的资料开源。楼主目前还是小白,大佬勿喷,欢迎大家参考和下载。
59BDE612A05D376C54131C66CF55B42C.jpg

小车采用三轮车结构,前驱,驱动部分为2个步进电机,驱动模块是A4988,电源采用2节3000mAH的松下18650锂电池,续航开源达到2-3小时。A4988模块供电电压为12V,所以板载集成了一个XL6009升压电路,电压升至12V,电源部分还有2个低压LDO,提供5V和3.3V电源,分别共给电磁循迹模块和单片机等等。XL6009升压电路有点小毛病,建议大家修改一下。
862CC9F20BEFE594FD0B27B0A0BC6771.jpg



57C200C46D3C745CFFF759A56C4D63CC.jpg



IMG_20191105_165128.jpg

底盘是咸鱼收的二手平衡小车之家底盘,然后自己找了2个42步进电机。
3.jpg

原理图和PCB大家可以参考参考,板载有集成2片TP4056X充电芯片,这样可以方便充电,不至于每次都要取出来用专门的充电器充电。至于为什么要用2片TP4056X并联,是因为电池容量较大,单片TP4056X充电电流只有1A,充满需要6小时,实在是太久了。
D26C1PT575EF(}15{6((DTT.png



%C@A_TX[M2RHG~JGZ{JHKRO.png

前期时间比较赶,而且是抱着划水的态度,程序比较Low,仅供参考。

单片机源程序如下:
  1. #include "led.h"
  2. #include "delay.h"
  3. #include "sys.h"
  4. #include "usart.h"
  5. #include "oled.h"
  6. #include "pwm.h"
  7. #include "key.h"
  8. #include "adc.h"
  9. #include "timer.h"
  10. #include "flash.h"

  11.        

  12. #define FLASH_START_ADDR  0x0801f000          //写入的起始地址

  13. u8 t=0,flag=0,valu;
  14. u16 pwm=15000,adc_1,adc_2,adc_3,adc_4,adc_5,adc_6;
  15. void ADC_display();         //ADC采集界面
  16. void PWM_speed();                      //PWM参数
  17. void ADC_collection();                //ADC采集
  18. void MOTOR_different();         //步进电机差速       
  19. void way();                 //寻迹
  20. int main(void)
  21. {       

  22.         delay_init();             //延时初始化
  23.         uart_init(9600);                 //串口初始化为9600
  24.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
  25.         LED_Init();                                //初始化与LED连接的硬件接口
  26.         KEY_Init();
  27.         Adc_Init();                                  //ADC初始化
  28.         OLED_Init();                        //初始化OLED          
  29. //        pwm = FLASH_R(FLASH_START_ADDR);//从指定页的地址读FLASH
  30.          
  31.     TIM3_Int_Init(4999,7199);//10Khz的计数频率,计数到5000为500ms  
  32.          
  33. //        TIM4_PWM_Init(pwm,0);//不分频。PWM频率=72000/(899+1)=80Khz
  34. //        TIM_SetCompare3(TIM4,pwm/2);            
  35. //       
  36. //        TIM5_PWM_Init(pwm,0);//不分频。PWM频率=72000/(899+1)=80Khz
  37. //        TIM_SetCompare2(TIM5,pwm/2);       
  38.          
  39.         DIR1=0;
  40.         ENA1=0;           //左轮
  41.         ENA2=0;
  42.         DIR2=1;    //右轮
  43.        
  44.        
  45.        
  46.          
  47.         OLED_Show_Font_16x16(0,00,8);
  48.         OLED_Show_Font_16x16(0+16,00,9);
  49.         OLED_Show_Font_16x16(0,16,10);
  50.         OLED_Show_Font_16x16(0+16,16,11);
  51.         OLED_Show_Font_16x16(0+32,16,12);   
  52.         OLED_Show_Font_16x16(0+48,16,13);       
  53.         OLED_ShowString(0+64,16,"......",16);  //系统初始化界面
  54.         OLED_Refresh_Gram();      //更新显示到OLED
  55.         delay_ms(500);
  56.         for(valu=0;valu<128;valu++)                                  //加载系统读条
  57.         {
  58.                 valu++;
  59.                 OLED_Fill(0,48,valu,64,1);   
  60.                 delay_ms(10);
  61.         }
  62.        

  63.                 while(1)
  64.                 {
  65.                         way();              //寻迹
  66.                        
  67.                 }

  68. }

  69. void ADC_display()
  70. {
  71.        
  72.         if(flag==0)
  73.         {
  74.                 OLED_Clear();       //清屏
  75.                 OLED_ShowString(5,0," ADC",24);  
  76.                 OLED_Show_Font_24x24(0+58,00,7);   
  77.                 OLED_Show_Font_24x24(0+80,00,8);                //显示ADC采集 字样
  78.                 OLED_ShowString(0,24,"CH1:       CH2:",12);  
  79.                 OLED_ShowString(0,38,"CH3:       CH4:",12);  
  80.                 OLED_ShowString(0,52,"CH5:       CH6:",12);  
  81.                 OLED_Refresh_Gram();      //更新显示到OLED         
  82.                 flag=1;     //标志位置1
  83.         }
  84.        
  85.        
  86. //        while(1)
  87. //        {
  88.                
  89.                 OLED_ShowNum(28,24, adc_1,4,12);    //ADC值
  90.                 OLED_ShowNum(100,24,adc_2,4,12);    //ADC值
  91.                 OLED_ShowNum(28,38, adc_3,4,12);    //ADC值
  92.                 OLED_ShowNum(100,38,adc_4,4,12);    //ADC值
  93.                 OLED_ShowNum(28,52, adc_5,4,12);    //ADC值
  94.                 OLED_ShowNum(100,52,adc_6,4,12);    //ADC值
  95.             OLED_Refresh_Gram();       //更新显示到OLED
  96.                 LED0=!LED0;
  97.                
  98.                 t=KEY_Scan(0);
  99. //            if(t==KEY2_PRES)
  100. //                PWM_speed();
  101. //        }
  102.        
  103. }

  104. void PWM_speed()
  105. {
  106.         u16 a,r,p;
  107.        
  108.         OLED_Clear();        //清屏
  109.         OLED_ShowString(5,0," PWM",24);         
  110.         OLED_Show_Font_24x24(0+56,00,9);                       
  111.         OLED_Show_Font_24x24(0+80,00,10);                        //显示PWM参数 字样
  112.         OLED_ShowString(0,24, "PWM CCRx:",16);  
  113.         OLED_ShowString(0,40,"Pulse:       Hz",12);  
  114.         OLED_ShowString(0,52,"Speed:       r/min",12);  
  115.        
  116.         OLED_ShowNum(70,24,pwm,5,16);  //pwm CCRx值    恢复上一次退出前的值
  117.         OLED_ShowNum(40,40,p,5,12);    //脉冲速度
  118.         OLED_ShowNum(45,52,r,3,12);    //电机转速
  119.         OLED_Refresh_Gram();       //更新显示到OLED                
  120.    

  121. //        while(1)
  122. //        {       

  123.    
  124.         t=KEY_Scan(0);                //得到键值
  125.                 switch(t)
  126.                 {                                 
  127.                         case KEY0_PRES:
  128.                                 pwm=pwm-500;   //6000-50000
  129.                                         if(pwm<=6000)
  130.                                                 pwm=6000;
  131.                                         p=(72000000/pwm);
  132.                                         r=((p*60)/3200);
  133.                                 TIM4_PWM_Init(pwm,0);
  134.                             TIM_SetCompare3(TIM4,pwm/2);
  135.                                 TIM5_PWM_Init(pwm,0);
  136.                             TIM_SetCompare2(TIM5,pwm/2);
  137.                                 OLED_ShowNum(70,24,pwm,5,16);  //pwm CCRx值
  138.                             OLED_ShowNum(40,40,p,5,12);    //脉冲速度
  139.                             OLED_ShowNum(45,52,r,3,12);    //电机转速
  140.                             OLED_Refresh_Gram();  //更新显示到OLED
  141.                         //        FLASH_W(FLASH_START_ADDR,pwm); //从指定页的地址写入FLASH
  142.                                 break;
  143.                         case KEY1_PRES:
  144.                                 pwm=pwm+500;
  145.                                         if(pwm>=50000)
  146.                                                 pwm=50000;
  147.                                         p=(72000000/pwm);
  148.                                         r=((p*60)/3200);
  149.                                 TIM4_PWM_Init(pwm,0);
  150.                             TIM_SetCompare3(TIM4,pwm/2);
  151.                                 TIM5_PWM_Init(pwm,0);
  152.                             TIM_SetCompare2(TIM5,pwm/2);
  153.                                 OLED_ShowNum(70,24,pwm,5,16);
  154.                             OLED_ShowNum(40,40,p,5,12);
  155.                             OLED_ShowNum(45,52,r,3,12);
  156.                                 OLED_Refresh_Gram();//更新显示到OLED
  157.                         //        FLASH_W(FLASH_START_ADDR,pwm); //从指定页的地址写入FLASH
  158.                                 break;
  159.                         case KEY2_PRES:                               
  160.                                 ADC_display();
  161.                                 break;
  162.                         default:
  163.                                 delay_ms(10);       
  164. //                }
  165. //                OLED_ShowChar(36,52,t,12,1);//显示ASCII字符       
  166. //                OLED_ShowNum(94,52,t,3,12);        //显示ASCII字符的码值   
  167. //                OLED_ShowNum(36,52,t,3,12);        //显示ASCII字符的码值   
  168. //                OLED_Refresh_Gram();//更新显示到OLED

  169.         }          
  170. }

  171. void ADC_collection()
  172. {
  173.         adc_1=Get_Adc_Average(ADC_Channel_7,10);  //得到ADC采集值  CH7
  174.         adc_2=Get_Adc_Average(ADC_Channel_6,10);  //得到ADC采集值  CH6
  175.         adc_3=Get_Adc_Average(ADC_Channel_5,10);  //得到ADC采集值  CH5
  176.         adc_4=Get_Adc_Average(ADC_Channel_4,10);  //得到ADC采集值  CH4
  177.         adc_5=Get_Adc_Average(ADC_Channel_3,10);  //得到ADC采集值  CH3
  178.         adc_6=Get_Adc_Average(ADC_Channel_2,10);  //得到ADC采集值  CH2
  179. }

  180. void MOTOR_different()
  181. {
  182.         OLED_Show_Font_16x16(16,00,0);
  183.         OLED_Show_Font_16x16(16+16,00,1);
  184.         OLED_Show_Font_16x16(16+32,00,2);
  185.         OLED_Show_Font_16x16(16+48,00,3);
  186.         OLED_Show_Font_16x16(16+64,00,6);
  187.         OLED_Show_Font_16x16(16+80,00,7);
  188.                 while(1)
  189.                 {
  190.                        
  191.                 }
  192. }

  193. void way()
  194. {       
  195.         PWM_speed();
  196.         while(1)
  197.         {
  198.                 ADC_collection();      //ADC信号采集
  199.                 ADC_display();
  200.                
  201.                
  202.                 if(1500<adc_3 && adc_3<3000 && 1500<adc_4 && adc_4<3000)        //直行
  203.                 {
  204.                         if(ENA1==1)
  205.                         {
  206.                                 ENA1=0;           //左轮使能开启
  207.                                 ENA2=0;           //右轮使能开启
  208.                         }
  209.                                 TIM4_PWM_Init(pwm,0);
  210.                                 TIM_SetCompare3(TIM4,pwm/2);
  211.                                 TIM5_PWM_Init(pwm,0);
  212.                                 TIM_SetCompare2(TIM5,pwm/2);
  213.                                
  214.                                 OLED_ShowString(116,0," ",24);
  215.                                 OLED_ShowString(116,0,"M",24);
  216.                                 OLED_Refresh_Gram();//更新显示到OLED
  217.                
  218.                 }
  219.                
  220.                 if(2500<=adc_4 && adc_3<=2000)     //左转弯
  221.                 {
  222.                         if(ENA1==1)
  223.                         {
  224.                                 ENA1=0;           //左轮使能开启
  225.                                 ENA2=0;           //右轮使能开启
  226.                         }
  227.                                 TIM4_PWM_Init(pwm,0);
  228.                                 TIM_SetCompare3(TIM4,pwm/2);
  229.                                 TIM5_PWM_Init(pwm/2,0);
  230.                                 TIM_SetCompare2(TIM5,pwm/4);
  231.                                
  232.                                 OLED_ShowString(116,0," ",24);
  233.                                 OLED_ShowString(116,0,"L",24);
  234.                                 OLED_Refresh_Gram();//更新显示到OLED
  235.                
  236.                 }
  237.                
  238.                 if(adc_4<2000 && 2500<adc_3)     //右转弯
  239.                 {
  240.                         if(ENA1==1)
  241.                         {
  242.                                 ENA1=0;           //左轮使能开启
  243.                                 ENA2=0;           //右轮使能开启
  244.                         }               
  245.                                 TIM4_PWM_Init(pwm/2,0);
  246.                                 TIM_SetCompare3(TIM4,pwm/4);
  247.                                 TIM5_PWM_Init(pwm,0);
  248.                                 TIM_SetCompare2(TIM5,pwm/2);
  249.                                
  250.                                 OLED_ShowString(116,0," ",24);
  251.                                 OLED_ShowString(116,0,"R",24);
  252.                                 OLED_Refresh_Gram();//更新显示到OLED
  253.                
  254.                 }
  255.                
  256.                 if(adc_3<300 && adc_4<300)            //停止
  257.                 {
  258.                         if(ENA1==0)
  259.                         {
  260.                
  261.                                 ENA1=1;           //左轮使能关闭
  262.                                 ENA2=1;           //右轮使能关闭
  263.                                
  264.                         }
  265.                        
  266.                         OLED_ShowString(116,0," ",24);
  267.                         OLED_ShowString(116,0,"S",24);
  268.                         OLED_Refresh_Gram();//更新显示到OLED
  269.                        
  270.                        
  271.                 }
  272.                
  273. //                delay_ms(10);
  274.         }
  275.        
  276. }
复制代码

如果需要了解电磁循迹模块部分,可以添加QQ交流群:734257791,群里会有分享,加群备注:51黑论坛
51hei.png

全部资料51hei下载地址:
原理图PCB.rar (18.35 MB, 下载次数: 5)

评分

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

查看全部评分

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

本版积分规则

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

Powered by 单片机教程网

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