
👨💻个人主页 :@开发者-削好皮的Pineapple!
👨💻 hello 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!
👨💻 本文由 削好皮的Pineapple! 原创
👨💻 收录于专栏 :C语言到基于STM32 的智能矿探小车


文章目录
-
- ⭐前言⭐
- 🎶一、模块化编程思维
- 🎶二、直流电机
-
- [2.1 电机驱动模块](#2.1 电机驱动模块)
- 🎶三、小车运动控制代码实现
-
- [3.1 小车控制函数(`car.c`/`car.h`)](#3.1 小车控制函数(
car.c
/car.h
)) - [3.2 程序下载与运行设置](#3.2 程序下载与运行设置)
- [3.3 速度控制](#3.3 速度控制)
- [3.1 小车控制函数(`car.c`/`car.h`)](#3.1 小车控制函数(
⭐前言⭐
今天是实习培训的新一天,学习聚焦于模块化编程思维以及直流电机控制相关知识,包括电机驱动模块的使用、小车运动控制代码的实现以及PWM技术在速度调节中的应用,为后续智能矿探小车的开发进一步夯实基础。
🎶一、模块化编程思维
模块化编程是按照不同功能将程序拆分为对应的源文件(.c)和头文件(.h),以提高代码的可维护性和复用性。
-
源文件(.c) :用于保存函数接口的具体实现。
例如led.c
:cvoid led_init(void) { // 初始化LED的具体代码 } void led_ctrl(...) { // 控制LED的具体代码 }
c
#include "led.h"
#include "stm32f4xx.h"
void LED_Init(void)
{
// 使能GPIOF和GPIOE外设时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOE, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
// 配置GPIOF的LED引脚(D1、D2)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOF, &GPIO_InitStruct);
// 配置GPIOE的LED引脚(D3、D4)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_Init(GPIOE, &GPIO_InitStruct);
// 默认关闭所有LED
GPIO_SetBits(GPIOF, GPIO_Pin_9 | GPIO_Pin_10);
GPIO_SetBits(GPIOE, GPIO_Pin_13 | GPIO_Pin_14);
}
void LED_Control(LEDNUM led_num, LEDSTA state)
{
switch(led_num)
{
case LED_D1:
if(state == LED_ON)
GPIO_ResetBits(GPIOF, GPIO_Pin_9);
else
GPIO_SetBits(GPIOF, GPIO_Pin_9);
break;
case LED_D2:
if(state == LED_ON)
GPIO_ResetBits(GPIOF, GPIO_Pin_10);
else
GPIO_SetBits(GPIOF, GPIO_Pin_10);
break;
case LED_D3:
if(state == LED_ON)
GPIO_ResetBits(GPIOE, GPIO_Pin_13);
else
GPIO_SetBits(GPIOE, GPIO_Pin_13);
break;
case LED_D4:
if(state == LED_ON)
GPIO_ResetBits(GPIOE, GPIO_Pin_14);
else
GPIO_SetBits(GPIOE, GPIO_Pin_14);
break;
}
}
-
头文件(.h) :用于保存函数声明、构造类型定义、全局变量声明等,且需添加防止重复包含的预处理指令。
例如led.h
:c#ifndef _LED_H // 如果未定义_LED_H #define _LED_H // 定义_LED_H,防止头文件重复包含 // 函数声明 void led_init(void); void led_ctrl(...); // 全局变量声明 // 构造类型定义 #endif
c
#ifndef _LED_H
#define _LED_H
#include <stdint.h> // 添加此头文件以使用uint8_t
typedef enum {
LED_D1,
LED_D2,
LED_D3,
LED_D4
} LEDNUM;
typedef enum {
LED_OFF,
LED_ON
} LEDSTA;
void LED_Init(void);
void LED_Control(LEDNUM led_num, LEDSTA state);
#endif
- 常见模块示例 :
delay.c
/delay.h
:实现延时功能,如void delay_ms(uint16_t nms);
(毫秒级延时)、void delay_us(uint16_t us);
(微秒级延时)。
🎶二、直流电机
2.1 电机驱动模块
-
接线说明:
-
两个绿色端子:直接连接直流电机。
-
6个排针:
VCC
:接5V或3.3V(5V驱动时小车力度大,状态改变较难;3.3V驱动时力度小,状态改变相对容易)。GND
:接GND(注意正负极不可接反)。- 控制引脚:
B-1A
、B-1B
用于控制一个电机,A-1A
、A-1B
用于控制另一个电机,具体对应哪个电机需看实物绿色端子的连接。以下是本次实训所用驱动电路板。
引脚依次是:B-1A、B-1B、GND、VCC、A-1A、A-1B
-
-
电机转动原理:直流电机由两个引脚驱动,当两个引脚电平状态不同时电机转动。
- 假设
B-1A
为高电平、B-1B
为低电平时,电机向前转动;则B-1A
为低电平、B-1B
为高电平时,电机向后转动。 - 当
B-1A
和B-1B
均为低电平或均为高电平时,电机停止转动。
- 假设
-
可用GPIO引脚 :在CAMERA处有部分GPIO引脚可用于连接控制,如2脚(GND)、4脚(PD6)、6脚、8脚、10脚...1脚(3V3)、3脚(PB7)、5脚、7脚、9脚...根据原理图(GEC-M4原理图2016-07-29.pdf)可得:
🎶三、小车运动控制代码实现
3.1 小车控制函数(car.c
/car.h
)
- 小车初始化函数:
c
void car_Init(void)
{
//1.时钟使能
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOD , ENABLE);
//2.初始化GPIO ---> 推挽输出模式
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOD, &GPIO_InitStruct);
// 配置GPIOE的LED引脚
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7| GPIO_Pin_6;
GPIO_Init(GPIOB, &GPIO_InitStruct);
//3.默认状态:小车停止
GPIO_SetBits(GPIOD, GPIO_Pin_6 | GPIO_Pin_7);//左
GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);//右
}
- 基本运动控制函数 :
- 前进:
c
int speed = 100;
void car_up(void)
{
//左轮电机前转
GPIO_ResetBits(GPIOD, GPIO_Pin_6 );//A-1B
GPIO_SetBits(GPIOD, GPIO_Pin_7 );// A-1A
//右轮电机前转
GPIO_ResetBits(GPIOB, GPIO_Pin_6 );//B-1A
GPIO_SetBits(GPIOB, GPIO_Pin_7 );//B-1B
delay_ms(speed);
GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);//右
delay_ms(100-speed);
}
- 后退:
c
void car_back(void)
{
//左轮电机后转
GPIO_ResetBits(GPIOD, GPIO_Pin_7 );
GPIO_SetBits(GPIOD, GPIO_Pin_6 );
//右轮电机后转
GPIO_ResetBits(GPIOB, GPIO_Pin_7 );
GPIO_SetBits(GPIOB, GPIO_Pin_6 );
}
- 左转:
c
void car_left(void)
{
//左轮不转 (后转)
GPIO_SetBits(GPIOD, GPIO_Pin_6 | GPIO_Pin_7);
//右轮前进
GPIO_ResetBits(GPIOB, GPIO_Pin_6 );
GPIO_SetBits(GPIOB, GPIO_Pin_7 );
}
- 右转:
c
void car_right(void)
{
//右轮不转 (后转)
GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);
//左轮前进
GPIO_ResetBits(GPIOD, GPIO_Pin_6 );
GPIO_SetBits(GPIOD, GPIO_Pin_7 );
}
- 停止:
c
void car_stop(void)
{
//右轮和左轮子都不转
GPIO_SetBits(GPIOD, GPIO_Pin_6 | GPIO_Pin_7);
GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);
}
3.2 程序下载与运行设置
- 下载程序时 :
BOOT0
接3V3,BOOT1
接GND,按下复位键,CPU执行引导程序,程序可下载到开发板。 - 下载完成后 :
BOOT0
接GND,BOOT1
接GND,重新上电或按复位键,程序重新运行。
3.3 速度控制
-
简单速度调节(上面已经实现):通过控制电机转动与停止的时间比例来调节速度。
cint speed = 100; void car_up(void) { // 左轮电机前转 // 右轮电机前转(右轮速度调节) B-1A = 1; B-1B = 0; // 右轮转动 delay_ms(speed); B-1B = 1; // 右轮停止转动 delay_ms(100 - speed); }
-
PWM(脉冲宽度调制):通过调节有效电平时间与整个周期的比例(占空比)来精确控制电机转速、蜂鸣器鸣叫等。
- 占空比 = 有效电平时间 / 整个周期。
- 例如:有效电平时间50ms,周期100ms,占空比为50%。
- 注意:使用PWM调节的周期不能太长。
-
主函数示例:
cint main() { while(1) { car_up(); // 小车前进 } }
-
练习目标 :调节小车轮子速度,使小车前进1m左右。

结束语🥇
🔥 订阅专栏持续学习:C语言到基于STM32的智能矿探小车
💬 欢迎点赞、收藏、留言讨论,一起攻克嵌入式开发!