当前位置: 首页 > article >正文

stm32实战项目:无刷驱动

目录

系统时钟配置

PWM模块初始化

ADC模块配置

霍尔接口配置

速度环定时器

换相逻辑实现

主控制循环


系统时钟配置

  • 启用72MHz主频:RCC_Configuration()设置PLL
  • 外设时钟使能:TIM1/ADC/GPIO时钟
#include "stm32f10x.h"void RCC_Configuration(void)
{// 时钟复位配置RCC_DeInit();// 1. 开启HSE并等待就绪RCC_HSEConfig(RCC_HSE_ON);while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);// 2. 配置PLL:HSE作为源,9倍频RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);// 3. 设置FLASH预取指和等待周期(必须)FLASH_SetLatency(FLASH_Latency_2);FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);// 4. 时钟分频配置RCC_HCLKConfig(RCC_SYSCLK_Div1);    // AHB=72MHzRCC_PCLK1Config(RCC_HCLK_Div2);    // APB1=36MHzRCC_PCLK2Config(RCC_HCLK_Div1);    // APB2=72MHz// 5. 启动PLL并切换时钟源RCC_PLLCmd(ENABLE);while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);while(RCC_GetSYSCLKSource() != 0x08);// 6. 外设时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 |    // TIM1时钟RCC_APB2Periph_ADC1 |    // ADC1时钟RCC_APB2Periph_GPIOA |   // GPIOA时钟(示例)RCC_APB2Periph_GPIOC,    // GPIOC时钟(示例)ENABLE);
}// 主函数初始化调用示例
int main(void)
{RCC_Configuration();// 其他初始化代码...while(1);
}

PWM模块初始化

  • 定时器1通道1-3配置:
    TIM_OCInitTypeDef.Pulse = 50%占空比
    TIM_BDTRInitStruct配置死区时间(50-100ns)
  • 互补输出使能:
    TIM_CCxNCmd(TIM1, ENABLE)
#include "stm32f10x.h"void PWM_Configuration(void)
{GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;TIM_OCInitTypeDef TIM_OCStruct;TIM_BDTRInitTypeDef TIM_BDTRStruct;// 1. GPIO配置(以PA8/PA7为例)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_7; // CH1/CH1NGPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);// 2. 定时器基础配置(72MHz时钟)RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);TIM_TimeBaseStruct.TIM_Period = 1000-1;      // ARR决定PWM频率TIM_TimeBaseStruct.TIM_Prescaler = 0;        // 无分频TIM_TimeBaseStruct.TIM_ClockDivision = 0;TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);// 3. PWM通道配置(50%占空比)TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable;TIM_OCStruct.TIM_Pulse = 500; // 50% of ARR(1000)TIM_OCStruct.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OC1Init(TIM1, &TIM_OCStruct); // 通道1TIM_OC2Init(TIM1, &TIM_OCStruct); // 通道2TIM_OC3Init(TIM1, &TIM_OCStruct); // 通道3// 4. 死区时间配置(约55.5ns)TIM_BDTRStruct.TIM_DeadTime = 0x04; // DTG=4: 4*Tdts (Tdts=13.89ns@72MHz)TIM_BDTRStruct.TIM_Break = TIM_Break_Disable;TIM_BDTRStruct.TIM_LOCKLevel = TIM_LOCKLevel_OFF;TIM_BDTRStruct.TIM_OSSRState = TIM_OSSRState_Disable;TIM_BDTRStruct.TIM_OSSIState = TIM_OSSIState_Disable;TIM_BDTRStruct.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;TIM_BDTRConfig(TIM1, &TIM_BDTRStruct);// 5. 互补输出使能TIM_CCxNCmd(TIM1, TIM_Channel_1, ENABLE); // CH1NTIM_CCxNCmd(TIM1, TIM_Channel_2, ENABLE); // CH2NTIM_CCxNCmd(TIM1, TIM_Channel_3, ENABLE); // CH3N// 6. 启动定时器TIM_Cmd(TIM1, ENABLE);TIM_CtrlPWMOutputs(TIM1, ENABLE); // MOE置位
}

ADC模块配置

  • 规则组通道选择:
    ADC_RegularChannelConfig(ADC1, ADC_Channel_x, 1...)
  • DMA循环模式设置:
    DMA_InitStruct.Mode = DMA_Mode_Circular

// 示例:配置ADC1规则组的3个通道(顺序:通道5→通道1→通道11)
ADC_RegularChannelConfig(ADC1, ADC_Channel_5,  1); // 第1个转换
ADC_RegularChannelConfig(ADC1, ADC_Channel_1,  2); // 第2个转换
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 3); // 第3个转换ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_NbrOfChannel = 3; // 规则组总通道数
ADC_Init(ADC1, &ADC_InitStruct);DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; // 循环模式
DMA_InitStruct.DMA_BufferSize = 3;           // 缓冲区大小(与规则组通道数匹配)
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址固定
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;         // 内存地址递增
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16位数据
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);// 设置外设地址(ADC数据寄存器)
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
// 设置内存地址(自定义缓冲区)
extern uint16_t adc_buffer[3];
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)adc_buffer;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 启动转换DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE); // 绑定ADC到DMA

霍尔接口配置

  • GPIO输入模式:
    GPIO_Init(GPIOx, GPIO_Pin_x, GPIO_Mode_IPU)
  • EXTI中断触发:
    EXTI_Trigger = EXTI_Trigger_Rising_Falling

霍尔传感器 → GPIO上拉输入 → EXTI双沿中断 → NVIC优先级配置 → 中断服务函数 → 换向逻辑

GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIO时钟
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; // 霍尔传感器连接的PA0/PA1/PA2
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;  // 上拉输入
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 输入模式下速度可忽略,但需设置
GPIO_Init(GPIOA, &GPIO_InitStruct);EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;// 将GPIO引脚映射到EXTI中断线(以PA0为例)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);EXTI_InitStruct.EXTI_Line = EXTI_Line0; // 对应PA0
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 双沿触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);// 配置NVIC中断优先级
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

void EXTI0_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_Line0) != RESET) {uint8_t hall_state = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0); // 读取霍尔信号// 执行换向逻辑(例如BLDC电机驱动)EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志}
}

速度环定时器

  • 定时器2基础配置:
    TIM_TimeBaseInit(TIM2, 1kHz)
  • 中断服务程序:
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE)
// 系统时钟假设为72MHz(STM32F1系列)
TIM_TimeBaseInitTypeDef TIM_InitStruct;
TIM_InitStruct.TIM_Prescaler = 7200 - 1;    // 分频系数7200 → 72MHz/7200=10kHz
TIM_InitStruct.TIM_Period = 10 - 1;         // 自动重载值 → 10kHz/10=1kHz
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_InitStruct);// 使能TIM2更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 允许定时器溢出中断[citation:9][citation:10]// 配置NVIC中断优先级
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
void TIM2_IRQHandler(void) {if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {// 执行速度环PID计算或数据采集SpeedControl_Algorithm(); // 用户自定义速度环处理函数TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除中断标志[citation:9][citation:10]}
}

换相逻辑实现

  • Hall状态机:
    switch(Hall_Value & 0x07){
    case 0b101: PWM_SetPhaseA_High();...
    }
const PhaseAction phase_table[6] = {{0b101, PWM_A, OFF_C},  // 状态0{0b100, PWM_B, OFF_A},  // 状态1// ...其他状态
};

switch(Hall_Value & 0x07) {case 0b101:  // 对应霍尔状态HA=1, HB=0, HC=1PWM_SetPhaseA_High();  // 上桥臂A相PWM调制,下桥臂B相常通PWM_SetPhaseB_Low();PWM_SetPhaseC_Off();   // C相关闭(互补逻辑)break;case 0b100:  // 其他状态类似调整// ...
}

主控制循环

  • while(1){
    ADC_Convert();
    Speed_PID_Calc();
    Current_Limit_Check();
    }
void Current_Limit_Check() {if (ADC_Current > MAX_CURRENT) {PWM_Disable();  // 立即关闭功率输出Fault_LED_On(); // 故障指示System_Reset(); // 可选:进入安全状态或重启}
}

相关文章:

stm32实战项目:无刷驱动

目录 系统时钟配置 PWM模块初始化 ADC模块配置 霍尔接口配置 速度环定时器 换相逻辑实现 主控制循环 系统时钟配置 启用72MHz主频:RCC_Configuration()设置PLL外设时钟使能:TIM1/ADC/GPIO时钟 #include "stm32f10x.h"void RCC_Configu…...

python打卡训练营打卡记录day30

一、导入官方库 我们复盘下学习python的逻辑,所谓学习python就是学习python常见的基础语法学习你所处理任务需要用到的第三方库。 1.1标准导入:导入整个库 这是最基本也是最常见的导入方式,直接使用import语句。 # 方式1:导入整…...

2025年- H33-Lc141 --148. 排序链表(快慢指针,快指针先出发一步)--Java版

1.题目描述 2.思路 时间空间复杂度分别为 O(nlogn) 和 O(1),根据时间复杂度想到二分法,从而联想到归并排序;对数组做归并排序的空间复杂度为 O(n),分别由新开辟数组 O(n) 和递归函数调用 O(logn) 组成,而根据链表特性…...

【prometheus+Grafana篇】基于Prometheus+Grafana实现Oracle数据库的监控与可视化

💫《博主主页》: 🔎 CSDN主页 🔎 IF Club社区主页 🔥《擅长领域》:擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控;并对SQLserver、NoSQL(MongoDB)有了…...

板凳-------Mysql cookbook学习 (四)

综合对比与选择建议 维度 PHP Java Python Ruby Perl 学习门槛 低(适合新手) 高(语法复杂) 低(语法简洁) 中(需理解 Rails 理念) 中(特殊语法&#xf…...

【D1,2】 贪心算法刷题

文章目录 不同路径 II整数拆分 不同路径 II 初始化的时候不能整列初始化为1,因为如果有障碍物,后面的都不能到达 也不能整列初始化为0,因为状态转移的时候第一行第一列都没有检查,因此不能部分初始化 整数拆分 需要考虑几种情况…...

算法题(150):拼数

审题: 本题需要我们将数组中的数据经过排序,使得他们拼接后得到的数是所有拼接方案中最大的 思路: 方法一:排序贪心 贪心策略1:直接排序 如果我们直接按照数组数据的字典序进行排序,会导致部分情况出错 eg&…...

Denoising Score Matching with Langevin Dynamics

在自然图像等复杂数据集中,真实数据往往集中分布在一个低维流形上,概率密度函数的梯度(即得分函数)难以定义与估计。为缓解该问题,SMLD 提出使用不同强度的高斯噪声对数据进行扰动,扰动后的数据不再集中于低…...

Docker构建 Dify 应用定时任务助手

概述 Dify 定时任务管理工具是一个基于 GitHub Actions 的自动化解决方案,用于实现 Dify Workflow 的定时执行和状态监控。无需再为缺乏定时任务支持而感到困扰,本工具可以帮助设置自动执行任务并获取实时通知,优化你的工作效率。 注意&…...

mongodb管理工具的使用

环境: 远程服务器的操作系统:centOS stream 9; mongoDB version:8.0; 本地电脑 navicat premium 17.2 ; 宝塔上安装了mongoDB 目的:通过本地的navicat链接mongoDB,如何打通链接,分2步: 第一步:宝塔-&…...

第2篇 水滴穿透:IGBT模块的绝对防御体系

引言:从《三体》水滴到功率模块的哲学思考 科幻映照现实:三体探测器"水滴"的绝对光滑表面 → IGBT模块的可靠性设计哲学行业现状痛点:2023年OEM质量报告显示,电控系统23%的故障源自功率模块技术演进悖论:开关频率提升与可靠性保障的永恒博弈 一、基础理论:IGBT…...

LVGL(lv_dropdown下拉列表控件)

文章目录 🔧 一、基本概念🚀 二、创建一个 Dropdown🧰 三、常用函数1. 设置选项2. 获取选项3. 设置当前选中项4. 获取当前选中项索引5. 获取当前选中项文本🎨 四、样式与模式设置方向(最多显示多少项)设置显示模式设置提示文本📞 五、事件回调🧪 六、使用示例📌…...

2.微服务-配置

引入springcloud的pom配置 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.12</version><relativePath/></parent> <dependencyManagemen…...

python实现pdf转图片(针对每一页)

from pdf2image import convert_from_path import ospdf_file rC:\Users\\Desktop\拆分\产权证.pdf poppler_path rC:\poppler-24.08.0\Library\bin # 这里改成你自己的路径output_dir rC:\Users\\Desktop\拆分\output_images os.makedirs(output_dir, exist_okTrue)image…...

C语言练手磨时间

167. 两数之和 II - 输入有序数组 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] &#xff0c;则 1 <…...

数字图像处理——图像压缩

背景 图像压缩是一种减少图像文件大小的技术&#xff0c;旨在在保持视觉质量的同时降低存储和传输成本。随着数字图像的广泛应用&#xff0c;图像压缩在多个领域如互联网、移动通信、医学影像和卫星图像处理中变得至关重要。 技术总览 当下图像压缩JPEG几乎一统天下&#xff…...

验证器回调中value值没有数据

复杂的响应式&#xff0c;导致回调中value值没有数据&#xff0c;最终还是通过手动判断获取值处理 原理没有搞清楚&#xff0c;为什么回调中value没有值背景&#xff1a;动态增加了form表单的字段&#xff0c;通过for循环处理的。对每个新增的字段还要添加字段验证其。就出现了…...

Python | 需求预测模型

目录 需求预测 1.方法选择 2.颗粒度选择 3.在医药行业的应用 预测模型 1.模型对比 2.Prophet 3.Holt-Winters 需求预测 1.方法选择 方法 适用范围分类移动平均法中小企业、SKU较少的卖家低成本预测方案Excel趋势线预测中小企业、SKU较少的卖家低成本预测方案季节性系数法中小企…...

双指针算法:原理与应用详解

文章目录 一、什么是双指针算法二、双指针算法的适用场景三、双指针的三种常见形式1. 同向移动指针2. 相向移动指针3. 分离指针 四、总结 一、什么是双指针算法 双指针算法&#xff08;Two Pointers Technique&#xff09;是一种在数组或链表等线性数据结构中常用的高效算法技…...

打造灵感投掷器:我的「IdeaDice」开发记录

我正在参加CodeBuddy「首席试玩官」内容创作大赛&#xff0c;本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 起源&#xff1a;我只是想“摇”出点灵感 有时候面对写作或者做产品设计&#xff0c;我会卡在「不知道从哪开始…...

2025ICPC邀请赛南昌游记

滚榜时候队伍照片放的人家的闹麻了&#xff0c;手机举了半天 。 最后银牌700小几十罚时&#xff0c;rank60多点。 参赛体验还行&#xff0c;队长是福建人&#xff0c;说感觉这个热度是主场作战哈哈哈哈。空调制冷确实不太行吧。 9s过A是啥&#xff0c;没见过&#xff0c;虽然…...

python重庆旅游系统-旅游攻略

目录 技术栈介绍具体实现截图系统设计研究方法&#xff1a;设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理&#xff0c;难度适中&#xf…...

MySQL企业版免费开启,强先体验

近期Oracle突然宣布&#xff0c;MySQL企业版面向开发者免费开放下载&#xff0c;这一消息瞬间引爆DBA圈。作为数据库领域的“顶配车型”&#xff0c;企业版长期因高昂授权费让中小团队望而却步&#xff0c;如今免费开放无异于“劳斯莱斯开进菜市场”。 本文将深度拆解企业版的…...

从纸质契约到智能契约:AI如何改写信任规则与商业效率?​——从智能合约到监管科技,一场颠覆传统商业逻辑的技术革命

一、传统合同的“低效困境”&#xff1a;耗时、昂贵、风险失控 近年来&#xff0c;全球商业环境加速向数字化转型&#xff0c;但合同管理却成为企业效率的“阿喀琉斯之踵”。据国际商会&#xff08;International Chamber of Commerce&#xff09;数据显示&#xff0c;全球企业…...

常见的 HTTP 接口(请求方法)

一&#xff1a;GET 作用&#xff1a;从服务器获取资源&#xff08;查询数据&#xff09;。特点&#xff1a; 请求参数通过 URL 传递&#xff08;如https://api.example.com/users?id123&#xff09;&#xff0c;参数会显示在地址栏中。不修改服务器数据&#xff0c;属于幂等操…...

iOS 抓包实战:从 Charles 到Sniffmaster 的日常工具对比与使用经验

iOS 抓包实战&#xff1a;从 Charles 到抓包大师 Sniffmaster 的日常工具对比与使用经验 抓包这件事&#xff0c;不是高级黑客才要做的。作为一名移动端开发&#xff0c;我几乎每天都要和网络请求打交道&#xff0c;尤其是 HTTPS 请求——加密、重定向、校验证书&#xff0c;各…...

Lodash isEqual 方法源码实现分析

Lodash isEqual 方法源码实现分析 Lodash 的 isEqual 方法用于执行两个值的深度比较&#xff0c;以确定它们是否相等。这个方法能够处理各种 JavaScript 数据类型&#xff0c;包括基本类型、对象、数组、正则表达式、日期对象等&#xff0c;并且能够正确处理循环引用。 1. is…...

Qt Widgets模块功能详细说明,基本控件:QCheckBox(三)

一、基本控件&#xff08;Widgets&#xff09; Qt 提供了丰富的基本控件&#xff0c;如按钮、标签、文本框、复选框、单选按钮、列表框、组合框、菜单、工具栏等。 1、QCheckBox 1.1、概述 (用途、状态、继承关系) QCheckBox 是 Qt 框架中的复选框控件&#xff0c;用于表示二…...

第四天的尝试

目录 一、每日一言 二、练习题 三、效果展示 四、下次题目 五、总结 一、每日一言 很抱歉的说一下&#xff0c;我昨天看白色巨塔电视剧&#xff0c;看的入迷了&#xff0c;同时也看出一些道理&#xff0c;学到东西&#xff1b; 但是把昨天的写事情给忘记了&#xff0c;今天…...

【git进阶】git rebase(变基)

git rebase有很多用武之地,我一一道来 合并分支 当多人协作同一个分支时,在提交我们自己版本之前,我们会先用git pull获取远端最新的版本。但是 git pull = git fetch + git mergegit merge是一个非线性的合并操作,大量的merge会造成日志线的分散和交错。实际上 git pu…...