STM32F103C8T6蓝牙智能小车

目录

一、电机驱动函数

左右电机

左右电机调速

二、输出比较(PWM)

三、蓝牙代码

四、主函数

总结


OLED显示屏代码部分没有给出,该部分较为常用和容易获取就不给出了 ,其他部分的代码都完整给出了,不影响使用。

推荐STM32学习链接:

[9-6] FlyMcu串口下载&STLINK Utility_哔哩哔哩_bilibili[9-6] FlyMcu串口下载&STLINK Utility是STM32入门教程-2022持续更新中的第29集视频,该合集共计29集,视频收藏或关注UP主,及时了解更多相关视频内容。https://www.bilibili.com/video/BV1th411z7sn/?p=29&vd_source=ed36b2700bbc2bac7746c270bc391540

 蓝牙APP制作:

蓝牙APP制作(App inventor开发APP、AT指令配置蓝牙模块)_哔哩哔哩_bilibili软件:xcom、App inventor工具:CH340、HC05蓝牙模块讲解内容:App inventor开发APP流程、AT指令配置蓝牙模块及一些简单的AT指令, 视频播放量 54472、弹幕量 81、点赞数 1169、投硬币枚数 850、收藏人数 2866、转发人数 623, 视频作者 初明忆冥, 作者简介 PPT和代码仓库:https://gitee.com/hello-nccya学到了好东西就会发出来,相关视频:【蓝牙APP】第一期:AT指令配置蓝牙模块HC05;APP按下按钮发送数据,自制安卓App,APP inventor基本操作介绍,一个简易app的制作过程,App Inventor制作蓝牙控制app,蓝牙APP2(APP接收蓝牙发送的数据并显示),Wifi模块--esp8266(AT指令版本),串口蓝牙app的制作,STM32第四次培训(串口),【蓝牙APP】第三期:计时器的使用,APP接收数据进行显示,STM32第七次培训(舵机:PWM),STM32应用(蓝牙APP控制电机转速转向)https://www.bilibili.com/video/BV1Cy4y1h7ma/?spm_id_from=333.1007.top_right_bar_window_default_collection.content.click

OLED显示屏代码:

 STM32F103C8T6延时函数和OLED显示屏代码_HX091624的博客-CSDN博客

一、电机驱动函数

使用的是L298N

IN1、IN2和IN3、IN4两两一对控制电机的正转、反转和停止,两个调速端分别控制两个电机调速

左右电机

#include "stm32f10x.h"                 
#include "PWM.h"

void Motor_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//电机控制
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	//控制左电机->PA0 PA1 控制右电机->PA4 PA5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	PWM_Init();
}

//右边电机向前
void Right_moto_go(void)
{
	//正转
	GPIO_SetBits(GPIOA, GPIO_Pin_4);
	GPIO_ResetBits(GPIOA, GPIO_Pin_5);
}
//右边电机向后
void Right_moto_back(void)
{
	//反转
	GPIO_ResetBits(GPIOA, GPIO_Pin_4);
	GPIO_SetBits(GPIOA, GPIO_Pin_5);
}
//右边电机停止
void Right_moto_Stop(void)
{
	//停车
	GPIO_ResetBits(GPIOA, GPIO_Pin_4);
	GPIO_ResetBits(GPIOA, GPIO_Pin_5);
}
//左边电机向前
void Left_moto_go(void)
{
	//正转
	GPIO_SetBits(GPIOA, GPIO_Pin_0);
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
//左边电机向后
void Left_moto_back(void)
{
	//反转
	GPIO_ResetBits(GPIOA, GPIO_Pin_0);
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
//左边电机停止
void Left_moto_Stop(void)
{
	//停车
	GPIO_ResetBits(GPIOA, GPIO_Pin_0);
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

左右电机调速

#include "stm32f10x.h"                  // Device header
#include "Motor.h"
#include "PWM.h"

//小车调速函数
void Speed_Control(uint16_t Compare)
{
	Compare*=200; //100->20000
	PWM_SetCompare1(Compare); //调速
	PWM_SetCompare2(Compare);
}

//小车前进函数
void  run(uint16_t Compare)          //小车前进函数
{
	Speed_Control(Compare);
	Left_moto_go();      //左电机往前
	Right_moto_go();       //右电机往前
}

//小车后退函数
void  backrun(uint16_t Compare)      //小车后退函数
{
	Speed_Control(Compare);
	Left_moto_back();      //左电机往后
	Right_moto_back();     //右电机往后
}

//小车左转函数
void  leftrun(uint16_t Compare)      //小车左转函数
{	 
	Speed_Control(Compare);
	Left_moto_back();      //左电机往后
	Right_moto_go();       //右电机往前
}

//小车右转函数
void  rightrun(uint16_t Compare)     //小车右转函数
{ 
	Speed_Control(Compare);
	Right_moto_back();     //右电机向后
	Left_moto_go();        //左电机向前
}

//小车左倒车函数
void leftback(uint16_t Compare)
{	 
	Speed_Control(Compare);
	Left_moto_go();      		//左电机往前
	Right_moto_back();       	//右电机往后
}

//小车右倒车函数
void rightback(uint16_t Compare)
{
	Speed_Control(Compare);
	Right_moto_go();     		//右电机向前
	Left_moto_back();        	//左电机向后
}

//小车停车函数
void  stop(void)         //小车停车函数
{   	
	Left_moto_Stop();      //左电机停止
	Right_moto_Stop();     //右电机停止
}

二、输出比较(PWM)

#include "stm32f10x.h"                  // Device header
//定时器3PWM调速  周期20MS  计一个数->1US
void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	//电动机PWM输出 PA6 PA7
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//舵机PWM输出 PB0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM3);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC1Init(TIM3, &TIM_OCInitStructure); //PWM输出引脚
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);
	TIM_OC3Init(TIM3, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM3, ENABLE);
}
//左右电机输出比较
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM3, Compare);
}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM3, Compare);
}

三、蓝牙代码

使用的是JDY-31

#include "stm32f10x.h"              

uint8_t Serial_RxData;
uint8_t Serial_RxFlag;

void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	//串口波形空闲状态是高电平,所以不使用下拉输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送和接受
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &USART_InitStructure);
	//查询的流程是,在主函数里不断判断RXNE标志位,置1说明接受到数据了
	//再调用ReceiveData,读取DR寄存器  自动清除标志位
	//接受需要中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//RXNE的中断
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1, ENABLE);
}

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

uint8_t Serial_GetRxFlag(void)
{
	if (Serial_RxFlag == 1)
	{
		Serial_RxFlag = 0;
		return 1;
	}
	return 0;
}

uint8_t Serial_GetRxData(void)
{
	return Serial_RxData;
}
//中断
void USART1_IRQHandler(void)
{
	//目前只支持一个字节的接受
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		Serial_RxData = USART_ReceiveData(USART1);
		Serial_RxFlag = 1;
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

四、主函数

#include "stm32f10x.h"           
#include "OLED.h"
#include "Serial.h"
#include "Motor.h"
#include "MotorRun.h"

uint8_t RxFlag;
uint8_t RxData;
uint16_t Speed=20;

int main(void)
{
	OLED_Init();
	Serial_Init();
	Motor_Init();
	OLED_ShowString(1, 1, "RxData:");
	OLED_ShowString(2, 1, "Speed:");
	
	while (1)
	{
		RxFlag = Serial_GetRxFlag();
		if (RxFlag == 1)
		{
			RxData = Serial_GetRxData();
			Serial_SendByte(RxData);
			switch(RxData)
			{
				case 1:run(Speed);		//前进
					break;
				case 2:backrun(Speed);	//后退
					break;
				case 3:leftrun(Speed);	//左转
					break;
				case 4:rightrun(Speed);	//右转
					break;
				case 5:stop();			//停车
					break;				
			}	
			OLED_ShowNum(1,8,RxData,1);
		}
		OLED_ShowNum (2,7,Speed,2);    	//显示速度
	}
}

总结

关于电源和L298N的介绍和用法:

https://blog.csdn.net/m0_47278454/article/details/117792924

其中的12V电源可以选用18650锂电池

 

希望大家多多留言,有任何问题都可以在评论区留言,需要源代码的可以留下QQ邮箱。 

猜你喜欢

转载自blog.csdn.net/HX091624/article/details/127322994