一、实验目的
使用GPIO引脚,外接LED灯,编写程序让LED灯周期性亮灭。
二、存储器映像
自我理解就是存储器中的存储的东西给出它地址。
下图就是我们本次要用到的存储器映像对应的地址
三、寄存器映像
自我理解就是给寄存器地址取一个名字。
四、点灯步骤
1、打开对应GPIO口的时钟
2、配置GPIO的输出模式(本次选用推挽输出)
3、设置电平
1、打开对应GPIO口的时钟
想要打开对应的IO的时钟,我们就需要查阅STM32手册上的时钟使能寄存器。如下图。
本次我们选用A口的最低三个端口进行试验,所以我们需要将A口的时钟打开。配置时钟代码如下
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
/*1、首先先从存储器映像那里找到RCC的地址,从存储器映像中,我们可以看见时钟起始地址为0x40021000-0x400213ff
2、这句代码就可以看作寄存器映像,又类似于宏定义。我们用时钟的起始地址加上偏移地址就是对应的寄存器地址
3、所以我们现在就相当于找到了这个这个寄存器所在地方
*/
RCC_APB2ENR |=(1<<2);
// 打开 GPIOA 时钟,(1<<2)意思是,将1左移两位,然后再与RCC或运算,这样就能将IOPA置一。
2、配置输出模式
STM32F103C8T6每个端口都有16个输入输出口,所以就将端口分为了端口配置低寄存器与端口配置高寄存器
端口配置低寄存器如下
从图中我们可以看见,低就是指的0-7端口。红色方框圈出来的就是A0口,所以就是4位为一个IO口。我们只需要用A0~A2口,所以就用配置低寄存器就足够
配置代码如下
//首先寄存器映射,找到寄存器所在地。图中的复位值就是指当单片机复位时,对应的寄存器中存入的值。
#define GPIOA_CRL (*(unsigned int *)0x40010800)
//操作A0~A2口,配置CNFy与MODEy。注意这是16进制的,总共八位16进制的数,转换为对应的2进制,就有32位了。
GPIOA_CRL &=0xfffff000;
GPIOA_CRL |=0x00000111;
3、设置电平
端口输出寄存器
配置代码如下
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
GPIOA_ODR |=0xffffffff;//先将A0~2口全部变为1(设置为高电平)。因为在目前的模式下,单片机上电,默认为低电平。
五、代码
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
int main()
{
RCC_APB2ENR |=(1<<2);// 打开 GPIOA 时钟,(1<<2)意思是,将1左移两位,然后再与RCC或运算
GPIOA_CRL &=0xfffff000;//端口低配置寄存器
GPIOA_CRL |=0x00000111;
GPIOA_ODR |=0xffffffff;//端口电平设置
while(1)
{
GPIOA_ODR &=0xfffffffe;//将A0口置0,点亮LED
Delay_ms(10000); //延时函数
GPIOA_ODR |=0xffffffff;//又将输出端口全部变为高电平,灭灯
Delay_ms(10000);
GPIOA_ODR &=0xfffffffd;//A1口
Delay_ms(10000);
GPIOA_ODR |=0xffffffff;
Delay_ms(10000);
GPIOA_ODR &=0xfffffffb;//A2口
Delay_ms(10000);
GPIOA_ODR |=0xffffffff;
Delay_ms(10000);
}
}
六、效果
七、加上 PC13led实现流水灯
步骤跟以上一样,就不再细讲,直接俄上代码
//#include "stm32f10x.h" // Device header
//#include "Delay.h"
//#define GPIOA_BASE 0x40010800
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
#define GPIOC_CRH (*(unsigned int *)0x40011004)//c口的高八位配置
#define GPIOC_ODR (*(unsigned int *)0x4001100c)//c口输出寄存器配置
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
int main()
{
RCC_APB2ENR |=(1<<2);// 打开 GPIOA 时钟,(1<<2)意思是,将1左移两位,然后再与RCC或运算
RCC_APB2ENR |=(1<<4);//c时钟
GPIOA_CRL &=0xfffff000;//端口A低配置寄存器
GPIOA_CRL |=0x00000111;
GPIOC_CRH &=0xff0fffff;//端口C
GPIOC_CRH |=0x00100000;
GPIOC_ODR |=0xffffffff;
GPIOA_ODR |=0xffffffff;//端口电平设置
while(1)
{
GPIOA_ODR &=0xfffffffe;//将A0口置0,点亮LED
Delay_ms(10000); //延时函数
GPIOA_ODR |=0xffffffff;//又将输出端口全部变为高电平,灭灯
Delay_ms(10000);
GPIOA_ODR &=0xfffffffd;//A1口
Delay_ms(10000);
GPIOA_ODR |=0xffffffff;
Delay_ms(10000);
GPIOA_ODR &=0xfffffffb;//A2口
Delay_ms(10000);
GPIOA_ODR |=0xffffffff;
Delay_ms(10000);
GPIOC_ODR &=0xffffdfff;//pc13口
Delay_ms(10000);
GPIOC_ODR |=0xffffffff;
Delay_ms(10000);
}
}
八、效果图
九、总结
通过寄存器操作STM32略微有些复杂,且耗时,费眼。但能更好的理解原理