赞
踩
暑假无聊,手头又有一个闲置的单片机一直放着,就想着做个遥控小车出来,复习一下单片机嵌入式编程。该遥控小车项目参考CSDN博主你就叫我李大帅的文章:STM32智能遥控小车,超详细-附下载直接可以用,双电源跑贼快!。自己在原文的基础上添加了电脑端的控制,然后做了一个安卓定制软件来控制小车。
注:
最终实物图:
硬件方面与李大帅博主的硬件组成差不多:使用两个L298N电机驱动模块驱动四个电机,STM32开发板用来控制这两个电机驱动模块,并通过JDY-31蓝牙透传模块与手机或电脑通信。整体采用两个独立电源分别为单片机和L298N供电。
该模块用于驱动电机,一个L298N可以驱动两个电机,有关L298N模块的讲解可以看这个视频:l298n电机驱动模块 电机正反转 电机调速。下图为L298N与单片机的连接示意图。
左侧L298N:
右侧L298N
说明:
JDY-31这个蓝牙模块属于透明传输模块,意思就是在使用时可以不用关心蓝牙协议的细节,连接好以后可以直接将其当做串口使用。该模块的RXD与TXD连接至单片机的UART接口,连接示意图如下图所示:
说明:
我使用了两块独立电源,4个干电池构成6.5V电压给单片机供电,我所购买的单片机上有DCDC降压芯片,能将6.5V降为3.3V供单片机使用。第二块独立电源由一个12V锂电池提供,为L298N供电。
6.5V电源:
12V电源:
我采用的单片机型号为STM32F407VET6,这个并不是很重要的,使用其他单片机型号找到对应的固件库也能完成这样的功能。
下面部分为程序中主要程序的介绍,详细代码见百度网盘:[下载地址]。
程序结构目录如下:
代码片段:
int main(void) { //设置外部中断优先组 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //各部分的初始化 uart_init(9600); delay_init(168); LED_Init(); Bluetooth_Init(); SPEEDER_Init(); MTR_GPIOInit(); LED0 = 1; //主程序 while(1) { if(BLUTOOTH_STATE) { LED0 = 0; delay_ms(100); LED0 = 1; delay_ms(100); } else { LED0 = 0; MTR_CarBrakeAll(); } } }
代码说明:
代码片段:
#include "bluetooth.h"
#include "delay.h"
void Bluetooth_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOE时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //STATE连接的引脚PE0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//down pull
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE
}
说明:
#define BLUTOOTH_STATE GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_0) //PE0
代码片段:
#include "motor.h" //刹车 void MTR_CarBrakeAll(void){ MTR1_BRAKE; MTR2_BRAKE; MTR3_BRAKE; MTR4_BRAKE; } //前进 void MTR_CarGo(void){ MTR1_ROTA_F; MTR2_ROTA_F; MTR3_ROTA_F; MTR4_ROTA_F; } //后退 void MTR_CarBack(void){ MTR1_ROTA_B; MTR2_ROTA_B; MTR3_ROTA_B; MTR4_ROTA_B; } //顺时针转 void MTR_CarCW(void){ MTR1_ROTA_F; MTR2_ROTA_F; MTR3_ROTA_B; MTR4_ROTA_B; } //逆时针转 void MTR_CarCCW(void){ MTR1_ROTA_B; MTR2_ROTA_B; MTR3_ROTA_F; MTR4_ROTA_F; } //电机驱动控制初始化 void MTR_GPIOInit(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(MTR1_GPIO_CLK|MTR2_GPIO_CLK|MTR3_GPIO_CLK|MTR4_GPIO_CLK,ENABLE);//时钟 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//推挽输出 //电机1 GPIO_InitStructure.GPIO_Pin = MTR1_GPIO_PIN; GPIO_Init(MTR1_GPIO_PORT, &GPIO_InitStructure); //电机2 GPIO_InitStructure.GPIO_Pin = MTR2_GPIO_PIN; GPIO_Init(MTR2_GPIO_PORT, &GPIO_InitStructure); //电机3 GPIO_InitStructure.GPIO_Pin = MTR3_GPIO_PIN; GPIO_Init(MTR3_GPIO_PORT, &GPIO_InitStructure); //电机4 GPIO_InitStructure.GPIO_Pin = MTR4_GPIO_PIN; GPIO_Init(MTR4_GPIO_PORT, &GPIO_InitStructure); //小车刹车 MTR_CarBrakeAll(); }
说明:
代码片段:
#include "sys.h" #include "speeder.h" u16 SPEED_LEVEL = SPEED_LEVEL1; u8 CAR_STATE = STRAIGHT_STATE; //GPIO初始化 static void SPEEDER_GPIO_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(SPEEDER_GPIO_CLK,ENABLE);//时钟 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//推挽输出 //初始化GPIO 将复用的引脚与对应的定时器绑定在一起。 GPIO_InitStructure.GPIO_Pin = SPEEDER_GPIO_PIN; GPIO_Init(SPEEDER_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(SPEEDER_GPIO_PORT,GPIO_PinSource12,GPIO_AF_TIM4); GPIO_PinAFConfig(SPEEDER_GPIO_PORT,GPIO_PinSource13,GPIO_AF_TIM4); GPIO_PinAFConfig(SPEEDER_GPIO_PORT,GPIO_PinSource14,GPIO_AF_TIM4); GPIO_PinAFConfig(SPEEDER_GPIO_PORT,GPIO_PinSource15,GPIO_AF_TIM4); } //定时器初始化 static void SPEEDER_TIM_Init(void){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(GENERAL_TIM_CLK,ENABLE); /*--------------------TIME BASE 结构体初始化-------------------------*/ TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_Period; //自动重装载的值 TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_Prescaler; //预分频值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定时器 TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure); /*--------------------输出比较结构体初始化-------------------*/ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 配置为PWM2模式 计数器值大于occr时输出有效信号 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出通道电平极性配置 有效信号为高电平 TIM_OCInitStructure.TIM_Pulse = SPEED_LEVEL; //比较的值:0 TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure); // 输出比较通道 1 TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); TIM_OCInitStructure.TIM_Pulse = SPEED_LEVEL; TIM_OC2Init(GENERAL_TIM, &TIM_OCInitStructure); // 输出比较通道 2 TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); TIM_OCInitStructure.TIM_Pulse = SPEED_LEVEL; TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure); // 输出比较通道 3 TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); TIM_OCInitStructure.TIM_Pulse = SPEED_LEVEL; TIM_OC4Init(GENERAL_TIM, &TIM_OCInitStructure); // 输出比较通道 4 TIM_OC4PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(GENERAL_TIM,ENABLE); TIM_Cmd(GENERAL_TIM, ENABLE); // 使能定时器 } //整体的使能 void SPEEDER_Init(void){ SPEEDER_GPIO_Init(); SPEEDER_TIM_Init(); CAR_STATE = STRAIGHT_STATE; } //向右转 void SET_RIGHT_TURN(void){ CAR_STATE = RIGHT_STATE; TIM_SetCompare1(GENERAL_TIM,SPEED_LEVEL); TIM_SetCompare2(GENERAL_TIM,SPEED_LEVEL); TIM_SetCompare3(GENERAL_TIM,0); TIM_SetCompare4(GENERAL_TIM,0); } //向左转 void SET_LEFT_TURN(void){ CAR_STATE = LEFT_STATE; TIM_SetCompare1(GENERAL_TIM,0); TIM_SetCompare2(GENERAL_TIM,0); TIM_SetCompare3(GENERAL_TIM,SPEED_LEVEL); TIM_SetCompare4(GENERAL_TIM,SPEED_LEVEL); } //变直道 void RESET_DIRECTION(void){ CAR_STATE = STRAIGHT_STATE; TIM_SetCompare1(GENERAL_TIM,SPEED_LEVEL); TIM_SetCompare2(GENERAL_TIM,SPEED_LEVEL); TIM_SetCompare3(GENERAL_TIM,SPEED_LEVEL); TIM_SetCompare4(GENERAL_TIM,SPEED_LEVEL); } //根据当前的小车状态将当前的速度等级赋值到对应的定时器中。 static void RESET_SPEED_LEVEL(void){ switch(CAR_STATE){ case STRAIGHT_STATE: RESET_DIRECTION(); break; case LEFT_STATE: SET_LEFT_TURN(); break; case RIGHT_STATE: SET_RIGHT_TURN(); break; } } //变速:加速 void SPEED_UP(void){ switch(SPEED_LEVEL){ case SPEED_LEVEL0: SPEED_LEVEL = SPEED_LEVEL1; break; case SPEED_LEVEL1: SPEED_LEVEL = SPEED_LEVEL2; break; case SPEED_LEVEL2: SPEED_LEVEL = SPEED_LEVEL3; break; case SPEED_LEVEL3: SPEED_LEVEL = SPEED_LEVEL3; break; } RESET_SPEED_LEVEL(); } //变速:减速 void SPEED_DOWN(void){ switch(SPEED_LEVEL){ case SPEED_LEVEL0: SPEED_LEVEL = SPEED_LEVEL0; break; case SPEED_LEVEL1: SPEED_LEVEL = SPEED_LEVEL0; break; case SPEED_LEVEL2: SPEED_LEVEL = SPEED_LEVEL1; break; case SPEED_LEVEL3: SPEED_LEVEL = SPEED_LEVEL2; break; } RESET_SPEED_LEVEL(); }
说明:
代码部分:
void USART1_IRQHandler(void) //串口1中断服务程序 { uint8_t CMD = 0;//接收的命令 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){ USART_ClearFlag(USART1,USART_FLAG_RXNE); USART_ClearITPendingBit(USART1,USART_IT_RXNE); CMD = USART_ReceiveData(USART1);//读取一个字节 switch(CMD){ case 0x00: RESET_DIRECTION(); MTR_CarGo(); printf("forward\r\n"); break; case 0x01: RESET_DIRECTION(); MTR_CarBack(); printf("back\r\n"); break; case 0x02: SET_RIGHT_TURN(); printf("right turn\r\n"); break; case 0x03: SET_LEFT_TURN(); printf("left turn\r\n"); break; case 0x04: MTR_CarCW(); printf("right CW\r\n"); break; case 0x05: MTR_CarCCW(); printf("left CW\r\n"); break; case 0x06://==================加速 SPEED_UP(); printf("speed up\r\n"); break; case 0x07://===================减速 SPEED_DOWN(); printf("speed down\r\n"); break; case 0x0a: RESET_DIRECTION(); printf("reset straight\r\n"); break; case 0xff: MTR_CarBrakeAll(); printf("stop\r\n"); break; case 0x1f: //================ 测试连接 printf("connect successfully"); break; } } }
说明:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。