博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于STM32CubeMX使用LL库设置PWM输出
阅读量:5291 次
发布时间:2019-06-14

本文共 5347 字,大约阅读时间需要 17 分钟。

HAL和LL库

  HAL是ST为了实现代码在ST家族的MCU上的移植性,推出的一个库,称为硬件抽象层,很明显,这样做将会牺牲存储资源,所以项目最后的代码比较冗余,且运行效率大大降低,运行速度受制于flash的速度,所以很多人设计的时候出现了各种各样的问题。而LL库更精简,他更接近底层,直接操作寄存器来实现,二者在资源消耗上别人已做过比较,。个人更看重代码的效率以及精简,所以选择使用LL库。

利用LL配置TIM1输出PWM

  1. 首先进行时钟配置,手中STM32F1的板子外部晶振为8MHz,将系统的主频配置为72MHz,得益于STM32CubeMX的可视化配置设计,时钟的配置变得轻松起来
  2. 使用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 = 0;  /* 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(),0, 0));  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 (1)  {                LL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);        delay_ms(500);    //    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库。

祝大家学习顺利!

 

 

 

 

 

转载于:https://www.cnblogs.com/yhpbook/p/yhp_stm32_tim.html

你可能感兴趣的文章
Swift 常量&变量
查看>>
Sqli labs系列-less-4 这关好坑!!!
查看>>
路由跟踪工具0trace
查看>>
给大家分享一张CSS选择器优选级图谱 !
查看>>
Win7中不能调试windows service
查看>>
T-SQL触发器,限制一次只能删除一条数据
查看>>
boost库使用:vs2013下boost::container::vector编译出错解决
查看>>
通过httplib2 探索的学习的最佳方式
查看>>
理解运算符重载 4
查看>>
快来熟练使用 Mac 编程
查看>>
第二周
查看>>
断言简介
查看>>
Node.js 入门:Express + Mongoose 基础使用
查看>>
plsql使用,为什么可以能看见其他用户的表
查看>>
一步步教你轻松学奇异值分解SVD降维算法
查看>>
Scripting Java #3:Groovy与invokedynamic
查看>>
2014-04-21-阿里巴巴暑期实习-后台研发-二面经验
查看>>
数据结构中线性表的基本操作-合并两个线性表-依照元素升序排列
查看>>
使用pager进行分页
查看>>
吐医疗器械研发可配置性需求的槽点
查看>>