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

news2024/11/14 19:51:27

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);  //
}

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

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

相关文章

OSG编程指南<二十三>:基于OSG+ImGui制作模型编辑器,实现三轴方向的实时平移、旋转和缩放变化

1、概述 在OSG的开发应用过程中&#xff0c;我们有时候总会纠结于使用MFC还是Qt来嵌入OSG窗口以便于后续的功能开发&#xff0c;毕竟选择一个合适的UI框架&#xff0c;对于后续的开发还是省去很多麻烦的。但对于初学者来说&#xff0c;可能对框架消息机制的不熟悉&#xff0c;尤…

每日复盘-20240515

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 国联证券 (1)|[9:25]|[133765万]|31.12 一…

selenium发展史

Selenium Core 2004 年&#xff0c;Thoughtworks 的工程师 Jason Huggins 正在负责一个 Web 应用的测试工作&#xff0c;由于这个项目需要频繁回归&#xff0c;这导致他不得不每天做着重复且低效的工作。为了解决这个困境&#xff0c;Jason 开发了一个运行在 JavaScript 沙箱中…

表白成功率百分百的向女朋友表白网页源代码,向女友表白HTML源代码

表白成功率百分百的向女朋友表白网页源代码&#xff0c;向女友表白HTML源代码 效果&#xff1a; 完整代码下载地址&#xff1a;向女友表白HTML源代码 <!DOCTYPE html> <!--STATUS OK--> <html><head><meta http-equiv"Content-Type" c…

Linux|基础环境开发工具使用(1)

目录 Linux 软件包管理器 yum 什么是软件包 关于 rzsz 注意事项 查看软件包 如何安装软件 如何卸载软件 Linux编辑器-vim介绍 vi与vim的相同点 vi与vim区别 Linux 软件包管理器 yum 什么是软件包 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译…

【Windows】回忆Win98

回忆Win98&#xff0c;又看到了这个Excel界面&#xff0c;上次还是十多年前的计算机课上 1、安装环境 Win11家庭版,23H2,VMware Workstation Pro 16 , 2、安装步骤及参考 虚拟机里的硬盘设置成SATA&#xff08;否则各种错误&#xff09;&#xff0c;安装MSDOS7.1&#xff…

VP Codeforces Round 944 (Div 4)

感受&#xff1a; A~G 其实都不难&#xff0c;都可以试着补起来。 H看到矩阵就放弃了。 A题&#xff1a; 思路&#xff1a; 打开编译器 代码&#xff1a; #include <iostream> #include <vector> #include <algorithm> #define int long long using na…

基于Springboot的学生心理压力咨询评判(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的学生心理压力咨询评判&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

【Unity之FairyGUI】你了解FGUI吗,跨平台多功能高效UI插件

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

免费体验GPT-4o这5大功能,非常好用!

这几天&#xff0c;OpenAI发布了新的GPT版本&#xff0c;GPT-4o&#xff0c;比GPT4更加智能也更快。 据说&#xff0c;GPT-4o在文本、推理和编码智能方面实现了GPT-4 Turbo级别的性能&#xff0c;在多语言、文本、音频和视觉功能方面甚至超过了市面上所有同类产品。 有几个亮点…

Anaconda安装-超详细版(2024)

扫盲&#xff1a;先装Python还是先装anaconda? 安装anaconda即可&#xff0c;不需要单独装python anaconda 是一个python的发行版&#xff0c;包括了python和很多常见的软件库, 和一个包管理器conda。 一、下载Anaconda 安装包&#xff08;官网和国内镜像资源&#xff09; …

SpringBoot之远程调用的三大方式

为什么要使用远程调用&#xff1f; SpringBoot不仅继承了Spring框架原有的优秀特性&#xff0c;而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。在Spring-Boot项目开发中&#xff0c;存在着本模块的代码需要访问外面模块接口&#xff0c;或外部url链接的需求…

基于SpringBoot设计模式之创建型设计模式·工厂方法模式

文章目录 介绍开始架构图样例一定义工厂定义具体工厂&#xff08;上衣、下装&#xff09;定义产品定义具体生产产品&#xff08;上衣、下装&#xff09; 测试样例 总结优点缺点与抽象工厂不同点 介绍 在 Factory Method模式中&#xff0c;父类决定实例的生成方式&#xff0c;但…

Git使用(3):版本管理

一、查看历史 编写一个java类进行测试 选择Git -> Show Git Log查看日志。 第一次修改推送到远程仓库了&#xff0c;所以有origin&#xff08;远程仓库地址&#xff09;&#xff0c;第二次修改只提交到本地仓库所以没有。 二、版本回退 1、本地回退 在要回退的版本上右键&a…

嵌入式学习-输入捕获

简介 框图介绍 输入通道部分 比较捕获寄存器与事件生成 相关寄存器

Linux基本工具的使用

什么是工具&#xff1f; 在Linux中&#xff0c;工具的本质也是指令&#xff0c;只是因为这些指令与我们的开发的关系不是很大&#xff0c;所以就被称为工具 1 软件包管理器yum 在我们的Windows上如果想要安装软件&#xff0c;第一件事就是要先下载软件安装包&#xff0c;然后…

Linux的常用指令 和 基础知识穿插巩固(巩固知识必看)

目录 前言 ls ls 扩展知识 ls -l ls -a ls -al cd cd 目录名 cd .. cd ~ cd - pwd 扩展知识 路径 / cp [选项] “源文件名” “目标文件名” mv [选项] “源文件名” “目标文件名” rm 作用 用法 ./"可执行程序名" mkdir rmdir touch m…

海外住宅IP介绍

住宅IP&#xff0c;通俗的来讲就是分配给家庭的IP地址&#xff0c;ISP默认分配用户为家庭用户&#xff0c;其真实性与安全性都有一定保障。海外住宅IP是指由海外互联网服务提供商分配给家庭用户的IP地址&#xff0c;IP地址通常是静态的&#xff0c;稳定的&#xff0c;可以为用户…

U盘中毒文件变乱码?揭秘原因与高效恢复方法!

在日常使用U盘的过程中&#xff0c;有时我们会遭遇到一个非常棘手的问题——文件突然出现乱码。当你满怀期待地插入U盘&#xff0c;准备打开某个重要文件时&#xff0c;却发现文件名或内容变成了一堆无法识别的字符&#xff0c;这种心情无异于晴天霹雳。乱码文件不仅影响了我们…

鸿蒙生态融合进行时!菊风启动适配HarmonyOS NEXT,赋能原生应用实时

​​今日话题 鸿蒙HarmonyOS NEXT 自华为公开宣布鸿蒙 HarmonyOS NEXT 系统以来&#xff0c;该系统受到了业内广泛关注&#xff0c;和以往鸿蒙系统不同的是该系统底座完全由华为自研&#xff0c;摒弃了 Linux 内核和安卓 AOSP 代码&#xff0c;仅兼容鸿蒙内核及鸿蒙系统的应用…