关于STM32CubeMX使用LL库设置PWM输出
HAL和LL库
HAL是ST为了实现代码在ST家族的MCU上的移植性,推出的一个库,称为硬件抽象层,很明显,这样做将会牺牲存储资源,所以项目最后的代码比较冗余,且运行效率大大降低,运行速度受制于flash的速度,所以很多人设计的时候出现了各种各样的问题。而LL库更精简,他更接近底层,直接操作寄存器来实现,二者在资源消耗上别人已做过比较,https://blog.csdn.net/wping1234/article/details/80197287。个人更看重代码的效率以及精简,所以选择使用LL库。
利用LL配置TIM1输出PWM
- 首先进行时钟配置,手中STM32F1的板子外部晶振为8MHz,将系统的主频配置为72MHz,得益于STM32CubeMX的可视化配置设计,时钟的配置变得轻松起来
- 使用STM32CubeMX配置定时器TIM1,本次设计PWM的周期为1s,将PWM输出控制LED灯,可以看出明显的效果,因此将TIM1的时钟进行7200的分频,对其计数10000次将会得到1s的定时时间,配置如下:
为了可以调节频率,保证调整后的频率可以维持1个周期,开启update中断。也可不开启,可输出PWM。
选择LL库生成代码:
其他的SWD的配置省略,配置好后使用STM32CubeMX生成代码。
软件对LL库的支持不及HAL,生成后需要手动修改和添加少量代码。
这两个地方是我手动修改的,自动生成的这一部分存在错误,请注意。
要开启定时器,则要使用LL库的库函数,关于定时器的控制的库函数在以下这个文件,
我们可以打开这个文件,然后打开他的头文件查看里面可用的函数,使用MDK查看不太方便,可以使用notepad++查看,利用notepad++的函数列表很方便,关于TIM的定时器,打开它需要寻找ENABLE这个关键字:
有些人说LL库没有HAL好理解,需要看手册,其实不需要,看这个库文件就可以了,然后对单片机有一定的了解就可以使用了。这里我们肯定需要使能计数器,.h文件中直接看函数就能知道函数功能
/** @defgroup TIM_LL_EF_Time_Base Time Base configuration
* @{
*/
/**
* @brief Enable timer counter.
* @rmtoll CR1 CEN LL_TIM_EnableCounter
* @param TIMx Timer instance
* @retval None
*/
__STATIC_INLINE void LL_TIM_EnableCounter(TIM_TypeDef *TIMx)
{
SET_BIT(TIMx->CR1, TIM_CR1_CEN);
}
而我们配置的定时器RIM1的ch1,所以看看是否有chi的使能函数,LL库很有规律,关于通道配置的都有CC这两个字母,包括配ch1
我们只是用了TIM1的ch1,就要使能ch1,只需要搜索LL_TIM_CC_E
/**
* @brief Enable capture/compare channels.
* @rmtoll CCER CC1E LL_TIM_CC_EnableChannel\n
* CCER CC1NE LL_TIM_CC_EnableChannel\n
* CCER CC2E LL_TIM_CC_EnableChannel\n
* CCER CC2NE LL_TIM_CC_EnableChannel\n
* CCER CC3E LL_TIM_CC_EnableChannel\n
* CCER CC3NE LL_TIM_CC_EnableChannel\n
* CCER CC4E LL_TIM_CC_EnableChannel
* @param TIMx Timer instance
* @param Channels This parameter can be a combination of the following values:
* @arg @ref LL_TIM_CHANNEL_CH1
* @arg @ref LL_TIM_CHANNEL_CH1N
* @arg @ref LL_TIM_CHANNEL_CH2
* @arg @ref LL_TIM_CHANNEL_CH2N
* @arg @ref LL_TIM_CHANNEL_CH3
* @arg @ref LL_TIM_CHANNEL_CH3N
* @arg @ref LL_TIM_CHANNEL_CH4
* @retval None
*/
__STATIC_INLINE void LL_TIM_CC_EnableChannel(TIM_TypeDef *TIMx, uint32_t Channels)
{
SET_BIT(TIMx->CCER, Channels);
}
将这两个函数加入到初始化后,发现还是不能运行定时器,再进头文件看看,是不是还需要使能什么,搜索LL_TIM_E
这有个输出使能,看看函数功能:
/**
* @brief Enable the outputs (set the MOE bit in TIMx_BDTR register).
* @note The MOE bit in TIMx_BDTR register allows to enable /disable the outputs by
* software and is reset in case of break or break2 event
* @note Macro @ref IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not
* a timer instance provides a break input.
* @rmtoll BDTR MOE LL_TIM_EnableAllOutputs
* @param TIMx Timer instance
* @retval None
*/
__STATIC_INLINE void LL_TIM_EnableAllOutputs(TIM_TypeDef *TIMx)
{
SET_BIT(TIMx->BDTR, TIM_BDTR_MOE);
}
可以发现是使能输出,加上这三个函数后定时器成功工作,LED以1Hz的频率闪烁,成功了!!
int main(void)
{
/* USER CODE BEGIN 1 */
uint32_t duty = ;
/* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); /* System interrupt init*/ /* Peripheral interrupt init*/
/* RCC_IRQn interrupt configuration */
NVIC_SetPriority(RCC_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),, ));
NVIC_EnableIRQ(RCC_IRQn); /** NOJTAG: JTAG-DP Disabled and SW-DP Enabled
*/
LL_GPIO_AF_Remap_SWJ_NOJTAG(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */
SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init(); /* Initialize interrupts */
MX_NVIC_Init();
/* USER CODE BEGIN 2 */
LL_TIM_CC_EnableChannel(TIM1,LL_TIM_CHANNEL_CH1);
LL_TIM_EnableCounter(TIM1);
LL_TIM_EnableAllOutputs(TIM1);
//HAL_TIM_Base_Start(&htim1);
/* USER CODE END 2 */ /* Infinite loop */
/* USER CODE BEGIN WHILE */
while ()
{ LL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
delay_ms();
// HAL_Delay(10);
/* USER CODE END WHILE */ /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
如果需要设置占空比,前面已经提到,关于每个输出通道的设置都有CC,再一想是要设置,那么应该是有Set,于是搜索LL_TIM_CC_S
哎呀,打脸没有找到,那么想一想,前面是配置通道的有CC,那应该是有一个C才对,发现里面有OC的关键字,搜索LL_TIM_OC_S试试
嗯哼,找到了,看看他的定义:
/**
* @brief Set compare value for output channel 1 (TIMx_CCR1).
* @note Macro @ref IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not
* output channel 1 is supported by a timer instance.
* @rmtoll CCR1 CCR1 LL_TIM_OC_SetCompareCH1
* @param TIMx Timer instance
* @param CompareValue between Min_Data=0 and Max_Data=65535
* @retval None
*/
__STATIC_INLINE void LL_TIM_OC_SetCompareCH1(TIM_TypeDef *TIMx, uint32_t CompareValue)
{
WRITE_REG(TIMx->CCR1, CompareValue);
}
其实在配置定时器的时候也能发现一些端倪。
前面也提到中断,经过前面的配置,我依稀觉得LL库自动生成的都是给我们配置好最基本的,我们要使用需要打开相应的开关,使能对应的选项。我想中断也应该是一样,到函数列表看一看:
嗯哼,还真有,打开这个开关,开启调试模式后验证,果不其然,要想使用中断,就需要使能这个中断。
总结
LL库的使用相较于HAL来说,似乎更加的晦涩,但是当你大概了解了这个LL库的设计框架,加上对单片机有一定的了解,根据库函数的函数列表就能成功的使用LL库。
祝大家学习顺利!
关于STM32CubeMX使用LL库设置PWM输出的更多相关文章
- STM32F0使用LL库实现PWM输出
在本次项目中,限于空间要求我们选用了STM32F030F4作为控制芯片.这款MCU不但封装紧凑,而且自带的Flash空间也非常有限,所以我们选择了LL库实现.本文我们将说明如何通过LL库实现PWM信号 ...
- STM32F103ZET6 PWM输出
1.通用定时器的PWM功能 STM32F103ZET6有4个通用定时器,分别是TIM2.TIM3.TIM4.TIM5. 通用定时器由一个可编程预分频器驱动的16位自动装载计数器构成. 通用定时器的很多 ...
- STM32 HAL库学习系列第4篇 定时器TIM----- 开始定时器与PWM输出配置
基本流程: 1.配置定时器 2.开启定时器 3.动态改变pwm输出,改变值 HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); 函数总结: __HAL_TIM ...
- Arduino学习经验(一)之解决舵机库和pwm输出冲突
一.前言 最近在公司学习Arduino uno ,用它实现小车超声波避障功能.实现的功能很简单,就是在小车前方挂一个超声波模块,当碰到障碍物时,会通过舵机进行摆头,判断两边的距离,进行左右转弯.但是碰 ...
- (五)转载:通用定时器PWM输出
1. TIMER输出PWM基本概念 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有 ...
- wiringPi库的pwm配置及使用说明
本文介绍树莓派(raspberry pi)在linux c 环境下的硬件pwm配置及使用方法. 1. 下载安装wiringPi 此步骤建议参考官网指南,wiringPi提供了对树莓派的硬件IO访问,包 ...
- TIMER门控模式控制PWM输出长度
TIMER门控模式控制PWM输出长度 参照一些网友代码做了些修改,由TIM4来控制TIM2的PWM输出长度, 采用主从的门控模式,即TIM4输出高时候TIM2使能输出 //TIM2 PWM输出,由TI ...
- STM32 PWM输出(映射)
STM32 的定时器除了 TIM6 和 7.其他的定时器都可以用来产生 PWM 输出.其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出.而通用定时器也能同时产生多达 4 ...
- NUCLEO-L053R8 TIM定时器 PWM输出
TIM2 PWM输出测试 今天给大伙分享一个TIM2 PWM输出小实验. 实验开发板:Nucleo-L053R8,即STM32L053R8T6. 开发环境:MDK5 图1 - 工程界面 本次实验测试的 ...
随机推荐
- mysql 备份命令
mysqldump --socket=/home/work/mysql/var/mysql.sock -u用户名 -p密码 -P端口 -h10.28.4.64 feedback > feedba ...
- 应用程序嵌入PowerBI报表登陆认证问题解决
https://github.com/AzureAD/azure-activedirectory-library-for-java/issues/144
- golang初识 - install go on ubuntu
WSL: Ubuntu 18.04 1. install go (1) unzip sudo mkdir -p /usr/local/go sudo tar zxvf go1.12.4.linux-a ...
- CentOS 7修改系统时间及硬件时间
转载于:https://www.cnblogs.com/LouisZJ/p/8554991.html [root@nginx ~]# timedatectl --help timedatectl [O ...
- java类的生命周期
https://www.cnblogs.com/aspirant/p/7200523.html 验证的内容:文件格式,字节码,符号引用,元数据 准备:给静态变量分配内存设置初始值(0) 初始化才是真正 ...
- C#;DataTable添加列;DataTable转List泛型集合;List泛型集合转DataTable泛型集合;
给DataTable添加列 string sql = "select * from cgpmb order by code"; DataTable dt = Bobole.Data ...
- Android 开发 蓝牙开发
前言 蓝牙开发其实分2个部分,一个是正常蓝牙功能的开发(比如Android蓝牙的互相连接.读取蓝牙列表.文件传输.蓝牙耳机等等).另外一个是BLE蓝牙开发(属于低功耗蓝牙设备,设备大多是血糖仪.蓝牙手 ...
- Android 开发 获取设备信息与App信息
设备信息 设备ID(DeviceId) 获取办法 android.telephony.TelephonyManager tm = (android.telephony.TelephonyManager ...
- Eclipse配置“运行时依赖路径”
Python项目 本地有项目A,项目B,项目A,依赖项目B,在eclipse中,将项目B的路径添加到项目A的PYTHONPATH中. Java项目Build path(略)
- VS 编译通过后 链接提示 无法使用的外部符号
1. 检查是否已经链接了需要的.lib静态库,如果是自己定义的头文件,检查cpp文件是否添加到了VS工程里 2. 头文件尽量不要包含其他头文件,容易造成包含混乱,如头文件里使用了自定义的类名,最好只用 ...