构建库函数

创建一个通用的模板,后面写程序直接使用这个模板。

$ ls
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         2023/11/8     23:27                Libraries
d-----         2023/11/8     23:27                Listing
d-----         2023/11/8     23:27                Output
d-----         2023/11/8     23:27                Project
d-----         2023/11/8     23:27                User
-a----         2020/2/27     13:45            401 keilkill.bat

前面都是新建的文件夹,keilkill.bat 是从 keil 编译程序中复制出来的一个脚本,可以删掉中间文件。

把固件库 Lib 里的 CMSIS 和 Driver 文件拷贝到 Libraries 文件夹中。CMSIS 中只保留 Device Include 文件夹。Device 中包含外设相关(比如 stm32f4xx.h system_stm32f4xx),Include 中只包含内核相关。

把 main.c stm32f4xx_it.c / stm32f4xx_it.h stm32f4xx_conf.h 拷贝到 User 文件夹中。

在 Project 文件夹里可以包含多给项目文件,不光只有 Keil 的。比如 IAR 的我们新建一个 IAR 文件夹,Keil 我们新建一个 RVMDK(uv5) 文件夹。RealView 是包含不止 MDK 的开发工具集合的称呼,MDK 是 MCU 开发工具集成包,uVersion 是 IDE,Keil 是公司名字。

uVision 里新建工程,新建在 RVMDK(uv5) 文件夹下。

新建组、添加文件如下:

野火霸天虎 STM32F407 学习笔记_4 构建库函数尝试;使用固件库点亮 LED 灯-LMLPHP

STM32F4xx_StdPeriph_Driver 添加 STM32F4xx_StdPeriph_Driver/src 下的所有文件,屏蔽掉 dma2d fmc ltdc,后两个是 sd 和 lcd 屏幕组件。

头文件如下:

野火霸天虎 STM32F407 学习笔记_4 构建库函数尝试;使用固件库点亮 LED 灯-LMLPHP

宏定义如下:

USE_STDPERIPH_DRIVER,STM32F40_41xxx

我现在好想明白为什么宏定义在这里了,这样后面换单片机型号的时候可以直接修改这个宏定义。

PS:我下载的是 1.8.1 版本 stm32f4xx.h 库函数,里面出现了一段重复定义导致编译产生了200多个 warning。我把下面那一段删掉了就好了。

野火霸天虎 STM32F407 学习笔记_4 构建库函数尝试;使用固件库点亮 LED 灯-LMLPHP

Output 里设置 Output 文件夹,不然都在 Proj 里太乱。

记得勾选 MicroLib。

点灯——官方库函数版

在 User 文件夹中新建 LED 文件夹,里面新建 bsp_led.c,代表板级支持包 LED 代码,也就是只针对我们当前这一款开发板的点灯程序。

  1. 设置时钟:rcc 时钟,在 stm32f4xx_rcc.c 中:

  2. /**
      * @brief  Enables or disables the AHB1 peripheral clock.
      * @note   After reset, the peripheral clock (used for registers read/write access)
      *         is disabled and the application software has to enable this clock before 
      *         using it.   
      * @param  RCC_AHBPeriph: specifies the AHB1 peripheral to gates its clock.
      *          This parameter can be any combination of the following values:
      *            @arg RCC_AHB1Periph_GPIOA:       GPIOA clock
      *            @arg RCC_AHB1Periph_GPIOB:       GPIOB clock 
      *            @arg RCC_AHB1Periph_GPIOC:       GPIOC clock
      *            @arg RCC_AHB1Periph_GPIOD:       GPIOD clock
      *            @arg RCC_AHB1Periph_GPIOE:       GPIOE clock
      *            @arg RCC_AHB1Periph_GPIOF:       GPIOF clock
      *            @arg RCC_AHB1Periph_GPIOG:       GPIOG clock
      *            @arg RCC_AHB1Periph_GPIOG:       GPIOG clock
      *            @arg RCC_AHB1Periph_GPIOI:       GPIOI clock
      *            @arg RCC_AHB1Periph_GPIOJ:       GPIOJ clock (STM32F42xxx/43xxx devices) 
      *            @arg RCC_AHB1Periph_GPIOK:       GPIOK clock (STM32F42xxx/43xxx devices)  
      *            @arg RCC_AHB1Periph_CRC:         CRC clock
      *            @arg RCC_AHB1Periph_BKPSRAM:     BKPSRAM interface clock
      *            @arg RCC_AHB1Periph_CCMDATARAMEN CCM data RAM interface clock
      *            @arg RCC_AHB1Periph_DMA1:        DMA1 clock
      *            @arg RCC_AHB1Periph_DMA2:        DMA2 clock
      *            @arg RCC_AHB1Periph_DMA2D:       DMA2D clock (STM32F429xx/439xx devices)  
      *            @arg RCC_AHB1Periph_ETH_MAC:     Ethernet MAC clock
      *            @arg RCC_AHB1Periph_ETH_MAC_Tx:  Ethernet Transmission clock
      *            @arg RCC_AHB1Periph_ETH_MAC_Rx:  Ethernet Reception clock
      *            @arg RCC_AHB1Periph_ETH_MAC_PTP: Ethernet PTP clock
      *            @arg RCC_AHB1Periph_OTG_HS:      USB OTG HS clock
      *            @arg RCC_AHB1Periph_OTG_HS_ULPI: USB OTG HS ULPI clock
      * @param  NewState: new state of the specified peripheral clock.
      *          This parameter can be: ENABLE or DISABLE.
      * @retval None
      */
    void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState)
    

    其他部分基本也是参照库函数(主要是 stm32f4xx_gpio.h)最终呈现如下:

    #include "bsp_led.h"
    
    void LED_GPIO_Config(void){
        //RCC set function in stm32f4xx_rcc.h
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
        {
            //Init structure
            GPIO_InitTypeDef GPIO_InitStructure;
            GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
            GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
            GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
            GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
            GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
            //init function
            GPIO_Init(GPIOF,&GPIO_InitStructure);
        }
        
    }
    

    置位可以使用 GPIO_SetBitsGPIO_ResetBits

    int main()
    {
        int i;
        LED_GPIO_Config();
        
        
        *(unsigned int *)(0x40021400+0x14)&=~(1<<6); 
      while (1)
      {
          GPIO_ResetBits(GPIOF,GPIO_Pin_6);
          i=12000000;
          while(i--);
          GPIO_SetBits(GPIOF,GPIO_Pin_6);
          i=12000000;
          while(i--);
      }
    }
    

    没有上下拉的时候推挽输出会直接被 ODR 值所影响,哪怕没有赋值其中本来的值也会影响。所以推挽输出无上下拉,不置位 LED 也会被点亮,因为 ODR 默认值0.

11-11 07:15