Table of contents
Left and right motor speed regulation
The OLED display code part is not given, and this part is more commonly used and easy to obtain, so it is not given. The codes of other parts are given in full, which will not affect the use.
Recommended STM32 learning link:
Bluetooth APP production:
OLED display code:
STM32F103C8T6 delay function and OLED display code_HX091624's Blog-CSDN Blog
1. Motor drive function
Using L298N
IN1, IN2 and IN3, IN4 are paired to control the forward rotation, reverse rotation and stop of the motor, and the two speed control terminals respectively control the speed regulation of the two motors
left and right motor
#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);
}
Left and right motor speed regulation
#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(); //右电机停止
}
2. Output comparison (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);
}
3. Bluetooth code
Using 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);
}
}
Fourth, the main function
#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); //显示速度
}
}
Summarize
Introduction and usage of power supply and L298N:
https://blog.csdn.net/m0_47278454/article/details/117792924
The 12V power supply can choose 18650 lithium battery
I hope you will leave a lot of comments. If you have any questions, you can leave a message in the comment area. If you need the source code, you can leave a QQ mailbox.