Windows下使用Keil MDK5进行stm32f401cc的开发和编译, 配合ST-LINK工具进行烧录, 使用原生非HAL的方式.
所需硬件
STM32F401CCU6 核心板
参数
- ARM 32-bit Cortex-M4 with FPU
- 80 MHz maximum frequency
- 256k flash
- 64k ram
- UFQFPN 封装48pin
外观
电路图(不完全一致)
ST-Link 烧录器
USB2TTL 转接卡
在观察串口输出时需要使用.
安装说明
略
ST官方库: 前往https://www.st.com/, 点击Tools&Software > Embedded Software > MCU & MPU Embedded Software > STM32 Embedded Software > STM32 Standard Peripheral Libraries
(链接), 下载F4, 解压备用.
ST官方库结构说明
STM32F4xx_DSP_StdPeriph_Lib_V1.8.0
目录结构及说明
├─Libraries
│ ├─CMSIS
│ │ ├─Device
│ │ │ └─ST
│ │ │ └─STM32F4xx
│ │ │ ├─Include # 需要
│ │ │ └─Source
│ │ │ └─Templates
│ │ │ ├─arm # startup文件, 需要
│ │ │ ├─gcc_ride7
│ │ │ ├─iar
│ │ │ ├─SW4STM32
│ │ │ ├─TASKING
│ │ │ └─TrueSTUDIO
│ │ ├─Documentation
│ │ ├─DSP_Lib
│ │ ├─Include # 需要
│ │ ├─Lib
│ │ │ ├─ARM
│ │ │ └─GCC
│ │ └─RTOS
│ │ └─Template
│ └─STM32F4xx_StdPeriph_Driver # 需要. 注意里面的xx_fmc.c和xx_fsmc.c不要包含, 因为这两个
# 用到的变量在F401里面没有, 只在少数几个F4xx型号里有.
│ ├─inc
│ └─src
├─Project
│ ├─STM32F4xx_StdPeriph_Examples
│ └─STM32F4xx_StdPeriph_Templates # 需要stm32f4xx_conf.h, stm32f4xx_it.c, stm32f4xx_it.h
│ ├─EWARM
│ ├─MDK-ARM
│ ├─SW4STM32
│ └─TrueSTUDIO
├─Utilities
│ ├─Media
│ ├─ST
│ │ └─STemWin
│ │ └─Software
│ ├─STM32_EVAL
│ │ ├─Common
│ │ ├─STM3240_41_G_EVAL
│ │ ├─STM324x7I_EVAL
│ │ └─STM324x9I_EVAL
│ └─Third_Party
└─_htmresc
开发说明
手工创建项目
创建项目
创建目录并填充文件
对于项目test001, 创建工作目录test001, 在工作目录下创建libraries, mdk-arm, user 这3个目录
- 复制LibrariesCMSIS目录下的Device和Include目录到libraries, 其他目录不需要
- 复制LibrariesSTM32F4xx_StdPeriph_Driver整个目录到libraries
- MDK-ARM
用于放置Keil MDK项目文件, 以及项目开发过程中生成的临时文件 - USER
- 复制 ProjectSTM32F4xx_StdPeriph_Templates 下面的stm32f4xx_conf.h, stm32f4xx_it.c, stm32f4xx_it.h三个文件到这个目录
- 用于放置用户编写的代码
在Keil uVision5中创建项目
Project -> New uVision Project
, 选择前面的user目录, 使用名称test001, 保存- 选择芯片型号stm32f401cc
配置项目
点击Manage Project Items
- 修改project targets名称为test001
- 添加groups
- CMSIS
- StdPeriph_Driver
- Startup
- User
对每个group, 添加的文件为
- CMSIS
- system_stm32f4xx.c
- StdPeriph_Driver
- 添加 librariesSTM32F4xx_StdPeriph_Driversrc 下面的所有c文件, 除了 stm32f4xx_fmc.c 和 stm32f4xx_fsmc.c
- Startup
- 添加 librariesCMSISDeviceSTSTM32F4xxSourceTemplatesarm 下面的 startup_stm32f401xx.s 文件
- User
- 添加 user 目录下的 stm32f4xx_it.c 文件
- 添加 user 目录下的其他文件
点击configure target options , 定位到c/c++
- Define: 写入 USE_STDPERIPH_DRIVER,STM32F401xx
- Include Paths: 如果是按上面的目录结构组织的项目, 可以直接复制下面的配置
..librariesCMSISInclude;..librariesCMSISDeviceSTSTM32F4xxInclude;..librariesSTM32F4xx_StdPeriph_Driverinc;..user
在c/c++下有完整的 compiler control string
--c99 --gnu -c --cpu Cortex-M4.fp -g -O0 --apcs=interwork --split_sections -I ../libraries/CMSIS/Include -I ../libraries/CMSIS/Device/ST/STM32F4xx/Include -I ../libraries/STM32F4xx_StdPeriph_Driver/inc -I ../user
-I./RTE/_stm32f401esp8366
-IC:/Keil_v5/ARM/PACK/Keil/STM32F4xx_DFP/2.15.0/Drivers/CMSIS/Device/ST/STM32F4xx/Include
-IC:/Keil_v5/ARM/CMSIS/Include
-D__UVISION_VERSION="525" -DSTM32F401xC -DUSE_STDPERIPH_DRIVER -DSTM32F401xx
-o .Objects*.o --omf_browse .Objects*.crf --depend .Objects*.d
示例代码
使用开发板自带的led灯实现间隔1秒的亮灭效果.
main.c
#include "main.h"
static __IO uint32_t uwTimingDelay;
RCC_ClocksTypeDef RCC_Clocks;
static void Delay(__IO uint32_t nTime);
void LED_Init(void)
{
GPIO_InitTypeDef aaa;
// 使能指定的GPIO模块时钟--默认复位后开机时钟不会全部提供给各个模块 使用时需要自己开启
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
// 初始化引脚
aaa.GPIO_Pin = GPIO_Pin_13; // 引脚号选择 PC13: RCC_AHB1Periph_GPIOC, GPIOC, GPIO_Pin_13
aaa.GPIO_Mode = GPIO_Mode_OUT; // 输出模式
aaa.GPIO_OType = GPIO_OType_PP; // 推挽输出
aaa.GPIO_Speed = GPIO_High_Speed; // 高速
GPIO_Init(GPIOC, &aaa);
}
void TIM2_init(void)
{
TIM_TimeBaseInitTypeDef aaa;
// 使能对应模块的时钟 TIM2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 初始化定时器
aaa.TIM_Prescaler = 8400; // 通过prescaler将84MHz降为10KHz
aaa.TIM_Period = 10000; // 再通过period设置计时器间隔为上面频率的10K个周期, 即1s
aaa.TIM_CounterMode = TIM_CounterMode_Up; // 选择递增模式
aaa.TIM_ClockDivision = TIM_CKD_DIV1; // 1分频 1 2 4
TIM_TimeBaseInit(TIM2, &aaa);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//使能TIM2的更新中断
TIM_Cmd(TIM2, ENABLE); // 使能TIM2
}
void NVIC_INIT(void)
{
NVIC_InitTypeDef ccc;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组 2分组
ccc.NVIC_IRQChannel = TIM2_IRQn;
ccc.NVIC_IRQChannelCmd = ENABLE;
ccc.NVIC_IRQChannelPreemptionPriority = 0;
ccc.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&ccc);
}
void TIM2_IRQHandler(void)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除溢出中断标志位
GPIO_ToggleBits(GPIOC, GPIO_Pin_13); // 触发值交替变化
}
int main(void)
{
LED_Init();//初始化LED
GPIO_WriteBit(GPIOC, GPIO_Pin_13, 0);
TIM2_init();
NVIC_INIT();
while(1)//卡住
{
}
}
/**
* @brief Inserts a delay time.
* @param nTime: specifies the delay time length, in milliseconds.
* @retval None
*/
void Delay(__IO uint32_t nTime)
{
uwTimingDelay = nTime;
while(uwTimingDelay != 0);
}
/**
* @brief Decrements the TimingDelay variable.
* @param None
* @retval None
*/
void TimingDelay_Decrement(void)
{
if (uwTimingDelay != 0x00)
{
uwTimingDelay--;
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* 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
main.h
#ifndef __MAIN_H
#define __MAIN_H
#include "stm32f4xx.h"
void TimingDelay_Decrement(void);
#endif /* __MAIN_H */
学习开发包中的例子
在官方库的压缩包里, 包含着这个版本各个外设功能的代码例子, 可以直接参考.
烧录
stlink与stm32核心板的连接需要4根线, 连接关系为
G -- GND
CLK -- SWCLK
IO -- SWDIO
V3 -- 3.3V
在Keil uvision5中
- 点击configure target options , 定位到Debug, Use选择ST-Link Debuger, 点击Settings
- 如果Debug Adapter里时空白没有显示ST-LINK/V2, 去windows设备管理器看下设备是否正常
- 切换到Flash Download标签, 勾选Reset and Run
- 点击Download按钮, 或者按F8, 进行烧录