harvardx 发表于 2017-5-18 16:40:53

【NUCLEO-L496ZG评测】第二部 : 基于LL库 ,进行GPIO 电平翻转测试

本帖最后由 harvardx 于 2017-5-18 21:24 编辑

       第一篇,已经熟悉了开发环境,熟悉了最新的cubemx. STM32CubeL4 Firmware Package 已经更新到V1.8.0/ 21-April-2017,增加了 对B-L475E-IOT01 物联网开发板的支持. 对于我们使用的L496,更新了CMSIS中的
[*]stm32l496xx.h and stm32l4a6xx.h device description files

[*]FIREWALL

[*]Fix FW_VDSSA_ADD_Msk and FW_VDSL_LENG_Msk definitions
[*]TIM16

[*]Fix TIM16_OR1_TI1_RMP_Msk definitio
[*]      
   本篇,我们将利用LL库,实现同样的功能,这次我们的控制对象改为LD1, 我们要完成LD1的闪烁功能.
   上篇,我们是直接去写端口,延时,然后再写不同电平,延时, 然后循环的思路来实现.本篇采用不同的手段实现, 直接采用d端口的toggle功能来实现. 实际上就是把当前的端口值在和1异或一下.    具体的实现在stm32L4xx_II_gpio.h
__STATIC_INLINE void LL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint32_t PinMask)
{
WRITE_REG(GPIOx->ODR, READ_REG(GPIOx->ODR) ^ PinMask);
}
   LL库的整个体系结构清晰, 效率高, 在库函数和直接寄存器操作中间找到一个合适的切入点. 对效率要求高的应用,可以 试试看LL库.
   主要程序摘录如下: 按照250ms的周期间隔, 不断的反转LD1所在的电平.


/**
******************************************************************************
* @file    Examples_LL/GPIO/GPIO_InfiniteLedToggling/Src/main.c
* @authorMCD Application Team
* @version V1.8.0
* @date    21-April-2017
* @brief   This example describes how to configure and use GPIOs through
*          the STM32L4xxGPIO LL API.
*          Peripheral initialization done using LL unitary services functions.
******************************************************************************
* @attention
*
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*   1. Redistributions of source code must retain the above copyright notice,
*      this list of conditions and the following disclaimer.
*   2. Redistributions in binary form must reproduce the above copyright notice,
*      this list of conditions and the following disclaimer in the documentation
*      and/or other materials provided with the distribution.
*   3. Neither the name of STMicroelectronics nor the names of its contributors
*      may be used to endorse or promote products derived from this software
*      without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/** @addtogroup STM32L4xx_LL_Examples
* @{
*/

/** @addtogroup GPIO_InfiniteLedToggling
* @{
*/

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void   SystemClock_Config(void);
void   Configure_GPIO(void);


/* Private functions ---------------------------------------------------------*/

/**
* @briefMain program
* @paramNone
* @retval None
*/
int main(void)
{
/* Configure the system clock to 40 MHz */
SystemClock_Config();

/* -2- Configure IO in output push-pull mode to drive external LED */
Configure_GPIO();

/* Toggle IO in an infinite loop */
while (1)
{
    LL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_PIN);
   
    /* Insert delay 250 ms */
    LL_mDelay(250);
}
}

/**
* @briefThis function configures GPIO
* @note   Peripheral configuration is minimal configuration from reset values.
*         Thus, some useless LL unitary functions calls below are provided as
*         commented examples - setting is default configuration from reset.
* @paramNone
* @retval None
*/
void Configure_GPIO(void)
{
/* Enable the LED1 Clock */
LED1_GPIO_CLK_ENABLE();

/* Configure IO in output push-pull mode to drive external LED1 */
LL_GPIO_SetPinMode(LED1_GPIO_PORT, LED1_PIN, LL_GPIO_MODE_OUTPUT);
/* Reset value is LL_GPIO_OUTPUT_PUSHPULL */
//LL_GPIO_SetPinOutputType(LED1_GPIO_PORT, LED1_PIN, LL_GPIO_OUTPUT_PUSHPULL);
/* Reset value is LL_GPIO_SPEED_FREQ_LOW */
//LL_GPIO_SetPinSpeed(LED1_GPIO_PORT, LED1_PIN, LL_GPIO_SPEED_FREQ_LOW);
/* Reset value is LL_GPIO_PULL_NO */
//LL_GPIO_SetPinPull(LED1_GPIO_PORT, LED1_PIN, LL_GPIO_PULL_NO);
}

/**
* @briefSystem Clock Configuration
*         The system Clock is configured as follows :
*            System Clock source            = PLL (MSI)
*            SYSCLK(Hz)                     = 40000000
*            HCLK(Hz)                     = 40000000
*            AHB Prescaler                  = 1
*            APB1 Prescaler               = 1
*            APB2 Prescaler               = 1
*            MSI Frequency(Hz)            = 4000000
*            PLL_M                        = 1
*            PLL_N                        = 40
*            PLL_R                        = 2
*            Flash Latency(WS)            = 4
* @paramNone
* @retval None
*/
void SystemClock_Config(void)
{
/* MSI configuration and activation */
LL_FLASH_SetLatency(LL_FLASH_LATENCY_4);
LL_RCC_MSI_Enable();
while(LL_RCC_MSI_IsReady() != 1)
{
};

/* Main PLL configuration and activation */
LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_MSI, LL_RCC_PLLM_DIV_1, 40, LL_RCC_PLLR_DIV_2);
LL_RCC_PLL_Enable();
LL_RCC_PLL_EnableDomain_SYS();
while(LL_RCC_PLL_IsReady() != 1)
{
};

/* Sysclk activation on the main PLL */
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
{
};

/* Set APB1 & APB2 prescaler*/
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);

/* Set systick to 1ms in using frequency set to 80MHz */
/* This frequency can be calculated through LL RCC macro */
/* ex: __LL_RCC_CALC_PLLCLK_FREQ(__LL_RCC_CALC_MSI_FREQ(LL_RCC_MSIRANGESEL_RUN, LL_RCC_MSIRANGE_6),
                                  LL_RCC_PLLM_DIV_1, 40, LL_RCC_PLLR_DIV_2)*/
LL_Init1msTick(40000000);

/* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
LL_SetSystemCoreClock(40000000);
}

#ifdefUSE_FULL_ASSERT

/**
* @briefReports the name of the source file and the source line number
*         where the assert_param error has occurred.
* @paramfile: pointer to the source file name
* @paramline: assert_param error line source number
* @retval None
*/
void assert_failed(char *file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
   ex: printf("Wrong parameters value: file %s on line %d", file, line) */

/* Infinite loop */
while (1)
{
}
}
#endif

/**
* @}
*/

/**
* @}
*/

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/




    由上看出, st的库描述,抽象,非常到位. 整个单片机要运作, 2大基础要做好. 各个内部模块都是时钟驱动的,所有第一要务要做好时钟配置.于是就有了函数:


                              void SystemClock_Config(void)

    这样,各个模块就可以有了生命之源,可以有条不紊的开动起来. 单片机运行,需要和外部打交道.IO口的配置就必须了. 那么再来个功能函数:
                           void Configure_GPIO(void);

    剩下的就是用户的事情了, 一般的单片机就是个前后台系统, 一个大的while1 搞定.不断的查询,计算,读取,处理. 构成用户的APP.
    纵观整个,LL库写出的IO口点灯的基本程序, 结构清晰,功能明确, 函数和变量都命名规范. 可以非常容易的上手这款最新的L496单片机.
















黑溱郎 发表于 2017-6-27 10:24:29

谢谢楼主分享。

harvardx 发表于 2017-6-29 10:35:05

:lol

俏如来 发表于 2018-4-4 14:55:40

好,解决了一个入门问题,LL_mDelay

stm8s003 发表于 2018-4-20 23:21:03

好!不仅将了过程,而且有一定的经验总结,这个很好。看资料最怕没有总结的。
页: [1]
查看完整版本: 【NUCLEO-L496ZG评测】第二部 : 基于LL库 ,进行GPIO 电平翻转测试