使用STM32定时器的PWM功能控制电机

news2024/11/24 4:31:52

目录

概述

1  系统框架结构

1.1 框架结构介绍

1.2 STM32 Cube配置PWM参数

2 软件实现

2.1 STM32Cube生成项目

2.2 PWM功能的User函数接口

3 测试

3.1 编写测试函数

3.2 功能测试


概述

本文主要介绍使用STM32定时器TIMER-8功能生成4路PWM,用于控制两路电机的运行状态,笔者使用STM32Cube工具配置定时器的相关参数,用于参数PWM信号,并编写测试函数验证其功能。还是用逻辑分析仪捕捉波形,以验证其控制逻辑是否符合设计需求。

1  系统框架结构

1.1 框架结构介绍

使用定时器TIMER8产生4路PWN控制信号,用于控制电机的正转或者反转

电机-1:

CH1   控制电机驱动器 IN1

CH2   控制电机驱动器 IN2

电机-2:

CH3   控制电机驱动器 IN1

CH4   控制电机驱动器 IN2

1.2 STM32 Cube配置PWM参数

1)配置通道参数,选择TIM8,使能4路PWM信号

其对应的IO接口如下:

GPIO配置参数:

2)配置参数

Prescaler 配置为71,定时器TIM8的基准工作频率为 1 M Hz

Count Mode:  配置为up, 

Counter Period: 9999 , 定时器重载计数周期为 10ms

3) 使能通道, 通道参数选择默认值,工作参数在程序中定义

2 软件实现

2.1 STM32Cube生成项目

完成项目参数配置之后,即可点击STM32Cube 上的GENERATE PROJECT生产项目代码,项目结构如下,在User/Core目录下可以找到tim.c文件,和PWM相关的配置代码如下,这部分代码不需要程序员编写,STM32Cube会自动生成,但作为一名合格的程序员,应该了解该函数具体干了哪些事情。

该程序主要配置了4个结构体:

 1)TIM_ClockConfigTypeDef sClockSourceConfig = {0};

       配置定时器的工作时钟


 2) TIM_MasterConfigTypeDef sMasterConfig = {0};

      配置定时器触发模式


  3)TIM_OC_InitTypeDef sConfigOC = {0};

      配置PWM的相关参数


 4) TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

       配置死锁时间 

/* TIM8 init function */
void MX_TIM8_Init(void)
{

  /* USER CODE BEGIN TIM8_Init 0 */

  /* USER CODE END TIM8_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  /* USER CODE BEGIN TIM8_Init 1 */

  /* USER CODE END TIM8_Init 1 */
  htim8.Instance = TIM8;
  htim8.Init.Prescaler = 71;
  htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim8.Init.Period = 9999;
  htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim8.Init.RepetitionCounter = 0;
  htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim8) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM8_Init 2 */

  /* USER CODE END TIM8_Init 2 */
  HAL_TIM_MspPostInit(&htim8);

}

2.2 PWM功能的User函数接口

1)初始化函数接口

代码53行:停止定时器

代码54~58行:启动对应通道的PWM

代码60~64行:设置对应通道的占空比

函数源代码:

void pwm_ctrl_Init( void )
{
    HAL_TIM_Base_Stop( &htim8 );
    HAL_TIM_PWM_Start( &htim8, TIM_CHANNEL_1);    // PC6 
    HAL_TIM_PWM_Start( &htim8, TIM_CHANNEL_2);    // PC7
    
    HAL_TIM_PWM_Start( &htim8, TIM_CHANNEL_3);    // PC8 
    HAL_TIM_PWM_Start( &htim8, TIM_CHANNEL_4);    // PC9
     
    HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);
    HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
    
    HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);
    HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);
}

 2)启动定时器函数

调用该函数后,定时器启动起来,此时,只需配置占空比就能得到所需的波形

void motor_enable(void)
{
    HAL_TIM_Base_Start( &htim8 );
}

3)工作波形控制函数

该函数通道控制不同通道的输入或者输出信号就能控制电机的正转或者反转,前进或者后退

void Motor_CtrlAct( uint8_t type )
{
     switch( type )
     {
         case IDLE:
             break;
         
         case STOP_RUN:
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
            
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);
            break;
         
         case LEFT_RUN:
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);
            HAL_TIM_SetPWM_Pulse( 2000, TIM_CHANNEL_2);
            
            HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_3);
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);
            break;
         
         case RIGHT_RUN:
            HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_1);
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
            
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);
            HAL_TIM_SetPWM_Pulse( 2000, TIM_CHANNEL_4);
            break;
         
         case UP_RUN:
            HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_1);
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
            
            HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_3);
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_4);
            break;
         
         case DOWN_RUN:
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_1);
            HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_2);
            
            HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_3);
            HAL_TIM_SetPWM_Pulse( 3000, TIM_CHANNEL_4);
            break;
     }
}

3 测试

3.1 编写测试函数

通过串口接收一个指令数据,以控制PWN的信号,命令参数如下:

enum RUN_STATE
{
      IDLE = 0,
      STOP_RUN=1,
     LEFT_RUN,
      RIGHT_RUN,
      UP_RUN,
      DOWN_RUN,
};

在串口的回调函数中,调用上面的函数

详细代码如下:

void protocol_data_recvByte(uint8_t data )
{
    recv_buf[stru_protocl.datCnt++] =  data;
    Motor_CtrlAct( data );
    if( stru_protocl.datCnt >= PROT_FRAME_LEN_RECV)
         stru_protocl.datCnt = 0;
}


void UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    uint8_t data;
    uint32_t isrflags   = READ_REG(huart->Instance->SR);
    uint32_t cr1its     = READ_REG(huart->Instance->CR1);

    if( huart->Instance==USART1 )
    {
        /* UART in mode Receiver -------------------------------------------------*/
        if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
        {
            data = huart->Instance->DR;
            protocol_data_recvByte(data);
        }
        SET_BIT(huart->Instance->CR1, USART_CR1_RXNEIE);
        CLEAR_BIT(huart->Instance->SR, USART_SR_ORE);
    }
}

 3.2 功能测试

使用逻辑分析仪捕捉PWM的波形

1)发送命令:STOP_RUN = 0x01

2)发送命令: LEFT_RUN=0x02

 3)发送命令: RIGHT_RUN=0x03

4)  发送命令: UP_RUN=0x04

5)  发送命令: DOWN_RUN=0x05

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2043883.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

五种Slowing Changing Dimensions(SCD)方法及案例

SCD Type Description Key Features Type 1 Overwriting the existing data with new data, without keeping any history of the previous values. 直接覆盖,不留痕迹 - Overwrites Existing Data - No Historical Data - Simple Implementation Type…

Composerize神器:自动化转换Docker运行命令至Compose配置,简化容器部署流程

Composerize神器:自动化转换Docker运行命令至Compose配置,简化容器部署流程 在现代的微服务架构中,Docker Compose 是管理多容器应用的重要工具,它允许我们通过一个简单的 docker-compose.yml 文件来定义和运行多个关联的容器。然…

重发布实验

一、实验拓扑图 二、实验需求 1.如图搭建网络拓扑,所有路由器各自创建一个环回接口,合理规划IP地址 2.R1-R2-R3-R4-R6之间使用OSPF协议,R4-R5-R6之间使用RIP协议 3.R1环回重发布方式引入OSPF网络 4.R4/R6上进行双点双向重发布 5.分析网络…

CSP-CCF 202012-1 期末预测之安全指数

一、问题描述 二、解答 #include<iostream> using namespace std; int main() {int n;cin >> n;int w[100001] { 0 };int score[100001] { 0 };for (int i 1; i < n; i){cin >> w[i] >> score[i];}int y 0;for (int i 1; i < n; i){y y …

Java——反射(2/4):获取构造器对象并使用(获取类的构造器、并对其进行操作,获取类构造器的作用,代码实例)

目录 获取类的构造器 获取类的构造器、并对其进行操作 代码实例一 代码实例二 获取类构造器的作用 代码示例三 获取类的构造器 获取类的构造器、并对其进行操作 Class提供了从类中获取构造器的方法。 方法说明Constructor<?>[] getConstructors()获取全部构造器…

激光测距传感器

系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 前言一、产品原理&#xff1a;二、产品介绍&#xff1a;三、应用特点四、应用案例&#xff1a;1.冶金钢铁板卷材开卷工…

深入理解JavaScript性能优化:从基础到高级

引言 在当今快速发展的Web世界中,性能已经成为衡量应用质量的关键指标。随着Web应用复杂度的不断提升,JavaScript作为前端开发的核心语言,其性能优化变得尤为重要。本文旨在全面深入地探讨JavaScript性能优化的各个方面,从基础概念到高级技巧,帮助开发者构建高效、流畅的Web应用…

Android Studio本地加速安装gradle

Android Studio本地加速安装gradle 镜像下载依赖本地JAVA-JDK配置阿里云镜像配置环境变量验证gradle项目文件的介绍项目配置gradle项目Gradle-Wrapper加速配置&#xff0c;防止下载失败Gradle的常用命令 镜像下载 腾讯软件镜像源&#xff1a;https://mirrors.cloud.tencent.co…

50ETF期权移仓是什么?50ETF期权移仓要注意什么?

今天带你了解50ETF期权移仓是什么&#xff1f;50ETF期权移仓要注意什么&#xff1f;当前火热的期权交易市场&#xff0c;“移仓”同样是一门非常重要的技术。上证50ETF期权投资的过程中&#xff0c;我们可以进行一定的移仓操作的&#xff0c;如果移仓操作得好&#xff0c;可以很…

CSP-CCF 202104-1 灰度直方图

一、问题描述 二、解答 思路&#xff1a;用一个二维数组和一个一维数组、以及三个嵌套的for循环即可 代码&#xff1a; #include<iostream> using namespace std; int A[500][500] { 0 }; int main() {int n, m, L;cin >> n >> m >> L;int h[256] …

CocoaPods 官宣进入维护模式,不在积极开发新功能,未来将是 Swift Package Manager 的时代

昨天 CocoaPods 官宣现在项目**处于维护模式 **&#xff0c;简单来说&#xff0c;就是 CocoaPods 不会再像以前一样积极投入资源进行开发&#xff0c;这里的维护模式&#xff0c;就是让项目处于「可用」的状态&#xff0c;而此时距离 CocoaPods 的出现&#xff0c;也过去了有 1…

一套完整的NVR网络硬盘录像机解决方案和NVR程序源码介绍

随着网络技术的发展&#xff0c;视频数据存储的需求激增&#xff0c;促使硬盘录像机&#xff08;DVR&#xff09;逐渐演变为具备网络功能的网络视频录像机&#xff08;NVR&#xff09;。NVR&#xff0c;即网络视频录像机&#xff0c;负责网络视音频信号的接入、存储、转发、解码…

鸿蒙开发入门day05-ArkTs语言(接口与关键字)

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;还请三连支持一波哇ヾ(&#xff20;^∇^&#xff20;)ノ&#xff09; 目录 ArkTS语言介绍 接口 接口属性 接口继承 泛型类型和函数 泛型…

Unity(2022.3.38LTS) - 变换组件和约束

目录 一. 变换组件 二. 约束 一. 变换组件 在 Unity 中&#xff0c;变换组件&#xff08;Transform Component&#xff09;是每个游戏对象都必备的组件&#xff0c;用于控制对象在场景中的位置、旋转和缩放。 位置&#xff08;Position&#xff09;&#xff1a; 表示对象在…

opencv-python实战项目十:二维码识别

文章目录 一&#xff1a;简介二&#xff1a;opencv二维码识别流程三&#xff1a;整体代码四&#xff1a;效果 一&#xff1a;简介 二维码识别是一种利用图像处理技术&#xff0c;从数字图像中提取并解析二维码信息的过程。该技术广泛应用于信息快速交换、移动支付、产品追踪等…

SpringCloud的能源管理系统-能源管理平台源码

介绍 基于SpringCloud的能源管理系统-能源管理平台源码-能源在线监测平台-双碳平台源码-SpringCloud全家桶-能管管理系统源码 软件架构

MySQL的InnoDB存储引擎中的Buffer Pool机制

目录 Buffer Pool 简介 定义 为什么需要Buffer Pool 图解重点知识 Buffer Pool 的组成 数据页&#xff08;Data Pages&#xff09; 索引页&#xff08;Index Pages&#xff09; 插入缓冲页&#xff08;Insert Buffer Pages&#xff09; undo页&#xff08;Undo Pages&a…

idea鼠标悬浮显示注释

鼠标悬停在代码上的时候会出现快速文档&#xff0c;如下图&#xff0c;这里介绍下如何去除快速文档的显示 2020版本之前 依次找到 File—>Settings—>Editor—>General 去掉勾选 Show quick documentation on mouse move 2020版本之后 依次找到 File—>Settings…

Python数据可视化案例——地图

目录 简单案例&#xff1a; 进阶案例&#xff1a; 继上文数据可视化案例&#xff0c;今天学习用pyecharts练习数据可视化案例2-构建地图。 简单案例&#xff1a; 首先构建一个简单的地图。 代码&#xff1a; import json from pyecharts.charts import MapmapMap() data[…

什么反人类设计?

一、什么反人类设计&#xff1f; 反人类设计&#xff0c;也被称为“诺曼”&#xff0c;是由美国心理学家唐纳德A诺曼提出的概念&#xff0c;指的是那些设计不佳、不利于用户使用的物品。这类设计的特点通常包括不符合人体工学原理、与日常认知和惯性思维相悖。在日常生活中&…