构建库函数
创建一个通用的模板,后面写程序直接使用这个模板。
$ 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) 文件夹下。
新建组、添加文件如下:
STM32F4xx_StdPeriph_Driver 添加 STM32F4xx_StdPeriph_Driver/src 下的所有文件,屏蔽掉 dma2d fmc ltdc,后两个是 sd 和 lcd 屏幕组件。
头文件如下:
宏定义如下:
USE_STDPERIPH_DRIVER,STM32F40_41xxx
我现在好想明白为什么宏定义在这里了,这样后面换单片机型号的时候可以直接修改这个宏定义。
PS:我下载的是 1.8.1 版本 stm32f4xx.h 库函数,里面出现了一段重复定义导致编译产生了200多个 warning。我把下面那一段删掉了就好了。
Output 里设置 Output 文件夹,不然都在 Proj 里太乱。
记得勾选 MicroLib。
点灯——官方库函数版
在 User 文件夹中新建 LED 文件夹,里面新建 bsp_led.c,代表板级支持包 LED 代码,也就是只针对我们当前这一款开发板的点灯程序。
-
设置时钟:rcc 时钟,在 stm32f4xx_rcc.c 中:
-
/** * @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_SetBits
或GPIO_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.