1、原理学习。学习和理解STM32F103系列芯片的地址映射和寄存器映射原理;了解GPIO端口的初始化设置三步骤(时钟配置、输入输出模式设置、最大速率设置)。
一、地址映射和寄存器映射
1.什么是寄存器
寄存器的功能是存储二进制代码,它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码,故存放n位二进制代码的寄存器,需用n个触发器来构成。
按照功能的不同,可将寄存器分为基本寄存器和移位寄存器两大类。基本寄存器只能并行送入数据,也只能并行输出。移位寄存器中的数据可以在移位脉冲作用下依次逐位右移或左移,数据既可以并行输入、并行输出,也可以串行输入、串行输出,还可以并行输入、串行输出,或串行输入、并行输出。
2.地址映射和寄存器映射原理
地址映射原理:为了保证CPU执行指令时可正确访问存储单元,需将用户程序中的逻辑地址转换为运行时由机器直接寻址的物理地址,这一过程称为地址映射。
寄存器映射原理:在存储器的区域单元中,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到每个单元的起始地址,然后通过 C 语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
二、GPIO端口初始化设置
1.时钟
1.1概述
时钟是单片机的脉搏,是单片机的驱动源,使用任何一个外设都必须打开相应的时钟。这样的好处是,如果不使用一个外设的时候,就把它的时钟关掉,从而可以降低系统的功耗,达到节能,实现低功耗的效果。每个时钟tick,系统都会处理一步数据,这样才能让工作不出现紊乱。
1.2原理
首先,任何外设都需要时钟,51单片机,STM32,430等等,因为寄存器是由D触发器组成的,往触发器里面写东西,前提条件是有时钟输入。
51单片机不需要配置时钟,是因为一个时钟开了之后所有的功能都可以用了,而这个时钟是默认开启的,比如有一个水库,水库有很多个门,这些门默认是开启的,所以每个门都会出水,我们需要哪个门的水的时候可以直接用,但是也存在一个问题,其他没用到的门也在出水,即也在耗能。这里水库可以认为是能源,门可以认为是每个外设的使用状态,时钟可以认为是门的开关。
STM32之所以是低功耗,他将所有的门都默认设置为disable,在你需要用哪个门的时候,开哪个门就可以,也就是说用到什么外设,只要打开对应外设的时钟就可以,其他的没用到的可以还是disable,这样耗能就会减少。
在51单片机中一个时钟把所有的都包了,而stm32的时钟是有分工的,并且每类时钟的频率不一样,因为没必要所有的时钟都是最高频率,只要够用就行,好比一个门出来水流大小,我只要洗脸,但是出来的是和洪水一样涌出来的水,那就gg了,消耗能源也多,所以不同的时钟也会有频率差别,或者在配置的时候可以配置时钟分频。
stm32需要配置时钟,就可以把不需要那些功能的功耗去掉。当你想关闭某个IO的时候,关闭它相对应的时钟使能就是了,还有在STM32中,有外部和内部时钟之分。
2.输入输出模式设置
GPIO有四种输入模式和四种输出模式,共八种模式。
输入模式:
浮空输入(GPIO_Mode_IN_FLOATING):什么电阻都不接,由施密特触发器输入,输入阻抗大,为一个不确定的值。
上拉输入(GPIO_Mode_IPU ):输入数字信号1
下拉输入(GPIO_Mode_IPD):输入数字信号0
模拟输入(GPIO_Mode_AIN):用于ADC外设的输入
输出模式;
开漏输出(GPIO_Mode_Out_OD):输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行. 适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
推挽输出(GPIO_Mode_Out_PP):推挽电路是两个参数相同的三极管或 MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。
复用开漏输出(GPIO_Mode_AF_OD)
复用推挽输出(GPIO_Mode_AF_PP)
输入:
浮空输入:此时的VDD和VSS 所在的路径的两个开关都是断开的状态,此时IO口的电平状态是不确定的,由外部输入决定。
上拉输入:此时IO口默认是高电平
下拉输入:此时IO口默认是低电平
模拟输入:此时的信号不经过TTL施密特触发器,直接进入ADC模块,CPU不能直接读取寄存器上的引脚状态。
输出:
开漏输出:此时只有N-MOS工作,而P-MOS不工作。当我们控制输出为0时,N-MOS管导通,使其IO口输出低电平。当我们控制输出为1时,此时N-MOS截止。输出指令就不会起到作用而是由I/O端口外部的上拉或者下拉决定,如果没有上拉或者下拉 IO口就处于悬空状态。
推挽输出:此时,N-MOS管和P-MOS管都工作,如果控制输出为0,则P-MOS管截止,N-MOS管导通,若控制输出为1,则P-MOS管导通N-MOS管截止。
复用开漏输出:即在开漏输出的基础上向复用功能输出端输出。
复用推挽输出:即在推挽输出的基础上向复用功能输出端输出。
3.最大速率设置
当STM32的GPIO端口设置为输出形式时,有三种速度能够挑选:2MHz、10MHz和50MHz,这个速度是指I/O口驱动电路的速度,是用来挑选不同的输出驱动模块,到达最佳的噪声控制和降低功耗的意图。
高频的驱动电路,噪声也高,当你不需求高的输出频率时,请选用低频驱动电路,这样十分有利于进步体系的EMI功能。
当然假设你要输出较高频率的信号,但却选用了较低频率的驱动模块,你很可能会得到失真的输出信号。
实际上芯片内部在I/O口的输出部分组织了多个响应速度不同的输出驱动电路,用户能够依据自己的需求挑选适宜的驱动电路。
2、假设你手中已有 STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿蓝LED,并搭建了电路,分别GPIOA-5、GPIOB-9、GPIOC-14 这3个引脚上控制LED灯(最高时钟2Mhz),轮流闪烁,间隔时长1秒。
1)写出程序设计思路,包括GPIOx端口的各寄存器地址和详细参数;
新建工程Light2文件,工程名为light,因为之后实验采用C8T6板,因此这里选择STM32F103C8\n之后弹出的添加库文件窗口Manage Run-Time Environment,在这个界面,我们可以添加自己需要的组件,从而方便构建开发环境,不过这里我们不做介绍。选择Cancel即可。
1、选择STM32F103C8开发板
2、创建项目出现弹窗,不勾选setgep,只勾选core项
3、添加驱动文件
到这里,我们还只是建了一个框架,还需要添加启动代码,以及.c 文件等。
ST 公司提供了 3 个启动文件给我们,分别用于不同容量的 STM32 芯片,这三个文件是:
startup_stm32f10x_ld.s,startup_stm32f10x_md.s,startup_stm32f10x_hd.s
其中,ld.s 适用于小容量 产品;md.s 适用于中等容量产品;hd 适用于大容量产品;
这里的容量是指 FLASH 的大小.判断方法如下:
小容量:FLASH≤32K
中容量:64K≤FLASH≤128K
大容量:256K≤FLASH
三、使用寄存器点亮LED灯
1.1 时钟配置
打开之前建立的工程模板
注意项目结构,使用的引脚是PA5,PB9,PC14,即GPIOA,B,C三个端口。该三个端口都属于APB2总线
1、找到时钟使能寄存器映射基地址
2、找到端口偏移地址以及对应端口所在位置
3、使能对应端口时钟
2.2输入输出模式和输出速率设置
本次实验采用通用推挽输出模式,最高输出时钟频率2Mhz。分别用到A5、B9、C14三个引脚。其中A5、B9属于端口配置低寄存器偏移地址为0x00,C14属于端口配置高寄存器偏移地址为0x04。
1、找到GPIOx端口基地址
2、配置对应引脚寄存器,基地址+偏移量
//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRL *((unsigned volatile int*)0x40010C00)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
3、设置输出模式为推挽输出,输出速度为2Mhz
GPIOA_CRL&=0xFFF0FFFF; //设置位 清零
GPIOA_CRL|=0x00020000; //PA5推挽输出,把第19、18、17、16位变为0010
GPIOB_CRL&=0xFF0FFFFF; //设置位 清零
GPIOB_CRL|=0x00200000; //PB9推挽输出,把第23、22、21、20变为0010
GPIOC_CRH&=0xFF0FFFFF; //设置位 清零
GPIOC_CRH|=0x00200000; //PC14推挽输出,把第23、22、21、20变为0010
2、代码实现
2.1流水灯原理
本次实验采用三个灯实现,亮灯状态用1表示,灭灯状态用0表示。
初始状态为0 0 0
状态一为1 0 0
状态二为0 1 0
状态三为0 0 1
状态三结束后继续进入状态一,一直循环达到流水灯效果。
2)用C语言 寄存器方式编程实现。
#include "stm32f10x.h"
//----------------APB2使能时钟寄存器 ---------------------
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
#define GPIOA_ODR *((unsigned volatile int*)0x4001080C)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRL *((unsigned volatile int*)0x40010C00)
#define GPIOB_ODR *((unsigned volatile int*)0x40010C0C)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
#define GPIOC_ODR *((unsigned volatile int*)0x4001100C)
//延时函数
void Delay()
{
u32 i=0;
for(;i<5000000;i++);
}
int main(void)
{
RCC_APB2ENR|=1<<2|1<<3|1<<4; //APB2-GPIOA、GPIOB、GPIOC外设时钟使能
GPIOA_CRL&=0xFFF0FFFF; //设置位 清零
GPIOA_CRL|=0x00020000; //PA5推挽输出
GPIOA_ODR&=~(1<<5); //设置初始灯为灭
GPIOB_CRL&=0xFF0FFFFF; //设置位 清零
GPIOB_CRL|=0x00200000; //PB9推挽输出
GPIOB_ODR&=~(1<<9); //设置初始灯为灭
GPIOC_CRH&=0xF0FFFFFF; //设置位 清零
GPIOC_CRH|=0x02000000; //PC14推挽输出
GPIOC_ODR&=~(1<<14); //设置初始灯为灭
while(1){
//A灯
GPIOA_ODR|=1<<5; //PA5高电平
Delay();
GPIOA_ODR&=~(1<<5); //PA5低电平,因为是置0,所以用按位与
//B灯
GPIOB_ODR|=1<<9; //PB9高电平
Delay();
GPIOB_ODR&=~(1<<9); //PB9低电平,因为是置0,所以用按位与
//C灯
GPIOC_ODR|=1<<14; //PC14高电平
Delay();
GPIOC_ODR&=~(1<<14); //PC14低电平,因为是置0,所以用按位与
}
}
3.安装 stm32CubeMX,用cubemx完成初始化过程,采用HAL库编程实现。
安装CubeMx一共需要三个:
JRE (Java Runtime Environment) :Java运行环境 运行JAVA程序所必须的环境的集合
STM32CubeMX
HAL库 :STM32HAL固件库,ST官方推出的另一套库
1.安装JRE
2.安装STM32CubeMx
3.安装HAL库
二、实验运行
1.新建工程
打开STM32CubeMx,点击ACCESS TO MCU SELECTOR。
在Part Number中搜索自己的所用芯片STM32F103C8
,点击选择,然后点击Start Project
.
2.引脚设置
左侧为引脚预览,右侧为系统预览引脚预览
:可以查看引脚配置了什么功能,和各个引脚的位置;任意点击一个引脚即可设置该引脚的各种功能。绿色表示配置成功系统预览
:可以查看配置的各种外设和GPIO的状态。
将我们需要的led流水灯的A5,B9,C14点击选择GPIO_OUTput。
3.外设设置
- 点击System Core,点击SYS,在Debug下选择
Serial Wire
。
- 点击Rcc,将HSE设置为
Crystal/Ceramic Resonator
。
配置GPIO
GPIO output level :Low将该串口初始化为低电平,当然也可以选择High,就是将初始电平拉高,这里按我们电路的接法,所以应该拉低;
GPIO mode:Outpull Pushpull的意思是选择输出模式为推挽输出模式,还有其他几种输出模式;
GPIO Pull-up/Pull-down :No pull-up and no pull-down的意思是设置为输出没有上拉和下拉输出,其实安逻辑来说我们是需要给我们的LED给一个下拉电阻才能点亮的,但是在实际的运用中为了简便发现这样也可以点亮,并且因为电流大,所以LED亮度很高;
Maximum output speed :Low配置的是输出速度,这里配置输出速度为低,目前碰到的大多数情况都选择低就可以
4.时钟配置
APB2总线的时钟由hse控制。点击Clock Configuration,在这个界面得把PLLCL选上,同时把8MHz改成72,并回车,会出现下列提示框,点击ok
5.工程配置
点开Project Manager,填写文件名,然后选择路径,最后将IDE改成MDK-ARM,后面改成V5
4.在Keil下用软件仿真运行上面代码,并用虚拟逻辑分析仪观察 对应管脚上的输出波形(高低电平转换),看是否是1秒的周期。