前言
本文分别通过库函数、寄存器以及位操作完成跑马灯实验,使用的开发板是正点原子的min核心板。
一、库函数
1.1 硬件连接
图1 LED 与 STM32 连接原理图
通过min板的原理图可以看出两个LED灯分别接到PD2和PA8引脚,并且LED灯是共阳极,当IO口输出高电平,LED灭;输出低电平,LED亮。
在实际的程序编程中我们需要用到GPIO文件也就是stm32f10x_gpio.h和stm32f10x_gpio.c,来操作对应IO口。同时我们需要设置时钟就要用到stm32f10x_rcc.c与其头文件进行时钟使能。
1.2 GPIO库函数介绍
-
重要函数
1个初始化函数:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
主要用途是用来初始化GPIO口的状态
第一个参数是一个结构体类型变量,指定哪组IO口,第二个同样是一个结构体类型变量,它共有三个变量,第一个指定哪个IO口,第二个指定速度,第三个指定Mode模式。
GPIO_Init函数初始化样例:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO口速度为50MHz
GPIO_Init(GPIOB,&GPIO_InitStructure); //根据设定参数初始化为GPIOB.5
2个读取输入电平函数:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, unit16_t GPIO_Pin);
作用:读取某个GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。
例如:
GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5);//读取GPIOA.5的输入电平
uint16_t GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:读取某个GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。
例如:
GPIO_ReadInputData(GPIOA);//读取GPIOA组中所有io口输入电平
2个读取输出电平函数:
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
上面两个函数的作用与读取输入电平大致相同,不同处在于这里读取的是某组或某个GPIO的输出电平。实际操作的是GPIO_ODR寄存器。
4个设置输出电平函数:
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:设置某个IO口输出为高电平(1)。实际操作BSRR寄存器。
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:设置某个IO口输出为低电平(0)。实际操作BRR寄存器。
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
这两个函数不常用,也是用来设置IO口输出电平。
所有的函数都是在主函数中设置寄存器的值,例如SetBits使用了BSRR,ResetBit使用了BRR寄存器。
1.3 跑马灯程序
库函数——步骤:
- 使能IO口时钟。调用函数RCC_APB2PeriphColckCmd();
不同的IO组,调用的始终使能函数不一样。
- 初始化IO口模式。调用函数GPIO_Init();
- 操作IO口,输出高低电平。
GPIO_SetBits();
GPIO_ResetBits();
注意:操作IO口之前,必须使能对应的时钟位。
在项目中新建一个HAREWARE文件夹,在其中新建程序文件夹,创建对应c文件与头文件,例如led.h与LED.c,在led.h头文件中定义LED_Init函数。
注意这里需要将对应头文件路径加入项目中来。以下是本次程序LED.c的代码内容,实现两个LED灯初始化。
接下来在USER文件夹中编写main函数,
编写完后利用flymcu烧录至开发板中,两个LED灯将同时点亮,间隔500毫秒后又同时熄灭,循环往复。
二、寄存器
2.1 硬件连接
连接如库函数。
2.2 跑马灯程序
寄存器——步骤:
- 使能IO口时钟。配置寄存器RCC_APB2ENR;
- 初始化IO口模式。配置寄存器GPIOx_CRH/CRL;
- 操作IO口,输出高低电平。配置寄存器GPIOX_ODR或者BSRR/BRR。
2.2.1 使能IO口时钟
mini板的LED引脚分别为PA8和PD2,所以选择配置寄存器RCC_APB2ENR的位5和位2如上面原理图所示。
同样在项目中新建HAREWARE文件夹,其余操作步骤如库函数,在led.h头文件中定义LED_Init函数,首先我们需要操作RCC寄存器,它的定义在stm23f10x.h中,可以看到定义中使用RCC结构体指针定义了所有寄存器,在代码中我们将RCC指向APB2ENR来操作寄存器。
2.2.2 初始化IO口模式
接下来操作端口配置寄存器,我们需要用GPIOx结构体指针指向该寄存器,配置为通用推挽输出模式,最大速度50MHz,对应到寄存器的每一个位是0011B,实际代码中先将对应位清零再进行配置,调用GPIOx的ODR寄存器,拉高需要操作的相应位。
2.2.3 操作IO口
main.c里面把stm32f10x.h、delay.h、led.h头文件包含进来,主函数中调用delay_init和LED_Init初始化函数,随后进入while死循环,在死循环中同样可以直接用ODR寄存器对LED进行操作。
程序编写完毕后烧录至开发板实现跑马灯功能。
三、位操作
3.1 位操作基本原理
位操作原理:
把每个比特膨胀为一个32位的字,当访问这些字的时候就达到了访问比特的目的,比如说BSRR寄存器有32个位,那么可以映射到32个地址上,我们去访问(读-改-写)这32个地址就达到访问32个比特的目的。
哪些区域支持位操作:
由于位带区一个位对应32位的地址,所以位带区1MB对应别名区32MB。
映射关系:
-
位带区:支持位带操作的地址区
-
位带别名:对别名地址的访问最终作用到位带区的访问上
3.2 硬件连接
硬件连接与前两个方法相同。
3.3 跑马灯程序
具体的代码实现里面,实际上运用的就是映射关系,比如要操作PA,就会宏定义一个PAout()函数,他的原理实际上就是在操作ODR寄存器,相应的,PAin()函数就是操作IDR寄存器,所有方法的最终原理都是操作寄存器,这是永恒不变的。
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080c
//IO口操作,针对单一IO口
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
位操作——步骤:
- 使能IO口时钟。调用函数RCC_APB2PeriphColckCmd();
- 初始化IO口模式。调用函数GPIO_Init();
- 操作IO口,输出高低电平。使用位带操作。
大体上位操作的步骤和库函数相同,其使用的模板与库函数相同。
3.3.1 使能IO口时钟
与库函数版本程序代码相同。
3.3.2 初始化IO口模式
与库函数版本程序代码相同。
3.3.3 操作IO口
文章来源:https://www.toymoban.com/news/detail-740455.html
在这里只需要通过宏定义的位带函数操作LED灯即可。文章来源地址https://www.toymoban.com/news/detail-740455.html
到了这里,关于STM32入门——三种编写跑马灯程序的方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!