创建一个通用的模板,后面写程序直接使用这个模板。
$ 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.