STM32F407 2个高级定时器生成2路无刷电机波形以及相电流采集程序(寄存器版)

stm32f407 高级定时1、定时8 生成20k 中心PWM 波形 并分别用其通道4 触发ADC1 ADC2 采样 用于分别两无刷电机foc 电流环控制,ADC1产生50us的电流采集完成中断,用于foc算法周期运算

主要参考高级定时器的寄存器和ADC寄存器

首先,要使用STM32F407的高级定时器1和定时器8生成20kHz的中心PWM波形,你需要进行以下步骤:

  1. 配置时钟:使能GPIO和相应的定时器时钟。

  2. 配置GPIO:选择用于输出PWM的引脚,并将这些引脚配置为复用功能。

  3. 配置定时器:对定时器1和定时器8进行相应的配置,使其能够生成PWM信号。

    • 配置定时器的基本参数:将定时器的模式设置为PWM模式。
    • 配置定时器的时钟分频器。
    • 配置定时器的周期值,并设置PWM信号的占空比。
  4. 配置ADC:使能ADC1和ADC2的时钟,并对它们进行相应的配置。

    • 配置ADC的时钟分频器。
    • 配置ADC的模式:选择连续模式,使得它们能够不间断地进行采样。
    • 配置ADC的触发源:选择定时器的通道4作为触发源。
  5. 配置ADC中断:使能ADC1的转换完成中断,并编写中断处理函数。在中断处理函数中进行foc算法的周期运算。

  6. 启动定时器和ADC

#include <string.h>
#include <MCU_HAL.h>      //for downlayer interface include the CHAL port
#include "CHAL_Config.h"  //

#define TIM_1_8_CLOCK_HZ 168000000
// #define TIM_1_8_PERIOD_CLOCKS 3500 //24k
#define TIM_1_8_PERIOD_CLOCKS 4199  // 20k
#define TIM_1_8_DEADTIME_CLOCKS 20
#define TIM_APB1_CLOCK_HZ 84000000
#define TIM_APB1_PERIOD_CLOCKS 4096
#define TIM_APB1_DEADTIME_CLOCKS 40
#define TIM_1_8_RCR 2

static void MX_ADC1_Init(void);
static void MX_ADC2_Init(void);

void CHAL_Pwm1Init(char *HIVersion, uint32_t runFreq, uint32_t deadTime, uint32_t sampHalfTime)
{
    uint32_t pwmTiks = CPUFREQ / 2 / runFreq;
    uint8_t deadTiks = deadTime / CPURATE;
    // 使能TIM1时钟
    RCC->APB2ENR |= 1 << 0;

    // 配置TIM1基本设置
    TIM1->CR1 = 0;
    TIM1->CR1 |= (1 << 5);  // 中心对齐模式 1 递减时产生
    TIM1->CR1 |= (1 << 0);  // 使能计数器
    // TIM1->CR1 |= TIM_CR1_ARPE; // 自动重载预装载使能
    // TIM1->CR1 |= TIM_CR1_CKD_0; // 时钟分频因子 = /1

    // 设置预分频器和周期
    TIM1->PSC = 0;        // 预分频器 = 0
    TIM1->ARR = pwmTiks;  // 周期

    // 重复计数器设置(如适用)
    TIM1->RCR = TIM_1_8_RCR;

    // 配置时钟源
    TIM1->CR2 = 0;
    // TIM1->CR2 |= TIM_CR2_MMS_1; // 主模式选择:更新事件产生TRGO
    TIM1->CCMR1 = 0;
    TIM1->CCMR1 |= 7 << 4;   // PWM模式
    TIM1->CCMR1 |= 1 << 3;   // 输出比较预装载使能
    TIM1->CCMR1 |= 7 << 12;  // PWM模式
    TIM1->CCMR1 |= 1 << 11;  // 输出比较预装载使能8 重复计数器8 重复计数器寄存器 (TIMx_RCR)寄存器 (TIMx_RCR)
    TIM1->CCMR2 = 0;
    TIM1->CCMR1 = 0;
    TIM1->CCMR2 |= 7 << 4;   // PWM模式
    TIM1->CCMR2 |= 1 << 3;   // 输出比较预装载使能
    TIM1->CCMR2 |= 7 << 12;  // PWM模式
    TIM1->CCMR2 |= 1 << 11;  // 输出比较预装载使能
    // 设置初始脉冲值(通道1、2、3)
    TIM1->CCR1 = 0;
    TIM1->CCR2 = 0;
    TIM1->CCR3 = 0;
    TIM1->CCR4 = 1;

    // 设置极性(通道1、2、3)
    TIM1->CCER = 0;
    /* 0       1     2      3 */
    /* CCE=1 CCP=0 CCNE=1 CCPN=0   */
    /* 0x5 */
    TIM1->CCER |= 5 << 0;   // 通道1
    TIM1->CCER |= 5 << 4;   // 通道2
    TIM1->CCER |= 5 << 8;   // 通道3
    TIM1->CCER |= 1 << 12;  // 通道4 极性高

    // 断开与死区时间配置
    TIM1->BDTR = deadTiks;  // 最大不超过255 tick
    TIM1->BDTR |= 1 << 15;  // 输出使能

    /* gpio 初始化 */
    RCC->AHB1ENR |= 1 << 0;  // 使能PORTA口时钟
    RCC->AHB1ENR |= 1 << 1;  // 使能PORTB口时钟

    GPIO_Set(GPIOA, PIN8 | PIN9 | PIN10, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
             GPIO_PUPD_PD);     // PA9,PA10,复用功能,上拉输出
    GPIO_AF_Set(GPIOA, 8, 1);   // PA8,AF1
    GPIO_AF_Set(GPIOA, 9, 1);   // PA8,AF1
    GPIO_AF_Set(GPIOA, 10, 1);  // PA8,AF1
    GPIO_Set(GPIOB, PIN13 | PIN14 | PIN15, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
             GPIO_PUPD_PD);     // PA9,PA10,复用功能,上拉输出
    GPIO_AF_Set(GPIOB, 13, 1);  // PA8,AF1
    GPIO_AF_Set(GPIOB, 14, 1);  // PA8,AF1
    GPIO_AF_Set(GPIOB, 15, 1);  // PA8,AF1
    MX_ADC1_Init();
}

void CHAL_M1_DisPwm123(void) { TIM1->CCER = 0x1000; }

void CHAL_M1_EnaPwm123(void) { TIM1->CCER = 0x1555; }

void CHAL_Pwm2Init(char *HIVersion, uint32_t runFreq, uint32_t deadTime, uint32_t sampHalfTime)
{
    uint32_t pwmTiks = CPUFREQ / 2 / runFreq;
    uint8_t deadTiks = deadTime / CPURATE;
    // 使能TIM2时钟
    RCC->APB2ENR |= 1 << 1;

    // 配置TIM2基本设置
    TIM8->CR1 = 0;
    TIM8->CR1 |= (1 << 5);  // 中心对齐模式 1 递减时产生
    TIM8->CR1 |= (1 << 0);  // 使能计数器
    // TIM8->CR1 |= TIM_CR1_ARPE; // 自动重载预装载使能
    // TIM8->CR1 |= TIM_CR1_CKD_0; // 时钟分频因子 = /1

    // 设置预分频器和周期
    TIM8->PSC = 0;        // 预分频器 = 0
    TIM8->ARR = pwmTiks;  // 周期

    // 重复计数器设置(如适用)
    TIM8->RCR = TIM_1_8_RCR;

    // 配置时钟源
    TIM8->CR2 = 0;
    // TIM8->CR2 |= TIM_CR2_MMS_1; // 主模式选择:更新事件产生TRGO

    // PWM模式配置(通道1、2、3)
    TIM8->CCMR1 = 0;
    TIM8->CCMR1 |= 7 << 4;   // PWM模式
    TIM8->CCMR1 |= 1 << 3;   // 输出比较预装载使能
    TIM8->CCMR1 |= 7 << 12;  // PWM模式
    TIM8->CCMR1 |= 1 << 11;  // 输出比较预装载使能
    TIM8->CCMR2 = 0;
    TIM8->CCMR2 |= 7 << 4;   // PWM模式
    TIM8->CCMR2 |= 1 << 3;   // 输出比较预装载使能
    TIM8->CCMR2 |= 7 << 12;  // PWM模式
    TIM8->CCMR2 |= 1 << 11;  // 输出比较预装载使能
    // 设置初始脉冲值(通道1、2、3)
    TIM8->CCR1 = 0;
    TIM8->CCR2 = 0;
    TIM8->CCR3 = 0;
    TIM8->CCR4 = 1;

    // 设置极性(通道1、2、3)
    TIM8->CCER = 0;
    /* 0       1     2      3 */
    /* CCE=1 CCP=0 CCNE=1 CCPN=0   */
    /* 0x5 */
    TIM8->CCER |= 5 << 0;   // 通道1
    TIM8->CCER |= 5 << 4;   // 通道2
    TIM8->CCER |= 5 << 8;   // 通道3
    TIM8->CCER |= 1 << 12;  // 通道4 极性高

    // 断开与死区时间配置
    TIM8->BDTR = deadTiks;  // 最大不超过255 tick
    TIM8->BDTR |= 1 << 15;  // 输出使能

    /* gpio 初始化 */
    RCC->AHB1ENR |= 1 << 0;  // 使能PORTA口时钟
    RCC->AHB1ENR |= 1 << 1;  // 使能PORTB口时钟
    RCC->AHB1ENR |= 1 << 2;  // 使能PORTc口时钟

    GPIO_Set(GPIOA, PIN7, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
             GPIO_PUPD_PD);    // PA9,PA10,复用功能,上拉输出
    GPIO_AF_Set(GPIOA, 7, 3);  // PA8,AF3
    GPIO_Set(GPIOB, PIN0 | PIN1 | PIN15, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
             GPIO_PUPD_PD);    // PA9,PA10,复用功能,上拉输出
    GPIO_AF_Set(GPIOB, 0, 3);  // PA8,AF1
    GPIO_AF_Set(GPIOB, 1, 3);  // PA8,AF1

    GPIO_Set(GPIOC, PIN6 | PIN7 | PIN8, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
             GPIO_PUPD_PD);    // PA9,PA10,复用功能,上拉输出
    GPIO_AF_Set(GPIOC, 6, 3);  // PA8,AF1
    GPIO_AF_Set(GPIOC, 7, 3);  // PA8,AF1
    GPIO_AF_Set(GPIOC, 8, 3);  // PA8,AF1
    MX_ADC2_Init();
}

void CHAL_M2_DisPwm123(void) { TIM8->CCER = 0x1000; }

void CHAL_M2_EnaPwm123(void) { TIM8->CCER = 0x1555; }



/**
 * @brief ADC1 初始化函数
 * @param 无
 * @retval 无
 */
static void MX_ADC1_Init(void)
{
    // 使能ADC1时钟
    RCC->APB2ENR |= 1 << 8;
    // ADC1->CR1 = 0x180;

    ADC1->CR1 |= 1 << 8;  // 使能扫描模式
    ADC1->CR1 |= 1 << 7;  // 注入通道中断完成中断使能
    ADC1->CR2 = 0;
    ADC1->CR2 |= 1 << 10;    // ADC 使能
    ADC1->CR2 |= 2 << 20;    // 下降沿触发 注入通道检测
    ADC1->CR2 |= 0 << 16;  // 注入通道 TIM1 CC4 事件
    ADC1->CR2 |= 1 << 0;     // ADC 使能
    ADC1->HTR = 0x0FFF;
    // ADC1->CR2 = 0x0200401;
    ADC1->HTR = 0x0FFF;

    ADC1->JSQR = 0;
    ADC1->JSQR |= 1 << 20;     // 注入通道序列长度:2
    ADC1->JSQR |= (10 << 10);  // 注入通道3   对应 adc 通道
    ADC1->JSQR |= (11 << 15);  // 注入通道4
    ADC1->SMPR1 = 0;
    ADC1->SMPR1 |= 0 << 0;  // 注入通道8采样时间: 3个周期
    ADC1->SMPR1 |= 0 << 3;  // 注入通道12采样时间:3个周期

    RCC->AHB1ENR |= 1 << 2;  // 使能PORTC口时钟

    GPIO_Set(GPIOC, PIN0 | PIN1, GPIO_MODE_AIN, 0, 0, GPIO_PUPD_PU);  //

    // // 启动ADC1
    MY_NVIC_Init(0, 0, ADC_IRQn, 0);  // 抢占1,子优先级3,组2
}

/**
 * @brief ADC2 初始化函数
 * @param 无
 * @retval 无
 */
static void MX_ADC2_Init(void)
{
    // 使能ADC2时钟
    RCC->APB2ENR |= 1 << 9;
    // ADC2->CR1 = 0x180;
    ADC2->CR1 = 0;
    ADC2->CR1 |= 1 << 8;  // 使能扫描模式
    ADC2->CR2 = 0;
    ADC2->CR2 |= 1 << 10;    // ADC 使能
    ADC2->CR2 |= 2 << 20;    // 下降沿触发 注入通道检测
    ADC2->CR2 |= 0xe << 16;  // 注入通道 TIM8 CC4 事件
    ADC2->CR2 |= 1 << 0;     // ADC 使能
    ADC2->HTR = 0x0FFF;

    //    // // 配置注入通道(通道8、12、6、13)
    ADC2->JSQR = 0;
    ADC2->JSQR |= 1 << 20;     // 注入通道序列长度:2
    ADC2->JSQR |= (12 << 10);  // 注入通道3
    ADC2->JSQR |= (13 << 15);  // 注入通道4

    ADC2->SMPR1 = 0;

    ADC2->SMPR1 |= 0 << 0;  // 注入通道8采样时间: 3个周期
    ADC2->SMPR1 |= 0 << 3;  // 注入通道12采样时间:3个周期

    RCC->AHB1ENR |= 1 << 2;  // 使能PORTC口时钟

    GPIO_Set(GPIOC, PIN2 | PIN3, GPIO_MODE_AIN, 0, 0, GPIO_PUPD_PU);  //
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

libcity笔记: HSTLSTMEncoder

1 __init__ 2 encode 得到的内容如下&#xff1a; data_feature的内容&#xff1a; 一共有多少个location1【包括pad的一个】最长的时间间隔&#xff08;秒&#xff09;最长的距离间隔&#xff08;千米&#xff09;多少个useer idpadding 的locationidpad_item的内容 location…

Docker三剑客从0到1

一、docker三剑客介绍 使用"三剑客"可以帮助我们解决docker host维护,多容器编排部署,多个docker host集群的各个难题。 docker-machine 创建虚拟机 我们知道docker使用了linux的内核技术(namespace 资源隔离,cgroup资源限制等),那么如果我想在windows或Mac系统上…

原地去重问题和合并有序数组问题

原地去重问题 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。这是leetcode上的一道题 这里我们用…

shell脚本之sort,uniq,tr,cut,sphit,paste,ecal与正则表达式

sort命令 uniq命令 tr命令 cut命令 sphit命令 paste命令 ecal命令 正则表达式 sort命令 sort命令---以行为单位对文件内容进行排序&#xff0c;也可以根据不同的数据类型来排序 比较原则是从首字符向后&#xff0c;依次按ASCII码值进行比较&#xff0c;最后将他们按升序…

54.指针

目录 一.什么是指针&#xff1f; 二&#xff0e;定义一个指针变量 三&#xff0e;指针变量类型 四&#xff0e;取地址运算符& 五.取值运算符* 六.视频教程 一.什么是指针&#xff1f; 口语中的指针一般指指针变量&#xff0c;指针变量存放的是一个地址。普通变量存放…

Blender雕刻建模_衰减

衰减 从中心点向外的强度衰减。 其中 中心点&#xff1a;即笔刷选中的顶点 半径&#xff1a;即笔刷的半径 衰减范围 从中心点向外的一个球形空间&#xff08;不仅是看见的2D球&#xff0c;而是一个3D球形的空间&#xff09; 为了避免误操作有如下几种方法&#xff1a; -Al…

u3d的ab文件注意事项

//----------------LoadAllAB.cs--------------------- using System.Collections;using UnityEngine;namespace System.IO{public class LoadAllAB : MonoBehaviour{ //读取本地string path "Assets/Actors/lznh/ab/animation/t_bl/";// Use this for initiali…

【吃透Java手写】6-Netty-NIO-BIO-简易版

Netty 1 BIO&NIO模型 1.1 BIO 在JDK1.4出来之前&#xff0c;我们建立网络连接的时候采用BIO模式&#xff0c;需要先在服务端启动一个ServerSocket&#xff0c;然后在客户端启动Socket来对服务端进行通信&#xff0c;默认情况下服务端需要对每个请求建立一堆线程等待请求&…

CUDA backend requires cuDNN. Please resolve dependency or disable的解决方法

先把 C:\Program Files\NVIDIA\CUDNN\v9.0里面的bin,include,lib文件夹中最里面的文件 复制到 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4中的bin,include,lib文件夹 你的路径或许有点不一样&#xff0c;但大概就是这样 注意&#xff0c;复制完后&#xff0c;文…

西南大学计算机考研,选学硕还是专硕?西南大学计算机考研考情分析!

西南大学&#xff08;Southwest University&#xff09;是教育部直属&#xff0c;教育部、农业农村部、重庆市共建的重点综合大学&#xff0c;是国家首批"双一流"建设高校&#xff0c;"211工程"和"985工程优势学科创新平台"建设高校。现任党委书…

Gradio 案例——将 dicom 文件转为 nii文件

文章目录 Gradio 案例——将 dicom 文件转为 nii文件界面截图依赖安装项目目录结构代码 Gradio 案例——将 dicom 文件转为 nii文件 利用 SimpleITK 库&#xff0c;将 dicom 文件转为 nii文件更完整、丰富的示例项目见 GitHub - AlionSSS/dcm2niix-webui: The web UI for dcm2…

OpenAI 刚刚宣布了 “GPT-4o“ 免费用户开放、通过 API 可用

OpenAI 刚刚宣布了 “GPT-4o”。它可以通过语音、视觉和文本进行推理。 该模型速度提高了 2 倍&#xff0c;价格降低了 50%&#xff0c;比 GPT-4 Turbo 的速率限制高出了 5 倍。 它将对免费用户开放、通过 API 可用。 与 GPT-4 相比&#xff0c;GPT-4o 的速度和额外的编码能力…

阿里巴巴发布最新财报,营收重回增长轨道

KlipC报道&#xff1a;5月14日&#xff0c;阿里巴巴集团发布2024财年及第四财季最新财报&#xff0c;财报显示第四财季收入2218.74亿元&#xff0c;同比增长7%&#xff0c;超出市场预期。2024财年收入同比增长8%&#xff0c;达9411.68亿元。 第四财季净利润244.2亿元人民币&am…

802.1X认证,梦回网吧的年代。

1、802.1x的原理 &#xff08;1&#xff09;802.1x的产生原因 802.1X协议作为局域网接口的一个普通接入控制机制在以太网中被广泛应用&#xff0c;主要解决以太网内认证和安全方面的问题。802.1X协议是一种基于接口的网络接入控制协议。“基于接口的网络接入控制”是指&#…

c++20---std::erase----std::erase_if

问题&#xff1a;如何删除满足条件的所有元素。 erase #include <iostream> #include <algorithm> #include <vector>int main(){std::vector<int> vec{1,2,3,1,1,1,1,1};std::erase(vec,1);for(int v:vec) std::cout<<v<<" "…

【Kafka】2.深入理解Kafka事件流平台及其核心概念

1.事件流(Event streaming) 事件流是人体中枢神经系统的数字化的等价物。它是构建“始终在线”世界的技术基础&#xff0c;在这个世界中&#xff0c;企业越来越多地被定义为软件化和自动化&#xff0c;而软件的用户本身也是软件。 从技术上讲&#xff0c;事件流是从数据库、传…

vue3专栏项目 -- 六、上传组件(上)

1、上传组件需求分析 我们还需要新建和展示文章&#xff0c;新建文章自然是发送post请求&#xff0c;同时在post中自带对应的数据&#xff0c;展示文章就是根据id取出已有的数据并且展示出来。 这里有一个难点就是上传组件&#xff0c;上传文件是App应用中最基本的需求&#…

如何在Idea离线情况下安装vue.js插件

亲践有效&#xff0c;步骤如下: 1. 互联网环境登陆vue.js官网(Vue.js - IntelliJ IDEs Plugin | Marketplace)。 2. 然后先确定你的IDEA的版本&#xff1a;在你IDEA的安装文件中找到product-info.json&#xff0c;里面的buildNumber记录着你IDEA的精确版本号&#xff0c;根据…

ROS2系统与px4通信测试

参考文章&#xff1a; No communication with ROS2 using MicroXRCEAgent with px4 board ROS2官方安装及测试程序 概要 新安装的ROS2与PixHawk开发板进行通信。 操作步骤 启动示例程序&#xff0c;在&#xff5e;/ws_sensor_combined/src路径下执行&#xff1a; ros2 l…

【Image captioning】基于检测模型网格特征提取——以Sydeny为例

【Image captioning】基于检测模型网格特征提取——以Sydeny为例 今天,我们将重点探讨如何利用Faster R-CNN检测模型来提取Sydeny数据集的网格特征。具体而言,这一过程涉及通过Faster R-CNN模型对图像进行分析,进而抽取出关键区域的特征信息,这些特征在网格结构中被系统地…