目录
SAIU R20 1 6 第1页
第1 章. 初识STM32...................................................................................................................... 1
1.1. 课前预习........................................................................................................................................... 1
1.2. 概述.................................................................................................................................................... 1
1.3. 什么是STM32....................................................................................................................................1
1.4. STM32 能做什么............................................................................................................................... 2
1.5. STM32 怎么选型.............................................................................................................................. 3
1.5.1. STM32 分类................................................................................................................................. 3
1.5.2. STM32 命名方法........................................................................................................................ 4
1.5.3. 选择合适的MCU...................................................................................................................... 4
1.5.4. PCB 哪里打样..............................................................................................................................6
1.6. 总结.................................................................................................................................................... 7
1.7. 课后练习........................................................................................................................................... 7
第2 章. STM32 的结构和组成...................................................................................................... 8
2.1. 课前预习........................................................................................................................................... 8
2.2. 概述.................................................................................................................................................... 8
2.3. 什么是寄存器.................................................................................................................................. 8
2.4. STM 32 长啥样..................................................................................................................................8
2.5. 芯片里面有什么............................................................................................................................10
2.5.1. ICode 总线.................................................................................................................................10
2.5.2. 驱动单元....................................................................................................................................10
2.5.3. 被动单元....................................................................................................................................11
2.6. 存储器映射.....................................................................................................................................13
2.7. 寄存器映射.....................................................................................................................................14
2.7.1. STM32 的外设地址映射.......................................................................................................... 15
2.7.2. 总线基地址................................................................................................................................15
2.7.3. 外设基地址................................................................................................................................15
2.7.4. 外设寄存器................................................................................................................................16
2.8. C 语言对寄存器的封装................................................................................................................16
2.8.1. 封装总线和外设基地址........................................................................................................... 16
2.8.2. 封装寄存器列表....................................................................................................................... 17
2.9. 课后练习......................................................................................................................................... 20
第3 章. 初识STM32 标准库..................................................................................................... 21
3.1. 课前预习......................................................................................................................................... 21
3.2. 概述.................................................................................................................................................. 21
3.3. 库目录、文件简介....................................................................................................................... 21
3.4. STM32F10x_StdPeriph_Driver 文件夹..................................................................................24
3.5. 库各文件间的关系....................................................................................................................... 26
3.6. 初识库函数.....................................................................................................................................28
目录
第2 页SAIUR201 6
陈德金老师编著
3.7. 课后练习......................................................................................................................................... 29
第4 章. GPIO 的使用.................................................................................................................. 30
4.1. 课前预习......................................................................................................................................... 30
4.2. 概述.................................................................................................................................................. 30
4.3. GPIO 简介.......................................................................................................................................30
4.4. GPIO 框图剖析.............................................................................................................................. 31
4.4.1. 保护二极管及上、下拉电阻................................................................................................... 31
4.4.2. P-MOS 管和N-MOS 管......................................................................................................... 31
4.4.3. 输出数据寄存器....................................................................................................................... 33
4.4.4. 复用功能输出........................................................................................................................... 34
4.4.5. 输入数据寄存器....................................................................................................................... 34
4.4.6. 复用功能输入........................................................................................................................... 34
4.4.7. 模拟输入输出........................................................................................................................... 34
4.5. GPIO 工作模式.............................................................................................................................. 35
4.5.1. 输入模式(模拟/浮空/上拉/下拉)............................................................................................. 35
4.5.2. 输出模式(推挽/开漏)................................................................................................................35
4.5.3. 复用功能(推挽/开漏)................................................................................................................35
4.6. 点亮LED-硬件设计...................................................................................................................... 37
4.7. 点亮LED-编程要点...................................................................................................................... 38
4.8. 点亮LED-代码分析...................................................................................................................... 38
4.8.1. LED 灯引脚宏定义...................................................................................................................38
4.8.2. 控制LED 灯亮灭状态的宏定义........................................................................................... 39
4.8.3. LED GPIO 初始化函数............................................................................................................ 40
4.8.4. 主函数........................................................................................................................................41
4.9. 点亮LED-下载验证...................................................................................................................... 42
4.10. 课后练习.......................................................................................................................................42
第5 章. STM32 RCC 时钟系统.................................................................................................... 43
5.1. 课前预习......................................................................................................................................... 43
5.2. 概述.................................................................................................................................................. 43
5.3. RCC 主要作用—时钟部分.......................................................................................................... 43
5.4. RCC 框图剖析—时钟部分.......................................................................................................... 43
5.5. 系统时钟......................................................................................................................................... 44
5.5.1. HSE 高速外部时钟信号...........................................................................................................44
5.5.2. PLL 时钟源............................................................................................................................... 45
5.5.3. PLL 时钟PLLCLK.................................................................................................................. 45
5.5.4. 系统时钟SYSCLK.................................................................................................................. 45
5.5.5. AHB 总线时钟HCLK............................................................................................................. 45
5.5.6. APB2 总线时钟HCLK2..........................................................................................................45
目录
SAIU R20 1 6 第3页
5.5.7. 总线时钟HCLK1.....................................................................................................................46
5.6. 设置系统时钟库函数................................................................................................................... 46
5.7. 其他时钟......................................................................................................................................... 47
5.7.1. USB 时钟...................................................................................................................................47
5.7.2. Cortex 系统时钟........................................................................................................................47
5.7.3. ADC 时钟.................................................................................................................................. 48
5.7.4. RTC 时钟、独立看门狗时钟.................................................................................................. 48
5.7.5. MCO 时钟输出......................................................................................................................... 48
5.8. 配置系统时钟实验....................................................................................................................... 48
5.8.1. 使用HSE..................................................................................................................................48
5.8.2. 使用HSI................................................................................................................................... 48
5.8.3. 硬件设计....................................................................................................................................49
5.8.4. 软件设计....................................................................................................................................49
5.8.5. 编程要点....................................................................................................................................49
5.8.6. 代码分析....................................................................................................................................49
5.8.7. 下载验证....................................................................................................................................54
第6 章. STM32 中断应用概览................................................................................................... 55
6.1. 课前预习......................................................................................................................................... 55
6.2. 概述.................................................................................................................................................. 55
6.3. 异常类型......................................................................................................................................... 55
6.4. NVIC 简介.......................................................................................................................................56
6.5. NVIC 寄存器简介..........................................................................................................................56
6.6. NVIC 中断配置固件库.................................................................................................................57
6.7. 优先级的定义................................................................................................................................ 58
6.7.1. 优先级定义................................................................................................................................58
6.7.2. 优先级分组................................................................................................................................58
6.8. 中断编程......................................................................................................................................... 59
6.9. 课后练习......................................................................................................................................... 60
第7 章. EXTI—外部中断/事件控制器..................................................................................... 61
7.1. 课前预习......................................................................................................................................... 61
7.2. 概述.................................................................................................................................................. 61
7.3. EXTI 简介.......................................................................................................................................61
7.4. EXTI 功能框图.............................................................................................................................. 61
7.5. 中断/事件线.................................................................................................................................. 63
7.6. EXTI 初始化结构体详解............................................................................................................ 64
7.7. 外部中断控制实验....................................................................................................................... 65
7.7.1. 硬件设计....................................................................................................................................65
7.7.2. 软件设计....................................................................................................................................65
目录
第4 页SAIUR201 6
陈德金老师编著
7.7.3. 编程要点....................................................................................................................................65
7.7.4. 代码分析....................................................................................................................................65
7.7.5. 下载验证....................................................................................................................................69
7.8. 课后练习......................................................................................................................................... 69
第8 章. SysTick 系统定时器.................................................................................................... 70
8.1. 课前预习......................................................................................................................................... 70
8.2. 概述.................................................................................................................................................. 70
8.3. SysTick 简介................................................................................................................................ 70
8.4. SysTick 寄存器介绍................................................................................................................... 70
8.5. SysTick 定时实验.......................................................................................................................... 72
8.5.1. 硬件设计....................................................................................................................................72
8.5.2. 软件设计....................................................................................................................................72
8.5.3. 编程要点....................................................................................................................................72
8.5.4. 代码分析....................................................................................................................................73
8.6. 课后练习......................................................................................................................................... 79
第9 章. USART—串口通讯......................................................................................................... 80
9.1. 课前预习......................................................................................................................................... 80
9.2. 概述.................................................................................................................................................. 80
9.3. 串口通讯协议简介....................................................................................................................... 80
9.3.1. 物理层........................................................................................................................................80
9.3.2. 协议层........................................................................................................................................84
9.4. STM32 的USART 简介................................................................................................................ 85
9.5. USART 功能框图............................................................................................................................85
9.6. USART 初始化结构体详解.......................................................................................................... 90
9.7. USART1 接发通信实验.................................................................................................................91
9.7.1. 硬件设计....................................................................................................................................92
9.7.2. 软件设计....................................................................................................................................92
9.7.3. 编程要点....................................................................................................................................92
9.7.4. 代码分析....................................................................................................................................93
9.7.5. 下载验证....................................................................................................................................97
9.8. 课后练习......................................................................................................................................... 97
第10 章. DMA 直接存储区访问.................................................................................................. 98
10.1. 课前预习.......................................................................................................................................98
10.2. 概述................................................................................................................................................98
10.3. DMA 简介.......................................................................................................................................98
10.4. DMA 功能框图.............................................................................................................................. 98
10.5. DMA 数据配置............................................................................................................................100
10.6. DMA 初始化结构体详解.......................................................................................................... 101
目录
SAIU R20 1 6 第5页
10.7. DMA 存储器到存储器模式实验.............................................................................................103
10.7.1. 硬件设计................................................................................................................................103
10.7.2. 软件设计................................................................................................................................103
10.7.3. 编程要点................................................................................................................................103
10.7.4. 代码分析................................................................................................................................104
10.7.5. 下载验证................................................................................................................................107
10.8. 课后练习.....................................................................................................................................107
第11 章. TIM 基本定时器........................................................................................................ 108
11.1. 课前预习.....................................................................................................................................108
11.2. 概述..............................................................................................................................................108
11.3. 定时器分类................................................................................................................................ 108
11.4. 基本定时器功能框图讲解......................................................................................................109
11.5. 定时器初始化结构体详解......................................................................................................110
11.6. 基本定时器定时实验...............................................................................................................111
11.6.1. 硬件设计................................................................................................................................111
11.6.2. 软件设计................................................................................................................................111
11.6.3. 编程要点................................................................................................................................111
11.6.4. 软件分析................................................................................................................................111
11.6.5. 下载验证................................................................................................................................114
11.7. 课后练习.....................................................................................................................................114
第12 章. TIM 高级定时器........................................................................................................ 115
12.1. 课前预习.....................................................................................................................................115
12.2. 概述..............................................................................................................................................115
12.3. 高级控制定时器....................................................................................................................... 115
12.4. 高级控制定时器功能框图........................................................................................................116
12.4.1. 时钟源....................................................................................................................................117
12.4.2. 外部时钟模式1................................................................................................................... 117
12.4.3. 外部时钟模式2................................................................................................................... 118
12.4.4. 内部触发输入....................................................................................................................... 119
12.4.5. 输入捕获................................................................................................................................121
12.4.6. 输出比较................................................................................................................................122
12.4.7. 断路功能................................................................................................................................125
12.5. 输入捕获应用............................................................................................................................125
12.5.1. 测量频率................................................................................................................................126
12.5.2. 测量脉宽................................................................................................................................126
12.6. PWM 输入模式............................................................................................................................126
12.7. 输出比较应用............................................................................................................................128
12.7.1. PWM 输出模式.....................................................................................................................128
目录
第6 页SAIUR201 6
陈德金老师编著
12.7.2. PWM 边沿对齐模式.............................................................................................................128
12.7.3. PWM 中心对齐模式.............................................................................................................129
12.8. 定时器初始化结构体详解......................................................................................................129
12.8.1. TIM_TimeBaseInitTypeDef...................................................................................................130
12.8.2. TIM_OCInitTypeDef..............................................................................................................130
12.8.3. TIM_ICInitTypeDef............................................................................................................... 131
12.8.4. TIM_BDTRInitTypeDef.........................................................................................................132
12.9. PWM 互补输出实验................................................................................................................... 133
12.9.1. 硬件设计................................................................................................................................133
12.9.2. 软件设计................................................................................................................................133
12.9.3. 编程要点................................................................................................................................133
12.9.4. 软件分析................................................................................................................................134
12.9.5. 下载验证................................................................................................................................136
第13 章. I2C 通讯.................................................................................................................... 138
13.1. 课前预习.....................................................................................................................................138
13.2. 概述..............................................................................................................................................138
13.3. I2C 协议简介............................................................................................................................138
13.3.1. I2C 物理层............................................................................................................................. 139
13.3.2. 协议层....................................................................................................................................140
13.3.3. 通讯的起始和停止信号....................................................................................................... 141
13.4. STM32 的I2C 特性及架构................................................................................................... 144
13.4.1. STM32 的I2C 外设简介.................................................................................................... 144
13.4.2. STM32 的I2C 架构剖析.................................................................................................... 145
13.4.3. 通讯过程................................................................................................................................147
13.5. I2C 初始化结构体详解.......................................................................................................... 149
13.6. I2C—读写EEPROM 实验........................................................................................................150
13.6.1. 硬件设计................................................................................................................................150
13.6.2. 软件设计................................................................................................................................151
13.6.3. 编程要点................................................................................................................................151
13.6.4. 代码分析................................................................................................................................152
13.6.5. 下载验证................................................................................................................................167
13.7. 课后练习.....................................................................................................................................168
第14 章. SPI 通讯.................................................................................................................... 169
14.1. 课前预习.....................................................................................................................................169
14.2. 概述..............................................................................................................................................169
14.3. SPI 协议简介............................................................................................................................169
14.3.1. SPI 物理层.............................................................................................................................169
14.3.2. 协议层....................................................................................................................................171
目录
SAIU R20 1 6 第7页
14.4. STM32 的SPI 特性及架构................................................................................................... 173
14.4.1. STM32 的SPI 外设简介.................................................................................................... 173
14.4.2. TM32 的SPI 架构剖析...................................................................................................... 174
14.4.3. 通讯过程................................................................................................................................175
14.5. SPI 初始化结构体详解.......................................................................................................... 177
14.6. SPI—读写串行FLASH 实验................................................................................................. 178
14.6.1. 硬件设计................................................................................................................................179
14.6.2. 软件设计................................................................................................................................179
14.6.3. 编程要点................................................................................................................................180
14.6.4. 代码分析................................................................................................................................180
14.6.5. 下载验证................................................................................................................................198
14.7. 课后练习.....................................................................................................................................198
第15 章. 陀螺仪姿态检测....................................................................................................... 199
15.1. 课前预习.....................................................................................................................................199
15.2. 概述..............................................................................................................................................199
15.3. 姿态检测.....................................................................................................................................199
15.3.1. 基本认识................................................................................................................................199
15.3.2. 坐标系....................................................................................................................................200
15.4. 利用陀螺仪检测角度...............................................................................................................201
15.5. 利用加速度计检测角度............................................................................................................ 202
15.6. 利用磁场检测角度................................................................................................................... 203
15.7. 利用GPS 检测角度................................................................................................................ 204
15.8. 姿态融合与四元数..................................................................................................................... 204
15.9. MPU6050 模块简介...................................................................................................................... 204
15.9.1. MPU6050 模块功能及外观..................................................................................................204
15.9.2. MPU6050 模块的引脚功能说明......................................................................................... 205
15.9.3. MPU6050 模块的硬件原理图..............................................................................................205
15.10. MPU6050 模块的特性参数.......................................................................................................206
15.11. MPU6050—获取原始数据实验............................................................................................. 207
15.11.1. 硬件设计............................................................................................................................. 207
15.11.2. 配套程序简介..................................................................................................................... 208
15.11.3. 软件设计............................................................................................................................. 209
15.11.4. 程序设计要点..................................................................................................................... 209
15.11.5. 代码分析............................................................................................................................. 209
15.11.6. 下载验证............................................................................................................................. 215
15.12. MPU6050—利用DMP 进行姿态解算..................................................................................216
15.12.1. 硬件设计............................................................................................................................. 216
15.12.2. 软件设计............................................................................................................................. 216
15.12.3. 程序设计要点..................................................................................................................... 216
目录
第8 页SAIUR201 6
陈德金老师编著
15.12.4. 代码分析............................................................................................................................. 216
15.12.5. 下载验证............................................................................................................................. 226
15.13. MPU6050—使用第三方上位机............................................................................................. 227
15.13.1. 硬件设计............................................................................................................................. 227
15.13.2. 软件设计............................................................................................................................. 227
15.13.3. 程序设计要点..................................................................................................................... 227
15.13.4. 代码分析............................................................................................................................. 227
15.13.5. 下载验证............................................................................................................................. 231
第1 章.初识STM32
SAIU R20 1 6 第1页
第1 章. 初识STM32
1.1. 课前预习
在书上找到答案。
1. 什么是STM32。
2. STM32 能做什么什么?
1.2. 概述
本章所讲内容:
(1)STM32 简介
(2)STM32 功能介绍
1.3. 什么是STM32
STM32,从字面上来理解,ST 是意法半导体,M 是Microelectronics 的缩写,32 表示32 位,
合起来理解,STM32 就是指ST 公司开发的32 位微控制器。在如今的32 位控制器当中,STM32 可
以说是最璀璨的新星,它受宠若娇,大受工程师和市场的青睐,无芯能出其右。
51 是嵌入式学习中一款入门级的精典MCU,因其结构简单,易于教学,且可以通过串口编程而不
需要额外的仿真器,所以在教学时被大量采用,至今很多大学在嵌入式教学中用的还是51。51 诞生
于70 年代,属于传统的8 位单片机,如今,久经岁月的洗礼,既有其辉煌又有其不足。现在的市场
产品竞争越来越激烈,对成本极其敏感,相应地对MCU 的性能要求也更苛刻:更多功能,更低功耗,
易用界面和多任务。面对这些要求,51 现有的资源就显得得抓襟见肘。所以无论是高校教学还是市
场需求,都急需一款新的MCU 来为这个领域注入新的活力。基于这样的市场需求, ARM 公司推出了其
全新的基于ARMv7 架构的32 位Cortex-M3 微控制器内核。紧随其后,ST(意法半导体)公司就推出
了基于Cortex-M3 内核的MCU— STM32。STM32 凭借其产品线的多样化、极高的性价比、简单易用的
库开发方式,迅速在众多Cortex-M3 MCU 中脱颖而出,成为最闪亮的一颗新星。STM32 一上市就迅
速占领了中低端MCU 市场,受到了市场和工程师的无比青睐,颇有星火燎原之势。作为一名合格的嵌
入式工程师,面对新出现的技术,我们不是充耳不闻,而是要尽快吻合市场的需要,跟上技术的潮流。
第1 章.初识STM32
第2 页SAIUR201 6
图1-2 STM32F103 搭建的系统界面
如今STM32 的出现就是一种趋势,一种潮流,我们要做的就是搭上这趟快车,让自己的技术更有竞争
力。
1.4. STM32 能做什么
STM32 属于一个微控制器,自带了各种常用通信接口,比如USART、I2C、SPI 等,可接非常多的传感
器,可以控制很多的设备。现实生活中,我们接触到的很多电器产品都有STM32 的身影,比如智能手环,
微型四轴飞行器,平衡车、移动POST 机,智能电饭锅,3D 打印机等等。下面我们以最近最为火爆的两个
产品来讲解下,一个是手环,一个是飞行器。
图1-1 三星GearFit 智能手环
红圈:STM32F439ZIY6S 处理器,2048KB FLASH ,256KB RAM ,WLCSP143 封装。橙圈:Macronix
MX69V28F64 16 MB 闪存,基于MCP 封装的存储器,是一种包含了NOR 和SRAM 的闪存,这在手环手
机这种移动设备中经常使用,优点是体积小,可以减小PCB 的尺寸。这个闪存用的439 的FSMC 接口
驱动。黄圈:InvenSense MPU-6500 陀螺仪/加速度计,用
439 的I2C 接口驱动。绿圈:博通BCM4334WKUBG 芯片,
支持802.11n,蓝牙4.0+HS 以及FM 接收芯片,用439 的
SDIO 或者SPI 接口驱动。显示:1.84"可弯曲屏幕(Super
AMOLED),432 x 128 像素。触摸部分用439 的I2C 接口
驱动,OLED 显示部分用LTDC 接口驱动。
除了这几个重要资源的对比,我们的霸道开发板上还集
成了以太网,音频,CAN, 485 , 232 , USB 转串口, 蜂
鸣器, LED , 电容按键等外设资源, 可以充分的学习
STM32F103ZET6 这个芯片。在板子上面,还可以跑系统
ucosiii,学习图形界面emwin。如果功夫所至,学完之后,
自己都可以做一个类似Gear Fit 这样的手环。可很多人又
会说,Gear Fit 涉及硬件和软件,整个系统这么复杂,并不
是一个人可以完成的。说的没错,我们可以做不了,但是我们
第1 章.初识STM32
SAIU R20 1 6 第3页
的能力可以无限接近,多学点,技多不压身嘛。现在无人机非常火热,高端的无人机用STM32 做不来,
但是小型的四轴飞行器用STM32 还是绰绰有余的。如图1-3 所示飞行器的基本都可以用STM32 搞定。
图1-3 四轴飞行器
1.5. STM32 怎么选型
1.5.1. STM32 分类
STM32 有很多系列,可以满足市场的各种需求,从内核上分有Cortex-M0、M3、M4 和M7 这几
种,每个内核又大概分为主流、高性能和低功耗。具体的见表格1-1。
表格1-2 STM8 和STM32 分类
单纯从学习的角度出发,可以选择F1 和F4,F1 代表了基础型,基于Cortex-M3 内核,主频为
72MHZ,F4 代表了高性能,基于Cortex-M4 内核,主频180M。之于F1,F4(429 系列以上)除了
内核不同和主频的提升外,升级的明显特色就是带了LCD 控制器和摄像头接口,支持SDRAM,这
个区别在项目选型上会被优先考虑。但是从大学教学和用户初学来说,还是首选F1 系列,目前在市
场上资料最多,产品占有量最多的就是F1 系列的STM32。
第1 章.初识STM32
第4 页SAIUR201 6
1.5.2. STM32 命名方法
这里我们以STM32F103ZET6 来讲解下STM32 的命名方法。
表1--3 STM32F103ZET6 命名解释
有关更详细的命名方法见图1-4。
图1-4 STM8 和STM32 命名方法
1.5.3. 选择合适的MCU
了解了STM32 的分类和命名方法之后,就可以根据项目的具体需求先大概选择哪类内核的
MCU,普通应用,不需要接大屏幕的一般选择Cortex-M3 内核的F1 系列,如果要追求高性能,需要
大量的数据运算,且需要外接RGB 大屏幕的则选择Cortex-M4 内核的F429 系列。明确了大方向之后,
接下来就是细分选型,先确定引脚,引脚多的功能就多,价格也贵,具体得根据实际项目中需要使用到
什么功能,够用就好。确定好了引脚数目之后再选择FLASH 大小,相同引脚数的MCU 会有不同的
FLASH 大小可供选择,这个也是根据实际需要选择,程序大的就选择大点的FLASH,要是产品一量
产,这些省下来的都是钱啊。有些月出货量以KK(百万数量级)为单位的产品,不仅是MCU,连电
第1 章.初识STM32
SAIU R20 1 6 第5页
阻电容能少用就少用,更甚者连PCB 的过孔的多少都有讲究。项目中的元器件的选型的水深的很,很
多学问。
如何分配原理图IO
在画原理图之前,一般的做法是先把引脚分类好,然后才开始画原理图,引脚分类具体见表格1-5。
表格1-5 画原理图时的引脚分类
要想根据功能来分配IO,那就得先知道每个IO 的功能说明,这个我们可以从官方的数据手册里
面找到。在学习的时候,有两个官方资料我们会经常用到,一个是参考手册(英文叫Reference manual),
另外一个是数据手册(英文叫Data Sheet)。两者的具体区别见表格1-6。
表格1-6 参考手册和数据手册的内容区别
一句话概括:数据手册主要用于芯片选型和设计原理图时参考,参考手册主要用于在编程的时
候查阅。官方的这两个文档可以从官方网址里面下载:
http://www.stmcu.org/document/list/index/category-150
在数据手册中,有关引脚定义的部分在Pinouts and pin description 这个小节中,具体定义见表格
1-7。
第1 章.初识STM32
第6 页SAIUR201 6
表格1-7 数据手册中对引脚定义
表格1-8 对引脚定义的解读
开始分配原理图IO
比如MCU 型号是STM32F103ZET6,封装为LQFP144,我们在数据手册中找到这个封装的引脚
定义,然后根据引脚序号,一个一个复制出来,整理成excel 表。具体整理方法按照表格5-4 画原理
图时的引脚分类即可。分配好之后就开始画原理图。
1.5.4. PCB 哪里打样
设计好原理图,画好PCB 之后,需要把板子做出来,进行软硬件联调。首先得PCB 打样,可以
在网上找到一些专业的公司帮忙做,如果你足够懒,不想自己焊接电阻电容二三极管什么的,还可以帮
你把PCB 样板上的阻容贴好给你,打样贴片一条龙。
第1 章.初识STM32
SAIU R20 1 6 第7页
1.6. 总结
本章介绍了STM32 的基本概念、应用领域和芯片的选型方法。主要对STM32 芯片有一个比较清
晰的认识,后续章节将会详细介绍这个芯片的各个模块和功能。
1.7. 课后练习
1. 查看实训室的无人机和机器人使用的芯片是哪个?哪些使用的是STM32?
第2 章.STM32 的结构和组成
第8 页SAIUR201 6
陈德金老师编著
第2 章. STM32 的结构和组成
2.1. 课前预习
在书上找到答案。
1. STM32 里面有什么?
2. STM32 的开发方式和51 单片机有什么区别?
2.2. 概述
本章所讲内容:
(1)STM32 芯片结构
(2)寄存器映射
2.3. 什么是寄存器
我们经常说寄存器,那么什么是寄存器?这是我们本章需要讲解的内容,在学习的过程中,大家
带着这个疑问好好思考下,到最后看看大家能否用一句话给寄存器下一个定义。
2.4. STM 32 长啥样
STM32 的基本结构我们开发板中使用的芯片是144pin 的STM32F103ZET6,具体见图6-1。这个就
是我们接下来要学习的STM32,它将带领我们进入嵌入式的殿堂。芯片正面是丝印,ARM 应该是表示该
芯片使用的是ARM 的内核,STM32F103ZET6 是芯片型号,后面的字应该是跟生产批次相关,最上面的
是ST 的LOGO。芯片四周是引脚,左下角的小圆点表示1 脚,然后从1 脚起按照逆时针的顺序排列
(所有芯片的引脚顺序都是逆时针排列的)。开发板中把芯片的引脚引出来,连接到各种传感器上,
然后在STM32 上编程(实际就是通过程序控制这些引脚输出高电平或者低电平)来控制各种传感器工
作,通过做实验的方式来学习STM32 芯片的各个资源。开发板是一种评估板,板载资源非常丰富,引
脚复用比较多,力求在一个板子上验证芯片的全部功能。图2-1 STM32F103ZET6 实物图(红色框中部
分)
第2 章.STM32 的结构和组成
SAIU R20 1 6 第9页
图2-1 STM32F103ZET6 实物图
图2-2 STM32F103ZET6 正面引脚图
第2 章.STM32 的结构和组成
第10 页SAIUR2016
陈德金老师编著
2.5. 芯片里面有什么
我们看到的STM32 芯片是已经封装好的成品,主要由内核和片上外设组成。若与电脑类比,内
核与外设就如同电脑上的CPU 与主板、内存、显卡、硬盘的关系。STM32F103 采用的是Cortex-M3 内
核,内核即CPU,由ARM 公司设计。ARM 公司并不生产芯片,而是出售其芯片技术授权。芯片生产厂
商(SOC)如ST、TI、Freescale,负责在内核之外设计部件并生产整个芯片,这些内核之外的部件被称
为核外外设或片上外设。如GPIO、USART(串口)、I2C、SPI 等都叫做片上外设。具体见图2-3。
图2-3 STM32 芯片架构简图
芯片(这里指内核,或者叫CPU)和外设之间通过各种总线连接,其中驱动单元有4 个,被动单
元也有4 个,具体见图2-4。为了方便理解,我们都可以把驱动单元理解成是CPU 部分,被动单元
都理解成外设。下面我们简单介绍下驱动单元和被动单元的各个部件。
2.5.1. ICode 总线
ICode 中的I 表示Instruction,即指令。我们写好的程序编译之后都是一条条指令,存放在
FLASH 中,内核要读取这些指令来执行程序就必须通过ICode 总线,它几乎每时每刻都需要被使用,
它是专门用来取指的。
2.5.2. 驱动单元
DCode 总线
第2 章.STM32 的结构和组成
SAIUR201 6 第11页
DCode 中的D 表示Data,即数据,那说明这条总线是用来取数的。我们在写程序的时候,数据
有常量和变量两种,常量就是固定不变的,用C 语言中的const 关键字修饰,是放到内部的FLASH 当
中的,变量是可变的,不管是全局变量还是局部变量都放在内部的SRAM。因为数据可以被Dcode 总
线和DMA 总线访问,所以为了避免访问冲突,在取数的时候需要经过一个总线矩阵来仲裁,决定哪
个总线在取数。
系统总线
系统总线主要是访问外设的寄存器,我们通常说的寄存器编程,即读写寄存器都是通过这根系统
总线来完成的。
DMA 总线
DMA 总线也主要是用来传输数据,这个数据可以是在某个外设的数据寄存器,可以在SRAM,可
以在内部的FLASH。因为数据可以被Dcode 总线和DMA 总线访问,所以为了避免访问冲突,在取
数的时候需要经过一个总线矩阵来仲裁,决定哪个总线在取数。
2.5.3. 被动单元
内部的闪存存储器
内部的闪存存储器即FLASH,我们编写好的程序就放在这个地方。内核通过ICode 总线来取里
面的指令。
内部的SRAM
内部的SRAM,即我们通常说的RAM,程序的变量,堆栈等的开销都是基于内部的SRAM。内
核通过DCode 总线来访问它。
FSMC
FSMC 的英文全称是Flexible static memory controller,叫灵活的静态的存储器控制器, 是
STM32F10xx 中一个很有特色的外设,通过FSMC,我们可以扩展内存,如外部的SRAM,NANDFLASH
和NORFLASH。但有一点我们要注意的是,FSMC 只能扩展静态的内存,即名称里面的S:static,
不能是动态的内存,比如SDRAM 就不能扩展。
第2 章.STM32 的结构和组成
第12 页SAIUR2016
陈德金老师编著
AHB 到APB 的桥
从AHB 总线延伸出来的两条APB2 和APB1 总线,上面挂载着STM32 各种各样的特色外
设。我们经常说的GPIO、串口、I2C、SPI 这些外设就挂载在这两条总线上,这个是我们学习STM32
的重点,就是要学会编程这些外设去驱动外部的各种设备。
图2-4 STM32F10xx 系统框图(不包括互联型)
第2 章.STM32 的结构和组成
SAIUR201 6 第13页
2.6. 存储器映射
在图2-4 中,被控单元的FLASH,RAM,FSMC 和AHB 到APB 的桥(即片上外设),这些功能部
件共同排列在一个4GB 的地址空间内。我们在编程的时候,可以通过他们的地址找到他们,然后来操
作他们(通过C 语言对它们进行数据的读和写)。存储器本身不具有地址信息,它的地址是由芯片厂
商或用户分配,给存储器分配地址的过程就称为存储器映射,具体见图2-5。如果给存储器再分配一
个地址就叫存储器重映射。
图2-5 存储器映射
第2 章.STM32 的结构和组成
第14 页SAIUR2016
陈德金老师编著
在这4GB 的地址空间中,ARM 已经粗线条的平均分成了8 个块,每块512MB,每个块也都规
定了用途,具体分类见表格6-1。每个块的大小都有512MB,显然这是非常大的,芯片厂商在每个块
的范围内设计各具特色的外设时并不一定都用得完,都是只用了其中的一部分而已。
表格2-1 存储器功能分类
在这8 个Block 里面,有3 个块非常重要,也是我们最关心的三个块。Block0 用来设计成内
部FLASH,Block1 用来设计成内部RAM,Block2 用来设计成片上的外设,下面我们简单的介绍下
这三个Block 里面的具体区域的功能划分。存储器Block0 内部区域功能划分Block0 主要用于设计片
内的FLASH , 我们使用的STM32F103ZET6 的FLASH 是512KB,属于大容量。要在芯片
内部集成更大的FLASH 或者SRAM 都意味着芯片成本的增加,往往片内集成的FLASH 都不会太
大,ST 能在追求性价比的同时做到512KB,实乃良心之举。
2.7. 寄存器映射
我们知道,存储器本身没有地址,给存储器分配地址的过程叫存储器映射,那什么叫寄存器映射?
寄存器到底是什么?在存储器Block2 这块区域,设计的是片上外设,它们以四个字节为一个单元,共
32bit,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到每个
单元的起始地址,然后通过C 语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的
方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个
内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内
存单元取别名的过程就叫寄存器映射。比如,我们找到GPIOB 端口的输出数据寄存器ODR 的地址
是0x4001 0C0C(至于这个地址如何找到可以先跳过,后面我们会有详细的讲解),ODR 寄存器是
32bit,低16bit 有效,对应着16 个外部IO,写0/1 对应的的IO 则输出低/高电平。现在我们通过C
语言指针的操作方式,让GPIOB 的16 个IO 都输出高电平,具体见代码2-1。
第2 章.STM32 的结构和组成
SAIUR201 6 第15页
代码2-1 通过绝对地址访问内存单元
0x4001 0C0C 在我们看来是GPIOB 端口ODR 的地址,但是在编译器看来,这只是一个普通的
变量,是一个立即数,要想让编译器也认为是指针,我们得进行强制类型转换,把它转换成指针,即
(unsigned int *)0x4001 0C0C,然后再对这个指针进行* 操作。刚刚我们说了,通过绝对地址访问内存
单元不好记忆且容易出错,我们可以通过寄存器的方式来操作,具体见代码2-2。
代码2-2 通过寄存器别名方式访问内存单元
为了方便操作,我们干脆把指针操作“*”也定义到寄存器别名里面,具体见代码2-3。
代码2-3 通过寄存器别名访问内存单元
2.7.1. STM32 的外设地址映射
片上外设区分为三条总线,根据外设速度的不同,不同总线挂载着不同的外设,APB1 挂载低速外
设,APB2 和AHB 挂载高速外设。相应总线的最低地址我们称为该总线的基地址,总线基地址也是挂
载在该总线上的首个外设的地址。其中APB1 总线的地址最低,片外设从这里开始,也叫外设基地址。
2.7.2. 总线基地址
表格2-2 总线基地址
表格2-2 的“相对外设基地址偏移”即该总线地址与“片上外设”基地址0x4000 0000 的差值。关于
地址的偏移我们后面还会讲到。
2.7.3. 外设基地址
总线上挂载着各种外设,这些外设也有自己的地址范围,特定外设的首个地址称为“XX 外设基地
址”,也叫XX 外设的边界地址。具体有关STM32F10xx 外设的边界地址请参考《STM32F10xx 参考
手册》的2.3 小节的存储器映射的表1:STM32F10xx 寄存器边界地址。这里面我们以GPIO 这个外
设来讲解外设的基地址,GPIO 属于高速的外设,挂载到APB2 总线上,具体见表格2-3。
第2 章.STM32 的结构和组成
第16 页SAIUR2016
陈德金老师编著
表格2-3 外设GPIO 基地址
2.7.4. 外设寄存器
在XX 外设的地址范围内,分布着的就是该外设的寄存器。以GPIO 外设为例,GPIO 是通用输
入输出端口的简称,简单来说就是STM32 可控制的引脚,基本功能是控制引脚输出高电平或者低电
平。最简单的应用就是把GPIO 的引脚连接到LED 灯的阴极,LED 灯的阳极接电源,然后通过
STM32 控制该引脚的电平,从而实现控制LED 灯的亮灭。GPIO 有很多个寄存器,每一个都有特定
的功能。每个寄存器为32bit,占四个字节,在该外设的基地址上按照顺序排列,寄存器的位置都以相
对该外设基地址的偏移地址来描述。
2.8. C 语言对寄存器的封装
以上所有的关于存储器映射的内容,最终都是为大家更好地理解如何用C 语言控制读写外设寄存
器做准备,此处是本章的重点内容。
2.8.1. 封装总线和外设基地址
在编程上为了方便理解和记忆,我们把总线基地址和外设基地址都以相应的宏定义起来,总线或者
外设都以他们的名字作为宏名,具体见代码2-4。
第2 章.STM32 的结构和组成
SAIUR201 6 第17页
代码2-4 总线和外设基址宏定义
代码2-4 首先定义了“片上外设”基地址PERIPH_BASE,接着在PERIPH_BASE 上加入各个总
线的地址偏移, 得到APB1 、APB2 总线的地址APB1PERIPH_BASE 、APB2PERIPH_BASE,在
其之上加入外设地址的偏移,得到GPIOA-G 的外设地址,最后在外设地址上加入各寄存器的地址偏
移,得到特定寄存器的地址。一旦有了具体地址,就可以用指针读写,具体见代码2-5。
代码2-5 使用指针控制BSRR 寄存器
2.8.2. 封装寄存器列表
用上面的方法去定义地址,还是稍显繁琐,例如GPIOA-GPIOE 都各有一组功能相同的寄存器,
如GPIOA_ODR/GPIOB_ODR/GPIOC_ODR 等等,它们只是地址不一样,但却要为每个寄存器都定义
它的地址。为了更方便地访问寄存器,我们引入C 语言中的结构体语法对寄存器进行封装,具体见代
码2-6。
第2 章.STM32 的结构和组成
第18 页SAIUR2016
陈德金老师编著
代码2-6 使用结构体对GPIO 寄存器组的封装
这段代码用typedef 关键字声明了名为GPIO_TypeDef 的结构体类型,结构体内有7 个成员变
量,变量名正好对应寄存器的名字。C 语言的语法规定,结构体内变量的存储空间是连续的,其中32
位的变量占用4 个字节,16 位的变量占用2 个字节,具体见图2-6。
图2-6 GPIO_TypeDef 结构体成员的地址偏移
也就是说,我们定义的这个GPIO_TypeDef ,假如这个结构体的首地址为0x4001 0C00(这也是
第一个成员变量CRL 的地址), 那么结构体中第二个成员变量CRH 的地址即为0x4001 0C00
+0x04 ,加上的这个0x04 ,正是代表CRL 所占用的4 个字节地址的偏移量,其它成员变量相对于
结构体首地址的偏移,在上述代码右侧注释已给。这样的地址偏移与STM32 GPIO 外设定义的寄存器
地址偏移一一对应,只要给结构体设置好首地址,就能把结构体内成员的地址确定下来,然后就能以结
构体的形式访问寄存器,具体见代码2-7。
第2 章.STM32 的结构和组成
SAIUR201 6 第19页
代码2-7 通过结构体指针访问寄存器
这段代码先用GPIO_TypeDef 类型定义一个结构体指针GPIOx , 并让指针指向地址
GPIOB_BASE(0x4001 0C00),使用地址确定下来,然后根据C 语言访问结构体的语法,用GPIOx->ODR
及GPIOx->IDR 等方式读写寄存器。最后,我们更进一步,直接使用宏定义好GPIO_TypeDef 类型的
指针,而且指针指向各个GPIO 端口的首地址,使用时我们直接用该宏访问寄存器即可,具体代码2-8。
代码2-8 定义好GPIO 端口首地址址针
这里我们仅是以GPIO 这个外设为例,给大家讲解了C 语言对寄存器的封装。以此类推,其他外
设也同样可以用这种方法来封装。好消息是,这部分工作都由固件库帮我们完成了,这里我们只是分析
了下这个封装的过程,让大家知其然,也只其所以然。
第2 章.STM32 的结构和组成
第20 页SAIUR2016
陈德金老师编著
2.9. 课后练习
1、什么是存储器映射?什么是存储器重映射?
2、什么是寄存器?
第3 章.初识STM32 标准库
SAIUR201 6 第21页
第3 章. 初识STM32 标准库
3.1. 课前预习
在书上找到答案。
1. 什么是STM32 标准库。
2. STM32 使用标准库的开发方式和以前学的寄存器方式有什么不同
3.2. 概述
本章所讲内容:
(1)STM32 标准库的简介
(2)STM32 标准库的文件夹和功能介绍
在上一章中,我们构建了几个控制GPIO 外设的函数,算是实现了函数库的雏形,但GPIO 还有
很多功能函数我们没有实现,而且STM32 芯片不仅仅只有GPIO 这一个外设。如果我们想要亲自完
成这个函数库,工作量非常巨大。ST 公司提供的标准软件库,包含了STM32 芯片所有寄存器的控制
操作,我们直接学习如何使用ST 标准库,会极大地方便控制STM32 芯片。
3.3. 库目录、文件简介
STM32 标准库可以从官网获得,也可以直接从本书的配套资料得到。本书讲解的例程全部采用
3.5.0 库文件。以下内容请大家打开STM32 标准库文件配合阅读。解压库文件后进入其目录:
“STM32F10x_StdPeriph_Lib_V3.5.0\”软件库各文件夹的内容说明见图3-1。
第3 章.初识STM32 标准库
第22 页SAIUR2016
陈德金老师编著
图3-1 ST 标准库目录:STM32F10x_StdPeriph_Lib_V3.5.0\
1. Libraries:文件夹下是驱动库的源代码及启动文件,这个非常重要,我们要使用的固件库就在这
个文件夹里面。
2. Project :文件夹下是用驱动库写的例子和工程模板,其中那些为每个外设写好的例程对我们非常
有用,我们在学习的时候就可以参考这里面的例程,非常全面,简直就是穷尽了外设的所有功能。
3. Utilities:包含了基于ST 官方实验板的例程,不需要用到,略过即可。
4. stm32f10x_stdperiph_lib_um.chm: 库帮助文档,这个很有用,不喜欢直接看源码的可以在合理查
询每个外设的函数说明,非常详细。这是一个已经编译好的HTML 文件, 主要讲述如何使用驱
动库来编写自己的应用程序。说得形象一点,这个HTML 就是告诉我们:ST 公司已经为你写好
了每个外设的驱动了,想知道如何运用这些例子就来向我求救吧。不幸的是,这个帮助文档是英
文的,这对很多英文不好的朋友来说是一个很大的障碍。但这里要告诉大家,英文仅仅是一种工
具,绝对不能让它成为我们学习的障碍。其实这些英文还是很简单的,我们需要的是拿下它的勇
气。在使用库开发时,我们需要把libraries 目录下的库函数文件添加到工程中,并查阅库帮助文
档来了解ST 提供的库函数,这个文档说明了每一个库函数的使用方法。进入Libraries 文件夹
看到, 关于内核与外设的库文件分别存放在CMSIS 和STM32F10x_StdPeriph_Driver 文件夹
中。
STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\文件夹展开内容见图3-2。
第3 章.初识STM32 标准库
SAIUR201 6 第23页
图3-2 CMSIS 文件夹内容目录:Libraries\CMSIS\
其中黄色框框住的是我们需要用到的内容,下面我们一一讲解下这几个文件的作用。内核相关文件
在CoreSupport 文件夹中有core_cm3.c 和core_cm3.h 两个文件。Core_cm3.h 头文件里面实现了内核
的寄存器映射,对应外设头文件stm32f10x.h,区别就是一个针对内核的外设,一个针对片上(内核之
外)的外设。core_cm3.c 文件实现了一下操作内核外设寄存器的函数,用的比较少。我们还需要了解
的是core_cm3.h 头文件中包含了“stdint.h” 这个头文件,这是一个ANSI C 文件,是独立于处理器之
外的,就像我们熟知的C 语言头文件“stdio.h” 文件一样。位于RVMDK 这个软件的安装目录下,主
要作用是提供一些类型定义。见代码清单3-1。
代码清单3-1:stdint.h 文件中的类型定义
这些新类型定义屏蔽了在不同芯片平台时,出现的诸如int 的大小是16 位,还是32 位的差异。
所以在我们以后的程序中,都将使用新类型如uint8_t 、uint16_t 等。在稍旧版的程序中还经常会出现
如u8、u16、u32 这样的类型,分别表示的无符号的8 位、16 位、32 位整型。初学者碰到这样的旧
类型感觉一头雾水,它们定义的位置在STM32f10x.h 文件中。建议在以后的新程序中尽量使用
第3 章.初识STM32 标准库
第24 页SAIUR2016
陈德金老师编著
uint8_t 、uint16_t 类型的定义。启动文件启动文件放在startup/arm 这个文件夹下面,这里面启动文件
有很多个,不同型号的单片机用的启动文件不一样,有关每个启动文件的详细说明见表
我们开发板中用的STM32F103VET6 或者STM32F103ZET6 的FLASH 都是512K,属于基本型
的大容量产品,启动文件统一选择startup_stm32f10x_hd.s。
Stm32f10x.h
这个头文件实现了片上外设的所以寄存器的映射,是一个非常重要的头文件,在内核中与之想对应
的头文件是core_cm3.h。
system_stm32f10x.c
system_stm32f10x.c 文件实现了STM32 的时钟配置,操作的是片上的RCC 这个外设。系统在
上电之后,首选会执行由汇编编写的启动文件,启动文件中的复位函数中调用的SystemInit 函数就在
这个文件里面定义。调用完之后,系统的时钟就被初始化成72M。如果后面我们需要重新配置系统时
钟,我们就可以参考这个函数重写。为了维持库的完整性, 我们不会直接在这个文件里面修改时钟配
置函数。
3.4. STM32F10x_StdPeriph_Driver 文件夹
文件目录: Libraries\STM32F10x_StdPeriph_Driver 进入libraries 目录下的
STM32F10x_StdPeriph_Driver 文件夹,见图3-3。
图3-3 外设驱动
第3 章.初识STM32 标准库
SAIUR201 6 第25页
STM32F10x_StdPeriph_Driver 文件夹下有inc(include 的缩写)跟src(source 的简写) 这两
个文件夹,这里的文件属于CMSIS 之外的的、芯片片上外设部分。src 里面是每个设备外设的驱动
源程序,inc 则是相对应的外设头文件。src 及inc 文件夹是ST 标准库的主要内容,甚至不少人直接
认为ST 标准库就是指这些文件,可见其重要性。在src 和inc 文件夹里的就是ST 公司针对每个
STM32 外设而编写的库函数文件,每个外设对应一个.c 和.h 后缀的文件。我们把这类外设文件统称
为: stm32f10x_ppp.c 或stm32f10x_ppp.h 文件,PPP 表示外设名称。如在上一章中我们自建的
stm32f10x_gpio.c 及tm32f10x_gpio.h 文件,就属于这一类。如针对模数转换(ADC)外设,在src 文件
夹下有一个stm32f10x_adc.c 源文件,在inc 文件夹下有一个stm32f10x_adc.h 头文件,若我们开发的
工程中用到了STM32 内部的ADC,则至少要把这两个文件包含到工程里。见图3-4。
图3-4 驱动的源文件及头文件
这两个文件夹中,还有一个很特别的misc.c 文件,这个文件提供了外设对内核中的NVIC(中断向
量控制器) 的访问函数, 在配置中断时, 我们必须把这个文件添加到工程中。stm32f10x_it.c 、
stm32f10x_conf.h 和system_stm32f10x.c 文件
stm32f10x_it.c:这个文件是专门用来编写中断服务函数的,在我们修改前,这个文件
已经定义了一些系统异常(特殊中断)的接口,其它普通中断服务函数由我们自己添加。但是我们怎么知
道这些中断服务函数的接口如何写?是不是可以自定义呢?答案当然不是,
这些都可以在汇编启动文件中找到,在学习中断和启动文件的时候我们会详细介绍
system_stm32f10x.c:这个文件包含了STM32 芯片上电后初始化系统时钟、扩展外部存储器用的
第3 章.初识STM32 标准库
第26 页SAIUR2016
陈德金老师编著
函数,例如我们前两章提到供启动文件调用的“SystemInit”函数,用于上电后初始化时钟,该函数的定
义就存储在system_stm32f10x.c 文件。STM32F103 系列的芯片,调用库的这个SystemInit 函数后,
系统时钟被初始化为72MHz,如有需要可以修改这个文件的内容,设置成自己所需的时钟频率,但鉴
于保持库的完整性,我们在做系统时钟配置的时候会另外重写时钟配置函数。
stm32f10x_conf.h:这个文件被包含进stm32f10x.h 文件。当我们使用固件库编程的时候,如果需
要某个外设的驱动库,就需要包含该外设的头文件:stm32f10x_ppp.h,包含一个还好,如果是用了多
外设,就需要包含多个头文件,这不仅影响代码美观也不好管理,现我们用一个头文件stm32f10x_conf.h
把这些外设的头文件都包含在里面,让这个配置头文件统一管理这些外设的头文件,我们在应用程序中
只需要包含这个配置头文件即可,我们又知道这个头文件在stm32f10x.h 的最后被包含,所以最终我
们只需要包含stm32f10x.h 这个头文件即可,非常方便。Stm32f10x_conf.h 见代码清单3-2。默认情况
下是所以头文件都被包含,没有被注释掉。我们也可以把不要的都注释掉,只留下需要使用的即可。
代码清单3-2 stm32f10x_conf.h 文件配置软件库
3.5. 库各文件间的关系
前面向大家简单介绍了各个库文件的作用,库文件是直接包含进工程即可,丝毫不用修改,而有的
文件就要我们在使用的时候根据具体的需要进行配置。接下来从整体上把握一下各个文件在库工程中的
层次或关系,这些文件对应到CMSIS 标准架构上。见图3-5。
第3 章.初识STM32 标准库
SAIUR201 6 第27页
图3-5 库各文件关系
图3-5 描述了STM32 库各文件之间的调用关系,在实际的使用库开发工程的过程中,我们把位
于CMSIS 层的文件包含进工程,除了特殊系统时钟需要修改system_stm32f10x.c,其它文件丝毫不用
修改,也不建议修改。对于位于用户层的几个文件,就是我们在使用库的时候,针对不同的应用对库文
件进行增删(用条件编译的方法增删)和改动的文件。
第3 章.初识STM32 标准库
第28 页SAIUR2016
陈德金老师编著
3.6. 初识库函数
所谓库函数,就是STM32 的库文件中为我们编写好驱动外设的函数接口,我们只要调用这些库
函数,就可以对STM32 进行配置,达到控制目的。我们可以不知道库函数是如何实现的,但我们调
用函数必须要知道函数的功能、可传入的参数及其意义、和函数的返回值。于是,有读者就问那么多函
数我怎么记呀?我的回答是:会查就行了,哪个人记得了那么多。所以我们学会查阅库帮助文档是很
有必要的。打开库帮助文档《stm32f10x_stdperiph_lib_um.chm》见图3-6
图3-6 库帮助文档
层层打开文档的目录标签:标签目录:Modules\STM32F10x_StdPeriph_Driver\可看到STM32F10x
_StdPeriph_Driver 标签下有很多外设驱动文件的名字MISC、ADC、BKP、CAN 等标签。我们试着查
看GPIO 的“ 位设置函数GPIO_SetBits” 看看, 打开标签: 标签目录:
Modules\STM32F10x_StdPeriph_Driver\GPIO\Functions\GPIO_SetBits 见图3-7。
第3 章.初识STM32 标准库
SAIUR201 6 第29页
图3-7 库帮助文档的函数说明
利用这个文档,我们即使没有去看它的具体源代码,也知道要怎么利用它了。如GPIO_SetBits,
函数的原型为void GPIO_SetBits(GPIO_TypeDef * GPIOx , uint16_tGPIO_Pin)。它的功能是:输入一
个类型为GPIO_TypeDef 的指针GPIOx 参数,选定要控制的GPIO 端口;输入GPIO_Pin_x 宏,其
中x 指端口的引脚号,指定要控制的引脚。其中输入的参数GPIOx 为ST 标准库中定义的自定义数
据类型,这两个传入参数均为结构体指针。初学时,我们并不知道如GPIO_TypeDef 这样的类型是什
么意思,可以点击函数原型中带下划线的GPIO_TypeDef 就可以查看这个类型的声明了。就这样初步
了解了一下库函数,读者就可以发现STM32 的库是写得很优美的。每个函数和数据类型都符合见名
知义的原则,当然,这样的名称写起来特别长,而且对于我们来说要输入这么长的英文,很容易出错,
所以在开发软件的时候,在用到库函数的地方,直接把库帮助文档中的函数名称复制粘贴到工程文件就
可以了。而且,配合MDK 软件的代码自动补全功能,可以减少输入量。有的用户觉得使用库文档麻
烦,也可以直接查阅STM32 标准库的源码,库帮助文档的说明都是根据源码生成的,所以直接看源
码也可以了解函数功能。
3.7. 课后练习
打开ST 标准库,查看它的各个文件,对比一下ST 标准库与我们上一章中工程里的同名文件,
查看有何差异。
第4 章.GPIO 的使用
第30 页SAIUR2016
第4 章. GPIO 的使用
4.1. 课前预习
在书上找到答案。
1. STM32 f103zet6 的GPIO 有多少个?
2. STM32 f103zet6 的GPIO 工作模式有哪些?
4.2. 概述
本章所讲内容:
(1)STM32 的GPIO 的结构和功能
(2)使用GPIO 点亮LED 灯
利用库建立好的工程模板,就可以方便地使用STM32 标准库编写应用程序,可以说从这一章我
们真正开始迈入STM32 固件库开发的大门。
4.3. GPIO 简介
GPIO 是通用输入输出端口的简称,简单来说就是STM32 可控制的引脚,STM32 芯片的GPIO
引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。STM32 芯片的GPIO 被
分成很多组,每组有16 个引脚,如型号为STM32F103ZET6 型号的芯片有GPIOA、GPIOB、GPIOC
至GPIOG 共7 组GPIO,芯片一共144 个引脚,其中GPIO 就占了一大部分,所有的GPIO 引脚
都有基本的输入输出功能。最基本的输出功能是由STM32 控制引脚输出高、低电平,实现开关控制,
如把GPIO 引脚接入到LED 灯,那就可以控制LED 灯的亮灭,引脚接入到继电器或三极管,那就可
以通过继电器或三极管控制外部大功率电路的通断。最基本的输入功能是检测外部输入电平,如把
GPIO 引脚连接到按键,通过电平高低区分按键是否被按下。
第4 章.GPIO 的使用
SAIUR201 6 第31页
4.4. GPIO 框图剖析
图4-1 GPIO 结构框图
通过GPIO 硬件结构框图,就可以从整体上深入了解GPIO 外设及它的各种应用模式。该图从最
右端看起,最右端就是代表STM32 芯片引出的GPIO 引脚,其余部件都位于芯片内部。
4.4.1. 保护二极管及上、下拉电阻
引脚的两个保护二级管可以防止引脚外部过高或过低的电压输入,当引脚电压高于VDD 时,上方
的二极管导通,当引脚电压低于VSS 时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧
毁。尽管有这样的保护,并不意味着STM32 的引脚能直接外接大功率驱动器件,如直接驱动电机,
强制驱动要么电机不转,要么导致芯片烧坏,必须要加大功率及隔离电路驱动。
4.4.2. P-MOS 管和N-MOS 管
GPIO 引脚线路经过两个保护二极管后,向上流向“输入模式”结构,向下流向“输出模式”结构。
先看输出模式部分,线路经过一个由P-MOS 和N-MOS 管组成的单元电路。这个结构使GPIO 具有
了“推挽输出”和“开漏输出”两种模式。所谓的推挽输出模式,是根据这两个MOS 管的工作方式来命名
的。在该结构中输入高电平时,经过反向后,上方的P-MOS 导通,下方的N-MOS 关闭,对外输出
高电平;而在该结构中输入低电平时,经过反向后,N-MOS 管导通,P-MOS 关闭,对外输出低电平。
当引脚高低电平切换时,两个管子轮流导通,P 管负责灌电流,N 管负责拉电流,使其负载能力和开
关速度都比普通的方式有很大的提高。推挽输出的低电平为0 伏,高电平为3.3 伏,具体参考图4-2,
它是推挽输出模式时的等效电路。
第4 章.GPIO 的使用
第32 页SAIUR2016
图4-2 推挽等效电路
而在开漏输出模式时,上方的P-MOS 管完全不工作。如果我们控制输出为0,低电平,则P-MOS
管关闭,N-MOS 管导通,使输出接地,若控制输出为1 (它无法直接输出高电平)时,则P-MOS 管和
N-MOS 管都关闭,所以引脚既不输出高电平,也不输出低电平,为高阻态。为正常使用时必须外部
接上拉电阻,参考图8-3 中等效电路。它具有“线与”特性, 也就是说,若有很多个开漏模式引脚连接
到一起时,只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,此高电平的电压为外部上拉电
阻所接的电源的电压。若其中一个引脚为低电平,那线路就相当于短路接地,使得整条线路都为低电
平,0 伏。推挽输出模式一般应用在输出电平为0 和3.3 伏而且需要高速切换开关状态的场合。在
STM32 的应用中,除了必须用开漏模式的场合,我们都习惯使用推挽输出模式。开漏输出一般应用在
I2C、SMBUS 通讯等需要“线与”功能的总线电路中。除此之外,还用在电平不匹配的场合,如需要输
出5 伏的高电平,就可以在外部接一个上拉电阻,上拉电源为5 伏,并且把GPIO 设置为开漏模式,
当输出高阻态时,由上拉电阻和电源向外输出5 伏的电平,具体见图4-3。
第4 章.GPIO 的使用
SAIUR201 6 第33页
图4-3 STM32 IO 对外输出5V 电平
4.4.3. 输出数据寄存器
前面提到的双MOS 管结构电路的输入信号,是由GPIO“输出数据寄存器GPIOx_ODR”提供的,
因此我们通过修改输出数据寄存器的值就可以修改GPIO 引脚的输出电平。而“置位/复位寄存器
GPIOx_BSRR”可以通过修改输出数据寄存器的值从而影响电路的输出。
第4 章.GPIO 的使用
第34 页SAIUR2016
4.4.4. 复用功能输出
“复用功能输出”中的“复用”是指STM32 的其它片上外设对GPIO 引脚进行控制,此时GPIO 引
脚用作该外设功能的一部分,算是第二用途。从其它外设引出来的“复用功能输出信号”与GPIO 本身
的数据据寄存器都连接到双MOS 管结构的输入中,通过图中的梯形结构作为开关切换选择。例如我
们使用USART 串口通讯时,需要用到某个GPIO 引脚作为通讯发送引脚,这个时候就可以把该
GPIO 引脚配置成USART 串口复用功能,由串口外设控制该引脚,发送数据。
4.4.5. 输入数据寄存器
GPIO 结构框图的上半部分,GPIO 引脚经过内部的上、下拉电阻,可以配置成上/下拉输入,然
后再连接到施密特触发器,信号经过触发器后,模拟信号转化为0、1 的数字信号,然后存储在“输入
数据寄存器GPIOx_IDR”中,通过读取该寄存器就可以了解GPIO 引脚的电平状态。
4.4.6. 复用功能输入
与“复用功能输出”模式类似,在“复用功能输入模式”时,GPIO 引脚的信号传输到STM32 其它片
上外设,由该外设读取引脚状态。同样,如我们使用USART 串口通讯时,需要用到某个GPIO 引脚
作为通讯接收引脚,这个时候就可以把该GPIO 引脚配置成USART 串口复用功能,使USART 可以
通过该通讯引脚的接收远端数据。
4.4.7. 模拟输入输出
当GPIO 引脚用于ADC 采集电压的输入通道时,用作“模拟输入”功能,此时信号是不经过施密
特触发器的,因为经过施密特触发器后信号只有0、1 两种状态,所以ADC 外设要采集到原始的模
拟信号,信号源输入必须在施密特触发器之前。类似地,当GPIO 引脚用于DAC 作为模拟电压输出
通道时,此时作为“模拟输出”功能,DAC 的模拟信号输出就不经过双MOS 管结构,模拟信号直接
输出到引脚。
第4 章.GPIO 的使用
SAIUR201 6 第35页
4.5. GPIO 工作模式
总结一下,由GPIO 的结构决定了GPIO 可以配置成以下模式:
在固件库中,GPIO 总共有8 种细分的工作模式,稍加整理可以大致归类为以下三类:
4.5.1. 输入模式(模拟/浮空/上拉/下拉)
在输入模式时,施密特触发器打开,输出被禁止,可通过输入数据寄存器GPIOx_IDR 读取I/O 状
态。其中输入模式,可设置为上拉、下拉、浮空和模拟输入四种。上拉和下拉输入很好理解,默认的电
平由上拉或者下拉决定。浮空输入的电平是不确定的,完全由外部的输入决定,一般接按键的时候用的
是这个模式。模拟输入则用于ADC 采集。
4.5.2. 输出模式(推挽/开漏)
在输出模式中,推挽模式时双MOS 管以轮流方式工作,输出数据寄存器GPIOx_ODR 可控制I/O
输出高低电平。开漏模式时,只有N-MOS 管工作,输出数据寄存器可控制I/O 输出高阻态或低电平。
输出速度可配置,有2MHz\10MHz\50MHz 的选项。此处的输出速度即I/O 支持的高低电平状态最
高切换频率,支持的频率越高,功耗越大,如果功耗要求不严格,把速度设置成最大即可。在输出模式
时施密特触发器是打开的,即输入可用,通过输入数据寄存器GPIOx_IDR 可读取I/O 的实际状态。
4.5.3. 复用功能(推挽/开漏)
复用功能模式中,输出使能,输出速度可配置,可工作在开漏及推挽模式,但是输出信号源于其
它外设,输出数据寄存器GPIOx_ODR 无效;输入可用,通过输入数据寄存器可获取I/O 实际状态,
但一般直接用外设的寄存器来获取该数据信号。通过对GPIO 寄存器写入不同的参数,就可以改变
GPIO 的工作模式,在GPIO 外设中,控制端口高低控制寄存器CRH 和CRL 可以配置每个GPIO 的
工作模式和工作的速度,每4 个位控制一个IO,CRH 控制端口的高八位,CRL 控制端口的低8 位,
具体的看CRH 和CRL 的寄存器描述。
第4 章.GPIO 的使用
第36 页SAIUR2016
图4-4 GPIO 端口配置低寄存器
第4 章.GPIO 的使用
SAIUR201 6 第37页
图4-5 GPIO 端口配置高寄存器
4.6. 点亮LED-硬件设计
在本教程中STM32 芯片与LED 灯的连接见图12-1,这是一个RGB 灯,里面由红蓝绿三个小灯构
成, 使用PWM 控制时可以混合成256*256*256 种不同的颜色。
图4-6 LED 硬件原理图
第4 章.GPIO 的使用
第38 页SAIUR2016
这些LED 灯的阴极都是连接到STM32 的GPIO 引脚,只要我们控制GPIO 引脚的电平输出
状态,即可控制LED 灯的亮灭。若您使用的实验板LED 灯的连接方式或引脚不一样, 只需根据我
们的工程修改引脚即可,程序的控制原理相同。点亮LED-软件设计这里只讲解核心部分的代码,有些
变量的设置,头文件的包含等可能不会涉及到,完整的代码请参考本章配套的工程。为了使工程更加有
条理,我们把LED 灯控制相关的代码独立分开存储,方便以后移植。在“工程模板”之上新建
“ bsp_led.c”及“bsp_led.h ”文件,其中的“bsp ”即Board Support Packet 的缩写(板级支持包),这些文件也
可根据您的喜好命名,这些文件不属于STM32 标准库的内容,是由我们自己根据应用需要编写的。
4.7. 点亮LED-编程要点
1. 使能GPIO 端口时钟;
2. 初始化GPIO 目标引脚为推挽输出模式;
3. 编写简单测试程序,控制GPIO 引脚输出高、低电平。
4.8. 点亮LED-代码分析
4.8.1. LED 灯引脚宏定义
在编写应用程序的过程中,要考虑更改硬件环境的情况,例如LED 灯的控制引脚与当前的不一样,
我们希望程序只需要做最小的修改即可在新的环境正常运行。这个时候一般把硬件相关的部分使用宏来
封装,若更改了硬件环境,只修改这些硬件相关的宏即可,这些定义一般存储在头文件,即本例子中的
“bsp_led.h”文件中,见代码清单4-1。
代码清单4-1 LED 控制引脚相关的宏
以上代码分别把控制LED 灯的GPIO 端口、GPIO 引脚号以及GPIO 端口时钟封装起来了。在
实际控制的时候我们就直接用这些宏,以达到应用代码硬件无关的效果。其中的GPIO 时钟宏
“RCC_APB2Periph_GPIOB” 是STM32 标准库定义的GPIO 端口时钟相关的宏, 它的作用与
“GPIO_Pin_x”这类宏类似,是用于指示寄存器位的,方便库函数使用,下面初始化GPIO 时钟的时候
可以看到它的用法。
第4 章.GPIO 的使用
SAIUR201 6 第39页
4.8.2. 控制LED 灯亮灭状态的宏定义
为了方便控制LED 灯,我们把LED 灯常用的亮、灭及状态反转的控制也直接定义成宏,见代码清单4-2。
代码清单4-2 控制LED 亮灭的宏
第4 章.GPIO 的使用
第40 页SAIUR2016
这部分宏控制LED 亮灭的操作是直接向BSRR、BRR 和ODR 这三个寄存器写入控制指令来实
现的,对BSRR 写1 输出高电平,对BRR 写1 输出低电平,对ODR 寄存器某位进行异或操作可
反转位的状态。RGB 彩灯可以实现混色,如最后一段代码我们控制红灯和绿灯亮而蓝灯灭,可混出黄
色效果。代码中的“\”是C 语言中的续行符语法,表示续行符的下一行与续行符所在的代码是同一行。
代码中因为宏定义关键字“#define”只是对当前行有效,所以我们使用续行符来连接起来,以下的代码是
等效的:
#define LED_YELLOW LED1_ON; LED2_ON; LED3_OFF
应用续行符的时候要注意,在“\”后面不能有任何字符(包括注释、空格),只能直接回车。
4.8.3. LED GPIO 初始化函数
利用上面的宏,编写LED 灯的初始化函数,见代码清单4-3。
代码清单4-3 LED GPIO 初始化函数
第4 章.GPIO 的使用
SAIUR201 6 第41页
整个函数与“构建库函数雏形”章节中的类似,主要区别是硬件相关的部分使用宏来代替,初始化
GPIO 端口时钟时也采用了STM32 库函数,函数执行流程如下:
1. 使用GPIO_InitTypeDef 定义GPIO 初始化结构体变量,以便下面用于存储GPIO 配置。
2. 调用库函数RCC_APB2PeriphClockCmd 来使能LED 灯的GPIO 端口时钟,在前面的章节中我
们是直接向RCC 寄存器赋值来使能时钟的,不如这样直观。该函数有两个输入参数,第一个参
数用于指示要配置的时钟,如本例中的“RCC_ APB2Periph_GPIOB”, 应用时我们使用“|”操作同时
配置3 个LED 灯的时钟;函数的第二个参数用于设置状态,可输入“Disable”关闭或“Enable”使
能时钟。
3. 向GPIO 初始化结构体赋值, 把引脚初始化成推挽输出模式, 其中的GPIO_Pin 使用宏
“LEDx_GPIO_PIN”来赋值,使函数的实现方便移植。
4. 使用以上初始化结构体的配置,调用GPIO_Init 函数向寄存器写入参数,完成GPIO 的初始化,
这里的GPIO 端口使用“LEDx_GPIO_PORT”宏来赋值,也是为了程序移植方便。
5. 使用同样的初始化结构体,只修改控制的引脚和端口,初始化其它LED 灯使用的GPIO 引脚。
6. 使用宏控制RGB 灯默认关闭。
4.8.4. 主函数
编写完LED 灯的控制函数后,就可以在main 函数中测试了,见代码清单4-4。
代码清单4-4 控制LED 灯,main 文件
第4 章.GPIO 的使用
第42 页SAIUR2016
代码清单4-4 控制LED 灯,main 文件main 函数中,调用我们前面定义的LED_GPIO_Config
初始化好LED 的控制引脚,然后直接调用各种控制LED 灯亮灭的宏来实现LED 灯的控制。以上,
就是一个使用STM32 标准软件库开发应用的流程。
4.9. 点亮LED-下载验证
把编译好的程序下载到开发板并复位,可看到RGB 彩灯轮流显示不同的颜色。
4.10. 课后练习
使用GPIO 让LED 灯显示不同的颜色。
第5 章.STM32 RCC 时钟系统
SAIUR201 6 第43页
第5 章. STM32 RCC 时钟系统
5.1. 课前预习
在书上找到答案。
1. APB2 时钟最大为多少?
2. 使用标准库怎么配置GPIO 的时钟?
5.2. 概述
本章所讲内容:
(1)时钟系统的结构和使用分析
(2)使用标准库配置系统时钟
RCC :reset clock control 复位和时钟控制器。本章我们主要讲解时钟部分,特别是要着重理解时
钟树,理解了时钟树,STM32 的一切时钟的来龙去脉都会了如指掌。
5.3. RCC 主要作用—时钟部分
设置系统时钟SYSCLK、设置AHB 分频因子(决定HCLK 等于多少)、设置APB2 分频因子
(决定PCLK2 等于多少)、设置APB1 分频因子(决定PCLK1 等于多少)、设置各个外设的分频
因子;控制AHB、APB2 和APB1 这三条总线时钟的开启、控制每个外设的时钟的开启。对于
SYSCLK、HCLK、PCLK2、PCLK1 这四个时钟的配置一般是:PCLK2 = HCLK = SYSCLK=PLLCLK =
72M,PCLK1=HCLK/2 = 36M。这个时钟配置也是库函数的标准配置,我们用的最多的就是这个。
5.4. RCC 框图剖析—时钟部分
时钟树单纯讲理论的话会比较枯燥,如果选取一条主线,并辅以代码,先主后次讲解的话会很容
易, 而且记忆还更深刻。我们这里选取库函数时钟系统时钟函数: SetSysClockTo72(); 以这个函数的
编写流程来讲解时钟树,这个函数也是我们用库的时候默认的系统时钟设置函数。该函数的功能是利
第5 章.STM32 RCC 时钟系统
第44 页SAIUR2016
用HSE 把时钟设置为:PCLK2 = HCLK = SYSCLK = 72M,PCLK1=HCLK/2 = 36M。下面我们就以这
个代码的流程为主线,来分析时钟树,对应的是图中的黄色部分,代码流程在时钟树中以数字的大小顺
序标识。
图5-1 STM32 时钟树
5.5. 系统时钟
5.5.1. HSE 高速外部时钟信号
HSE 是高速的外部时钟信号,可以由有源晶振或者无源晶振提供,频率从4-16MHZ 不等。当使
用有源晶振时,时钟从OSC_IN 引脚进入,OSC_OUT 引脚悬空,当选用无源晶振时,时钟从OSC_IN
和OSC_OUT 进入,并且要配谐振电容。HSE 最常使用的就是8M 的无源晶振。当确定PLL 时钟来
第5 章.STM32 RCC 时钟系统
SAIUR201 6 第45页
源的时候,HSE 可以不分频或者2 分频,这个由时钟配置寄存器CFGR 的位17:PLLXTPRE 设置,
我们设置为HSE 不分频。
5.5.2. PLL 时钟源
PLL 时钟来源可以有两个,一个来自HSE,另外一个是HSI/2,具体用哪个由时钟配置寄存器
CFGR 的位16:PLLSRC 设置。HSI 是内部高速的时钟信号,频率为8M,根据温度和环境的情况频
率会有漂移,一般不作为PLL 的时钟来源。这里我们选HSE 作为PLL 的时钟来源。
5.5.3. PLL 时钟PLLCLK
通过设置PLL 的倍频因子, 可以对PLL 的时钟来源进行倍频, 倍频因子可以
是:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],具体设置成多少,由时钟配置寄存器CFGR 的位21-18:
PLLMUL[3:0]设置。我们这里设置为9 倍频,因为上一步我们设置PLL 的时钟来源为HSE=8M,
所以经过PLL 倍频之后的PLL 时钟:PLLCLK = 8M *9 = 72M。72M 是ST 官方推荐的稳定运行时
钟,如果你想超频的话,增大倍频因子即可,最高为128M。我们这里设置PLL 时钟:PLLCLK = 8M
*9 = 72M。
5.5.4. 系统时钟SYSCLK
系统时钟来源可以是:HSI、PLLCLK、HSE,具体的时钟配置寄存器CFGR 的位1-0:SW[1:0]
设置。我们这里设置系统时钟:SYSCLK = PLLCLK = 72M。
5.5.5. AHB 总线时钟HCLK
系统时钟SYSCLK 经过AHB 预分频器分频之后得到时钟叫APB 总线时钟,即HCLK,分频因
子可以是:[1,2,4,8,16,64,128,256,512],具体的由时钟配置寄存器CFGR 的位7-4 :HPRE[3:0]
设置。片上大部分外设的时钟都是经过HCLK 分频得到,至于AHB 总线上的外设的时钟设置为多少,
得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB 的时钟即可。我们这里设
置为1 分频,即HCLK=SYSCLK=72M。
5.5.6. APB2 总线时钟HCLK2
APB1 APB2 总线时钟PCLK2 由HCLK 经过高速APB2 预分频器得到,分频因子可以
是:[1,2,4,8,16],具体由时钟配置寄存器CFGR 的位13-11:PPRE2[2:0]决定。HCLK2 属于高速的
总线时钟,片上高速的外设就挂载到这条总线上,比如全部的GPIO、USART1、SPI1 等。至于APB2
总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好
APB2 的时钟即可。我们这里设置为1 分频,即PCLK2 = HCLK =72M。
第5 章.STM32 RCC 时钟系统
第46 页SAIUR2016
5.5.7. 总线时钟HCLK1
APB1 总线时钟PCLK1 由HCLK 经过低速APB 预分频器得到,分频因子可以是:[1,2,4,8,16],
具体的由时钟配置寄存器CFGR 的位10-8:PRRE1[2:0]决定。HCLK1 属于低速的总线时钟,最高为
36M,片上低速的外设就挂载到这条总线上,比如USART2/3/4/5、SPI2/3,I2C1/2 等。至于APB1 总
线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好
APB1 的时钟即可。我们这里设置为2 分频,即PCLK1 = HCLK/2 = 36M。
5.6. 设置系统时钟库函数
上面的7 个步骤对应的设置系统时钟库函数如下, 该函数截取自固件库文件
system_stm32f10x.c。为了方便阅读,我已把互联型相关的代码删掉,把英文注释翻译成了中文,并把
代码标上了序号,总共七个步骤。该函数是直接操作寄存器的,有关寄存器部分请参考数据手册的RCC
的寄存器描述部分。
代码5-1 设置系统时钟库函数
第5 章.STM32 RCC 时钟系统
SAIUR201 6 第47页
5.7. 其他时钟
通过对系统时钟设置的讲解,整个时钟树我们已经把握的有六七成,剩下的时钟部分我们讲解几个
重要的。
5.7.1. USB 时钟
USB 时钟是由PLLCLK 经过USB 预分频器得到,分频因子可以是:[1,1.5],具体的由时钟配置
寄存器CFGR 的位22:USBPRE 配置。USB 的时钟最高是48M,根据分频因子反推过来算,PLLCLK
只能是48M 或者是72M 。一般我们设置PLLCLK=72M , USBCLK=48M。USB 对时钟要求比较
高,所以PLLCLK 只能是由HSE 倍频得到,不能使用HSI 倍频。
5.7.2. Cortex 系统时钟
Cortex 系统时钟由HCLK 8 分频得到,等于9M,Cortex 系统时钟用来驱动内核的系统定时器
SysTick,SysTick 一般用于操作系统的时钟节拍,也可以用做普通的定时。
第5 章.STM32 RCC 时钟系统
第48 页SAIUR2016
5.7.3. ADC 时钟
ADC 时钟由PCLK2 经过ADC 预分频器得到,分频因子可以是[2,4,6,8],具体的由时钟配置寄
存器CFGR 的位15-14:ADCPRE[1:0]决定。很奇怪的是怎么没有1 分频。ADC 时钟最高只能是
14M,如果采样周期设置成最短的1.5 个周期的话,ADC 的转换时间可以达到最短的1us。如果真要
达到最短的转换时间1us 的话,那ADC 的时钟就得是14M,反推PCLK2 的时钟只能是:28M、56M、
84M、112M,鉴于PCLK2 最高是72M,所以只能取28M 和56M。
5.7.4. RTC 时钟、独立看门狗时钟
RTC 时钟可由HSE/128 分频得到,也可由低速外部时钟信号LSE 提供,频率为32.768KHZ,也
可由低速内部时钟信号HSI 提供,具体选用哪个时钟由备份域控制寄存器BDCR 的位9-8:
RTCSEL[1:0]配置。独立看门狗的时钟由LSI 提供,且只能是由LSI 提供,LSI 是低速的内部时钟信
号,频率为30~60KHZ 直接不等,一般取40KHZ。
5.7.5. MCO 时钟输出
MCO 是microcontroller clock output 的缩写,是微控制器时钟输出引脚,在STM32 F1 系列中由
PA8 复用所得,主要作用是可以对外提供时钟,相当于一个有源晶振。MCO 的时钟来源可以是:
PLLCLK/2 、HSI、HSE 、SYSCLK ,具体选哪个由时钟配置寄存器CFGR 的位26-24:MCO[2:0]
决定。除了对外提供时钟这个作用之外,我们还可以通过示波器监控MCO 引脚的时钟输出来验证我
们的系统时钟配置是否正确。
5.8. 配置系统时钟实验
5.8.1. 使用HSE
一般情况下,我们都是使用HSE,然后HSE 经过PLL 倍频之后作为系统时钟。通常的配置是:
HSE=8M,PLL 的倍频因子为:9,系统时钟就设置成:SYSCLK = 8M * 9 = 72M。使用HSE,系统时钟
SYSCLK 最高是128M。我们使用的库函数就是这么干的, 当程序来到main 函数之前,启动文件:
statup_stm32f10x_hd.s 已经调用SystemInit()函数把系统时钟初始化成72MHZ,SystemInit()在库文件:
system_stm32f10x.c 中定义。如果我们想把系统时钟设置低一点或者超频的话,可以修改底层的库文件,
但是为了维持库的完整性,我们可以根据时钟树的流程自行写一个。
5.8.2. 使用HSI
HSE 故障的时候,如果PLL 的时钟来源是HSE,那么当HSE 故障的时候,不仅HSE 不能使
用,连PLL 也会被关闭,这个时候系统会自动切换HSI 作为系统时钟,此时SYSCLK=HSI=8M,如
果没有开启CSS 和CSS 中断的话,那么整个系统就只能在低速率运行,这是系统跟瘫痪没什么两样。
第5 章.STM32 RCC 时钟系统
SAIUR201 6 第49页
如果开启了CSS 功能的话,那么可以当HSE 故障时,在CSS 中断里面采取补救措施,使用HSI,
并把系统时钟设置为更高的频率,最高是64M, 64M 的频率足够一般的外设使用,如:ADC 、SPI、
I2C 等。但是这里就又有一个问题了, 原来SYSCLK=72M,现在因为故障改成64M,那么那些外设
的时钟肯定被改变了,那么外设工作就会被打乱,那我们是不是在设置HSI 时钟的时候,也重新调
整外设总线的分频因子,即AHB,APB2 和APB1 的分频因子,使外设的时钟达到跟HSE 没有故
障之前一样。但是这个也不是最保障的办法,毕竟不能一直使用HSI,所以当HSE 故障时还是要采
取报警措施。还有一种情况是,有些用户不想用HSE,想用HSI,但是又不知道怎么用HSI 来设置
系统时钟,因为调用库函数都是使用HSE,下面我们给出个使用HSI 配置系统时钟例子, 起个抛砖
引玉的作用。
5.8.3. 硬件设计
1、RCC
2、LED 一个
RCC 是单片机内部资源,不需要外部电路。通过LED 闪烁的频率来直观的判断不同系统时钟频
率对软件延时的效果。
5.8.4. 软件设计
我们编写两个RCC 驱动文件,bsp_clkconfig.h 和bsp_clkconfig.c,用来存放RCC 系统时钟配置
函数。
5.8.5. 编程要点
编程要点对应着时钟树图中的序号。
1、开启HSE/HSI ,并等待HSE/HSI 稳定
2、设置AHB、APB2、APB1 的预分频因子
3、设置PLL 的时钟来源,和PLL 的倍频因子,设置各种频率主要就是在这里设置
4、开启PLL,并等待PLL 稳定
5、把PLLCK 切换为系统时钟SYSCLK
6、读取时钟切换状态位,确保PLLCLK 被选为系统时钟
5.8.6. 代码分析
这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考
本章配套的工程。使用HSE 配置系统时钟
第5 章.STM32 RCC 时钟系统
第50 页SAIUR2016
代码5-2 HSE 作为系统时钟来源
第5 章.STM32 RCC 时钟系统
SAIUR201 6 第51页
这个函数采用库函数编写, 函数有个形参pllmul,pllmul 用来设置PLL 的倍频因子,在调用的
时候形参可以是:RCC_PLLMul_x , x:[2,3,...16],这些宏来源于库函数的定义,宏展开是一些32 位的
十六进制数,具体功能是配置了时钟配置寄存器CFGR 的位21-18 PLLMUL[3:0],预先定义好倍频因
子,方便调用。函数调用举例:HSE_SetSysClock(RCC_PLLMul_9); 则设置系统时钟为:8MHZ * 9 =
72MHZ。HSE_SetSysClock(RCC_PLLMul_16); 则设置系统时钟为:8MHZ * 16 = 128MHZ 超频慎用。
代码5-3 实用HSI 配置系统时钟
第5 章.STM32 RCC 时钟系统
第52 页SAIUR2016
HSI 设置
系统时钟函数跟HSE 设置系统时钟函数在原理上是一样的,有一个区别的地方就是,HSI 必须2 分
频之后才能作为PLL 的时钟来源,所以使用HSI 时,最大的系统时钟SYSCLK 只能是
HSI/2*16=4*16=64MHZ。函数调用举例:HSI_SetSysClock(RCC_PLLMul_9); 则设置系统时钟为:4MHZ
* 9 =使用HSI 配置系统时钟36MHZ。软件延时
软件延时函数,使用不同的系统时钟,延时时间不一样,可以通过LED 闪烁的频率来判断。
MCO 输出
在STM32F103 系列中,PA8 可以复用为MCO 引脚,对外提供时钟输出,我们也可以用示波器
监控该引脚的输出来判断我们的系统时钟是否设置正确。
第5 章.STM32 RCC 时钟系统
SAIUR201 6 第53页
代码5-4 MCO GPIO 初始化
代码5-5 MCO 输出时钟选择
我们初始化MCO 引脚之后,可以直接调用库函数RCC_MCOConfig()来选择MCO 时钟来源。主
函数如代码5-5
第5 章.STM32 RCC 时钟系统
第54 页SAIUR2016
代码5-5 主函数
在主函数中,可以调用HSE_SetSysClock()或者HSI_SetSysClock()这两个函数把系统时钟设置成
各种常用的时钟,然后通过MCO 引脚监控,或者通过LED 闪烁的快慢体验不同的系统时钟对同一
个软件延时函数的影响。
5.8.7. 下载验证
把编译好的程序下载到开发板,可以看到设置不同的系统时钟时,LED 闪烁的快慢不一样。更精
确的数据我们可以用示波器监控MCO 引脚看到。
图5-2 MCO=SYSCLK=72M 图5-3 MCO=HSI=8M
第6 章.STM32 中断应用概述
SAIUR201 6 第55页
第6 章. STM32 中断应用概览
6.1. 课前预习
在书上找到答案。
1. 什么是中断控制器?
2. 怎么配置NVIC 寄存器
6.2. 概述
本章所讲内容:
(1)NVIC 的介绍
(2)NVIC 的配置方法
STM32 中断非常强大,每个外设都可以产生中断,所以中断的讲解放在哪一个外设里面去讲都
不合适,这里单独抽出一章来做一个总结性的介绍,这样在其他章节涉及到中断部分的知识我们就不
用费很大的篇幅去讲解,只要示意性带过即可。本章如无特别说明,异常就是中断,中断就是异常,请
不要刻意钻牛角尖较劲。
6.3. 异常类型
STM32F103 在内核水平上搭载了一个异常响应系统, 支持为数众多的系统异常和外部中断。其
中系统异常有8 个(如果把Reset 和HardFault 也算上的话就是10 个),外部中断有60 个。除了
个别异常的优先级被定死外,其它异常的优先级都是可编程的。有关具体的系统异常和外部中断可在标
准库文件stm32f10x.h 这个头文件查询到,在IRQn_Type 这个结构体里面包含了F103 系列全部的异
常声明。
表格6-1 F103 系统异常清单
第6 章.STM32 中断应用概述
第56 页SAIUR2016
表格6-2 F103 外部中断清单
6.4. NVIC 简介
在讲如何配置中断优先级之前,我们需要先了解下NVIC。NVIC 是嵌套向量中断控制器,控制着
整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。但是各个芯片厂商在设计芯片
的时候会对Cortex-M3 内核里面的NVIC 进行裁剪,把不需要的部分去掉,所以说STM32 的NVIC
是Cortex-M3 的NVIC 的一个子集。
6.5. NVIC 寄存器简介
在固件库中,NVIC 的结构体定义可谓是颇有远虑,给每个寄存器都预留了很多位,恐怕为的是日
后扩展功能。不过STM32F103 可用不了这么多,只是用了部分而已,具体使用了多少可参考
第6 章.STM32 中断应用概述
SAIUR201 6 第57页
《Cortex-M3 内核编程手册》-4.3.11:NVIC 寄存器映射。
代码6-1 NVIC 结构体定义,来自固件库头文件:core_cm3.h
在配置中断的时候我们一般只用ISER、ICER 和IP 这三个寄存器,ISER 用来使能中断,ICER 用
来失能中断,IP 用来设置中断优先级。
6.6. NVIC 中断配置固件库
固件库文件core_cm3.h 的最后,还提供了NVIC 的一些函数,这些函数遵循CMSIS 规则,只
要是Cortex-M3 的处理器都可以使用,具体如下:
表格6-3 符合CMSIS 标准的NVIC 库函数
这些库函数我们在编程的时候用的都比较少,甚至基本都不用。在配置中断的时候我们还有更简洁
的方法,请看中断编程小节。
第6 章.STM32 中断应用概述
第58 页SAIUR2016
6.7. 优先级的定义
6.7.1. 优先级定义
在NVIC 有一个专门的寄存器:中断优先级寄存器NVIC_IPRx,用来配置外部中断的优先级,IPR
宽度为8bit,原则上每个外部中断可配置的优先级为0~255,数值越小,优先级越高。但是绝大多数
CM3 芯片都会精简设计,以致实际上支持的优先级数减少,在F103 中,只使用了高4bit,如下所示:
表格6-4 F103 使用4bit 表达优先级
用于表达优先级的这4bit,又被分组成抢占优先级和子优先级。如果有多个中断同时响应,抢占
优先级高的就会抢占抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如果抢
占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。
6.7.2. 优先级分组
优先级的分组由内核外设SCB 的应用程序中断及复位控制寄存器AIRCR 的
PRIGROUP[10:8]位决定,F103 分为了5 组,具体如下:主优先级=抢占优先级
表格6-5 优先级表
设置优先级分组可调用库函数NVIC_PriorityGroupConfig()实现,有关NVIC 中断相关的库函数
都在库文件misc.c 和misc.h 中。
表格6-7 优先级分组真值表
第6 章.STM32 中断应用概述
SAIUR201 6 第59页
代码6-2 中断优先级分组库函数NVIC_PriorityGroupConfig()
6.8.中断编程
在配置每个中断的时候一般有3 个编程要点:
1. 使能外设某个中断,这个具体由每个外设的相关中断使能位控制。比如串口有发送完成中断,接
收完成中断,这两个中断都由串口控制寄存器的相关中断使能位控制。
2. 初始化NVIC_InitTypeDef 结构体,配置中断优先级分组,设置抢占优先级和子优先级,使能中
断请求。NVIC_InitTypeDef 结构体在固件库头文件misc.h 中定义。
代码6-3 NVIC 初始化结构体
有关NVIC 初始化结构体的成员我们一一解释下:
NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即使写错了程序也不会
报错,只会导致不响应中断。具体的成员配置可参考stm32f10x.h 头文件里面的IRQn_Type 结构体定
义,这个结构体包含了所有的中断源。
代码6-4 IRQn_Type 中断源结构体
第6 章.STM32 中断应用概述
第60 页SAIUR2016
NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来确定.。
NVIC_IRQChannelSubPriority:子优先级,具体的值要根据优先级分组来确定,具体参考表格17-5 优
先级分组真值表。
NVIC_IRQChannelCmd:中断使能(ENABLE)或者失能(DISABLE)。操作的是NVIC_ISER 和
NVIC_ICER 这两个寄存器。
3. 编写中断服务函数
在启动文件startup_stm32f10x_hd.s 中我们预先为每个中断都写了一个中断服务函数, 只是这些
中断函数都是为空,为的只是初始化中断向量表。实际的中断服务函数都需要我们重新编写,为了方
便管理我们把中断服务函数统一写在stm32f10x_it.c 这个库文件中。关于中断服务函数的函数名必须
跟启动文件里面预先设置的一样,如果写错,系统就在中断向量表中找不到中断服务函数的入口,直
接跳转到启动文件里面预先写好的空函数, 并且在里面无限循环,实现不了中断。
6.9. 课后练习
1、库文件core_cm3.h 主要实现了什么?
2、库文件mics.c 和mics.h 主要实现了什么?
3、如果实现一次软件系统复位,具体是操作哪个寄存器的哪个位实现?
第7 章.EXTI-外部中断/事件控制器
SAIUR201 6 第61页
第7 章. EXTI—外部中断/事件控制器
7.1. 课前预习
在书上找到答案。
1. EXTI 有多少种?
2. 怎么使用标准库配置EXTI
7.2. 概述
本章所讲内容:
(1)EXTI 的介绍
(2)EXTI 的配置方法
上一章节我们已经详细介绍了NVIC,对STM32F10x 系列中断管理系统有个全局的了解,我们
这章的内容是NVIC 的实例应用,也是STM32F10x 控制器非常重要的一个资源。学习本章时,配
合《STM32F10X-中文参考手册》中断和事件章节一起阅读,效果会更佳,特别是涉及到寄存器说明的
部分。
7.3. EXTI 简介
EXTI(External interrupt/event controller)—外部中断/事件控制器,管理了控制器的20 个中断/事
件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。
EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属
性。
7.4. EXTI 功能框图
EXTI 的功能框图包含了EXTI 最核心内容,掌握了功能框图,对EXTI 就有一个整体的把握,
在编程时思路就非常清晰。EXTI 功能框图见图7-1。在图18-1 可以看到很多在信号线上打一个斜杠
并标注“20”字样,这个表示在控制器内部类似的信号线路有20 个,这与EXTI 总共有20 个中断/事
陈德金老师编著
第7 章.EXTI-外部中断/事件控制器
第62 页SAIUR2016
件线是吻合的。所以我们只要明白其中一个的原理,那其他19 个线路原理也就知道了。
图7-1 EXTI 功能框图
EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,这两个功能从硬件上就有所不
同。首先我们来看图18-1 中红色虚线指示的电路流程。它是一个产生中断的线路,最终信号流入到
NVIC 控制器内。编号1 是输入线,EXTI 控制器有19 个中断/事件输入线,这些输入线可以通过寄
存器设置为任意一个GPIO,也可以是一些外设的事件,这部分内容我们将在后面专门讲解。输入线一
般是存在电平变化的信号。编号2 是一个边沿检测电路,它会根据上升沿触发选择寄存器(EXTI_RTSR)
和下降沿触发选择寄存器(EXTI_FTSR)对应位的设置来控制信号触发。边沿检测电路以输入线作为信号
输入端,如果检测到有边沿跳变就输出有效信号1 给编号3 电路,否则输出无效信号0。而
EXTI_RTSR 和EXTI_FTSR 两个寄存器可以控制器需要检测哪些类型的电平跳变过程,可以是只有上
升沿触发、只有下降沿触发或者上升沿和下降沿都触发。编号3 电路实际就是一个或门电路,它一个
输入来自编号2 电路,另外一个输入来自软件中断事件寄存器(EXTI_SWIER)。EXTI_SWIER 允许我
们通过程序控制就可以启动中断/事件线,这在某些地方非常有用。我们知道或门的作用就是有1 就为
1,所以这两个输入随便一个有有效信号1 就可以输出1 给编号4 和编号6 电路。编号4 电路是一
个与门电路,它一个输入是编号3 电路,另外一个输入来自中断屏蔽寄存器(EXTI_IMR)。与门电路要
求输入都为1 才输出1,导致的结果是如果EXTI_IMR 设置为0 时,那不管编号3 电路的输出信
号是1 还是0,最终编号4 电路输出的信号都为0;如果EXTI_IMR 设置为1 时,最终编号4 电
路输出的信号才由编号3 电路的输出信号决定,这样我们可以简单的控制EXTI_IMR 来实现是否产
生中断的目的。编号4 电路输出的信号会被保存到挂起寄存器(EXTI_PR)内,如果确定编号4 电路输
出为1 就会把EXTI_PR 对应位置1。编号5 是将EXTI_PR 寄存器内容输出到NVIC 内,从而实
现系统中断事件控制。接下来我们来看看绿色虚线指示的电路流程。它是一个产生事件的线路,最终
第7 章.EXTI-外部中断/事件控制器
SAIUR201 6 第63页
输出一个脉冲信号。产生事件线路是在编号3 电路之后与中断线路有所不同,之前电路都是共用的。
编号6 电路是一个与门,它一个输入来自编号3 电路, 另外一个输入来自事件屏蔽寄存器
(EXTI_EMR)。如果EXTI_EMR 设置为0 时,那不管编号3 电路的输出信号是1 还是0,最终编
号6 电路输出的信号都为0;如果EXTI_EMR 设置为1 时,最终编号6 电路输出的信号才由编号
3 电路的输出信号决定,这样我们可以简单的控制EXTI_EMR 来实现是否产生事件的目的。编号7 是
一个脉冲发生器电路,当它的输入端,即编号6 电路的输出端,是一个有效信号1 时就会产生一个
脉冲;如果输入端是无效信号就不会输出脉冲。编号8 是一个脉冲信号,就是产生事件的线路最终的
产物,这个脉冲信号可以给其他外设电路使用,比如定时器TIM、模拟数字转换器ADC 等等,这样
的脉冲信号一般用来触发TIM 或者ADC 开始转换。产生中断线路目的是把输入信号输入到NVIC,
进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号
给其他外设使用,并且是电路级别的信号传输,属于硬件级的。另外,EXTI 是在APB2 总线上的,
在编程时候需要注意到这点。
7.5. 中断/事件线
EXTI 有20 个中断/事件线,每个GPIO 都可以被设置为输入线,占用EXTI0 至EXTI15,还有另外
七根用于特定的外设事件,见表7-1。4 根特定外设中断/事件线由外设触发。
表7-1 EXTI 中断/事件线
EXTI0 至EXTI15 用于GPIO,通过编程控制可以实现任意一个GPIO 作为EXTI 的输入源。
陈德金老师编著
第7 章.EXTI-外部中断/事件控制器
第64 页SAIUR2016
由表7-1 可知,EXTI0 可以通过AFIO 的外部中断配置寄存器1(AFIO_EXTICR1)的EXTI0[3:0]位选
择配置为PA0、PB0、PC0、PD0、PE0、PF0、PG0、PH0 或者PI0,见图7-2。其他EXTI 线(EXTI 中
断/事件线)使用配置都是类似的。
图7-2 EXTI0 输入源选择
7.6. EXTI 初始化结构体详解
标准库函数对每个外设都建立了一个初始化结构体,比如EXTI_InitTypeDef,结构体成员用于设
置外设工作参数,并由外设初始化配置函数,比如EXTI_Init()调用,这些设定参数将会设置外设相应
的寄存器,达到配置外设工作环境的目的。初始化结构体和初始化库函数配合使用是标准库精髓所在,
理解了初始化结构体每个成员意义基本上就可以对该外设运用自如了。初始化结构体定义在
stm32f10x_exti.h 文件中,初始化库函数定义在stm32f10x_exti.c 文件中,编程时我们可以结合这两个
文件内注释使用。
代码清单7-1 EXTI 初始化结构体
EXTI_Line:EXTI 中断/事件线选择,可选EXTI0 至EXTI19,可参考表7-1 选择。
EXTI_Mode : EXTI 模式选择, 可选为产生中断(EXTI_Mode_Interrupt) 或者产生事件
(EXTI_Mode_Event)。
EXTI_Trigger:EXTI 边沿触发事件,可选上升沿触发(EXTI_Trigger_Rising)、下降沿触发
( EXTI_Trigger_Falling) 或者上升沿和下降沿都触发( EXTI_Trigger_Rising_Falling)。
EXTI_LineCmd:控制是否使能EXTI 线,可选使能EXTI 线(ENABLE)或禁用(DISABLE)。
第7 章.EXTI-外部中断/事件控制器
SAIUR201 6 第65页
7.7. 外部中断控制实验
中断在嵌入式应用中占有非常重要的地位,几乎每个控制器都有中断功能。中断对保证紧急事件
得到第一时间处理是非常重要的。我们设计使用外接的按键来作为触发源,使得控制器产生中断,并在
中断服务函数中实现控制RGB 彩灯的任务。
7.7.1. 硬件设计
轻触按键在按下时会使得引脚接通,通过电路设计可以使得按下时产生电平变化,见图7-3。
图7-3 按键电路设计
7.7.2. 软件设计
这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参
考本章配套的工程。我们创建了两个文件:bsp_exti.c 和bsp_exti.h 文件用来存放EXTI 驱动程序及相
关宏定义,中断服务函数放在stm32f10x_it.h 文件中。
7.7.3. 编程要点
1.初始化用来产生中断的GPIO;
2.初始化EXTI;
3.配置NVIC;
4.编写中断服务函数;
7.7.4. 代码分析
使用宏定义方法指定与硬件电路设计相关配置,这对于程序移植或升级非常有用的。在上面的宏定
义中,我们除了开GPIO 的端口时钟外,我们还打开了AFIO 的时钟,这是因为等下配置EXTI 信号
源的时候需要用到AFIO 的外部中断控制寄存器AFIO_EXTICRx,具体见《STM32F10X-中文参考手
册》8.4 章节AFIO 寄存器描述。嵌套向量中断控制器NVIC 配置有关NVIC 配置问题可参考《STM32
中断应用概览》章节内容,这里不做过多解释。这里我们配置两个的中断软件优先级一样,如果出现了
两个按键同时按下的情况,那怎么办,到底该执行哪一个中断?当两个中断的软件优先级一样的时候,
陈德金老师编著
第7 章.EXTI-外部中断/事件控制器
第66 页SAIUR2016
中断来临时,具体先执行哪个中断服务函数由硬件的中断编号决定,编号越小,优先级越高。有关外设
的硬件编号可查询《STM32F10X-中文参考手册》的中断和事件章节中的向量表,表中的位置编号即
是每个外设的硬件中断优先级。当然,我们也可以把抢占优先级设置成一样,子优先级设置成不一样,
这样就可以区别两个按键同时按下的情况,而不用硬件去对比硬件编号。
代码清单7-2 按键和EXTI 宏定义
代码清单7-3 NVIC 配置
第7 章.EXTI-外部中断/事件控制器
SAIUR201 6 第67页
EXTI 中断配置
代码清单7-4 EXTI 中断配置
首先,使用GPIO_InitTypeDef 和EXTI_InitTypeDef 结构体定义两个用于GPIO 和EXTI 初始化
配置的变量,关于这两个结构体前面都已经做了详细的讲解。使用GPIO 之前必须开启GPIO 端口的
时钟;用到EXTI 必须开启AFIO 时钟。调用NVIC_Configuration 函数完成对按键1、按键2 优
先级配置并使能中断通道。作为中断/事件输入线时需把GPIO 配置为输入模式,具体为浮空输入,由
外部电路完全决定引脚的状态。GPIO_EXTILineConfig 函数用来指定中断/事件线的输入源,它实际是
陈德金老师编著
第7 章.EXTI-外部中断/事件控制器
第68 页SAIUR2016
设定外部中断配置寄存器的AFIO_EXTICRx 值,该函数接收两个参数,第一个参数指定GPIO 端口
源,第二个参数为选择对应GPIO 引脚源编号。我们的目的是产生中断,执行中断服务函数,EXTI 选
择中断模式,按键1 使用上升沿触发方式,并使能EXTI 线。按键2 基本上采用与按键1 相关参数
配置,只是改为下降沿触发方式。两个按键的电路是一样的,可代码中我们设置按键1 是上升沿中断,
按键2 是下降沿中断,有人就会问这是不是设置错了?实际上可以这么理解,按键1 检测的是按键按
下的状态,按键2 检测的是按键弹开的状态,那这样就解释的通了。
代码清单7-5 EXTI 中断服务函数
当中断发生时,对应的中断服务函数就会被执行,我们可以在中断服务函数实现一些控制。一般为
确保中断确实发生,我们会在中断服务函数中调用中断标志位状态读取函数读取外设中断标志位并判断
标志位状态。EXTI_GetITStatus 函数用来获取EXTI 的中断标志位状态,如果EXTI 线有中断发生函
数返回“ SET ” 否则返回“ RESET ” 。实际上, EXTI_GetITStatus 函数是通过读取EXTI_PR
寄存器值来判断EXTI 线状态的。按键1 的中断服务函数我们让LED1 翻转其状态,按键2 的中断
服务函数我们让LED2 翻转其状态。执行任务后需要调用EXTI_ClearITPendingBit 函数清除EXTI 线
的中断标志位。主函数
代码清单7-6 主函数
主函数非常简单,只有两个任务函数。LED_GPIO_Config 函数定义在bsp_led.c 文件内,完成RGB
第7 章.EXTI-外部中断/事件控制器
SAIUR201 6 第69页
彩灯的GPIO 初始化配置。EXTI_Key_Config 函数完成两个按键的GPIO 和EXTI 配置。
7.7.5. 下载验证
保证开发板相关硬件连接正确,把编译好的程序下载到开发板。此时RGB 彩色灯是暗的,如果
我们按下开发板上的按键1,RGB 彩灯变亮,再按下按键1,RGB 彩灯又变暗;如果我们按下开发
板上的按键2 并弹开,RGB 彩灯变亮,再按下开发板上的KEY2 并弹开,RGB 彩灯又变暗。按键
按下表示上升沿,按键弹开表示下降沿,这跟我们软件设置是一样的。
7.8. 课后练习
1、是否可以同时使用PA0 和PB0 中断?如果不可以,有什么解决方法。
2、从硬件角度结合程序分析,为什么按下按键1RGB 彩灯就马上变化,而按键2 却需要按下
按键再弹开之后RGB 彩灯才变化?
第8 章.SysTick 系统定时器
第70 页SAIUR2016
第8 章. SysTick 系统定时器
8.1. 课前预习
在书上找到答案。
1. SysTIck 和系统时钟有什么区别?
8.2. 概述
本章所讲内容:
(1)SysTick 的说明和使用
8.3. SysTick 简介
SysTick—系统定时器是属于CM3 内核中的一个外设,内嵌在NVIC 中。系统定时器是一个24bit
的向下递减的计数器,计数器每计数一次的时间为1/SYSCLK,一般我们设置系统时钟SYSCLK 等于
72M。当重装载数值寄存器的值递减到0 的时候,系统定时器就产生一次中断,以此循环往复。因为
SysTick 是属于CM3 内核的外设,所以所有基于CM3 内核的单片机都具有这个系统定时器,使得
软件在CM3 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作
系统的心跳。
8.4. SysTick 寄存器介绍
SysTick—系统定时器有4 个寄存器,简要介绍如下。在使用SysTick 产生定时的时候,需要配置
前三个寄存器,最后一个校准寄存器不需要使用。
表8-1 SysTick 寄存器汇总
第8 章.SysTick 系统定时器
SAIUR201 6 第71页
表8-2 SysTick 控制及状态寄存器
表8-3 SysTick 重装载数值寄存器
表8-4 SysTick 当前数值寄存器
第8 章.SysTick 系统定时器
第72 页SAIUR2016
表8-5 SysTick 当前数值寄存器
系统定时器的校准数值寄存器在定时实验中不需要用到。有关各个位的描述这里引用手册里面的英
文版本,比较晦涩难懂,暂时不知道这个寄存器用来干什么。有研究过的朋友可以交流,起个抛砖引玉
的作用。
8.5. SysTick 定时实验
利用SysTick 产生1s 的时基,LED 以1s 的频率闪烁。
8.5.1. 硬件设计
SysTick 属于单片机内部的外设,不需要额外的硬件电路,剩下的只需一个LED 灯即可。
8.5.2. 软件设计
这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参
考本章配套的工程。我们创建了两个文件:bsp_SysTick.c 和bsp_ SysTick.h 文件用来存放SysTick 驱
动程序及相关宏定义,中断服务函数放在stm32f10x_it.h 文件中。
8.5.3. 编程要点
1、设置重装载寄存器的值
2、清除当前数值寄存器的值
3、配置控制与状态寄存器
第8 章.SysTick 系统定时器
SAIUR201 6 第73页
8.5.4. 代码分析
SysTick 属于内核的外设, 有关的寄存器定义和库函数都在内核相关的库文件core_cm3.h 中。
SysTick 配置库函数
代码8-1 SysTick 配置库函数
用固件库编程的时候我们只需要调用库函数SysTick_Config()即可,形参ticks 用来设置重装载寄
存器的值,最大不能超过重装载寄存器的值224,当重装载寄存器的值递减到0 的时候产生中断,然
后重装载寄存器的值又重新装载往下递减计数,以此循环往复。紧随其后设置好中断优先级,最后配置
系统定时器的时钟等于AHBCLK=72M,使能定时器和定时器中断,这样系统定时器就配置好了,一个
库函数搞定。SysTick_Config()库函数主要配置了SysTick 中的三个寄存器:LOAD、VAL 和CTRL,
有关具体的部分看代码注释即可。
配置SysTick 中断优先级
在SysTick_Config()库函数还调用了固件库函数NVIC_SetPriority()来配置系统定时器的中断优先
级,该库函数也在core_m3.h 中定义,原型如下:
函数首先先判断形参IRQn 的大小,如果是小于0,则表示这个是系统异常,系统异常的优先级
由内核外设SCB 的寄存器SHPRx 控制,如果大于0 则是外部中断,外部中断的优先级由内核外设
NVIC 中的IPx 寄存器控制。因为SysTick 属于内核外设,跟普通外设的中断优先级有些区别,并没
有抢占优先级和子优先级的说法。在STM32F103 中,内核外设的中断优先级由内核SCB 这个外设的
第8 章.SysTick 系统定时器
第74 页SAIUR2016
寄存器:SHPRx(x=1.2.3)来配置。有关SHPRx 寄存器的详细描述可参考《Cortex-M3 内核编程手册》
4.4.8 章节。下面我们简单介绍下这个寄存器。SPRH1-SPRH3 是一个32 位的寄存器,但是只能通过
字节访问,每8 个字段控制着一个内核外设的中断优先级的配置。在STM32F103 中,只有位7:3 这
高四位有效,低四位没有用到,所以内核外设的中断优先级可编程为:0~15,只有16 个可编程优先
级,数值越小,优先级越高。如果软件优先级配置相同,那就根据他们在中断向量表里面的位置编号来
决定优先级大小,编号越小,优先级越高。
表8-6 系统异常优先级字段
如果要修改内核外设的优先级,只需要修改下面三个寄存器对应的某个字段即可。
图8-1 SHPR1 寄存器
图8-2 SHPR2 寄存器
第8 章.SysTick 系统定时器
SAIUR201 6 第75页
图8-3 SHPR3 寄存器
系统定时器中, 配置优先级为(1UL << __NVIC_PRIO_BITS) - 1UL) , 其中宏
__NVIC_PRIO_BITS 为4,那计算结果就等于15,可以看出系统定时器此时设置的优先级在内核外设
中是最低的,如果要修改优先级则修改这个值即可,范围为:0~15。
systick 和片上外设呢?而且片上外设也刚好需要使用中断,那systick 的中断优先级跟外设的中
断优先级怎么设置?会不会因为systick 是内核里面的外设,所以它的中断优先级就一定比内核之外的
外设的优先级高?
从《STM32 中断应用概览》这章我们知道,外设在设置中断优先级的时候,首先要分组,然后
设置抢占优先级和子优先级。而systick 这类内核的外设在配置的时候,只需要配置一个寄存器即可,
取值范围为0~15。既然配置方法不同,那如何区分两者的优先级?下面举例说明。比如配置一个外设
的中断优先级分组为2,抢占优先级为1,子优先级也为1,systick 的优先级为固件库默认配置的15。
当我们比较内核外设和片上外设的中断优先级的时候,我们只需要抓住NVIC 的中断优先级分组不仅
对片上外设有效,同样对内核的外设也有效。我们把systick 的优先级15 转换成二进制值就是
1111(0b),又因为NVIC 的优先级分组2,那么前两位的11(0b)就是3,后两位的11(0b)也是3。无
论从抢占还是子优先级都比我们设定的外设的优先级低。如果当两个的软件优先级都配置成一样,那么
就比较他们在中断向量表中的硬件编号,编号越小,优先级越高。
第8 章.SysTick 系统定时器
第76 页SAIUR2016
SysTick 初始化函数
代码8-2 SysTick 初始化函数
SysTick 初始化函数由用户编写,里面调用了SysTick_Config()这个固件库函数,通过设置该固件
库函数的形参,就决定了系统定时器经过多少时间就产生一次中断。
SysTick 中断时间的计算
SysTick 定时器的计数器是向下递减计数的,计数一次的时间TDEC=1/CLKAHB,当重装载寄存
器中的值VALUELOAD 减到0 的时候, 产生中断, 可知中断一次的时间TINT=VALUELOAD *
TDEC= VALUELOAD/CLKAHB , 其中CLKAHB =72MHZ 。如果设置VALUELOAD 为72,
那中断一次的时间TINT=72/72M=1us。不过1us 的中断没啥意义,整个程序的重心都花在进出中断上
了,根本没有时间处理其他的任务。
SysTick_Config()的形我们配置为SystemCoreClock / 100000=72M/100000=720,从刚刚分析我
们知道这个形参的值最终是写到重装载寄存器LOAD 中的,从而可知我们现在把SysTick 定时器中断
一次的时间TINT=720/72M=10us。
SysTick 定时时间的计算
当设置好中断时间TINT 后,我们可以设置一个变量t,用来记录进入中断的次数,那么变量t 乘
以中断的时间TINT 就可以计算出需要定时的时间。
第8 章.SysTick 系统定时器
SAIUR201 6 第77页
SysTick 定时函数
现在我们定义一个微秒级别的延时函数,形参为nTime,当用这个形参乘以中断时间TINT 就得
出我们需要的延时时间,其中TINT 我们已经设置好为10us。关于这个函数的具体调用看注释即可。
函数Delay_us()中我们等待TimingDelay 为0,当TimingDelay 为0 的时候表示延时时间到。变
量TimingDelay 在中断函数中递减,即SysTick 每进一次中断即10us 的时间TimingDelay 递减一次。
SysTick 中断服务函数
中断复位函数调用了另外一个函数TimingDelay_Decrement(),原型如下:
TimingDelay 的值等于延时函数中传进去的nTime 的值,比如nTime=100000,则延时的时间等于
100000*10us=1s。
第8 章.SysTick 系统定时器
第78 页SAIUR2016
主函数中初始化了LED 和SysTick,然后在一个while 循环中以1s 的频率让LED 闪烁。另
外一种更简洁的定时编程上面的实验,我们是使用了中断,而且经过多个函数的调用,还使用了全局变
量,理解起来挺费劲的,其实还有另外一种更简洁的写法。我们知道,systick 的counter 从reload 值
往下递减到0 的时候,CTRL 寄存器的位16:countflag 会置1,且读取该位的值可清0,所有我们可
以使用软件查询的方法来实现延时。具体代码见代码8-3 和代码8-4,我敢肯定这样的写法,初学者
肯定会更喜欢,因为它直接,套路浅。
代码8-3 systick 微秒级延时
在这两个微秒和毫秒级别的延时函数中,我们还是调用了SysTick_Config 这个固件库函数, 有关
这个函数的说明具体见代码19-5 。配套代码注释理解即可。其中SystemCoreClock 是一个宏,大
小为72000000,如果不想使用这个宏,也可以直接改成数字。
第8 章.SysTick 系统定时器
SAIUR201 6 第79页
8.6. 课后练习
1、如果修改SysTick 的中断优先级?
2、如何计算SysTick 进入一次中断的时间?
3、如何利用SysTick 实现一个1ms 的延时?
第9 章.USART-串口通讯
第80 页SAIUR2016
第9 章. USART—串口通讯
9.1. 课前预习
在书上找到答案。
1. 同步和异步的区别?
2. USART 有多少个引脚?
9.2. 概述
本章所讲内容:
(1)USART 的介绍
(2)使用串口发送和接收数据
9.3. 串口通讯协议简介
串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此
大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息。
在计算机科学里,大部分复杂的问题都可以通过分层来简化。如芯片被分为内核层和片上外设;STM32
标准库则是在寄存器与用户代码之间的软件层。对于通讯协议,我们也以分层的方式来理解,最基本
的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数
据在物理媒体的传输。协议层主要规定通讯逻辑, 统一收发双方的数据打包、解包标准。简单来说物
理层规定我们用嘴巴还是用肢体来交流, 协议层则规定我们用中文还是英文来交流。下面我们分别对
串口通讯协议的物理层及协议层进行讲解。
9.3.1. 物理层
串口通讯的物理层有很多标准及变种,我们主要讲解RS-232 标准,RS-232 标准主要规定了信
号的用途、通讯接口以及信号的电平标准。使用RS-232 标准的串口设备间常见的通讯结构见图9-1。
第9 章.USART-串口通讯
SAIUR201 6 第81页
图9-1 串口通讯结构图
在上面的通讯方式中,两个通讯设备的“DB9 接口”之间通过串口信号线建立起连接, 串口信号线
中使用“RS-232 标准”传输数据信号。由于RS-232 电平标准的信号不能直接被控制器直接识别,所以
这些信号会经过一个“电平转换芯片”转换成控制器能识别的“TTL 标准”的电平信号,才能实现通讯。
电平标准
根据通讯使用的电平标准不同,串口通讯可分为TTL 标准及RS-232 标准,见表9-1。
表9-1 TTL 电平标准与RS232 电平标准
我们知道常见的电子电路中常使用TTL 的电平标准,理想状态下,使用5V 表示二进制逻辑1,
使用0V 表示逻辑0;而为了增加串口通讯的远距离传输及抗干扰能力,它使用-15V 表示逻辑1,+15V
表示逻辑0。使用RS232 与TTL 电平校准表示同一个信号时的对比见图8-2。
图9-2 RS-232 与TTL 电平标准下表示同一个信号
因为控制器一般使用TTL 电平标准,所以常常会使用MA3232 芯片对TTL 及RS-232 电平的信
第9 章.USART-串口通讯
第82 页SAIUR2016
号进行互相转换。
RS-232 信号线
在最初的应用中,RS-232 串口标准常用于计算机、路由与调制调解器(MODEN,俗称“猫”)之间的
通讯,在这种通讯系统中,设备被分为数据终端设备DTE(计算机、路由)和数据通讯设备DCE(调制
调解器)。我们以这种通讯模型讲解它们的信号线连接方式及各个信号线的作用。在旧式的台式计算机
中一般会有RS-232 标准的COM 口(也称DB9 接口),见图9-3。
图9-3 电脑主板上的COM 口及串口线
其中接线口以针式引出信号线的称为公头,以孔式引出信号线的称为母头。在计算机中一般引出
公头接口,而在调制调解器设备中引出的一般为母头,使用上图中的串口线即可把它与计算机连接起
来。通讯时,串口线中传输的信号就是使用前面讲解的RS-232 标准调制的。在这种应用场合下,DB9
接口中的公头及母头的各个引脚的标准信号线接法见图9-4 及表9-2。
第9 章.USART-串口通讯
SAIUR201 6 第83页
图9-4 DB9 标准的公头及母头接法
表9-2 DB9 信号线说明(公头,为方便理解,可把DTE 理解为计算机,DCE 理解为调制调解
器)
上表中的是计算机端的DB9 公头标准接法,由于两个通讯设备之间的收发信号(RXD 与TXD)应
交叉相连,所以调制调解器端的DB9 母头的收发信号接法一般与公头的相反,两个设备之间连接时,
只要使用“直通型”的串口线连接起来即可,见图9-5。
第9 章.USART-串口通讯
第84 页SAIUR2016
图9-5 计算机与调制调解器的信号线连接
串口线中的RTS、CTS、DSR、DTR 及DCD 信号,使用逻辑1 表示信号有效,逻辑0 表示信
号无效。例如,当计算机端控制DTR 信号线表示为逻辑1 时,它是为了告知远端的调制调解器,本
机已准备好接收数据,0 则表示还没准备就绪。在目前的其它工业控制使用的串口通讯中,一般只使用
RXD、TXD 以及GND 三条信号线,直接传输数据信号,而RTS、CTS、DSR、DTR 及DCD 信号
都被裁剪掉了。
9.3.2. 协议层
串口通讯的数据包由发送设备通过自身的TXD 接口传输到接收设备的RXD 接口。在串口通讯
的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据
包格式要约定一致才能正常收发数据,其组成见图9-6。
图9-6 串口数据包的基本组成
波特率
本章中主要讲解的是串口异步通讯,异步通讯中由于没有时钟信号(如前面讲解的DB9 接口中是没
有时钟信号的),所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码,
图21-6 中用虚线分开的每一格就是代表一个码元。常见的波特率为4800、9600、115200 等。
通讯的起始和停止信号
串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑0 的
数据位表示,而数据包的停止信号可由0.5、1、1.5 或2 个逻辑1 的数据位表示,只要双方约定一致
即可。
有效数据
在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常
被约定为5、6、7 或8 位长。
第9 章.USART-串口通讯
SAIUR201 6 第85页
数据校验
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据
出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0 校
验(space)、1 校验(mark)以及无校验(noparity)。奇校验要求有效数据和校验位中“1”的个数为奇数,比如
一个8 位长的有效数据为:01101001,此时总共有4 个“1”,为达到奇校验效果,校验位为“1”,最后
传输的数据将是8 位的有效数据加上1 位的校验位总共9 位。偶校验与奇校验要求刚好相反,要求
帧数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时数据帧“1”的个数为4 个,所以偶
校验位为“0”。0 校验是不管有效数据中的内容是什么,校验位总为“0”,1 校验是校验位总为“1”。
9.4. STM32 的USART 简介
通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信
设备,可以灵活地与外部设备进行全双工数据交换。有别于USART 还有一个UART(Universal
Asynchronous Receiver and Transmitter),它是在USART 基础上裁剪掉了同步通信功能,只有异步通信。
简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是
UART。串行通信一般是以帧格式传输数据,即是一帧一帧的传输,每帧包含有起始信号、数据信息、
停止信息,可能还有校验信息。USART 就是对这些传输参数有具体规定,当然也不是只有唯一一个
参数值,很多参数值都可以自定义设置,只是增强它的兼容性。USART 满足外部设备对工业标准NRZ
异步串行数据格式的要求,并且使用了小数波特率发生器,可以提供多种波特率,使得它的应用更加
广泛。USART 支持同步单向通信和双工单线通信;还支持局域互连网络LIN、智能卡(SmartCard)协议
与lrDA(红外线数据协会) SIR ENDEC 规范。USART 支持使用DMA,可实现高速数据通信,有关
DMA 具体应用将在DMA 章节作具体讲解。USART 在STM32 应用最多莫过于“打印”程序信息,一
般在硬件设计时都会预留一个USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息
“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、如果出错哪具体哪里出错等等。
9.5. USART 功能框图
USART 的功能框图包含了USART 最核心内容,掌握了功能框图,对USART 就有一个整体的
把握,在编程时就思路就非常清晰。USART 功能框图见图9-7。
第9 章.USART-串口通讯
第86 页SAIUR2016
图9-7 USART 功能框图
功能引脚
TX:发送数据输出引脚。
RX:接收数据输入引脚。
SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。
nRTS:请求以发送(Request To Send),n 表示低电平有效。如果使能RTS 流控制,当
USART 接收器准备好接收新数据时就会将nRTS 变成低电平;当接收寄存器已满时,nRTS 将被
设置为高电平。该引脚只适用于硬件流控制。
nCTS:清除以发送(Clear To Send),n 表示低电平有效。如果使能CTS 流控制,发送器在发送下
一帧数据之前会检测nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前
数据帧之后停止发送。该引脚只适用于硬件流控制。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
USART 引脚在STM32F103ZET6 芯片具体分布见表21-3。
表9-3 STM32F103VET6 芯片的USART 引脚
第9 章.USART-串口通讯
SAIUR201 6 第87页
STM32F103VET6 系统控制器有三个USART 和两个UART,其中USART1 和时钟来源于
APB2 总线时钟,其最大频率为72MHz,其他四个的时钟来源于APB1 总线时钟,其最大频率为
36MHz。UART 只是异步传输功能,所以没有SCLK、nCTS 和nRTS 功能引脚。
数据寄存器
USART 数据寄存器(USART_DR)只有低9 位有效,并且第9 位数据是否有效要取决于USART
控制寄存器1(USART_CR1)的M 位设置,当M 位为0 时表示8 位数据字长,当M 位为1 表示9
位数据字长,我们一般使用8 位数据字长。USART_DR 包含了已发送的数据或者接收到的数据。
USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写TDR,一个专门用于接收的可读
RDR。当进行发送操作时, 往USART_DR 写入数据会自动存储在TDR 内;当进行读取操作时,向
USART_DR 读取数据会自动提取RDR 数据。TDR 和RDR 都是介于系统总线和移位寄存器之间。
串行通信是一个位一个位传输的, 发送时把TDR 内容转移到发送移位寄存器,然后把移位寄存器数
据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到RDR。
USART 支持DMA 传输,可以实现高速数据传输,具体DMA 使用将在DMA 章节讲解。
控制器
USART 有专门控制发送的发送器、控制接收的接收器,还有唤醒单元、中断控制等等。
使用USART 之前需要向USART_CR1 寄存器的UE 位置1 使能USART,UE 位用来开启供
给给串口的时钟。发送或者接收数据字长可选8 位或9 位,由USART_CR1 的M 位控制。发送器
当USART_CR1 寄存器的发送使能位TE 置1 时,启动数据发送,发送移位寄存器的数据会在TX
引脚输出,低位在前,高位在后。如果是同步模式SCLK 也输出时钟信号。一个字符帧发送需要三个
部分:起始位+数据帧+停止位。起始位是一个位周期的低电平,位周期就是每一位占用的时间;数据
帧就是我们要发送的8 位或9 位数据,数据是从最低位开始传输的;停止位是一定时间周期的高电
平。停止位时间长短是可以通过USART 控制寄存器2(USART_CR2)的STOP[1:0]位控制,可选0.5
个、1 个、1.5 个和2 个停止位。默认使用1 个停止位。2 个停止位适用于正常USART 模式、单线
模式和调制解调器模式。0.5 个和1.5 个停止位用于智能卡模式。当选择8 位字长,使用1 个停止位
时,具体发送字符时序图见图9-8。
第9 章.USART-串口通讯
第88 页SAIUR2016
图9-8 字符发送时序图
当发送使能位TE 置1 之后,发送器开始会先发送一个空闲帧(一个数据帧长度的高电平),接下
来就可以往USART_DR 寄存器写入要发送的数据。在写入最后一个数据后,需要等待USART 状
态寄存器(USART_SR) 的TC 位为1 , 表示数据传输完成, 如果USART_CR1 寄存器的TCIE
位置1,将产生中断。在发送数据时,编程的时候有几个比较重要的标志位我们来总结下。
接收器
如果将USART_CR1 寄存器的RE 位置1,使能USART 接收,使得接收器在RX 线开始搜
索起始位。在确定到起始位后就根据RX 线电平状态把数据存放在接收移位寄存器内。接收完成后
就把接收移位寄存器数据移到RDR 内,并把USART_SR 寄存器的RXNE 位置1,同时如果
USART_CR2 寄存器的RXNEIE 置1 的话可以产生中断。在接收数据时,编程的时候有几个比较
重要的标志位我们来总结下。
小数波特率生成
波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示, 单位为波
特。比特率指单位时间内传输的比特数,单位bit/s(bps)。对于USART 波特率与比特率相等,以后不
区分这两个概念。波特率越大,传输速率越快。USART 的发送器和接收器使用相同的波特率。计算公
式如下:
公式9-1 波特率计算
其中,fPLCK 为USART 时钟, USARTDIV 是一个存放在波特率寄存器(USART_BRR)的一个无
符号定点数。其中DIV_Mantissa[11:0] 位定义USARTDIV 的整数部分,DIV_Fraction[3:0]位定义
第9 章.USART-串口通讯
SAIUR201 6 第89页
USARTDIV 的小数部分。例如: DIV_Mantissa=24(0x18) , DIV_Fraction=10(0x0A) , 此时
USART_BRR 值为0x18A;那么USARTDIV 的小数位10/16=0.625;整数位24,最终USARTDIV 的
值为24.625。如果知道USARTDIV 值为27.68,那么DIV_Fraction=16*0.68=10.88,最接近的正整数
为11,所以DIV_Fraction[3:0]为0xB;DIV_Mantissa=整数(27.68)=27,即为0x1B。波特率的常用值
有2400、9600、19200、115200。下面以实例讲解如何设定寄存器值得到波特率的值。我们知道USART1
使用APB2 总线时钟,最高可达72MHz,其他USART 的最高频率为36MHz。我们选取USART1 作
为实例讲解,即fPLCK=72MHz。为得到115200bps 的波特率,此时:
解得USARTDIV=39.0625,可算得DIV_Fraction=0.0625*16=1=0x01,DIV_Mantissa=39=0x17,即
应该设置USART_BRR 的值为0x171。
校验控制
STM32F103 系列控制器USART 支持奇偶校验。当使用校验位时,串口传输的长度将是8 位的
数据帧加上1 位的校验位总共9 位,此时USART_CR1 寄存器的M 位需要设置为1,即9 数据位。
将USART_CR1 寄存器的PCE 位置1 就可以启动奇偶校验控制,奇偶校验由硬件自动完成。启动
了奇偶校验控制之后,在发送数据帧时会自动添加校验位,接收数据时自动验证校验位。接收数据时
如果出现奇偶校验位验证失败,会见USART_SR 寄存器的PE 位置1,并可以产生奇偶校验中断。
使能了奇偶校验控制后,每个字符帧的格式将变成:起始位+数据帧+校验位+停止位。
中断控制
USART 有多个中断请求事件,具体见表9-4。
表9-4 USART 中断请求
第9 章.USART-串口通讯
第90 页SAIUR2016
9.6. USART 初始化结构体详解
标准库函数对每个外设都建立了一个初始化结构体,比如USART_InitTypeDef,结构体成员用于
设置外设工作参数,并由外设初始化配置函数,比如USART_Init()调用,这些设定参数将会设置外设
相应的寄存器,达到配置外设工作环境的目的。初始化结构体和初始化库函数配合使用是标准库精髓所
在,理解了初始化结构体每个成员意义基本上就可以对该外设运用自如了。初始化结构体定义在
stm32f10x_usart.h 文件中,初始化库函数定义在stm32f10x_usart.c 文件中,编程时我们可以结合这两
个文件内注释使用。
USART_BaudRate:波特率设置。一般设置为2400、9600、19200、115200。标准库函数会根据
设定值计算得到USARTDIV 值,从而设置USART_BRR 寄存器值。
USART_WordLength:数据帧字长,可选8 位或9 位。它设定USART_CR1 寄存器的M 位的
值。如果没有使能奇偶校验控制,一般使用8 数据位;如果使能了奇偶校验则一般设置为9 数据位。
USART_StopBits:停止位设置,可选0.5 个、1 个、1.5 个和2 个停止位,它设定USART_CR2
寄存器的STOP[1:0]位的值,一般我们选择1 个停止位。
USART_Parity : 奇偶校验控制选择, 可选USART_Parity_No( 无校验) 、
USART_Parity_Even( 偶校验) 以及USART_Parity_Odd( 奇校验) , 它设定USART_CR1
寄存器的PCE 位和PS 位的值。
USART_Mode:USART 模式选择,有USART_Mode_Rx 和USART_Mode_Tx,允许使用逻辑或
运算选择两个,它设定USART_CR1 寄存器的RE 位和TE 位。
USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效, 可选有⑴使能
RTS、⑵使能CTS、⑶同时使能RTS 和CTS、⑷不使能硬件流。当使用同步模式时需要配置SCLK 引
脚输出脉冲的属性,标准库使用一个时钟初始化结构体USART_ClockInitTypeDef 来设置,该结构体内
容也只有在同步模式才需要设置。
第9 章.USART-串口通讯
SAIUR201 6 第91页
USART_Clock : 同步模式下SCLK 引脚上时钟输出使能控制, 可选禁止时钟输出
(USART_Clock_Disable)或开启时钟输出(USART_Clock_Enable);如果使用同步模式发送,一般都需要
开启时钟。它设定USART_CR2 寄存器的CLKEN 位的值。
USART_CPOL:同步模式下SCLK 引脚上输出时钟极性设置,可设置在空闲时SCLK 引脚为低
电平(USART_CPOL_Low)或高电平(USART_CPOL_High)。它设定USART_CR2 寄存器的CPOL 位的
值。
USART_CPHA:同步模式下SCLK 引脚上输出时钟相位设置,可设置在时钟第一个变化沿捕获数
据(USART_CPHA_1Edge)或在时钟第二个变化沿捕获数据。它设定USART_CR2 寄存器的CPHA 位
的值。USART_CPHA 与USART_CPOL 配合使用可以获得多种模式时钟关系。
USART_LastBit:选择在发送最后一个数据位的时候时钟脉冲是否在SCLK 引脚输出, 可以
是不输出脉冲(USART_LastBit_Disable) 、输出脉冲(USART_LastBit_Enable)。它设定
USART_CR2 寄存器的LBCL 位的值。
9.7. USART1 接发通信实验
USART 只需两根信号线即可完成双向通信,对硬件要求低,使得很多模块都预留USART 接口来
实现与其他模块或者控制器进行数据传输,比如GSM 模块,WIFI 模块、蓝牙模块等等。在硬件设
计时,注意还需要一根“共地线”。我们经常使用USART 来实现控制器与电脑之间的数据传输。这使
得我们调试程序非常方便,比如我们可以把一些变量的值、函数的返回值、寄存器标志位等等通过
USART 发送到串口调试助手,这样我们可以非常清楚程序的运行状态,当我们正式发布程序时再把
这些调试信息去除即可。我们不仅仅可以将数据发送到串口调试助手,我们还可以在串口调试助手发
送数据给控制器,控制器程序根据接收到的数据进行下一步工作。首先,我们来编写一个程序实现开
发板与电脑通信,在开发板上电时通过USART 发送一串字符串给电脑,然后开发板进入中断接收等
待状态,如果电脑有发送数据过来,开发板就会产生中断,我们在中断服务函数接收数据,并马上把
数据返回发送给电脑。
第9 章.USART-串口通讯
第92 页SAIUR2016
9.7.1. 硬件设计
为利用USART 实现开发板与电脑通信,需要用到一个USB 转USART 的IC,我们选择
CH340G 芯片来实现这个功能,CH340G 是一个USB 总线的转接芯片,实现USB 转USART、USB
转lrDA 红外或者USB 转打印机接口,我们使用其USB 转USART 功能。具体电路设计见图9-9。
我们将CH340G 的TXD 引脚与USART1 的RX 引脚连接,CH340G 的RXD 引脚与USART1 的
TX 引脚连接。CH340G 芯片集成在开发板上,其地线(GND)已与控制器的GND 连通。
图9-9 USB 转串口硬件设计
9.7.2. 软件设计
这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参
考本章配套的工程。我们创建了两个文件:bsp_usart.c 和bsp _usart.h 文件用来存放USART 驱动程
序及相关宏定义。
9.7.3. 编程要点
1.使能RX 和TX 引脚GPIO 时钟和USART 时钟;
2.初始化GPIO,并将GPIO 复用到USART 上;
3.配置USART 参数;
4.配置中断控制器并使能USART 接收中断;
5.使能USART;
6.在USART 接收中断服务函数实现数据接收和发送。
第9 章.USART-串口通讯
SAIUR201 6 第93页
9.7.4. 代码分析
代码清单9-1 GPIO 和USART 宏定义
使用宏定义方便程序移植和升级。开发板中的CH340G 的收发引脚默认通过跳帽连接到
USART1,如果想使用其他串口,可以把CH340G 跟USART1 直接的连接跳帽拔掉,然后再把其他
串口的IO 用杜邦线接到CH340G 的收发引脚即可。这里我们使用USART1,设定波特率为115200,
选定USART 的GPIO 为PA9 和PA10。嵌套向量中断控制器NVIC 配置。
代码清单9-2 中断控制器NVIC 配置
第9 章.USART-串口通讯
第94 页SAIUR2016
代码清单9-3 USART 初始化配置
第9 章.USART-串口通讯
SAIUR201 6 第95页
使用GPIO_InitTypeDef 和USART_InitTypeDef 结构体定义一个GPIO 初始化变量以及一个
USART 初始化变量,这两个结构体内容我们之前已经有详细讲解。调用RCC_APB2PeriphClockCmd
函数开启GPIO 端口时钟, 使用GPIO 之前必须开启对应端口的时钟。使用
RCC_APB2PeriphClockCmd 函数开启USART 时钟。使用GPIO 之前都需要初始化配置它,并且还要
添加特殊设置,因为我们使用它作为外设的引脚,一般都有特殊功能。我们在初始化时需要把它的模式
设置为复用功能。这里把串口的Tx 引脚配置为复用推挽输出,Rx 引脚为浮空输入,数据完全由外部
输入决定。接下来,我们配置USART1 通信参数为:波特率115200,字长为8,1 个停止位,没有
校验位,不使用硬件流控制,收发一体工作模式,然后调用USART 初始化函数完成配置。程序用到
USART 接收中断,需要配置NVIC,这里调用NVIC_Configuration 函数完成配置。配置完NVIC 之
后调用USART_ITConfig 函数使能USART 接收中断。
最后调用USART_Cmd 函数使能USART,这个函数最终配置的是USART_CR1 的UE 位,具体
的作用是开启USART 的工作时钟,没有时钟那USART 这个外设自然就工作不了。
代码清单9-4 字符发送函数
Usart_SendByte 函数用来在指定USART 发送一个ASCLL 码值字符,它有两个形参,第一个为
USART,第二个为待发送的字符。它是通过调用库函数USART_SendData 来实现的,并且增加了等待
发送完成功能。通过使用USART_GetFlagStatus 函数来获取USART 事件标志来实现发送完成功能等
待,它接收两个参数,一个是USART,一个是事件标志。这里我们循环检测发送数据寄存器为空这个
标志,当跳出while 循环时说明发送数据寄存器为空这个事实。Usart_SendString 函数用来发送一个字
符串,它实际是调用Usart_SendByte 函数发送每个字符,直到遇到空字符才停止发送。最后使用循环
检测发送完成的事件标志TC 来实现保证数据发送完成后才退出函数。
第9 章.USART-串口通讯
第96 页SAIUR2016
USART 中断服务函数
代码清单21-5 USART 中断服务函数
这段代码是存放在stm32f10x_it.c 文件中的,该文件用来集中存放外设中断服务函数。当我们使
能了中断并且中断发生时就会执行这里的中断服务函数。我们在代码清单21-3 使能了USART 接收
中断,当USART 有接收到数据就会执行USART_IRQHandler 函数。USART_GetITStatus 函数与
USART_GetFlagStatus 函数类似用来获取标志位状态,但USART_GetITStatus 函数是专门用来获取中
断事件标志的,并返回该标志位状态。使用if 语句来判断是否是真的产生USART 数据接收这个中断
事件,如果是真的就使用USART 数据读取函数USART_ReceiveData 读取数据到指定存储区。然后
再调用USART 数据发送函数USART_SendData 把数据又发送给源设备,即PC 端的串口调试助手。
主函数
代码清单9-6 主函数
首先我们需要调用USART_Config 函数完成USART 初始化配置,包括GPIO 配置,USART 配
置,接收中断使能等等信息。接下来就可以调用字符发送函数把数据发送给串口调试助手了。最后主函
数什么都不做,只是静静地等待USART 接收中断的产生,并在中断服务函数把数据回传。
第9 章.USART-串口通讯
SAIUR201 6 第97页
9.7.5. 下载验证
保证开发板相关硬件连接正确,用USB 线连接开发板的USB 转串口跟电脑,在电脑端打开串口
调试助手并配置好相关参数:115200 8-N-1,把编译好的程序下载到开发板,此时串口调试助手即可收
到开发板发过来的数据。我们在串口调试助手发送区域输入任意字符,点击发送按钮,马上在串口调试
助手接收区即可看到相同的字符。
图9-10 实验现象
9.8. 课后练习
1.使用Usart 控制RGB 彩灯
第10 章.DMA 直接存储区访问
第98 页SAIUR2016
第10 章.DMA 直接存储区访问
10.1.课前预习
在书上找到答案。
1. 什么是DMA
10.2.概述
本章所讲内容:
(1)DMA 功能和配置
(2)使用DMA 读写存储器数据
10.3. DMA 简介
DMA(Direct Memory Access)—直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数
据,但是不需要占用CPU,即在传输数据的时候,CPU 可以干其他的事情,好像是多线程一样。数据
传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是SRAM 或者是FLASH。DMA 控
制器包含了DMA1 和DMA2,其中DMA1 有7 个通道,DMA2 有5 个通道,这里的通道可以理
解为传输数据的一种管道。要注意的是DMA2 只存在于大容量的单片机中。
10.4. DMA 功能框图
DMA 控制器独立于内核,属于一个单独的外设,结构比较简单,从编程的角度来看,我们只需掌
握功能框图中的三部分内容即可,具体见图10-1:DMA 控制器的框图。
第10 章.DMA 直接存储区访问
SAIUR201 6 第99页
图10-1 DMA 框图
DMA 请求
如果外设要想通过DMA 来传输数据,必须先给DMA 控制器发送DMA 请求,DMA 收到请求
信号之后,控制器会给外设一个应答信号,当外设应答后且DMA 控制器收到应答信号之后,就会启
动DMA 的传输,直到传输完毕。DMA 有DMA1 和DMA2 两个控制器,DMA1 有7 个通道,DMA2
有5 个通道,不同的DMA 控制器的通道对应着不同的外设请求,这决定了我们在软件编程上该怎么
设置,具体见DMA 请求映像表。
图10-2 DMA1 各个通道的请求映像
第10 章.DMA 直接存储区访问
第100 页SAIUR2016
图10-3 DMA2 各个通道的请求映像
其中ADC3、SDIO 和TIM8 的DMA 请求只在大容量产品中存在,这个在具体项目时要注意。
通道
DMA 具有12 个独立可编程的通道,其中DMA1 有7 个通道,DMA2 有5 个通道,每个通道
对应不同的外设的DMA 请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,
不能同时接收多个。
仲裁器
当发生多个DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器也管理。
仲裁器管理DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在DMA_CCRx 寄存器中设
置,有4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的DMA
通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高,比如通道0 高于
通道1。在大容量产品和互联型产品中,DMA1 控制器拥有高于DMA2 控制器的优先级。
10.5. DMA 数据配置
使用DMA,最核心就是配置要传输的数据,包括数据从哪里来,要到哪里去,传输的数据的单位
是什么,要传多少数据,是一次传输还是循环传输等等。
从哪里来到哪里去
我们知道DMA 传输数据的方向有三个:从外设到存储器,从存储器到外设,从存储器到存储器。
具体的方向DMA_CCR 位4 DIR 配置:0 表示从外设到存储器,1 表示从存储器到外设。这里面涉
及到的外设地址由DMA_CPAR 配置,存储器地址由DMA_CMAR 配置。外设到存储器当我们使用
从外设到存储器传输时,以ADC 采集为例。DMA 外设寄存器的地址对应的就是ADC 数据寄存器的
地址,DMA 存储器的地址就是我们自定义的变量(用来接收存储AD 采集的数据)的地址。方向我
第10 章.DMA 直接存储区访问
SAIUR201 6 第101页
们设置外设为源地址。存储器到外设当我们使用从存储器到外设传输时,以串口向电脑端发送数据为
例。DMA 外设寄存器的地址对应的就是串口数据寄存器的地址,DMA 存储器的地址就是我们自定
义的变量(相当于一个缓冲区,用来存储通过串口发送到电脑的数据)的地址。方向我们设置外设为目
标地址。存储器到存储器当我们使用从存储器到存储器传输时,以内部FLASH 向内部SRAM 复制数
据为例。DMA 外设寄存器的地址对应的就是内部FLASH(我们这里把内部FALSH 当作一个外设来
看)的地址,DMA 存储器的地址就是我们自定义的变量(相当于一个缓冲区,用来存储来自内部FLASH
的数据)的地址。方向我们设置外设(即内部FLASH)为源地址。跟上面两个不一样的是,这里需要
把DMA_CCR 位14:MEM2MEM:存储器到存储器模式配置为1,启动M2M 模式。
要传多少,单位是什么
当我们配置好数据要从哪里来到哪里去之后,我们还需要知道我们要传输的数据是多少,数据的
单位是什么。以串口向电脑发送数据为例,我们可以一次性给电脑发送很多数据,具体多少由
DMA_CNDTR 配置,这是一个32 位的寄存器,一次最多只能传输65535 个数据。要想数据传输正
确,源和目标地址存储的数据宽度还必须一致,串口数据寄存器是8 位的,所以我们定义的要发送的
数据也必须是8 位。外设的数据宽度由DMA_CCR 的PSIZE[1:0]配置,可以是8/16/32 位,存储器
的数据宽度由DMA_CCR 的MSIZE[1:0]配置, 可以是8/16/32 位。
在DMA 控制器的控制下,数据要想有条不紊的从一个地方搬到另外一个地方,还必须正确设置
两边数据指针的增量模式。外设的地址指针由DMA_CCRx 的PINC 配置,存储器的地址指针由
MINC 配置。以串口向电脑发送数据为例,要发送的数据很多,每发送完一个,那么存储器的地址指
针就应该加1,而串口数据寄存器只有一个,那么外设的地址指针就固定不变。具体的数据指针的增量
模式由实际情况决定。
什么时候传输完成
数据什么时候传输完成,我们可以通过查询标志位或者通过中断的方式来鉴别。每个DMA 通道
在DMA 传输过半、传输完成和传输错误时都会有相应的标志位,如果使能了该类型的中断后,则会
产生中断。有关各个标志位的详细描述请参考DMA 中断状态寄存器DMA_ISR 的详细描述。传输完
成还分两种模式,是一次传输还是循环传输,一次传输很好理解,即是传输一次之后就停止,要想再传
输的话,必须关断DMA 使能后再重新配置后才能继续传输。循环传输则是一次传输完成之后又恢复
第一次传输时的配置循环传输,不断的重复。具体的DMA_CCR 寄存器的CIRC 循环模式位控制。
10.6. DMA 初始化结构体详解
标准库函数对每个外设都建立了一个初始化结构体xxx_InitTypeDef(xxx 为外设名称),结构体成
员用于设置外设工作参数,并由标准库函数xxx_Init()调用这些设定参数进入设置外设相应的寄存器,
达到配置外设工作环境的目的。结构体xxx_InitTypeDef 和库函数xxx_Init 配合使用是标准库精髓所
第10 章.DMA 直接存储区访问
第102 页SAIUR2016
在, 理解了结构体xxx_InitTypeDef 每个成员意义基本上就可以对该外设运用自如。结构体
xxx_InitTypeDef 定义在stm32f10x_xxx.h(后面xxx 为外设名称)文件中,库函数xxx_Init 定义在
stm32f10x_xxx.c 文件中,编程时我们可以结合这两个文件内注释使用。
DMA_PeripheralBaseAddr:外设地址,设定DMA_CPAR 寄存器的值;一般设置为外设的数据
寄存器地址,如果是存储器到存储器模式则设置为其中一个存储器地址。
DMA_Memory0BaseAddr:存储器地址,设定DMA_CMAR 寄存器值;一般设置为我们自定义
存储区的首地址。
DMA_DIR : 传输方向选择, 可选外设到存储器、存储器到外设。它设定DMA_CCR 寄存器
的DIR[1:0]位的值。这里并没有存储器到存储器的方向选择, 当使用存储器到存储器时,只需要把其
中一个存储器当作外设使用即可。
DMA_BufferSize:设定待传输数据数目,初始化设定DMA_CNDTR 寄存器的值。
DMA_PeripheralInc:如果配置为DMA_PeripheralInc_Enable,使能外设地址自动递增功能,它
设定DMA_CCR 寄存器的PINC 位的值;一般外设都是只有一个数据寄存器,所以一般不会使能该
位。
DMA_MemoryInc:如果配置为DMA_MemoryInc_Enable,使能存储器地址自动递增功能,它设
定DMA_CCR 寄存器的MINC 位的值;我们自定义的存储区一般都是存放多个数据的,所以要使能
存储器地址自动递增功能。
DMA_PeripheralDataSize:外设数据宽度,可选字节(8 位)、半字(16 位)和字(32 位), 它设定
DMA_CCR 寄存器的PSIZE[1:0]位的值。
DMA_MemoryDataSize:存储器数据宽度,可选字节(8 位)、半字(16 位)和字(32 位),它设定
DMA_CCR 寄存器的MSIZE[1:0]位的值。当外设和存储器之间传数据时,两边的数据宽度应该设置
为一致大小。
DMA_Mode : DMA 传输模式选择, 可选一次传输或者循环传输, 它设定DMA_CCR 寄存
第10 章.DMA 直接存储区访问
SAIUR201 6 第103页
器的CIRC 位的值。例程我们的ADC 采集是持续循环进行的,所以使用循环传输模式。
DMA_Priority:软件设置通道的优先级,有4 个可选优先级分别为非常高、高、中和低,它设
定DMA_CCR 寄存器的PL[1:0]位的值。DMA 通道优先级只有在多个DMA 通道同时使用时才有意
义,如果是单个通道,优先级可以随便设置。
DMA_M2M : 存储器到存储器模式, 使用存储器到存储器时用到, 设定DMA_CCR 的位14
MEN2MEN 即可启动存储器到存储器模式。
10.7. DMA 存储器到存储器模式实验
本章只讲解存储器到存储器和存储器到外设这两种模式,其他功能模式在其他章节使用到的时候再
讲。存储器到存储器模式可以实现数据在两个内存的快速拷贝。我们先定义一个静态的源数据,存放在
内部FLASH,然后使用DMA 传输把源数据拷贝到目标地址上(内部SRAM),最后对比源数据和
目标地址的数据,看看是否传输准确。
10.7.1. 硬件设计
DMA 存储器到存储器实验不需要其他硬件要求,只用到RGB 彩色灯用于指示程序状态。
10.7.2. 软件设计
这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参
考本章配套的工程。这个实验代码比较简单,主要程序代码都在main.c 文件中。
10.7.3. 编程要点
1.使能DMA 时钟;
2.配置DMA 数据参数;
3.使能DMA,进行传输;
4.等待传输完成,并对源数据和目标地址数据进行比较。
第10 章.DMA 直接存储区访问
第104 页SAIUR2016
10.7.4. 代码分析
DMA 宏定义及相关变量定义
代码清单10-1 DMA 数据流和相关变量定义
使用宏定义设置外设配置方便程序修改和升级。存储器到存储器传输通道没有硬性规定,可以随意
选择。aSRC_Const_Buffer[BUFFER_SIZE]定义用来存放源数据,并且使用了const 关键字修饰,即常
量类型,使得变量是存储在内部flash 空间上。
第10 章.DMA 直接存储区访问
SAIUR201 6 第105页
DMA 数据配置
代码清单10-2 DMA 传输参数配置
使用DMA_InitTypeDef 结构体定义一个DMA 初始化变量,这个结构体内容我们之前已经有详细
讲解。调用RCC_AHBPeriphClockCmd 函数开启DMA 时钟,使用DMA 控制器之前必须开启对应
的时钟。源地址和目标地址使用之前定义的数组首地址,传输的数据量为宏BUFFER_SIZE 决定,源
和目标地址指针地址递增,使用一次传输模式不能循环传输,因为只有一个DMA 通道,优先级随便
设置,最后调用DMA_Init 函数完成DMA 的初始化配置。
DMA_ClearFlag 函数用于清除DMA 标志位,代码用到传输完成标志位,使用之前先清除传输完
成标志位以免产生不必要干扰。DMA_ClearFlag 函数需要1 个形参,即事件标志位,可选有传输完成
标志位、半传输标志位、FIFO 错误标志位、传输错误标志位等等,非常多,我们这里选择传输完成标
志位,由宏DMA_FLAG_TC 定义。
DMA_Cmd 函数用于启动或者停止DMA 数据传输,它接收两个参数,第一个是DMA 通道,另
外一个是开启ENABLE 或者停止DISABLE。存储器数据对比
第10 章.DMA 直接存储区访问
第106 页SAIUR2016
代码清单10-3 源数据与目标地址数据对比
判断指定长度的两个数据源是否完全相等,如果完全相等返回1;只要其中一对数据不相等返回0。
它需要三个形参,前两个是两个数据源的地址,第三个是要比较数据长度。
主函数
代码清单10-4 存储器到存储器模式主函数
第10 章.DMA 直接存储区访问
SAIUR201 6 第107页
首先定义一个变量用来保存存储器数据比较结果。RGB 彩色灯用来指示程序进程,使用之前需要
初始化它,LED_GPIO_Config 定义在bsp_led.c 文件中。开始设置RGB 彩色灯为紫色,LED_PURPLE
是定义在bsp_led.h 文件的一个宏定义。Delay 函数只是一个简单的延时函数。调用DMA_Config 函
数完成DMA 数据流配置并启动DMA 数据传输。DMA_GetFlagStatus 函数获取DMA 事件标志位的
当前状态,这里获取DMA 数据传输完成这个标志位,使用循环持续等待直到该标志位被置位,即
DMA 传输完成这个事件发生,然后退出循环,运行之后程序。确定DMA 传输完成之后就可以调用
Buffercmp 函数比较源数据与DMA 传输后目标地址的数据是否一一对应。TransferStatus 保存比较结
果,如果为1 表示两个数据源一一对应相等说明DMA 传输成功;相反,如果为0 表示两个数据源
数据存在不等情况,说明DMA 传输出错。如果DMA 传输成功设置RGB 彩色灯为蓝色,如果DMA
传输出错设置RGB 彩色灯为红色。
10.7.5. 下载验证
确保开发板供电正常,编译程序并下载。观察RGB 彩色灯变化情况。正常情况下RGB 彩色灯先
为紫色,然后变成蓝色。如果DMA 传输出错才会为红色。
10.8.课后练习
1. 根据存储器至外设模式实验编写一个外设到存储器程序,实现USART 的DMA 接收请求功能,
在接收数据的同时LED 不断的亮灭,相当于两个任务在执行。
第11 章.TIM 基本定时器
第108 页SAIUR2016
第11 章. TIM 基本定时器
11.1.课前预习
在书上找到答案。
1. 什么是TIM 基本定时器?
11.2.概述
本章所讲内容:
(1)定时器的分类
(2)定时器功能框图
(3)使用基本定时器编写程序
11.3.定时器分类
STM32F1 系列中,除了互联型的产品,共有8 个定时器,分为基本定时器,通用定时器和高级
定时器。基本定时器TIM6 和TIM7 是一个16 位的只能向上计数的定时器,只能定时,没有外部
IO。通用定时器TIM2/3/4/5 是一个16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可
以输入捕捉,每个定时器有四个外部IO。高级定时器TIM1/8 是一个16 位的可以向上/下计数的定时
器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有8 个
外部IO。更加具体的分类详情见图11-1。
第11 章.TIM 基本定时器
SAIUR201 6 第109页
图11-1 定时器分类
11.4.基本定时器功能框图讲解
基本定时器的核心是时基,不仅基本定时器有,通用定时器和高级定时器也有。学习定时器时,我
们先从简单的基本定时器学起,到了后面的通用和高级定时器的学习中,我们直接跳过时基部分的讲解
即可。基本定时器的功能框图见图11-2。
图11-2 基本定时器功能框图
时钟源
定时器时钟TIMxCLK,即内部时钟CK_INT,经APB1 预分频器后分频提供,如果APB1 预分
频系数等于1,则频率不变,否则频率乘以2,库函数中APB1 预分频的系数是2,即PCLK1=36M,
所以定时器时钟TIMxCLK=36*2=72M。
计数器时钟
定时器时钟经过PSC 预分频器之后,即CK_CNT,用来驱动计数器计数。PSC 是一个16 位的
预分频器,可以对定时器时钟TIMxCLK 进行1~65536 之间的任何一个数进行分频。具体计算方式
第11 章.TIM 基本定时器
第110 页SAIUR2016
为:CK_CNT=TIMxCLK/(PSC+1)。
计数器
计数器CNT 是一个16 位的计数器,只能往上计数,最大计数值为65535。当计数达到自动重
装载寄存器的时候产生更新事件,并清零从头开始计数。
自动重装载寄存器
自动重装载寄存器ARR 是一个16 位的寄存器,这里面装着计数器能计数的最大数值。当计数
到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
定时时间的计算
定时器的定时时间等于计数器的中断周期乘以中断的次数。计数器在CK_CNT 的驱动下,计一
个数的时间则是CK_CLK 的倒数,等于:1/(TIMxCLK/(PSC+1)),产生一次中断的时间则等于:1/
(CK_CLK * ARR)。如果在中断服务程序里面设置一个变量time,用来记录中断的次数, 那么就
可以计算出我们需要的定时时间等于: 1/CK_CLK * (ARR+1)*time。
11.5.定时器初始化结构体详解
在标准库函数头文件stm32f10x_tim.h 中对定时器外设建立了四个初始化结构体,基本定时器只用
到其中一个即TIM_TimeBaseInitTypeDef,具体的见代码清单11-1,其他三个我们在高级定时器章节讲
解。
代码清单11-1 定时器基本初始化结构体
TIM_Prescaler:定时器预分频器设置,时钟源经该预分频器才是定时器时钟,它设定TIMx_PSC 寄
存器的值。可设置范围为0 至65535,实现1 至65536 分频。
TIM_CounterMode:定时器计数方式,可是在为向上计数、向下计数以及三种中心对齐模式。基
本定时器只能是向上计数,即TIMx_CNT 只能从0 开始递增,并且无需初始化。TIM_Period:定时
器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄存器。可设置范围为0 至
65535。
TIM_ClockDivision:时钟分频,设置定时器时钟CK_INT 频率与数字滤波器采样时钟频率分频
第11 章.TIM 基本定时器
SAIUR201 6 第111页
比,基本定时器没有此功能,不用设置。
TIM_RepetitionCounter:重复计数器,属于高级控制寄存器专用寄存器位,利用它可以非常容易
控制输出PWM 的个数。这里不用设置。虽然定时器基本初始化结构体有5 个成员,但对于基本定时
器只需设置其中两个就可以,想想使用基本定时器就是简单。
11.6.基本定时器定时实验
11.6.1. 硬件设计
本实验利用基本定时器TIM6/7 定时1s,1s 时间到LED 翻转一次。基本定时器是单片机内部
的资源,没有外部IO,不需要接外部电路,现只需要一个LED 即可。
11.6.2. 软件设计
这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到, 完整的代码请参
考本章配套的工程。我们编写两个定时器驱动文件,bsp_TiMbase.h 和bsp_TiMbase.h,用来配置定时
器中断优先级和和初始化定时器。
11.6.3. 编程要点
1.开定时器时钟TIMx_CLK, x[6,7];
2.初始化时基初始化结构体;
3.使能TIMx, x[6,7] update 中断;
4.打开定时器;
5.编写中断服务程序
通用定时器和高级定时器的定时编程要点跟基本定时器差不多,只是还要再选择下计数器的计数模
式,是向上还是向下。因为基本定时器只能向上计数,且没有配置计数模式的寄存器,默认是向上。
11.6.4. 软件分析
基本定时器宏
第11 章.TIM 基本定时器
第112 页SAIUR2016
代码清单11-2 宏定义
基本定时器有TIM6 和TIM7,我们可以有选择的使用,为了提高代码的可移植性,我们把当需
要修改定时器时需要修改的代码定义成宏,默认使用的是定时器6,如果想修改成定时器7,只需要把
宏BASIC_TIM6 注释掉即可。
基本定时器配置
代码清单11-3 基本定时器模式配置
第11 章.TIM 基本定时器
SAIUR201 6 第113页
我们把定时器设置自动重装载寄存器ARR 的值为1000,设置时钟预分频器为71,则驱动计数器
的时钟:CK_CNT = CK_INT / (71+1)=1M,则计数器计数一次的时间等于:1/CK_CNT=1us,当计数器
计数到ARR 的值1000 时,产生一次中断,则中断一次的时间为:1/CK_CNT*ARR=1ms。在初始化
定时器的时候, 我们定义了一个结构体: TIM_TimeBaseInitTypeDef , TIM_TimeBaseInitTypeDef 结
构体里面有5 个成员,TIM6 和TIM7 的寄存器里面只有TIM_Prescaler 和TIM_Period,另外三个成
员基本定时器是没有的,所以使用TIM6 和TIM7 的时候只需初始化这两个成员即可, 另外三个成员
是通用定时器和高级定时器才有,具体说明如下:
其中TIM15/16/17 只存在与互联型产品中,在F1 大/中/小容量型号中没有。
定时器中断优先级配置
我们设置中断分组为0,主优先级为0,抢占优先级为3。
定时器中断服务程序
定时器中断一次的时间是1ms,我们定义一个全局变量time,每当进一次中断的时候,让time 来
记录进入中断的次数。如果我们想实现一个1s 的定时,我们只需要判断time 是否等于1000 即可,
1000 个1ms 就是1s。然后把time 清0,重新计数,以此循环往复。在中断服务程序的最后,要把
相应的中断标志位清除掉,切记。
第11 章.TIM 基本定时器
第114 页SAIUR2016
主函数
主函数做一些必须的初始化,然后在一个死循环中不断的判断time 的值,time 的值在定时器中
断改变,每加一次表示定时器过了1ms,当time 等于1000 时,1s 时间到,LED1 翻转一次,并把time
清0。
11.6.5. 下载验证
把编写好的程序下载到开发板,可以看到LED1 以1s 的频率闪烁一次。
11.7.课后练习
1.计算基本定时器一次最长定时时间,如果需要使用基本定时器产生100s 周期事件有什么办法实
现?
2.修改实验程序,在保使其每0.5s 翻转一次LED1 的同时在每10s 翻转LED2。
第12 章.TIM 高级定时器
SAIUR201 6 第115页
第12 章.TIM 高级定时器
12.1.课前预习
在书上找到答案。
1. 什么是TIM 高级定时器?
12.2.概述
本章所讲内容:
(1)高级定时器功能框图
(2)使用高级定时器编写程序
12.3.高级控制定时器
高级控制定时器(TIM1 和TIM8)和通用定时器在基本定时器的基础上引入了外部引脚,可以实现
输入捕获和输出比较功能。高级控制定时器比通用定时器增加了可编程死区互补输出、重复计数器、带
刹车(断路)功能,这些功能都是针对工业电机控制方面。这几个功能在本书不做详细的介绍,主要介绍
常用的输入捕获和输出比较功能。高级控制定时器时基单元包含一个16 位自动重装载寄存器ARR,
一个16 位的计数器CNT,可向上/下计数,一个16 位可编程预分频器PSC,预分频器时钟源有多种
可选,有内部的时钟、外部时钟。还有一个8 位的重复计数器RCR,这样最高可实现40 位的可编程
定时。STM32F103ZET6 的高级/通用定时器的IO 分配具体见表12-1。配套开发板因为IO 资源紧缺,
定时器的IO 很多已经复用它途,故下表中的IO 只有部分可用于定时器的实验。
第12 章.TIM 高级定时器
第116 页SAIUR2016
表12-1 高级控制和通用定时器通道引脚分布
12.4. 高级控制定时器功能框图
高级控制定时器功能框图包含了高级控制定时器最核心内容,掌握了功能框图,对高级控制定时器
就有一个整体的把握,在编程时思路就非常清晰,见,图中有些寄存器是带影子的,表示其有影子寄存
器。
图12-1 高级控制定时器功能框图
第12 章.TIM 高级定时器
SAIUR201 6 第117页
12.4.1. 时钟源
高级控制定时器有四个时钟源可选:
1.内部时钟源CK_INT
2.外部时钟模式1:外部输入引脚TIx(x=1,2,3,4)
3.外部时钟模式2:外部触发输入ETR
4.内部触发输入(ITRx)
5.内部时钟源(CK_INT)
内部时钟CK_INT 即来自于芯片内部,等于72M,一般情况下,我们都是使用内部时钟。当从模
式控制寄存器TIMx_SMCR 的SMS 位等于000 时,则使用内部时钟。
12.4.2. 外部时钟模式1
图12-2 外部时钟模式1 框图
①:时钟信号输入引脚
当使用外部时钟模式1 的时候,时钟信号来自于定时器的输入通道,总共有4 个,分别为
TI1/2/3/4,即TIMx_CH1/2/3/4。具体使用哪一路信号,由TIM_CCMRx 的位CCxS[1:0]配置,其中
CCMR1 控制TI1/2,CCMR2 控制TI3/4。
②:滤波器
如果来自外部的时钟信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对信号
重新采样,来达到降频或者去除高频干扰的目的,具体的由TIMx_CCMRx 的位ICxF[3:0]配置。
③:边沿检测
边沿检测的信号来自于滤波器的输出,在成为触发信号之前,需要进行边沿检测,决定是上升沿有
效还是下降沿有效,具体的由TIMx_CCER 的位CCxP 和CCxNP 配置。
第12 章.TIM 高级定时器
第118 页SAIUR2016
④:触发选择
当使用外部时钟模式1 时,触发源有两个,一个是滤波后的定时器输入1(TI1FP1)和滤波后的
定时器输入2(TI2FP2),具体的由TIMxSMCR 的位TS[2:0]配置。
⑤:从模式选择
选定了触发源信号后,最后我们需把信号连接到TRGI 引脚,让触发信号成为外部时钟模式1 的
输入,最终等于CK_PSC,然后驱动计数器CNT 计数。具体的配置TIMx_SMCR 的位SMS[2:0]为000
即可选择外部时钟模式1。
⑥:使能计数器
经过上面的5 个步骤之后,最后我们只需使能计数器开始计数,外部时钟模式1 的配置就算完成。
使能计数器由TIMx_CR1 的位CEN 配置。
12.4.3. 外部时钟模式2
图12-3 外部时钟模式2 框图
①:时钟信号输入引脚
当使用外部时钟模式2 的时候,时钟信号来自于定时器的特定输入通道TIMx_ETR,只有1 个。
②:外部触发极性
来自ETR 引脚输入的信号可以选择为上升沿或者下降沿有效,具体的由TIMx_SMCR 的位ETP
配置。
③:外部触发预分频器
由于ETRP 的信号的频率不能超过TIMx_CLK(72M)的1/4,当触发信号的频率很高的情况下,
就必须使用分频器来降频,具体的由TIMx_SMCR 的位ETPS[1:0]配置。
④:滤波器
如果ETRP 的信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对ETRP
信号重新采样,来达到降频或者去除高频干扰的目的。具体的由TIMx_SMCR 的位ETF[3:0]配置,其
中的fDTS 是由内部时钟CK_INT 分频得到,具体的由TIMx_CR1 的位CKD[1:0]配置。
第12 章.TIM 高级定时器
SAIUR201 6 第119页
⑤:从模式选择
经过滤波器滤波的信号连接到ETRF 引脚后,触发信号成为外部时钟模式2 的输入, 最终等于
CK_PSC,然后驱动计数器CNT 计数。具体的配置TIMx_SMCR 的位ECE 为1 即可选择外部时钟
模式2。
⑥:使能计数器
经过上面的5 个步骤之后,最后我们只需使能计数器开始计数,外部时钟模式2 的配置就算完成。
使能计数器由TIMx_CR1 的位CEN 配置。
12.4.4. 内部触发输入
内部触发输入是使用一个定时器作为另一个定时器的预分频器。硬件上高级控制定时器和通用定
时器在内部连接在一起,可以实现定时器同步或级联。主模式的定时器可以对从模式定时器执行复位、
启动、停止或提供时钟。
控制器
高级控制定时器控制器部分包括触发控制器、从模式控制器以及编码器接口。触发控制器用来针对
片内外设输出触发信号,比如为其它定时器提供时钟和触发DAC/ADC 转换。编码器接口专门针对编
码器计数而设计。从模式控制器可以控制计数器复位、启动、递增/递减、计数。有关控制器部分只需
熟练阅读寄存器描述即可。
时基单元
图12-4 高级定时器时基单元
高级控制定时器时基单元功能包括四个寄存器,分别是计数器寄存器(CNT)、预分频器寄存器
(PSC)、自动重载寄存器(ARR)和重复计数器寄存器(RCR)。其中重复计数器RCR 是高级定时器独有,
通用和基本定时器没有。前面三个寄存器都是16 位有效,TIMx_RCR 寄存器是8 位有效。
预分频器PSC
预分频器PSC ,有一个输入时钟CK_PSC 和一个输出时钟CK_CNT 。输入时钟CK_PSC 就是
上面时钟源的输出,输出CK_CNT 则用来驱动计数器CNT 计数。通过设置预分频器PSC 的值可以
第12 章.TIM 高级定时器
第120 页SAIUR2016
得到不同的CK_CNT,实际计算为:fCK_CNT 等于fCK_PSC/(PSC[15:0]+1),可以实现1 至65536 分
频。
计数器CNT
高级控制定时器的计数器有三种计数模式,分别为递增计数模式、递减计数模式和递增/递减(中心
对齐)计数模式。
1. 递增计数模式下,计数器从0 开始计数,每来一个CK_CNT 脉冲计数器就增加1,直到计数器
的值与自动重载寄存器ARR 值相等,然后计数器又从0 开始计数并生成计数器上溢事件,计
数器总是如此循环计数。如果禁用重复计数器,在计数器生成上溢事件就马上生成更新事件
(UEV);如果使能重复计数器,每生成一次上溢事件重复计数器内容就减1,直到重复计数器内
容为0 时才会生成更新事件。
2. 递减计数模式下,计数器从自动重载寄存器ARR 值开始计数,每来一个CK_CNT 脉冲计数器
就减1,直到计数器值为0,然后计数器又从自动重载寄存器ARR 值开始递减计数并生成计数
器下溢事件,计数器总是如此循环计数。如果禁用重复计数器,在计数器生成下溢事件就马上生
成更新事件;如果使能重复计数器,每生成一次下溢事件重复计数器内容就减1,直到重复计数
器内容为0 时才会生成更新事件。
3. 中心对齐模式下,计数器从0 开始递增计数,直到计数值等于(ARR-1)值生成计数器上溢事件,
然后从ARR 值开始递减计数直到1 生成计数器下溢事件。然后又从0 开始计数,如此循环。
每次发生计数器上溢和下溢事件都会生成更新事件。
自动重载寄存器ARR
自动重载寄存器ARR 用来存放与计数器CNT 比较的值,如果两个值相等就递减重计数器。可以
通过TIMx_CR1 寄存器的ARPE 位控制自动重载影子寄存器功能,如果ARPE 位置1,自动重载影
子寄存器有效,只有在事件更新时才把TIMx_ARR 值赋给影子寄存器。如果ARPE 位为0,则修改
TIMx_ARR 值马上有效。
重复计数器RCR
在基本/通用定时器发生上/下溢事件时直接就生成更新事件,但对于高级控制定时器却不是这样,
高级控制定时器在硬件结构上多出了重复计数器,在定时器发生上溢或下溢事件是递减重复计数器的
值,只有当重复计数器为0 时才会生成更新事件。在发生N+1 个上溢或下溢事件(N 为RCR 的值)
时产生更新事件。
第12 章.TIM 高级定时器
SAIUR201 6 第121页
12.4.5. 输入捕获
图12-5 输入捕获功能框图
输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常用的有测量输入信号的脉宽
和测量PWM 输入信号的频率和占空比这两种。输入捕获的大概的原理就是,当捕获到信号的跳变沿
的时候,把计数器CNT 的值锁存到捕获寄存器CCR 中,把前后两次捕获到的CCR 寄存器中的值相
减,就可以算出脉宽或者频率。如果捕获的脉宽的时间长度超过你的捕获定时器的周期,就会发生溢出,
这个我们需要做额外的处理。
①输入通道
需要被测量的信号从定时器的外部引脚TIMx_CH1/2/3/4 进入,通常叫TI1/2/3/4,在后面的捕获
讲解中对于要被测量的信号我们都以TIx 为标准叫法。
②输入滤波器和边沿检测器
当输入的信号存在高频干扰的时候,我们需要对输入信号进行滤波,即进行重新采样, 根据采样
定律,采样的频率必须大于等于两倍的输入信号。比如输入的信号为1M,又存在高频的信号干扰,
那么此时就很有必要进行滤波,我们可以设置采样频率为2M,这样可以在保证采样到有效信号的基
础上把高于2M 的高频干扰信号过滤掉。滤波器的配置由CR1 寄存器的位CKD[1:0]和CCMR1/2 的
位ICxF[3:0]控制。从ICxF 位的描述可知,采样频率fSAMPLE 可以由fCK_INT 和fDTS 分频后的
时钟提供,其中是fCK_INT 内部时钟,fDTS 是fCK_INT 经过分频后得到的频率,分频因子由
CKD[1:0]决定,可以是不分频,2 分频或者是4 分频。边沿检测器用来设置信号在捕获的时候是什
么边沿有效,可以是上升沿,下降沿,或者是双边沿,具体的由CCER 寄存器的位CCxP 和CCxNP
决定。
③捕获通道
第12 章.TIM 高级定时器
第122 页SAIUR2016
捕获通道就是图中的IC1/2/3/4,每个捕获通道都有相对应的捕获寄存器CCR1/2/3/4,当发生捕获
的时候,计数器CNT 的值就会被锁存到捕获寄存器中。这里我们要搞清楚输入通道和捕获通道的区
别,输入通道是用来输入信号的,捕获通道是用来捕获输入信号的通道,一个输入通道的信号可以同时
输入给两个捕获通道。比如输入通道TI1 的信号经过滤波边沿检测器之后的TI1FP1 和TI1FP2 可以
进入到捕获通道IC1 和IC2,其实这就是我们后面要讲的PWM 输入捕获,只有一路输入信号(TI1)
却占用了两个捕获通道(IC1 和IC2)。当只需要测量输入信号的脉宽时候,用一个捕获通道即可。输
入通道和捕获通道的映射关系具体由寄存器CCMRx 的位CCxS[1:0]配置。
④预分频器
ICx 的输出信号会经过一个预分频器,用于决定发生多少个事件时进行一次捕获。具体的由寄存
器CCMRx 的位ICxPSC 配置,如果希望捕获信号的每一个边沿,则不分频。
⑤捕获寄存器
经过预分频器的信号ICxPS 是最终被捕获的信号,当发生捕获时(第一次),计数器CNT 的值
会被锁存到捕获寄存器CCR 中,还会产生CCxI 中断,相应的中断位CCxIF(在SR 寄存器中)会
被置位,通过软件或者读取CCR 中的值可以将CCxIF 清0。如果发生第二次捕获(即重复捕获:CCR
寄存器中已捕获到计数器值且CCxIF 标志已置1),则捕获溢出标志位CCxOF(在SR 寄存器中)
会被置位,CCxOF 只能通过软件清零。
12.4.6. 输出比较
图12-6 输出比较功能框图
第12 章.TIM 高级定时器
SAIUR201 6 第123页
输出比较就是通过定时器的外部引脚对外输出控制信号, 有冻结、将通道X(x=1,2,3,4)设置
为匹配时输出有效电平、将通道X 设置为匹配时输出无效电平、翻转、强制变为无效电平、强制变为
有效电平、PWM1 和PWM2 这八种模式,具体使用哪种模式由寄存器CCMRx 的位OCxM[2:0]配置。
其中PWM 模式是输出比较中的特例,使用的也最多。
①比较寄存器
当计数器CNT 的值跟比较寄存器CCR 的值相等的时候,输出参考信号OCxREF 的信号的极
性就会改变,其中OCxREF=1(高电平)称之为有效电平,OCxREF=0(低电平) 称之为无效电平,
并且会产生比较中断CCxI,相应的标志位CCxIF(SR 寄存器中)会置位。然后OCxREF 再经过一
系列的控制之后就成为真正的输出信号OCx/OCxN。
②死区发生器
在生成的参考波形OCxREF 的基础上,可以插入死区时间,用于生成两路互补的输出信号OCx
和OCxN,死区时间的大小具体由BDTR 寄存器的位DTG[7:0]配置。死区时间的大小必须根据与输
出信号相连接的器件及其特性来调整。下面我们简单举例说明下带死区的PWM 信号的应用,我们以
一个板桥驱动电路为例。
图12-7 半桥驱动电路
在这个半桥驱动电路中,Q1 导通,Q2 截止,此时我想让Q1 截止Q2 导通,肯定是要先让Q1 截
止一段时间之后,再等一段时间才让Q2 导通,那么这段等待的时间就称为死区时间,因为Q1 关闭
需要时间(由MOS 管的工艺决定)。如果Q1 关闭之后,马上打开Q2,那么此时一段时间内相当
于Q1 和Q2 都导通了,这样电路会短路。图12-8 是针对上面的半桥驱动电路而画的带死区插入的
PWM 信号,图中的死区时间要根据MOS 管的工艺来调节。
第12 章.TIM 高级定时器
第124 页SAIUR2016
图12-8 带死区插入的互补输出
图12-9 输出比较(通道1~3)的输出控制框图
③输出控制
在输出比较的输出控制中,参考信号OCxREF 在经过死区发生器之后会产生两路带死区的互补信
号OCx_DT 和OCxN_DT(通道1~3 才有互补信号,通道4 没有,其余跟通道1~3 一样),这两路
带死区的互补信号然后就进入输出控制电路,如果没有加入死区控制, 那么进入输出控制电路的信号
就直接是OCxREF。进入输出控制电路的信号会被分成两路,一路是原始信号,一路是被反向的信号,
具体的由寄存器CCER 的位CCxP 和CCxNP 控制。经过极性选择的信号是否由OCx 引脚输出到外
部引脚CHx/CHxN 则由寄存器CCER 的位CxE/CxNE 配置。如果加入了断路(刹车)功能,则断路
和死区寄存器BDTR 的MOE、OSSI 和OSSR 这三个位会共同影响输出的信号。
④输出引脚
输出比较的输出信号最终是通过定时器的外部IO 来输出的,分别为CH1/2/3/4,其中前面三个
通道还有互补的输出通道CH1/2/3N。更加详细的IO 说明还请查阅相关的数据手册。
第12 章.TIM 高级定时器
SAIUR201 6 第125页
12.4.7. 断路功能
断路功能就是电机控制的刹车功能,使能断路功能时,根据相关控制位状态修改输出信号电平。
在任何情况下,OCx 和OCxN 输出都不能同时为有效电平,这关系到电机控制常用的H 桥电路结构
原因。断路源可以是时钟故障事件,由内部复位时钟控制器中的时钟安全系统(CSS)生成,也可以是外
部断路输入IO,两者是或运算关系。系统复位启动都默认关闭断路功能,将断路和死区寄存器
(TIMx_BDTR)的BKE 为置1,使能断路功能。可通过TIMx_BDTR 寄存器的BKP 位设置设置断路
输入引脚的有效电平, 设置为1 时输入BRK 为高电平有效,否则低电平有效。
发送断路时,将产生以下效果:
1. TIMx_BDTR 寄存器中主输出模式使能(MOE)位被清零,输出处于无效、空闲或复位状态;
2. 根据相关控制位状态控制输出通道引脚电平;当使能通道互补输出时,会根据情况自动控制输出
通道电平;
3. 将TIMx_SR 寄存器中的BIF 位置1,并可产生中断和DMA 传输请求。
4. 如果TIMx_BDTR 寄存器中的自动输出使能(AOE)位置1,则MOE 位会在发生下一个UEV
事件时自动再次置1。
12.5.输入捕获应用
输入捕获一般应用在两个方面,一个方面是脉冲跳变沿时间测量,另一方面是PWM 输入测量。
图12-10 脉宽/频率测量示意图
第12 章.TIM 高级定时器
第126 页SAIUR2016
12.5.1. 测量频率
当捕获通道TIx 上出现上升沿时,发生第一次捕获,计数器CNT 的值会被锁存到捕获寄存器
CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标志变量来记录),
并把捕获寄存器中的值读取到value1 中。当出现第二次上升沿时,发生第二次捕获,计数器CNT 的
值会再次被锁存到捕获寄存器CCR 中,并再次进入捕获中断,在捕获中断中,把捕获寄存器的值读取
到value3 中,并清除捕获记录标志。利用value3 和value1 的差值我们就可以算出信号的周期(频率)。
12.5.2. 测量脉宽
当捕获通道TIx 上出现上升沿时,发生第一次捕获,计数器CNT 的值会被锁存到捕获寄存器
CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标志变量来记录),
并把捕获寄存器中的值读取到value1 中。然后把捕获边沿改变为下降沿捕获,目的是捕获后面的下降
沿。当下降沿到来的时候,发生第二次捕获,计数器CNT 的值会再次被锁存到捕获寄存器CCR 中,
并再次进入捕获中断,在捕获中断中,把捕获寄存器的值读取到value3 中,并清除捕获记录标志。然
后把捕获边沿设置为上升沿捕获。
在测量脉宽过程中需要来回的切换捕获边沿的极性,如果测量的脉宽时间比较长,定时器就会发生
溢出,溢出的时候会产生更新中断,我们可以在中断里面对溢出进行记录处理。
12.6. PWM 输入模式
测量脉宽和频率还有一个更简便的方法就是使用PWM 输入模式,该模式是输入捕获的特例,只
能使用通道1 和通道2,通道3 和通道4 使用不了。与上面那种只使用一个捕获寄存器测量脉宽和
频率的方法相比,PWM 输入模式需要占用两个捕获寄存器。
图12-11 输入通道和捕获通道的关系映射图
第12 章.TIM 高级定时器
SAIUR201 6 第127页
当使用PWM 输入模式的时候,因为一个输入通道(TIx)会占用两个捕获通道(ICx),所以一个定时
器在使用PWM 输入的时候最多只能使用两个输入通道(TIx)。我们以输入通道TI1 工作在PWM 输
入模式为例来讲解下具体的工作原理,其他通道以此类推即可。
PWM 信号由输入通道TI1 进入,因为是PWM 输入模式的缘故,信号会被分为两路, 一路是
TI1FP1,另外一路是TI2FP2。其中一路是周期,另一路是占空比,具体哪一路信号对应周期还是占
空比,得从程序上设置哪一路信号作为触发输入,作为触发输入的哪一路信号对应的就是周期,另一
路就是对应占空比。作为触发输入的那一路信号还需要设置极性,是上升沿还是下降沿捕获,一旦设
置好触发输入的极性,另外一路硬件就会自动配置为相反的极性捕获,无需软件配置。一句话概括就
是:选定输入通道,确定触发信号,然后设置触发信号的极性即可,因为是PWM 输入的缘故,另一
路信号则由硬件配置,无需软件配置。当使用PWM 输入模式的时候必须将从模式控制器配置为复位
模式(配置寄存器SMCR 的位SMS[2:0]来实现),即当我们启动触发信号开始进行捕获的时候,同时
把计数器CNT 复位清零。下面我们以一个更加具体的时序图来分析下PWM 输入模式。
图12-12 PWM 输入模式时序
PWM 信号由输入通道TI1 进入,配置TI1FP1 为触发信号,上升沿捕获。当上升沿的时候IC1 和
IC2 同时捕获,计数器CNT 清零,到了下降沿的时候,IC2 捕获,此时计数器CNT 的值被锁存到捕
获寄存器CCR2 中,到了下一个上升沿的时候,IC1 捕获,计数器CNT 的值被锁存到捕获寄存器
CCR1 中。其中CCR2+1 测量的是脉宽,CCR1+1 测量的是周期。这里要注意的是CCR2 和CCR1
的值在计算占空比和频率的时候都必须加1,因为计数器是从0 开始计数的。从软件上来说,用PWM
输入模式测量脉宽和周期更容易,付出的代价是需要占用两个捕获寄存器。
第12 章.TIM 高级定时器
第128 页SAIUR2016
12.7.输出比较应用
输出比较模式总共有8 种,具体的由寄存器CCMRx 的位OCxM[2:0]配置。我们这里只讲解最
常用的PWM 模式,其他几种模式具体的看数据手册即可。
12.7.1. PWM 输出模式
PWM 输出就是对外输出脉宽(即占空比)可调的方波信号,信号频率由自动重装寄存器ARR 的
值决定,占空比由比较寄存器CCR 的值决定。PWM 模式分为两种,PWM1 和PWM2,总得来说是
差不多,就看你怎么用而已,具体的区别见表格12-1。
表格12-1 PWM1 与PWM2 模式的区别
下面我们以PWM1 模式来讲解,以计数器CNT 计数的方向不同还分为边沿对齐模式和中心对齐
模式。PWM 信号主要都是用来控制电机,一般的电机控制用的都是边沿对齐模式,FOC 电机一般用
中心对齐模式。我们这里只分析这两种模式在信号感官上(即信号波形)的区别,具体在电机控制中的
区别不做讨论,到了你真正需要使用的时候就会知道了。
12.7.2. PWM 边沿对齐模式
在递增计数模式下,计数器从0 计数到自动重载值( TIMx_ARR 寄存器的内容),然后重新从0
开始计数并生成计数器上溢事件
图12-13 PWM1 模式的边沿对齐波形
在边沿对齐模式下,计数器CNT 只工作在一种模式,递增或者递减模式。这里我们以CNT 工作
在递增模式为例,在中,ARR=8,CCR=4,CNT 从0 开始计数,当CNT<CCR 的值时, OCxREF 为
有效的高电平, 于此同时, 比较中断寄存器CCxIF 置位。当CCR=<CNT<=ARR 时,OCxREF 为
第12 章.TIM 高级定时器
SAIUR201 6 第129页
无效的低电平。然后CNT 又从0 开始计数并生成计数器上溢事件,以此循环往复。
12.7.3. PWM 中心对齐模式
图12-14 PWM1 模式的中心对齐波形
在中心对齐模式下,计数器CNT 是工作做递增/递减模式下。开始的时候,计数器CNT 从0 开
始计数到自动重载值减1(ARR-1),生成计数器上溢事件;然后从自动重载值开始向下计数到1 并生
成计数器下溢事件。之后从0 开始重新计数。图12-14 是PWM1 模式的中心对齐波形,ARR=8,
CCR=4。第一阶段计数器CNT 工作在递增模式下,从0 开始计数,当CNT<CCR 的值时,OCxREF
为有效的高电平,当CCR=<CNT<<ARR 时,OCxREF 为无效的低电平。第二阶段计数器CNT 工作
在递减模式,从ARR 的值开始递减,当CNT>CCR 时,OCxREF 为无效的低电平,当CCR=>CNT>=1
时,OCxREF 为有效的高电平。
在波形图上我们把波形分为两个阶段,第一个阶段是计数器CNT 工作在递增模式的波形,这个
阶段我们又分为①和②两个阶段,第二个阶段是计数器CNT 工作在递减模式的波形,这个阶段我们
又分为③和④两个阶段。要说中心对齐模式下的波形有什么特征的话, 那就是①和③阶段的时间相等,
②和④阶段的时间相等。中心对齐模式又分为中心对齐模式1/2/3 三种,具体由寄存器CR1 位
CMS[1:0]配置。具体的区别就是比较中断中断标志位CCxIF 在何时置1:中心模式1 在CNT 递减
计数的时候置1,中心对齐模式2 在CNT 递增计数时置1,中心模式3 在CNT 递增和递减计数时
都置1。
12.8.定时器初始化结构体详解
在标准库函数头文件stm32f10x_tim.h 中对定时器外设建立了四个初始化结构体,分别为时基
初始化结构体TIM_TimeBaseInitTypeDef 、输出比较初始化结构体
TIM_OCInitTypeDef 、输入捕获初始化结构体TIM_ICInitTypeDef 和断路和死区初始化结构体
TIM_BDTRInitTypeDef , 高级控制定时器可以用到所有初始化结构体, 通用定时器不能使用
TIM_BDTRInitTypeDef 结构体,基本定时器只能使用时基结构体。接下来我们具体讲解下这四个结构
第12 章.TIM 高级定时器
第130 页SAIUR2016
体。
12.8.1. TIM_TimeBaseInitTypeDef
时基结构体TIM_TimeBaseInitTypeDef 用于定时器基础参数设置,与TIM_TimeBaseInit 函数配合
使用完成配置。
代码清单12-1 定时器基本初始化结构体
TIM_Prescaler:定时器预分频器设置,时钟源经该预分频器才是定时器计数时钟CK_CNT,它设定
PSC 寄存器的值。计算公式为:计数器时钟频率(fCK_CNT) 等于fCK_PSC / (PSC[15:0] + 1),可实现
1 至65536 分频。
TIM_CounterMode:定时器计数方式,可设置为向上计数、向下计数以及中心对齐。高级控制定时器
允许选择任意一种。
TIM_Period:定时器周期,实际就是设定自动重载寄存器ARR 的值,ARR 为要装载到实际自动重
载寄存器(即影子寄存器)的值,可设置范围为0 至65535。
TIM_ClockDivision:时钟分频,设置定时器时钟CK_INT 频率与死区发生器以及数字滤波器采样时
钟频率分频比。可以选择1、2、4 分频。
TIM_RepetitionCounter:重复计数器,只有8 位,只存在于高级定时器。
12.8.2. TIM_OCInitTypeDef
输出比较结构体TIM_OCInitTypeDef 用于输出比较模式,与TIM_OCxInit 函数配合使用完成指
定定时器输出通道初始化配置。高级控制定时器有四个定时器通道,使用时都必须单独设置。
代码清单12-2 定时器比较输出初始化结构体
TIM_OCMode:比较输出模式选择,总共有八种,常用的为PWM1/PWM2。它设定CCMRx 寄存器
第12 章.TIM 高级定时器
SAIUR201 6 第131页
OCxM[2:0]位的值。
TIM_OutputState:比较输出使能,决定最终的输出比较信号OCx 是否通过外部引脚输出。它设定
TIMx_CCER 寄存器CCxE/CCxNE 位的值。
TIM_OutputNState:比较互补输出使能,决定OCx 的互补信号OCxN 是否通过外部引脚输出。它设
定CCER 寄存器CCxNE 位的值。
TIM_Pulse:比较输出脉冲宽度,实际设定比较寄存器CCR 的值,决定脉冲宽度。可设置范围为0 至
65535。
TIM_OCPolarity:比较输出极性,可选OCx 为高电平有效或低电平有效。它决定着定时器通道有效
电平。它设定CCER 寄存器的CCxP 位的值。
TIM_OCNPolarity : 比较互补输出极性, 可选OCxN 为高电平有效或低电平有效。它设定
TIMx_CCER 寄存器的CCxNP 位的值。
TIM_OCIdleState:空闲状态时通道输出电平设置,可选输出1 或输出0,即在空闲状态(BDTR_MOE
位为0)时,经过死区时间后定时器通道输出高电平或低电平。它设定CR2 寄存器的OISx 位的值。
TIM_OCNIdleState:空闲状态时互补通道输出电平设置,可选输出1 或输出0,即在空闲状态
(BDTR_MOE 位为0)时,经过死区时间后定时器互补通道输出高电平或低电平,设定值必须与
TIM_OCIdleState 相反。它设定是CR2 寄存器的OISxN 位的值。
12.8.3. TIM_ICInitTypeDef
输入捕获结构体TIM_ICInitTypeDef 用于输入捕获模式,与TIM_ICInit 函数配合使用完成定时器
输入通道初始化配置。如果使用PWM 输入模式需要与TIM_PWMIConfig 函数配合使用完成定时器
输入通道初始化配置。
代码清单12-3 定时器输入捕获初始化结构体
TIM_Channel:捕获通道ICx 选择,可选TIM_Channel_1、TIM_Channel_2、TIM_Channel_3 或
TIM_Channel_4 四个通道。它设定CCMRx 寄存器CCxS 位的值。
TIM_ICPolarity:输入捕获边沿触发选择,可选上升沿触发、下降沿触发或边沿跳变触发。它设定
CCER 寄存器CCxP 位和CCxNP 位的值。
TIM_ICSelection : 输入通道选择, 捕获通道ICx 的信号可来自三个输入通道, 分别为
第12 章.TIM 高级定时器
第132 页SAIUR2016
TIM_ICSelection_DirectTI 、TIM_ICSelection_IndirectTI 或TIM_ICSelection_TRC , 具体的区别见图
33-15。如果是普通的输入捕获,4 个通道都可以使用,如果是PWM 输入则只能使用通道1 和通道
2。它设定CCRMx 寄存器的CCxS[1:0]位的值。
图12-15 输入通道与捕获通道IC 的映射图
TIM_ICPrescaler:输入捕获通道预分频器,可设置1、2、4、8 分频,它设定CCMRx 寄存器的
ICxPSC[1:0]位的值。如果需要捕获输入信号的每个有效边沿,则设置1 分频即可。IM_ICFilter:输
入捕获滤波器设置,可选设置0x0 至0x0F。它设定CCMRx 寄存器ICxF[3:0]位的值。一般我们不使
用滤波器,即设置为0。
12.8.4. TIM_BDTRInitTypeDef
断路和死区结构体TIM_BDTRInitTypeDef 用于断路和死区参数的设置,属于高级定时器专用,用
于配置断路时通道输出状态,以及死区时间。它与TIM_BDTRConfig 函数配置使用完成参数配置。这
个结构体的成员只对应BDTR 这个寄存器,有关成员的具体使用配置请参考手册BDTR 寄存器的详
细描述。
代码清单12-4 断路和死区初始化结构体
TIM_OSSRState:运行模式下的关闭状态选择,它设定BDTR 寄存器OSSR 位的值。
TIM_OSSIState:空闲模式下的关闭状态选择,它设定BDTR 寄存器OSSI 位的值。
TIM_LOCKLevel:锁定级别配置, BDTR 寄存器LOCK[1:0]位的值。
TIM_DeadTime:配置死区发生器,定义死区持续时间,可选设置范围为0x0 至0xFF。它设定BDTR
寄存器DTG[7:0]位的值。
第12 章.TIM 高级定时器
SAIUR201 6 第133页
TIM_Break:断路输入功能选择,可选使能或禁止。它设定BDTR 寄存器BKE 位的值。
TIM_BreakPolarity:断路输入通道BRK 极性选择,可选高电平有效或低电平有效。它设定BDTR 寄
存器BKP 位的值。
TIM_AutomaticOutput:自动输出使能,可选使能或禁止,它设定BDTR 寄存器AOE 位的值。
12.9. PWM 互补输出实验
输出比较模式比较多,这里我们以PWM 输出为例讲解,并通过示波器来观察波形。实验中不仅
在主输出通道输出波形,还在互补通道输出与主通道互补的的波形,并且添加了断路和死区功能。
12.9.1. 硬件设计
根据开发板引脚使用情况,并且参考表12-1 中定时器引脚信息,使用高级定时器TIM1 的通道1
及其互补通道作为本实验的波形输出通道,对应选择PA8 和PB13 引脚。将示波器的两个输入通道分
别与PA8 和PB13 引脚连接,用于观察波形,还有注意共地。为增加