Nucleo-F411RE (STM32F411)LL库体验 8 - PWM的使用

news2024/11/15 18:06:50

Nucleo-F411RE (STM32F411)LL库体验 8 - PWM的使用

1、简述

LD2连接PA5,而PA5可以映射TIM2_CH1,配合TIM2,可以输出PWM。
本片文章大量工作是添加了shell命令,可以通过pwm命令开关pwm以及设置pwm的频率,占空比等。
在这里插入图片描述
在这里插入图片描述

2、TIM2的初始化

prescaler以及period的计算,之前的文章里已经讲了很多了,不管gd32、mm32 ,stm32都是类似了。

__STATIC_INLINE void  BOARD_ConfigureTim2PwmOutput(void)
{
	/*************************/
	/* GPIO AF configuration */
	/*************************/
	/* Enable the peripheral clock of GPIOs */
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
	
	/* GPIO TIM2_CH1 configuration */
	LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_ALTERNATE);
	LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_5, LL_GPIO_PULL_DOWN);
	LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_HIGH);
	LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_5, LL_GPIO_AF_1);
	
	/***********************************************/
	/* Configure the NVIC to handle TIM2 interrupt */
	/***********************************************/
	NVIC_SetPriority(TIM2_IRQn, 0);
	NVIC_EnableIRQ(TIM2_IRQn);
	
	/******************************/
	/* Peripheral clocks enabling */
	/******************************/
	/* Enable the timer peripheral clock */
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); 
	
	/***************************/
	/* Time base configuration */
	/***************************/
	/* Set counter mode */
	/* Reset value is LL_TIM_COUNTERMODE_UP */
	//LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
	
	/* Set the pre-scaler value to have TIM2 counter clock equal to 10 kHz */
	LL_TIM_SetPrescaler(TIM2, __LL_TIM_CALC_PSC(SystemCoreClock, 1000000));
	
	/* Enable TIM2_ARR register preload. Writing to or reading from the         */
	/* auto-reload register accesses the preload register. The content of the   */
	/* preload register are transferred into the shadow register at each update */
	/* event (UEV).                                                             */  
	LL_TIM_EnableARRPreload(TIM2);
	
	/* Set the auto-reload value to have a counter frequency of 1000 Hz */
	/* TIM2CLK = SystemCoreClock / (APB prescaler & multiplier)               */

	LL_TIM_SetAutoReload(TIM2, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM2), 1000));
	
	/*********************************/
	/* Output waveform configuration */
	/*********************************/
	/* Set output mode */
	/* Reset value is LL_TIM_OCMODE_FROZEN */
	LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);
	
	/* Set output channel polarity */
	/* Reset value is LL_TIM_OCPOLARITY_HIGH */
	LL_TIM_OC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_OCPOLARITY_HIGH);
	
	/* Set compare value to half of the counter period (50% duty cycle ) */
	LL_TIM_OC_SetCompareCH1(TIM2, ( (LL_TIM_GetAutoReload(TIM2) + 1 ) / 2));
	
	/* Enable TIM2_CCR1 register preload. Read/Write operations access the      */
	/* preload register. TIM2_CCR1 preload value is loaded in the active        */
	/* at each update event.                                                    */
	LL_TIM_OC_EnablePreload(TIM2, LL_TIM_CHANNEL_CH1);
	
	/**************************/
	/* TIM2 interrupts set-up */
	/**************************/
	/* Enable the capture/compare interrupt for channel 1*/
	LL_TIM_EnableIT_CC1(TIM2);
	
	/**********************************/
	/* Start output signal generation */
	/**********************************/
	/* Enable output channel 1 */
	LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1);
	
	/* Enable counter */
	LL_TIM_EnableCounter(TIM2);
	
	/* Force update generation */
	LL_TIM_GenerateEvent_UPDATE(TIM2);
}

这边开了一个捕获中断,这里只是在捕获到高电平时,获取了一下当前的计数值,用来计算占空比。

void TIM2_IRQHandler(void)
{
	/* Check whether CC1 interrupt is pending */
	if(LL_TIM_IsActiveFlag_CC1(TIM2) == 1)
	{
		/* Clear the update interrupt flag*/
		LL_TIM_ClearFlag_CC1(TIM2);

		/* TIM2 capture/compare interrupt processing(function defined in main.c) */
		TimerCaptureCompare_Callback();
	}
}
uint16_t uwMeasuredDutyCycle;

void TimerCaptureCompare_Callback(void)
{
  	uwMeasuredDutyCycle = (LL_TIM_GetCounter(TIM2) * 100) / ( LL_TIM_GetAutoReload(TIM2) + 1 );
}

3、shell 命令添加。

pwm -i 获取系统信息
在这里插入图片描述

pwm -h 命令帮助
在这里插入图片描述

pwm -d xx 设置占空比
在这里插入图片描述

pwm -f xx 设置pwm的频率
在这里插入图片描述
pwm -p xx 设置tim的presclaer,设置后频率设置为1000HZ

在这里插入图片描述
pwm -b 1开启呼吸灯,pwm -b 0关闭呼吸灯

命令代码:

#include "extend_shell.h"
#include "shell_port.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getopt.h"
#include "main.h"

volatile bool isRunBreath = false;

const char *ocMode[] = {
    "LL_TIM_OCMODE_FROZEN",
    "LL_TIM_OCMODE_ACTIVE",
    "LL_TIM_OCMODE_INACTIVE",
    "LL_TIM_OCMODE_TOGGLE",
    "LL_TIM_OCMODE_FORCED_INACTIVE",
    "LL_TIM_OCMODE_FORCED_ACTIVE",
    "LL_TIM_OCMODE_PWM1",
    "LL_TIM_OCMODE_PWM2"
};

uint32_t TypeOcMode[8] = {LL_TIM_OCMODE_FROZEN,LL_TIM_OCMODE_ACTIVE,
                        LL_TIM_OCMODE_INACTIVE,LL_TIM_OCMODE_TOGGLE,
                        LL_TIM_OCMODE_FORCED_INACTIVE,LL_TIM_OCMODE_FORCED_ACTIVE,
                        LL_TIM_OCMODE_PWM1,LL_TIM_OCMODE_PWM2};

static const char * Find_OCModeName(uint32_t ocModeType)
{
    uint32_t i=0;
    for (i=0; i< 8;i++)
    {
        if (ocModeType == TypeOcMode[i])
            break;
    }
    return ocMode[i];
}                        

void PWM_ShowUsage(void)
{
    printf("Usage:\r\n");
    printf("  pwm (-h | --help)\r\n");
    printf("  pwm (-i | --info)\r\n");
    printf("  pwm (-r | --reload)       set pwm reload (0-65535)\r\n");
    printf("  pwm (-p | --prescaler)    set pwm prescaler (0-65535)\r\n");
    printf("  pwm (-d | --duty)         set pwm duty (1-100)\r\n");
    printf("  pwm (-e | --enable)       enable/disable pwm mode (0/1) \r\n");
    printf("  pwm (-b | --breath)       enable/disable led breath mode (0/1)\r\n");

}

void PWM_ShowInfomation(void)
{
    LL_RCC_ClocksTypeDef rccClock;
    LL_RCC_GetSystemClocksFreq(&rccClock);
    printf("Nucleo-F411RE Info:\r\n");
    printf(" Version                : %s %s\r\n",__DATE__,__TIME__);
    printf(" System Clock           : %ld\r\n",rccClock.SYSCLK_Frequency);
    printf(" AHB Clock              : %ld\r\n",rccClock.HCLK_Frequency);
    printf(" APB1 Clock             : %ld\r\n",rccClock.PCLK1_Frequency);
    printf(" APB2 Clock             : %ld\r\n",rccClock.PCLK2_Frequency);
    printf(" TIM2 Status            : %s\r\n",LL_TIM_IsEnabledCounter(TIM2)==1?"enable" : "disable");
    printf(" TIM2 OC Mode           : %s\r\n",Find_OCModeName(LL_TIM_OC_GetMode(TIM2,LL_TIM_CHANNEL_CH1)));
    printf(" TIM2 CHannel Status    : %s\r\n",LL_TIM_CC_IsEnabledChannel(TIM2,LL_TIM_CHANNEL_CH1) ==1 ?"enable": "disable");
    printf(" TIM2 PWM Prescaler     : %ld\r\n",LL_TIM_GetPrescaler(TIM2) + 1);
    printf(" TIM2 PWM AutoReload    : %ld\r\n",LL_TIM_GetAutoReload(TIM2) + 1);
    printf(" TIM2 PWM Duty          : %.1f%%\r\n",(float)(LL_TIM_OC_GetCompareCH1(TIM2)* 100)/(LL_TIM_GetAutoReload(TIM2) + 1));
    printf(" TIM2 PWM Freq          : %ldHZ\r\n",(rccClock.SYSCLK_Frequency)/((LL_TIM_GetPrescaler(TIM2) + 1)*(LL_TIM_GetAutoReload(TIM2) + 1)));
}

int PWM_Control(int argc,char *argv[])
{       
    int c;
    int longindex = 0;
    int duty = 0;
    int breath = 0;
    const char short_options[] = "hid:e:b:p:f:";
    const struct option long_options[] =
    {
        {"help",            0,  NULL,     'h'},
        {"info",            0,  NULL,     'i'},
        {"duty",            1,  NULL,     'd'},
        {"enable",          1,  NULL,     'e'},
        {"breath",          1,  NULL,     'b'},
        {"freq",            1,  NULL,     'f'},
        {"prescaler",       1,  NULL,     'p'},
        {NULL,              0,  NULL,     0},
    };

    if (argc == 1)
    {
        /* goto the help */
        PWM_ShowUsage();
        return 0;
    }
   /* init 0 */
    optind = 0;
    opterr = 0;
    /* parse */
    do
    {
        /* parse the args */
        c = getopt_long(argc, argv, short_options, long_options, &longindex);
        switch (c)
        {
        case 'f':
            printf("Now set pwm freq %s\r\n",optarg);
            int freq = strtol(optarg,NULL,10);
            if (freq > 0)
            {
                int reload = __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM2), freq);
                if (reload + 1 > 65535)
                {
                    printf("auto reload value must 0-65535,please set prscaler first\r\n");
                    return 0;
                }
                else
                {
                    LL_TIM_DisableCounter(TIM2);
                    LL_TIM_SetAutoReload(TIM2, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM2), freq));
                    LL_TIM_OC_SetCompareCH1(TIM2, ( (LL_TIM_GetAutoReload(TIM2) + 1 ) / 2));
                    LL_TIM_EnableCounter(TIM2);
                }
            }
            else
            {
                printf(" set freq error ,must pwm -f xx\r\n");
                return 0;
            }
            break;    
        case 'p':
            printf("Now set pwm prescaler %s\r\n",optarg);
            int prescaler = strtol(optarg,NULL,10);
            if (prescaler > 0 && (prescaler) < 65535)
            {
                LL_TIM_DisableCounter(TIM2);
                LL_TIM_SetPrescaler(TIM2,prescaler-1);
                int reload = __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM2), 1000); //修改perscaler 默认1000HZ
                if (reload + 1 > 65535)
                {
                    printf("reload value must 0-65525\r\n");
                    return 0;
                }
                else
                {
                    LL_TIM_SetAutoReload(TIM2,reload);
                    LL_TIM_OC_SetCompareCH1(TIM2, ( (LL_TIM_GetAutoReload(TIM2) + 1 ) / 2));
                    LL_TIM_EnableCounter(TIM2);
                }
            }
            else
            {
                printf(" set prescaler error ,must pwm -f xx\r\n");
                return 0;
            }

            break;
        case 'h'/* constant-expression */:
            /* code */
            PWM_ShowUsage();
            return 0;
        case 'i':
            PWM_ShowInfomation();
            break;
        case 'd': 
            
            duty = strtol(optarg,NULL,10);
            printf("Now set pwm duty %s\r\n",optarg);
            if (duty >= 0 && duty <=100)
            {
                duty = (duty  * (LL_TIM_GetAutoReload(TIM2) + 1)) / 100;

                LL_TIM_OC_SetCompareCH1(TIM2, duty);
            }
            else
            {
                printf(" set duty error,must between 0 and 100\r\n");
                return 0;
            }
            
            break;
        case 'e': 
            printf("Now set pwm state\r\n");

            break;
        case 'b': 
            breath = strtol(optarg,NULL,10);
            if (breath == 1)
            {
                isRunBreath = true;
            }
            else if (breath == 0)
            {
                isRunBreath = false;
            }
            else
            {
                printf(" error ,must be 0/1\r\n");
            }

            printf("Now set pwm breath\r\n");
            break;
        default:
            break;
        }
        
    }while (c != -1);

    return 0;
}

SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), pwm, PWM_Control, PWM_Control);

代码

代码下载

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

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

相关文章

数字图像处理期末考点整理(全)

计算&#xff1a;傅里叶变换&#xff0c;双线性插值&#xff0c;直方图均衡化&#xff0c;灰度共生矩阵&#xff0c;霍夫曼编码&#xff0c;区域增长/合并&#xff0c;中值滤波 简答&#xff1a;窗口/模板处理&#xff0c;BMP文件存储格式&#xff0c;滤波器和平滑算子的特点&…

Servlet (上篇)

哥几个来学 Servlet 啦 ~~ 目录 &#x1f332;一、什么是 Servlet &#x1f333;二、第一个 Servlet 程序 &#x1f347;1. 创建项目 &#x1f348;2. 引入依赖 &#x1f349;3. 创建目录 &#x1f34a;4. 编写代码 &#x1f34b;5. 打包程序 &#x1f96d;6. 部署程序…

client-go的Indexer三部曲之二:性能测试

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 本文是《client-go的Indexer》系列的第二篇&#xff0c;在前文咱们通过实例掌握了client-go的Indexer的基本功能&#xff0c;本篇咱们尝试对下面这…

css小兔鲜项目搭建

目录 精灵图 精灵图的使用步骤 背景图片大小 background连写 文字阴影 盒子阴影 过渡 骨架标签 SEO三大标签 版心的介绍 css书写顺序 项目结构搭建 精灵图 场景&#xff1a;项目中将多张小图片&#xff0c;合并成一张大图片&#xff0c;这张大图片称之为精灵图 优点…

c语言实现 顺序存储和链式存储(几种链表)

目录 一、简介 二、一些问题 1、递归free 2、free单向循环链表&#xff1a; 3、free单向链表 4、free双向循环链表 5、free使用数组实现链式存储结构 6、sizeof&#xff08;&#xff09;求字符串大小的问题 三、总结 一、简介 花了几天的时间从头开始使用c语言…

UnityVR--UIManager--UI管理2

目录 前言 UIManger的实现 1. 需要用到的变量和数据 2. 在构造中的工作 3. 初始化面板 4. 显示面板 5. 隐藏面板和隐藏所有面板 6. 其他小工具 在场景中实现 1. 不同面板的类型设置 2. 场景中的设置 前言 接前篇&#xff0c;上一篇已经有了UITools.cs其中定义了UI面板需…

Web服务器群集:部署LAMP平台

目录 一、理论 1.LAMP平台 2.Apache网址服务基础 2.httpd服务器的基本配置 3.构建虚拟Web主机 4.MySQL服务 5.构建PHP运行环境 二、实验 1.LAMP架构DISCUZ论坛应用 三、问题 1.虚拟机内存分配上限问题&#xff0c;内存上限只能加到3G。 2.虚拟机CPU如何设置才更加合…

RISC-V 函数调用约定和Stack使用

RISC-V 函数调用约定和Stack使用 引言RISC-V vs x86RISC-V寄存器StackStruct补充函数调用约定寄存器约定函数跳转和返回指令的编程约定被调用函数的编程约定 RISC-V 汇编与 C 混合编程RISC-V 汇编调用 C 函数C 函数中嵌入 RISC-V 汇编 引言 MIT 6.S081 2020 操作系统 本文为M…

1744_Perl获取文件属性参数

全部学习汇总&#xff1a; GreyZhang/perl_basic: some perl basic learning notes. (github.com) 前阵子写通过Perl执行判断调用ImageMagick实现图像的批量压缩功能脚本时用到过这个功能&#xff0c;只是当时仅仅看了一个获取文件大小的功能。 今天看第六版的小骆驼书又看到了…

一篇十分硬核的QT开发经验文章!送给正在做QT开发或想从事QT开发的你

当编译发现大量错误的时候&#xff0c;从第一个看起&#xff0c;一个一个的解决&#xff0c;不要急着去看下一个错误&#xff0c;往往后面的错误都是由于前面的错误引起的&#xff0c;第一个解决后很可能都解决了。 定时器是个好东西&#xff0c;学会好使用它&#xff0c;有时…

别再为缓慢启动而失去用户! 让你的Android应用体验绝佳性能

为什么要启动优化&#xff1f; 启动优化是为了提升应用程序的启动性能&#xff0c;即减少应用程序从启动到可交互状态所需要的时间。以下是一些关键原因&#xff0c;解释了为什么启动优化是重要的&#xff1a; 用户体验&#xff1a; 启动时间是用户与应用程序互动的第一个体验…

常用API

文章目录 1、String类String概述创建对象的两种方式字符串的内容比较String常用APIString类开发验证码功能手机号码屏蔽功能 2、Object类Object类的作用Object类的常用方法**Object的toString方法**Object的equals方法 3、Objects类4、StringBuilder类5、Math类6、System类7、B…

2023-06-17:说一说redis中渐进式rehash?

2023-06-17&#xff1a;说一说redis中渐进式rehash&#xff1f; 答案2023-06-17&#xff1a; 在Redis中&#xff0c;如果哈希表的数组一直保持不变&#xff0c;就会增加哈希冲突的可能性&#xff0c;从而降低检索效率。为了解决这个问题&#xff0c;Redis会对数组进行扩容&am…

基于Spark的气象数据分析

研究背景与方案 1.1.研究背景 在大数据时代背景下&#xff0c;各行业数据的规模大幅度增加&#xff0c;数据类别日益复杂&#xff0c;给数据分析工作带来极大挑战。气象行业和人们的生活息息相关&#xff0c;随着信息时代的发展&#xff0c;大数据技术的出现为气象数据的发展…

第九章 形态学图像处理

文章目录 9形态学图像处理9.2腐蚀与膨胀9.2.1腐蚀9.2.2膨胀 9.3开操作和闭操作9.5一些基本形态学方法9.3.1边界提取 9.6灰度级形态学9.6.3一些基本的形态学算法 9形态学图像处理 9.2腐蚀与膨胀 9.2.1腐蚀 imgcv2.imread(dige.png,0) kernel np.ones((3,3),np.uint8) num[[…

第七章 原理篇:HOG特征提取

之前面试被问到了然后没有讲出来&#xff0c;所以今天复习一下&#xff01; 气死我了&#xff01; 参考教程&#xff1a; What Is a Feature Descriptor in Image Processing? https://medium.com/analytics-vidhya/a-gentle-introduction-into-the-histogram-of-oriented-…

scratch lenet(3): 直方图均衡化的C语言实现

文章目录 1. 目的2. 原理3. 实现3.1 获得直方图 int hist[256]3.2 获得累积分布 int cdf[256]3.3 均衡化公式3.4 遍历原图&#xff0c;逐点均衡化&#xff0c;得到结果 4. 完整代码和结果4.1 例子14.2 例子24.3 例子34.4 完整代码 5. References 1. 目的 用 C 语言实现直方图均…

低价618背后,看见品牌营销的「产业新洪流」

如今消费者对于低价与品质的兼得需求&#xff0c;正倒逼一个全新的产业经济模式出现&#xff0c;而企业恰是最直接承载者。只有具备真正“低价”的能力模型&#xff0c;企业才能参与到下一轮的产业经济&#xff0c;甚至是社会经济的发展浪潮中。 作者|皮爷 出品|产业家 成本不…

Elasticsearch设置密码

Elasticsearch设置密码 概述ES开启认证配置密码访问开启安全认证的EScurl浏览器直接访问Kibana 配置 es认证直接配置用户名密码到 kibana.yml以kibana密钥的形式使用命令行启动参数形式指定用户名密码 使用kibana 查看es用户 概述 ES默认没有开启安全组件&#xff0c;如果我们…

简单的Dubbo实验环境搭建

Dubbo-api中定义的UserQueryFacade接口可以发布在私服上&#xff0c;这样子dubbo-consumer和dubbo-provider就可以以maven依赖的形式导入使用。dubbo-provider需要提供接口的实现类&#xff0c;dubbo-consumer需要订阅该实现类&#xff0c;他们的元数据都通过zk进行记录。 许多…