Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发

时间:2023-02-22 11:13:34

Keil MDK STM32系列

概述

Windows下使用Keil MDK5进行stm32f103c8t6的开发和编译, 配合ST-LINK工具进行烧录, 使用标准外设库SPL.

所需硬件

stm32f103系列开发板

stm32f103c8t6核心板

参数

  • ARM 32-bit Cortex-M3
  • 72 MHz maximum frequency
  • 20k ram, 64k flash 这是一个规格比较低的stm32芯片
  • LQFP封装48pin

stm32f103vct6开发板

参数

  • ARM 32-bit Cortex-M3
  • 72 MHz maximum frequency
  • 48k ram, 256k flash
  • LQFP封装100pin

st-link烧录器

在烧录程序到目标芯片以及Debug时需要使用, 自ST-Link V2以来的所有ST-LINK板都带一个COMLED, 一般是红绿两色组合, 也有些是红蓝两色, 两色分别有常亮, 常灭, 闪烁等状态. 不同状态代表不同的含义:

  • 闪烁红色: 正在PC上创建USB模拟器, 如果持续闪烁有可能驱动未安装成功
  • 红色: 在PC与ST-Link之间已经建立连接(USB模拟已完成)
  • 闪烁交替绿色和红色: 目标芯片和PC之间正在交换数据
  • 绿色: ST-Link与目标芯片通信成功
  • 橙色(红绿同时亮): ST-Link与目标芯片通信失败。

USB2TTL转接卡

在观察串口输出时需要使用.

安装说明

文件准备

  • mdk525.exe

    不建议使用5.12等早期版本, 在更新时窗口容易卡, 且失败总会弹出需要手工消除.
  • keygen2032

    大部分找到的keygen, 有效期都是2020年的, 没法用, 必须要能生成2032有效期的版本
  • st-link驱动

    https://www.st.com/zh/development-tools/stsw-link004.html 不安装没法烧录
  • st官方库

    前往https://www.st.com/, 点击Tools&Software > Embedded Software > MCU & MPU Embedded Software > STM32 Embedded Software > STM32 Standard Peripheral Libraries(链接), 下载F1和F4, 解压备用.
    • 这里下载的F1的库文件, Release notes发布日期是2011年, 年代比较久远

安装

  1. 运行mdk525, 安装
  2. 安装完成后Pack Installer会自动运行, 可以让其自己更新
  3. 如果使用stlink下载器的, 还需要安装驱动

注册

  1. 以管理员身份运行Keil uVision5
    1. File->License Management, 复制Computer ID - CID的内容

安装开发包

在Pack Installer中

  1. 在左侧找到STMicroelectronics->STM32F1->STM32F103, 点击
  2. 在右侧会显示对应的Packs, 在Device Specific中找到Keil::STM32F1xx_DFP, 点击Install安装
  3. 同理安装STM32F401

名词解释

CMSIS

微控制器软件接口标准(CMSIS:Cortex Microcontroller Software Interface Standard)是 Cortex-M 处理器系列的与供应商无关的硬件抽象层(A vendor-independent hardware abstraction layer for the Cortex-M processor series and defines generic tool interfaces). 使用CMSIS可以为处理器和外设实现一致且简单的软件接口, 从而简化软件的重用、缩短微控制器新开发人员的学习过程,并缩短新设备的上市时间

ld, md, hd, xl; cl, vl

  • ld(low density), md(medium density), hd(high density), xl(XL-Density) 对应同一个型号线上, 不同flash和ram大小的芯片.
  • vl(value line), cl(connectivity line) 指的是同一型号下, 不同的细分型号线

对于stm32f1x, 各名词的对应关系为

  • Low-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers where the Flash memory density ranges between 16 and 32 Kbytes.
  • Medium-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers where the Flash memory density ranges between 64 and 128 Kbytes.
  • High-density devices are STM32F101xx and STM32F103xx microcontrollers where the Flash memory density ranges between 256 and 512 Kbytes.
  • XL-density devices are STM32F101xx and STM32F103xx microcontrollers where the Flash memory density ranges between 768 Kbytes and 1 Mbyte.
  • Connectivity line devices are STM32F105xx and STM32F107xx microcontrollers.

ST官方库结构说明

STM32F10x_StdPeriph_Lib_V3.5.0

目录结构及说明

├─Libraries
│ ├─CMSIS
│ │ ├─CM3
│ │ │ ├─CoreSupport # CMSIS核心外设访问层代码
│ │ │ └─DeviceSupport
│ │ │ └─ST
│ │ │ └─STM32F10x # stm32f10x相关代码
│ │ │ └─startup
│ │ │ ├─arm # startup_stm32f10x_ld/md/hd/xl.s文件,
# stm32f103c8t66规格为64k flash, 对应md
│ │ │ ├─gcc_ride7
│ │ │ ├─iar
│ │ │ └─TrueSTUDIO
│ │ └─Documentation
│ └─STM32F10x_StdPeriph_Driver # 对应stm32f10x的外设代码
│ ├─inc
│ └─src
├─Project
│ ├─STM32F10x_StdPeriph_Examples # 代码示例
│ └─STM32F10x_StdPeriph_Template # 代码模板, 需要用到stm32f10x_conf.h, stm32f10x_it.c, stm32f10x_it.h这三个文件(直接复制到新项目的USER目录)
│ ├─EWARM
│ ├─HiTOP
│ ├─MDK-ARM
│ ├─RIDE
│ └─TrueSTUDIO
├─Utilities
└─_htmresc

开发说明

创建项目

创建目录并填充文件

以stm32f103为例, 对于项目test001, 创建工作目录test001, 在工作目录下创建MDK-ARM, USER这两个目录

  1. 复制开发包下的Libraries整个目录到当前项目目录下
    • 这个目录中包含了CMSIS核心外设访问层代码
    • stm32的外设库文件
  2. mdk-arm

    用于放置Keil MDK项目文件, 以及项目开发过程中生成的临时文件
  3. hardware

    用于放置自定义的外设, 例如rfid, esp8266等
  4. user
    • 复制 STM32F10x_StdPeriph_Template下面的stm32f10x_conf.h, stm32f10x_it.c, stm32f10x_it.h三个文件到这个目录
    • 用于放置用户编写的代码

ld,md,hd的选择

md hd ld 根据芯片FLASH容量决定

  • 16K < FLASH < 32K ld
  • 64K < FLASH < 128K md
  • 256K < FLASH < 512K hd

在Keil uVision5中创建项目

  1. Project -> New uVision Project, 选择前面的MDK-ARM目录, 使用名称test001, 保存
  2. 选择对应的芯片型号

配置项目

点击Manage Project Items

  1. 修改project targets名称
  2. 添加groups
    1. CMSIS
    2. StdPeriph_Driver
    3. Hardware
    4. Startup
    5. User

对每个group, 添加的文件为

  • CMSIS
    • core_cm3.c
    • system_stm32f10x.c
  • StdPeriph_Driver
    • 添加 libraries/STM32F10x_StdPeriph_Driver/src 下面的所有c文件
  • Hardware
    • 添加 hardware目录下的c文件
  • Startup
    • 添加 libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/arm 下面对应的s文件
  • User
    • 添加 user 目录下的所有c文件

点击configure target options , 定位到c/c++

  1. Define: 写入 USE_STDPERIPH_DRIVER
    • 不需要填STM32F10X_MD, STM32F10X_HD 这些配置, 这个变量在前面选择芯片型号的时候就自动定义了, 不确定的话可以观察产生的Compiler Control String
  2. Include Paths: 如果是按上面的目录结构组织的项目, 可以直接复制下面的配置
..\Libraries\CMSIS\CM3\CoreSupport;..\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x;..\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm;..\Libraries\STM32F10x_StdPeriph_Driver\inc;..\hardware;..\user

在c/c++下能看到完整的编译Compile control string

-c --cpu Cortex-M3 -D__MICROLIB -g -O0 --apcs=interwork --split_sections -I ../Libraries/CMSIS/CM3/CoreSupport -I ../Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x -I ../Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/arm -I ../Libraries/STM32F10x_StdPeriph_Driver/inc -I ../Libraries/ STM32F10x_StdPeriph_Driver/src -I ../hardware -I ../user
-I./RTE/_test001
-IC:/Keil_v5/ARM/PACK/Keil/STM32F1xx_DFP/2.3.0/Device/Include
-IC:/Keil_v5/ARM/CMSIS/Include
-D__UVISION_VERSION="525" -DSTM32F10X_MD -DUSE_STDPERIPH_DRIVER
-o .\Obj\*.o --omf_browse .\Obj\*.crf --depend .\Obj\*.d

烧录

stlink与stm32f103c8t6核心板

连接需要4根线, 连接关系为

G   -- GND
CLK -- SWCLK
IO -- SWDIO
V3 -- 3.3V

stlink与stm32f103vct6开发板

有些开发板没有单独的SWC/SWD接口, 只能连接到JTAG接口, 连接方式为:

  1. 从PCB板上方俯视, 将JTAG接口座缺口朝上
  2. PIN1-PIN20为从上至下, 从右至左
  3. 最右侧为PIN1(上), PIN2(下), 都可以接stlink的3.3V
  4. 从右往左数第4个为PIN7, 接SWDIO, 第5个为PIN9, 接SWCLK
  5. 最左下角为PIN20, 接GND

    Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发

在Keil uvision5中

  1. 点击configure target options , 定位到Debug, Use选择ST-Link Debuger, 点击Settings
  2. 如果Debug Adapter里时空白没有显示ST-LINK/V2, 去windows设备管理器看下设备是否正常
  3. 切换到Flash Download标签, 勾选Reset and Run
  4. 点击Download按钮, 或者按F8, 进行烧录

Debug调试说明

在F7编译完代码, F8将程序通过ST-Link烧录至开发板后, 就可以对程序进行调试

快捷键汇总

  • 进入/跳出Debug模式: Ctrl + F5
  • 继续运行 F5
  • 逐步运行 F10
  • 单步执行(会跳入) F11
  • 从函数内跳出运行 Ctrl + F11
  • 运行到光标所在处 Ctrl + F10
  • 插入/移除断点 F9
  • 移除所有断点Ctrl + Shift + F9

调试要点

  1. 点击Start/Stop Debug SessionCtrl+F5进入Debug模式, 在进入Debug模式后, 会重启程序, 并暂停程序运行
  2. 这时候可以按F5往下执行, 或者按F10F11一步一步执行, 或者Ctrl + F10跳到光标指定的行
  3. 通过Reset按钮, 可以将程序恢复到初始的暂停状态
  4. 常用的调试小窗口
    1. Watch窗口: 选中变量 -> 右键 -> Add xxx to ->Watch1
    2. System Viewer窗口: 可以实时查看外设寄存器值, 通过View->System View -> 指定外设 打开.

stm32开发说明

代码结构

项目的目录结构比较*, 只要包含的C文件正确, 包含的头文件路径正确, 再加上正确的编译变量如USE_STDPERIPH_DRIVER, 编译就没问题. 但是在项目中还是需要注意目录结构, 建议将平时不需改动的代码, 需要频繁修改的代码, 以及IDE相关的文件, 编译中间产生的文件, 都按目录分隔开.

在项目中最终采的代码结构

├─Libraries
│ ├─CMSIS
│ ├─Hardware
│ └─STM32F10x_StdPeriph_Driver
├─MDK-ARM
└─User
  • 其中Libraries直接用开发库的原始文件结构, CMSIS和STM32F10x_StdPeriph_Driver是开发中不需要修改的
  • 将自定义的外设代码都放在单独的Hardware目录中, 这个目录可以放在Libraries下, 也可以放在最外层与Libraries平级
    • 外设代码的头文件中, 不应当包含全局头文件include.h, 而是包含stm32f10x.h, 以及其他需要用到的Hardware头文件.
  • 项目相关的代码, 例如main.c都放在User目录下
    • 创建一个include.h, 用于包含整体的项目头文件, stm32f10x.h以及用到的Hardware头文件, 在main.c中引用include.h
    • 创建一个config.h, 用于放置环境相关的变量, 在main.c以及需要用到的hardware中引用, 这个文件要加到.gitignore
  • IDE相关以及编译中间产生的文件, 都放在MDK-ARM目录下, 这个目录需要添加到.gitignore

代码逻辑

STM32F10x是基于ARM Cortex-M3 的32位内核, F4是基于M4的内核, M3跟M4比就是不带FPU和DSP指令集. 在STM32上的开发思路, 和一般的软件项目开发思路不太一样. STM32上跑的程序, 基本上就是围绕着它的外设进行的, 主要的外设包括 DMA, ETH, GPIO, TIM, U(S)ART, SPI, I2C, ADC等.

代码的套路一般是这样的

  1. 初始化需要的外设, 包括内建的定时器, GPIO, UART, SPI, I2C, 中断以及自定义的外设, 例如RFID, ESP8266等
    1. 对于自定义的外设, 需要自己编写外设驱动, 处理与STM32内建外设之间的通信
  2. 做一个while(1)循环, 在循环中完成业务逻辑
  3. 主体单进程, 在进程中通过各种中断, 触发和处理外设之间的通信

需要注意的地方

  1. 每个外设, 都有对应的总线, 对应的编号, 以及对应的PIN脚, 这些会直接体现到代码中
  2. 要根据总线频率, 自己控制时间, 定时和延迟都是自己控制的
  3. 传输是以byte为单位的, 一个中断可能只产生1个byte的数据
  4. 外设的初始化, 中断位的判断和清除, 都是固定用法
  5. 内存是有限的, 对每个byte都要计算精确, 不能浪费

内存管理

stm32f103c8t6的flash为64k, ram为20k, 容量都很小. 编译结果中的信息

Program Size: Code=8788 RO-data=424 RW-data=72 ZI-data=2328

与这两部分相关联的关系为

  • FLASH占用 = Code + RO Data + RW Data
  • RAM占用 = RW Data + ZI Data + Stack_Size + Heap_Size

实际测试发现, 不论RW Data + ZI Data多大, 运行中可以通过malloc+memset申请的内存只有500个字节, 只要申请的内存超过这个数量, 运行就会卡住.

在代码中, 尽量不要用malloc, 而应该直接声明为固定长度的数组, 这样声明的内存, 可以观察到会增长到ZI Data中去, 这种方式能使用的空间比500字节大得多.

问题排查

当遇到问题时, 例如引脚不工作, 不输出, 输出不正确, 需要通过各种手段检查和排查

  • 引脚不工作, 要检查对应的模块是否正确初始化, 是否使能. STM32中GPIO, UART, NVIC这些模块的启动基本上都是固定套路
    • 对于串口等外设语句上需要检查, AHB1, APB1, APB2 与外设对应关系是否正确, 是否错误使用RCC_APB1去启用RCC_APB2了
    • 是否在main中调用初始化方法了
  • 串口输出和输入的问题排查
    • 首先是在debug界面, 查看串口外设的寄存器值, 看看有没有初始化成功
    • 通过USB2TTL转接卡, 将信号输入输出转移到putty/xshell中进行检查
    • 排除连线断路的问题
  • 字符串输入输出. 因为有\r, \n等格式符号的存在, 会导致输出字符显示较乱, 当需要严格对照时, 需要将每个字符打印成双位16进制输出%02X
  • 程序执行卡住, 有可能是变量申请的内存过大超出了内存限制

参考代码

Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发的更多相关文章

  1. Keil MDK STM32系列&lpar;二&rpar; 基于标准外设库SPL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  2. Keil MDK STM32系列&lpar;三&rpar; 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  3. Keil MDK STM32系列&lpar;四&rpar; 基于抽象外设库HAL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  4. Keil MDK STM32系列&lpar;六&rpar; 基于抽象外设库HAL的ADC模数转换

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  5. Keil MDK STM32系列&lpar;九&rpar; 基于HAL和FatFs的FAT格式SD卡TF卡读写

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  6. Keil MDK STM32系列&lpar;七&rpar; STM32F4基于HAL的PWM和定时器

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  7. Keil MDK STM32系列&lpar;八&rpar; STM32F4基于HAL的PWM和定时器输出音频

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  8. Keil MDK STM32系列&lpar;五&rpar; 使用STM32CubeMX创建项目基础结构

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  9. STM32标准外设库、 HAL库、LL库

    工作以来一直使用ST的STM32系列芯片,ST为开发者提供了非常方便的开发库.到目前为止,有标准外设库(STD库).HAL库.LL库 三种.前两者都是常用的库,后面的LL库是ST最近才添加,目前支持的 ...

随机推荐

  1. Arduino示例教程超声波测距实验

    超声波传感器 超声波是一种超出人类听觉极限的声波即其振动频率高于20 kHz的机械波.超声波传感器在工作的时候就是将电压和超声波之间的互相转换,当超声波传感器发射超声波时,发射超声波的探头将电压转化的 ...

  2. SQL Server 优化器特性导致的内存授予相关BUG

    我们有时会遇到一些坑,要不填平,要不绕过.这里为大家介绍一个相关SQL Server优化器方面的特性导致内存授予的相关BUG,及相关解决方式,也顺便回答下邹建同学的相关疑问. 问题描述 一个简单的查询 ...

  3. Native OR WebApp &quest;

    前两天刚好和一帮产品同学聊过,特指一个APP里面的各页面应该怎么做,大家的总结如下,原理一样,关键是了解Native和Web各自的优劣势:1. 偏交互的Native,偏浏览的Web:交互指复杂操作,输 ...

  4. 2-Medium下的MultipleCommandAssembly

    1.首先创建一个控制台项目 2.添加引用[红色的都是将项目添加为引用,其中蓝色的log4net是直接从源代码下的Reference文件夹下引用的dll] 3.写代码 1)首先将config配置好[ht ...

  5. 查看MySQL还原出来的binlog日志中内容方法

    用mysqlbinlog查出需要查看的数据后,可以用more来查看: [root@yoon data]# more recover_sakila.sql | grep --ignore-case -E ...

  6. java RTTI笔记 之Class学习笔记(摘自java编程思想)

    1.java 使用Class对象来执行其RTTI.java 中每个类在编译后都会对应产生一个Class对象(更恰当地说是被保存在一个同名的.class文件中),甚至void和基本类型也都对应一个cla ...

  7. 转&colon; 谈JAVA&lowbar;OPTS环境变量不起作用

    谈JAVA_OPTS环境变量不起作用 2016-6-14 11:12 最近在处理运行一个java应用时,老是出现java.lang.OutOfMemoryError: Java heap space. ...

  8. SQL语句中Left join&comma;right join&comma;inner join用法

    转载于:https://blog.csdn.net/lichkui/article/details/2002895 一.先看一些最简单的例子 例子 Table Aaid   adate 1      ...

  9. Volley封装

    Volley.jar下载 在Application初始化 Volley queues=Volley.newRequestQueue(appContext); 并返回RequestQueue 对象 pu ...

  10. BZOJ 1211&lbrack;HNOI2004&rsqb;树的计数 - prufer数列

    描述 一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, …, dn,编程需要输出满足d(vi) ...