C语言模块化编程思维以及直流电机控制(第四天)


👨‍💻个人主页@开发者-削好皮的Pineapple!

👨‍💻 hello 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 削好皮的Pineapple! 原创

👨‍💻 收录于专栏C语言到基于STM32 的智能矿探小车


文章目录


⭐前言⭐

今天是实习培训的新一天,学习聚焦于模块化编程思维以及直流电机控制相关知识,包括电机驱动模块的使用、小车运动控制代码的实现以及PWM技术在速度调节中的应用,为后续智能矿探小车的开发进一步夯实基础。


🎶一、模块化编程思维


模块化编程是按照不同功能将程序拆分为对应的源文件(.c)和头文件(.h),以提高代码的可维护性和复用性。

  • 源文件(.c) :用于保存函数接口的具体实现。
    例如led.c

    c 复制代码
    void 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-1AB-1B用于控制一个电机,A-1AA-1B用于控制另一个电机,具体对应哪个电机需看实物绿色端子的连接。以下是本次实训所用驱动电路板。

        引脚依次是:B-1A、B-1B、GND、VCC、A-1A、A-1B
  • 电机转动原理:直流电机由两个引脚驱动,当两个引脚电平状态不同时电机转动。

    • 假设B-1A为高电平、B-1B为低电平时,电机向前转动;则B-1A为低电平、B-1B为高电平时,电机向后转动。
    • B-1AB-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 速度控制

  • 简单速度调节(上面已经实现):通过控制电机转动与停止的时间比例来调节速度。

    c 复制代码
    int 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调节的周期不能太长。
  • 主函数示例

    c 复制代码
    int main()
    {
      while(1)
      {
        car_up();  // 小车前进
      }
    }
  • 练习目标 :调节小车轮子速度,使小车前进1m左右。

结束语🥇

🔥 订阅专栏持续学习:C语言到基于STM32的智能矿探小车

💬 欢迎点赞、收藏、留言讨论,一起攻克嵌入式开发!

相关推荐
不想学习\??!5 分钟前
STM32-待机唤醒实验
stm32·单片机·嵌入式硬件
晓131312 分钟前
JavaScript基础篇——第五章 对象(最终篇)
开发语言·前端·javascript
不想学习\??!35 分钟前
STM32-中断
单片机·嵌入式硬件
LjQ204044 分钟前
Java的一课一得
java·开发语言·后端·web
阿蒙Amon1 小时前
C#正则表达式全面详解:从基础到高级应用
开发语言·正则表达式·c#
TianYaKe-天涯客1 小时前
嵌入式调试LOG日志输出(以STM32为例)
stm32·单片机·嵌入式硬件
芯岭技术1 小时前
MS32C001-C单片机,32位ARM M0+内核,宽电压、低功耗、小封装。
c语言·arm开发·单片机
CHANG_THE_WORLD2 小时前
「macOS 系统字体收集器 (C++17 实现)」
开发语言·c++·macos
妄想出头的工业炼药师2 小时前
python和C++相互调用使用
开发语言·c++
2301_764441332 小时前
Python管理咨询数据可视化实战:收入分布与顾问利用率双轴对比图表生成脚本
开发语言·python·信息可视化