第四周--用寄存器&amp:HAL库完成LED流水灯的程序


一.原理学习

1.STM332F103系列芯片的地址映射和寄存器映射

1.什么是寄存器

(1).基本含义

寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的时序逻辑电路,但这种时序逻辑电路只包含存储电路。寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器能存储1位二进制数,所以由N个锁存器或触发器可以构成N位寄存器。寄存器是中央处理器内的组成部分。寄存器是有限存储容量的高速存储部件,它们可用来暂存指令、数据和位址。

(2).基本概念

寄存器最起码具备以下4种功能。
①清除数码:将寄存器里的原有数码清除。
②接收数码:在接收脉冲作用下,将外输入数码存入寄存器中。
③存储数码:在没有新的写入脉冲来之前,寄存器能保存原有数码不变。
④输出数码:在输出脉冲作用下,才通过电路输出数码。
仅具有以上功能的寄存器称为数码寄存器;有的寄存器还具有移位功能,称为移位寄存器。

(3).通俗的讲

寄存器就是你的口袋。身上只有那么几个,只装最常用或者马上要用的东西。内存就是你的背包。有时候拿点什么放到口袋里,有时候从口袋里拿出点东西放在背包里。辅存就是你家里的抽屉。可以放很多东西,但存取不方便。

2.地址映射和寄存器映射原理

以STM32为例,操作硬件本质上就是操作寄存器。在存储器片上外设区域,四字节为一个单元,每个单元对应不同的功能。当我们控制这些单元时就可以驱动外设工作,我们可以找到每个单元的起始地址,然后通过C 语言指针的操作方式来访问这些单元。但若每次都是通过这种方式访问地址,不好记忆且易出错。这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名实质上就是寄存器名字。给已分配好地址(通过存储器映射实现)的有特定功能的内存单元取别名的过程就叫寄存器映射。

(1).寄存器地址查找

可参考博客:
STM32寄存器的简介、地址查找与直接操作寄存器

2.GPIO端口的初始化设置步骤

1.时钟配置

(1).时钟的作用

决定程序执行的速度,给芯片提供一个稳定的执行频率

(2).STM32时钟的设置
PLL的倍频因子:HSE * PLLMUL = 72M Hz
AHB的频率:72M Hz
APB2的频率:72M Hz
APB1的频率:36M Hz

2.GPIO

(1).简介

GPIO是通用输入输出端口的简称,简单来说就是STM32可控制的引脚,STM32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。STM32芯片的GPIO被分成很多组,每组有16个引脚,如型号STM32F4IGT6型号的芯片有GPIOA、GPIOB、GPIOC至GPIOI共9GPIO,芯片一共176个引脚,其中GPIO就占了一大部分,所有的GPIO引脚都有基本的输入输出功能。最基本的输出功能是由STM32控制引脚输出高、低电平,实现开关控制,如把GPIO引脚接入到LED灯,那就可以控制LED灯的亮灭,引脚接入到继电器或三极管,那就可以通过继电器或三极管控制外部大功率电路的通断。最基本的输入功能是检测外部输入电平,如把GPIO引脚连接到按键,通过电平高低区分按键是否被按下。

(2).工作模式

GPIO的八种工作模式:输入输出是相对于CPU,四种输入、四种输出模式及四种输出最大速度
(1)GPIO_Mode_AIN 模拟输入
将IO口作为模拟输入接口,输入的可能是变化的值,接收外部的模拟信号输入
(2)GPIO_Mode_IN_FLOATING 浮空输入
复位上电的时候,引脚不确定电平的高低
(3) GPIO_Mode_IPD 下拉输入
将IO口作为通用输入接口,只能输入0或者1,强制下拉,一般是为了输入强低电平
(4) GPIO_Mode_IPU 上拉输入
将IO口作为通用输入接口,只能输入0或者1,强制下拉,一般是为了输入强高电平
(5) GPIO_Mode_Out_OD 开漏输出(带上拉或者下拉)
要得到高电平状态需要上拉电阻才行,可以作为电流型驱动(6) GPIO_Mode_AF_OD 开漏复用输出(带上拉或者下拉)
复用功能,不只是单纯的作为输入输出,可以作为其他功能的引脚:串口、I2C、SPI,要得到高电平状态需要上拉电阻才行(7) GPIO_Mode_Out_PP 推挽输出(带上拉或者下拉)
——IO 输出 0-接 GND, IO 输出 1 -接 VCC,读输入值是未知的,输出0,就一定是0,输出1就一定是1
(8) GPIO_Mode_AF_PP 推挽复用输出(带上拉或者下拉)
复用功能,不只是单纯的作为输入输出,可以作为其他功能的引脚:串口、I2C、SPI,输出0,就一定是0,输出1就一定是1
(9)GPIO四种最大输出速度:2MHZ、25MHZ、50MHZ、100MHZ
GPIO八种工作模式

typedef enum
{
 GPIO_Mode_AIN = 0x0, // 模拟输入
 GPIO_Mode_IN_FLOATING = 0x04, // 浮空输入
 GPIO_Mode_IPD = 0x28, // 下拉输入
 GPIO_Mode_IPU = 0x48, // 上拉输入
 GPIO_Mode_Out_OD = 0x14, // 开漏输出
 GPIO_Mode_Out_PP = 0x10, // 推挽输出
 GPIO_Mode_AF_OD = 0x1C, // 复用开漏输出
 GPIO_Mode_AF_PP = 0x18 // 复用推挽输出
} GPIOMode_TypeDef;

3.输入和输出

输入 :进行数据的采集,外部电路通过IO口输入模拟量,然后通过“TTL肖特基触发器”(肖特基触发器是将相对缓慢变化的模拟信号变成矩形信号,便于后面读取),进入输入数据寄存器,最后就能给CPU读取数据。
输出: GPIO的输出与51的 IO口是差不多的概念,都是输出高、低电平来控制外部电路:\n\n处理过程:CPU下达输出高或低电平指令,指令配置“位设置/清除寄存器(GPIOx_BSRR)”(设置就是“1”高电平,清除就是“0”低电平),再由位寄存器配置输出数据寄存器(GPIOx_ODR),经过一个选择器(选择是一般输出还是复用功能输出),然后进行输出控制,控制是什么模式:推挽、开漏或者关闭,然后输出高或低电平到IO口。

(1)输入模式
输入浮空(GPIO_Mode_IN_FLOATING)
输入上拉(GPIO_Mode_IPU)
输入下拉(GPIO_Mode_IPD)
模拟输入(GPIO_Mode_AIN)

输入浮空:浮空就是逻辑器件与引脚即不接高电平,也不接低电平。由于逻辑器件的内部结构,当它输入引脚悬空时,
相当于该引脚接了高电平。一般实际运用时,引脚不建议悬空,易受干扰。通俗讲就是浮空就是浮在空中,就相当于此端口在默认情况下什么都不接,呈高阻态,这种设置在数据传输时用的比较多。浮空最大的特点就是电压的不确定性,它可能是0V,页可能是VCC,还可能是介于两者之间的某个值(最有可能) 浮空一般用来做ADC输入用,这样可以减少上下拉电阻对结果的影响
输入上拉模式:上拉就是把点位拉高,比如拉到Vcc。上拉就是将不确定的信号通过一个电阻嵌位在高电平。电阻同时起到限流的作用。弱强只是上拉电阻的阻值不同,没有什么严格区分
输入下拉:就是把电压拉低,拉到GND。与上拉原理相似
模拟输入:模拟输入是指传统方式的输入,数字输入是输入PCM数字信号,即0,1的二进制数字信号,通过数模转换,
转换成模拟信号,经前级放大进入功率放大器,功率放大器还是模拟的

(2)输出模式

开漏输出(GPIO_Mode_Out_OD)
开漏复用功能(GPIO_Mode_AF_OD)\n推挽式输出(GPIO_Mode_Out_PP)
推挽式复用功能(GPIO_Mode_AF_PP)
输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)
开漏复用功能:可以理解为GPIO口被用作第二功能时的配置情况(即并非作为通用IO口使用)。端口必须配置成复用功能输出模式(推挽或开漏)
推挽式输出:可以输出高,低电平,连接数字器件;推挽结构一般是指两个三级管分别受到互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源低定。
推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形方法任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小,效率高。输出即可以向负载灌电流。推拉式输出级即提高电路的负载能力,又提高开关速度
推挽式复用功能:可以理解为GPIO口被用作第二功能时的配置情况(并非作为通用IO口使用)

4.GPIO初始化设置

第一步:使能GPIOx口的时钟
第二步:指明GPIOx口的哪一位,这一位的速度大小以及模式第三步:调用GPIOx初始化函数进行初始化
第四步:调用GPIO-SetBits函数,进行相应位的位置

二、stm32

1.写出程序设计思路

2.用c语言stm32寄存器方式实现流水灯

1.GPIO端口初始化

(1).时钟配置

本次实验采用GPIOA、B、C三个端口。该三个端口属于APB2总线
1.找到时钟使能寄存器映射及基地址
在这里插入图片描述

2.找到端口偏移地址以及对应端口所在位置
在这里插入图片描述

3.使能对应端口时钟

//APB2使能时钟寄存器
#define RCC_APB2ENR	
	*((unsigned volatile int*)0x40021018)
RCC_APB2ENR|=1<<2|1<<3|1<<4;
//APB2-GPIOA、GPIOB、GPIOC外设时钟使能
(2).输入和输出模式和输出速率设置

本次实验采用通用推挽输出模式,最高输出时钟频率2Mhz。分别用到A4、B5、C14三个引脚。其中A4、B5属于端口配置低寄存器偏移地址为0x00,C13属于端口配置高寄存器偏移地址为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;		//PA4推挽输出,把第19、18、17、16位变为0010
	
	GPIOB_CRL&=0xFF0FFFFF;		//设置位 清零	
	GPIOB_CRL|=0x00200000;		//PB5推挽输出,把第23、22、21、20变为0010
	 
	GPIOC_CRH&=0xFF0FFFFF;		//设置位 清零	
	GPIOC_CRH|=0x00200000;		//PC14推挽输出,把第23、22、21、20变为0010

2.C语言代码实现

(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;		//PB5推挽输出
	GPIOA_ODR&=~(1<<4);			//设置初始灯为灭
	
	GPIOB_CRL&=0xFF0FFFFF;		//设置位 清零	
	GPIOB_CRL|=0x00200000;		//PB5推挽输出
	GPIOB_ODR&=~(1<<5);			//设置初始灯为灭
	 
	GPIOC_CRH&=0xF0FFFFFF;		//设置位 清零	
	GPIOC_CRH|=0x02000000;		//PB5推挽输出
	GPIOC_ODR&=~(1<<14);			//设置初始灯为灭		
	 

	 

	while(1){
		//A灯
		GPIOA_ODR|=1<<4;		//PB5高电平
	 	Delay();
		GPIOA_ODR&=~(1<<4);		//PB5低电平,因为是置0,所以用按位与


		
		//B灯
		GPIOB_ODR|=1<<5;		//PB5高电平
	 	Delay();
		GPIOB_ODR&=~(1<<5);		//PB5低电平,因为是置0,所以用按位与


		
		
		//C灯
		GPIOC_ODR|=1<<14;		//PB5高电平
	 	Delay();
		GPIOC_ODR&=~(1<<14);		//PB5低电平,因为是置0,所以用按位与


		
		}
}





在这里插入图片描述



 
	
	END







3.stm32cubeMX使用HAL库点亮LED流水灯

1.实验工具

在这里插入图片描述

2.STM32CubeMX生成代码使用HAL库点亮流水灯

(1).安装STM32CubeMX

1.安装STN32CubeMX
(1)管理员身份运行安装程序,点击next
在这里插入图片描述

(2) 点击"I accept the terms of this license agreement",接着选择Next:
在这里插入图片描述

(3)勾选第一个即可
在这里插入图片描述

(4)选择安装位置
在这里插入图片描述

(5)点击确定
(6)直接点击NEXT,其他不用设置,开始安装
在这里插入图片描述

(7)安装完成,点done退出
在这里插入图片描述

(2).安装HAL库

STM32 HAL固件库是Hardware Abstraction Layer的缩写,中文名称是:硬件抽象层。HAL库是ST公司为STM32的MCU最新推出的抽象层嵌入式软件,为更方便的实现跨STM32产品的最大可移植性。HAL库的推出,可以说ST也慢慢的抛弃了原来的标准固件库,这也使得很多老用户不满。但是HAL库推出的同时,也加入了很多第三方的中间件,有RTOS,USB,TCP / IP和图形等等。\n和标准库对比起来,STM32的HAL库更加的抽象,ST最终的目的是要实现在STM32系列MCU之间无缝移植,甚至在其他MCU也能实现快速移植。\n并且从16年开始,ST公司就逐渐停止了对标准固件库的更新,转而倾向于HAL固件库和 Low-layer底层库的更新,停止标准库更新,也就表示了以后使用STM32CubeMX配置HAL/LL库是主流配置环境;

(1)打开安装好的STMCubeMX
在这里插入图片描述

(2)点击HELP->Manage embedded software packages
在这里插入图片描述

(3)会跳出来一个选择型号界面 勾选上你要安装的HAL库,点击"Install Now",直到安装成功。如下图
在这里插入图片描述

(3).新建项目

(1)回到STMCubeMX的主界面,创建新项目
在这里插入图片描述

(2)在part name里选择自己的芯片,点击信息栏中的具体芯片信息选中,点击start projet
在这里插入图片描述

(3)点击system core,进入SYS,在debug下选择serial wire
在这里插入图片描述

(4)配置时钟,进入上面的rcc,有两个时钟,一个是hse和lse,我们要用是GPIO接口,而这些接口都在 APB2里
在这里插入图片描述

接下来观察时钟架构。APB2总线的时钟由hse控制,同时在这个界面得把PLLCLK右边选上
在这里插入图片描述

(5)将hse那里设为Crystal/Ceramic Resonator
在这里插入图片描述

(6)接下来就是点击相应的引脚设置输出寄存器了,就是output那一项了,一共选了三个,是PA4,PB9,PC15
在这里插入图片描述
在这里插入图片描述

(7)点击project manager,配置好自己的路径和项目名,然后IDE那项改为MDK-ARM
在这里插入图片描述

(8)进入code generate界面,选择生成初始化.c/.h文件,点击后面generate code,选择open project,然后就到KEIL5了
在这里插入图片描述

(4).keil仿真模式

1.打开.uvprojx文件(或者在上一步选择open project)
在这里插入图片描述

2.将下面代码放入主函数中(替代里面的内容)

SystemClock_Config();//系统时钟初始化
  MX_GPIO_Init();//gpio初始化
  while (1)
  {		
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);//PA4亮灯
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);//PB9熄灯
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);//PC15熄灯
		HAL_Delay(1000);//延时1s
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);//PA4熄灯
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);//PB9亮灯
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);//PC15熄灯
		HAL_Delay(1000);//延时1s		
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);//PA4熄灯
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);//PB9熄灯
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_RESET);//PC15亮灯
		HAL_Delay(1000);//延时1s
	}


在这里插入图片描述

3.观察GPIO端口的输出波形
(1)Target界面中,选择跟正确的晶振大小,我使用的是8MHz的外部晶振。这个选项在软件仿真中起到很重要的作用,如果选择错误,那么波形一定是错误的,因为时间不准确。
在这里插入图片描述

(2)Debug业的设置
在这里插入图片描述

(3)点击Debug,进入调试页面
在这里插入图片描述

(4)选择逻辑分析仪
在这里插入图片描述

(5)选择要观察的引脚
在这里插入图片描述

(6)相关设置
在这里插入图片描述

(7)运行程序
在这里插入图片描述

(8)观察波形
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值