近期为了迎接校赛,折腾了很久搞了一辆电磁循迹小车,现在决定将小车的资料开源。楼主目前还是小白,大佬勿喷,欢迎大家参考和下载。
小车采用三轮车结构,前驱,驱动部分为2个步进电机,驱动模块是A4988,电源采用2节3000mAH的松下18650锂电池,续航开源达到2-3小时。A4988模块供电电压为12V,所以板载集成了一个XL6009升压电路,电压升至12V,电源部分还有2个低压LDO,提供5V和3.3V电源,分别共给电磁循迹模块和单片机等等。XL6009升压电路有点小毛病,建议大家修改一下。
底盘是咸鱼收的二手平衡小车之家底盘,然后自己找了2个42步进电机。
原理图和PCB大家可以参考参考,板载有集成2片TP4056X充电芯片,这样可以方便充电,不至于每次都要取出来用专门的充电器充电。至于为什么要用2片TP4056X并联,是因为电池容量较大,单片TP4056X充电电流只有1A,充满需要6小时,实在是太久了。
前期时间比较赶,而且是抱着划水的态度,程序比较Low,仅供参考。
单片机源程序如下:- #include "led.h"
- #include "delay.h"
- #include "sys.h"
- #include "usart.h"
- #include "oled.h"
- #include "pwm.h"
- #include "key.h"
- #include "adc.h"
- #include "timer.h"
- #include "flash.h"
-
- #define FLASH_START_ADDR 0x0801f000 //写入的起始地址
- u8 t=0,flag=0,valu;
- u16 pwm=15000,adc_1,adc_2,adc_3,adc_4,adc_5,adc_6;
- void ADC_display(); //ADC采集界面
- void PWM_speed(); //PWM参数
- void ADC_collection(); //ADC采集
- void MOTOR_different(); //步进电机差速
- void way(); //寻迹
- int main(void)
- {
- delay_init(); //延时初始化
- uart_init(9600); //串口初始化为9600
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
- LED_Init(); //初始化与LED连接的硬件接口
- KEY_Init();
- Adc_Init(); //ADC初始化
- OLED_Init(); //初始化OLED
- // pwm = FLASH_R(FLASH_START_ADDR);//从指定页的地址读FLASH
-
- TIM3_Int_Init(4999,7199);//10Khz的计数频率,计数到5000为500ms
-
- // TIM4_PWM_Init(pwm,0);//不分频。PWM频率=72000/(899+1)=80Khz
- // TIM_SetCompare3(TIM4,pwm/2);
- //
- // TIM5_PWM_Init(pwm,0);//不分频。PWM频率=72000/(899+1)=80Khz
- // TIM_SetCompare2(TIM5,pwm/2);
-
- DIR1=0;
- ENA1=0; //左轮
- ENA2=0;
- DIR2=1; //右轮
-
-
-
-
- OLED_Show_Font_16x16(0,00,8);
- OLED_Show_Font_16x16(0+16,00,9);
- OLED_Show_Font_16x16(0,16,10);
- OLED_Show_Font_16x16(0+16,16,11);
- OLED_Show_Font_16x16(0+32,16,12);
- OLED_Show_Font_16x16(0+48,16,13);
- OLED_ShowString(0+64,16,"......",16); //系统初始化界面
- OLED_Refresh_Gram(); //更新显示到OLED
- delay_ms(500);
- for(valu=0;valu<128;valu++) //加载系统读条
- {
- valu++;
- OLED_Fill(0,48,valu,64,1);
- delay_ms(10);
- }
-
- while(1)
- {
- way(); //寻迹
-
- }
- }
- void ADC_display()
- {
-
- if(flag==0)
- {
- OLED_Clear(); //清屏
- OLED_ShowString(5,0," ADC",24);
- OLED_Show_Font_24x24(0+58,00,7);
- OLED_Show_Font_24x24(0+80,00,8); //显示ADC采集 字样
- OLED_ShowString(0,24,"CH1: CH2:",12);
- OLED_ShowString(0,38,"CH3: CH4:",12);
- OLED_ShowString(0,52,"CH5: CH6:",12);
- OLED_Refresh_Gram(); //更新显示到OLED
- flag=1; //标志位置1
- }
-
-
- // while(1)
- // {
-
- OLED_ShowNum(28,24, adc_1,4,12); //ADC值
- OLED_ShowNum(100,24,adc_2,4,12); //ADC值
- OLED_ShowNum(28,38, adc_3,4,12); //ADC值
- OLED_ShowNum(100,38,adc_4,4,12); //ADC值
- OLED_ShowNum(28,52, adc_5,4,12); //ADC值
- OLED_ShowNum(100,52,adc_6,4,12); //ADC值
- OLED_Refresh_Gram(); //更新显示到OLED
- LED0=!LED0;
-
- t=KEY_Scan(0);
- // if(t==KEY2_PRES)
- // PWM_speed();
- // }
-
- }
- void PWM_speed()
- {
- u16 a,r,p;
-
- OLED_Clear(); //清屏
- OLED_ShowString(5,0," PWM",24);
- OLED_Show_Font_24x24(0+56,00,9);
- OLED_Show_Font_24x24(0+80,00,10); //显示PWM参数 字样
- OLED_ShowString(0,24, "PWM CCRx:",16);
- OLED_ShowString(0,40,"Pulse: Hz",12);
- OLED_ShowString(0,52,"Speed: r/min",12);
-
- OLED_ShowNum(70,24,pwm,5,16); //pwm CCRx值 恢复上一次退出前的值
- OLED_ShowNum(40,40,p,5,12); //脉冲速度
- OLED_ShowNum(45,52,r,3,12); //电机转速
- OLED_Refresh_Gram(); //更新显示到OLED
-
- // while(1)
- // {
-
- t=KEY_Scan(0); //得到键值
- switch(t)
- {
- case KEY0_PRES:
- pwm=pwm-500; //6000-50000
- if(pwm<=6000)
- pwm=6000;
- p=(72000000/pwm);
- r=((p*60)/3200);
- TIM4_PWM_Init(pwm,0);
- TIM_SetCompare3(TIM4,pwm/2);
- TIM5_PWM_Init(pwm,0);
- TIM_SetCompare2(TIM5,pwm/2);
- OLED_ShowNum(70,24,pwm,5,16); //pwm CCRx值
- OLED_ShowNum(40,40,p,5,12); //脉冲速度
- OLED_ShowNum(45,52,r,3,12); //电机转速
- OLED_Refresh_Gram(); //更新显示到OLED
- // FLASH_W(FLASH_START_ADDR,pwm); //从指定页的地址写入FLASH
- break;
- case KEY1_PRES:
- pwm=pwm+500;
- if(pwm>=50000)
- pwm=50000;
- p=(72000000/pwm);
- r=((p*60)/3200);
- TIM4_PWM_Init(pwm,0);
- TIM_SetCompare3(TIM4,pwm/2);
- TIM5_PWM_Init(pwm,0);
- TIM_SetCompare2(TIM5,pwm/2);
- OLED_ShowNum(70,24,pwm,5,16);
- OLED_ShowNum(40,40,p,5,12);
- OLED_ShowNum(45,52,r,3,12);
- OLED_Refresh_Gram();//更新显示到OLED
- // FLASH_W(FLASH_START_ADDR,pwm); //从指定页的地址写入FLASH
- break;
- case KEY2_PRES:
- ADC_display();
- break;
- default:
- delay_ms(10);
- // }
- // OLED_ShowChar(36,52,t,12,1);//显示ASCII字符
- // OLED_ShowNum(94,52,t,3,12); //显示ASCII字符的码值
- // OLED_ShowNum(36,52,t,3,12); //显示ASCII字符的码值
- // OLED_Refresh_Gram();//更新显示到OLED
- }
- }
- void ADC_collection()
- {
- adc_1=Get_Adc_Average(ADC_Channel_7,10); //得到ADC采集值 CH7
- adc_2=Get_Adc_Average(ADC_Channel_6,10); //得到ADC采集值 CH6
- adc_3=Get_Adc_Average(ADC_Channel_5,10); //得到ADC采集值 CH5
- adc_4=Get_Adc_Average(ADC_Channel_4,10); //得到ADC采集值 CH4
- adc_5=Get_Adc_Average(ADC_Channel_3,10); //得到ADC采集值 CH3
- adc_6=Get_Adc_Average(ADC_Channel_2,10); //得到ADC采集值 CH2
- }
- void MOTOR_different()
- {
- OLED_Show_Font_16x16(16,00,0);
- OLED_Show_Font_16x16(16+16,00,1);
- OLED_Show_Font_16x16(16+32,00,2);
- OLED_Show_Font_16x16(16+48,00,3);
- OLED_Show_Font_16x16(16+64,00,6);
- OLED_Show_Font_16x16(16+80,00,7);
- while(1)
- {
-
- }
- }
- void way()
- {
- PWM_speed();
- while(1)
- {
- ADC_collection(); //ADC信号采集
- ADC_display();
-
-
- if(1500<adc_3 && adc_3<3000 && 1500<adc_4 && adc_4<3000) //直行
- {
- if(ENA1==1)
- {
- ENA1=0; //左轮使能开启
- ENA2=0; //右轮使能开启
- }
- TIM4_PWM_Init(pwm,0);
- TIM_SetCompare3(TIM4,pwm/2);
- TIM5_PWM_Init(pwm,0);
- TIM_SetCompare2(TIM5,pwm/2);
-
- OLED_ShowString(116,0," ",24);
- OLED_ShowString(116,0,"M",24);
- OLED_Refresh_Gram();//更新显示到OLED
-
- }
-
- if(2500<=adc_4 && adc_3<=2000) //左转弯
- {
- if(ENA1==1)
- {
- ENA1=0; //左轮使能开启
- ENA2=0; //右轮使能开启
- }
- TIM4_PWM_Init(pwm,0);
- TIM_SetCompare3(TIM4,pwm/2);
- TIM5_PWM_Init(pwm/2,0);
- TIM_SetCompare2(TIM5,pwm/4);
-
- OLED_ShowString(116,0," ",24);
- OLED_ShowString(116,0,"L",24);
- OLED_Refresh_Gram();//更新显示到OLED
-
- }
-
- if(adc_4<2000 && 2500<adc_3) //右转弯
- {
- if(ENA1==1)
- {
- ENA1=0; //左轮使能开启
- ENA2=0; //右轮使能开启
- }
- TIM4_PWM_Init(pwm/2,0);
- TIM_SetCompare3(TIM4,pwm/4);
- TIM5_PWM_Init(pwm,0);
- TIM_SetCompare2(TIM5,pwm/2);
-
- OLED_ShowString(116,0," ",24);
- OLED_ShowString(116,0,"R",24);
- OLED_Refresh_Gram();//更新显示到OLED
-
- }
-
- if(adc_3<300 && adc_4<300) //停止
- {
- if(ENA1==0)
- {
-
- ENA1=1; //左轮使能关闭
- ENA2=1; //右轮使能关闭
-
- }
-
- OLED_ShowString(116,0," ",24);
- OLED_ShowString(116,0,"S",24);
- OLED_Refresh_Gram();//更新显示到OLED
-
-
- }
-
- // delay_ms(10);
- }
-
- }
复制代码
全部资料51hei下载地址:
原理图PCB.rar
(18.35 MB, 下载次数: 264)
程序.7z
(211.78 KB, 下载次数: 215)
|