步骤:
1.观察LED灯的丝印,三个小灯名字叫LED1,LED2,LED3,并观察拓展板,找到三个小灯对应的电路图费,分析电路图可得知三个小灯的工作原理为引脚写高电平,灯点亮,引脚写低电平,灯熄灭。
2.知道了小灯扩展板上的名称,去芯片的资源扩展板J1上去寻找小灯对应的管脚,分别为
LED1----->PE10
LED2----->PF10
LED3----->PE8
3.了解SOC(stm32mp157a)芯片的框图
4.通过框图分析可知,实现小灯亮灭需要寻找芯片手册的GPIO章节和RCC章节
5.分析RCC章节
a.通过芯片手册2.5.2章节确定RCC在AHB4总线上,然后可以确定其基地址为0x50000000,而RCC寄存器中控制GPIO使能的寄存器名字为RCC_MP_AHB4ENSETR,其偏移地址为0xA28,所以其地址为0x50000A28。
b.通过上述分析得知小灯需要用到引脚有GPIOE,和GPIOF引脚,因此需要使这两个引脚使能,因此需要设置0x50000A28地址的第四个位置和第五个位置,设置参数为1使对应的GPIO控制器工作。
6.分析GPIO章节
a.分析GPIO的框图
b.分析13.3.3章节了解I/O端口控制寄存器的作用,通过分析可得知
GPIOx_MODER为GPIO模式寄存器(设置输出模式)
GPIOx_OTYPER为GPIO输出类型寄存器(设置为推挽/开漏模式)
GPIOx_OSPEEDR为GPIO输出速度寄存器(设置为输出速率)
GPIOx_PUPDR为GPIO是否需要上下拉电阻
GPIOx_ODR为GPIO为输出数据寄存器(输出高低电平,实现LED灯点亮熄灭)
c.分析GPIOx_MODER寄存器
LED1引脚分析,确定GPIOE_MODER寄存器的地址=基地址+偏移地址=0x50006000+0x00=0x50006000,设置PE10引脚为输出模式需要将GPIOE_MODER寄存器地址的第21位到20位的参数设置为01(输出模式)。
LED2引脚分析,确定GPIOF_MODER寄存器的地址=基地址+偏移地址=0x50006000+0x00=0x50006000,设置PF10引脚为输出模式需要将GPIOF_MODER寄存器地址的第21位到20位的参数设置为01(输出模式)。
LED3引脚分析,确定GPIOE_MODER寄存器的地址=基地址+偏移地址=0x50006000+0x00=0x50006000,设置PE8引脚为输出模式需要将GPIOE_MODER寄存器地址的第17位到16位的参数设置为01(输出模式)。
d.分析GPIOx_OTYPER寄存器
LED1引脚分析,确定GPIOE_OTYPER寄存器地址=基地址+偏移地址=0x50006000+0x04=0x50006004,设置PE10引脚为推挽输出模式需要将GPIOE_OTYPER寄存器地址的第10位的参数设置为0(推挽输出模式)。
LED2引脚分析,确定GPIOF_OTYPER寄存器地址=基地址+偏移地址=0x50006000+0x04=0x50006004,设置PE10引脚为推挽输出模式需要将GPIOF_OTYPER寄存器地址的第10位的参数设置为0(推挽输出模式)。
LED3引脚分析,确定GPIOE_OTYPER寄存器地址=基地址+偏移地址=0x50006000+0x04=0x50006004,设置PE10引脚为推挽输出模式需要将GPIOE_OTYPER寄存器地址的第8位的参数设置为0(推挽输出模式)。
e.分析GPIOx_OSPEEDR寄存器
LED1引脚分析,确定GPIOE_OSPEEDR寄存器地址=基地址+偏移地址=0x50006000+0x08=0x50006008,设置PE10引脚为低速输出模式需要将GPIOE_OTYPER寄存器地址的第21位和第20位的参数设置为00(低速输出模式)。
LED2引脚分析,确定GPIOF_OSPEEDR寄存器地址=基地址+偏移地址=0x50006000+0x08=0x50006008,设置PF10引脚为低速输出模式需要将GPIOF_OTYPER寄存器地址的第21位和第20位的参数设置为00(低速输出模式)。
LED3引脚分析,确定GPIOE_OSPEEDR寄存器地址=基地址+偏移地址=0x50006000+0x08=0x50006008,设置PE8引脚为低速输出模式需要将GPIOE_OTYPER寄存器地址的第17位和第16位的参数设置为00(低速输出模式)。
f.分析GPIOx_PUPDR寄存器
LED1引脚分析,确定GPIOE_PUPDR寄存器地址=基地址+偏移地址=0x50006000+0x0C=0x5000600C,设置PE10引脚为禁止上下拉模式需要将GPIOE_PUPDR寄存器地址的第21位和第20位的参数设置为00(低速输出模式)。
LED2引脚分析,确定GPIOF_PUPDR寄存器地址=基地址+偏移地址=0x50006000+0x0C=0x5000600C,设置PF10引脚为禁止上下拉模式需要将GPIOF_PUPDR寄存器地址的第21位和第20位的参数设置为00(低速输出模式)。
LED3引脚分析,确定GPIOE_PUPDR寄存器地址=基地址+偏移地址=0x50006000+0x0C=0x5000600C,设置PE8引脚为禁止上下拉模式需要将GPIOE_PUPDR寄存器地址的第17位和第16位的参数设置为00(低速输出模式)。
g.分析GPIOx_ODR寄存器
LED1引脚分析,确定GPIOE_ODR寄存器地址=基地址+偏移地址=0x50006000+0x14=0x50006014,设置PE10引脚为禁止上下拉模式需要将GPIOE_ODR寄存器地址的第10位的参数设置为0(低电平输出模式)或者1(高电平输出模式)。
LED1引脚分析,确定GPIOF_ODR寄存器地址=基地址+偏移地址=0x50006000+0x14=0x50006014,设置PF10引脚为禁止上下拉模式需要将GPIOF_ODR寄存器地址的第10位的参数设置为0(低电平输出模式)或者1(高电平输出模式)。
LED1引脚分析,确定GPIOE_ODR寄存器地址=基地址+偏移地址=0x50006000+0x14=0x50006014,设置PE8引脚为禁止上下拉模式需要将GPIOE_ODR寄存器地址的第8位的参数设置为0(低电平输出模式)或者1(高电平输出模式)。
7.汇编编写代码实现小灯亮灭
.text
.global _start
_start:
/**********LED1点亮**************/
LED1_INIT:
@1.通过RCC_AHB4_ENSETR:0x50000A28寄存器设置GPIOE控制器使能 0x50000A28[4] = 1
ldr r0,=0x50000A28
ldr r1,[r0] @将r0寄存器地址中的值,读到r1寄存器中
orr r1,r1,#(0x1 << 4)
@将r1寄存器中的第4位置1
str r1,[r0]
@2.通过GPIOE_MODER:0x50006000寄存器设置PE10引脚为输出模式 0x50006000[21:20]= 01
ldr r0,=0x50006000
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
orr r1,r1,#(0x1 << 20)
str r1,[r0]
@3.通过GPIOE_OTYPER:0x50006004寄存器设置PE10引脚为推挽输出模式 0x50006004[10]= 0
ldr r0,=0x50006004
ldr r1,[r0]
and r1,r1,#(~(0x1 << 10))
str r1,[r0]
@4.通过GPIOE_OSPEEDR:0x50006008寄存器设置PE10引脚为低速输出模式0x50006008[21:20]= 00
ldr r0,=0x50006008
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
str r1,[r0]
@5.通过GPIOE_PUPDR:0x5000600C寄存器设置PE10引脚为禁止上下拉0x5000600C[21:20]= 00
ldr r0,=0x5000600C
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
str r1,[r0]
/**********LED2点亮PF10**************/
LED2_INIT:
@1.通过RCC_AHB4_ENSETR:0x50000A28寄存器设置GPIOF控制器使能 0x50000A28[5] = 1
ldr r0,=0x50000A28
ldr r1,[r0] @将r0寄存器地址中的值,读到r1寄存器中
orr r1,r1,#(0x1 << 5)
@将r1寄存器中的第4位置1
str r1,[r0]
@2.通过GPIOF_MODER:0x50006000寄存器设置PF10引脚为输出模式 0x50007000[21:20]= 01
ldr r0,=0x50007000
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
orr r1,r1,#(0x1 << 20)
str r1,[r0]
@3.通过GPIOF_OTYPER:0x50006004寄存器设置PF10引脚为推挽输出模式 0x50007004[10]= 0
ldr r0,=0x50007004
ldr r1,[r0]
and r1,r1,#(~(0x1 << 10))
str r1,[r0]
@4.通过GPIOF_OSPEEDR:0x50006008寄存器设置PE10引脚为低速输出模式0x50007008[21:20]= 00
ldr r0,=0x50007008
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
str r1,[r0]
@5.通过GPIOF_PUPDR:0x5000700C寄存器设置PE10引脚为禁止上下拉0x5000700C[21:20]= 00
ldr r0,=0x5000700C
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
str r1,[r0]
/**********LED3点亮PE8**************/
LED3_INIT:
@1.通过RCC_AHB4_ENSETR:0x50000A28寄存器设置GPIOE控制器使能 0x50000A28[4] = 1
ldr r0,=0x50000A28
ldr r1,[r0] @将r0寄存器地址中的值,读到r1寄存器中
orr r1,r1,#(0x1 << 4)
@将r1寄存器中的第4位置1
str r1,[r0]
@2.通过GPIOE_MODER:0x50006000寄存器设置PE8引脚为输出模式 0x50006000[17:16]= 01
ldr r0,=0x50006000
ldr r1,[r0]
and r1,r1,#(~(0x3 << 16))
orr r1,r1,#(0x1 << 16)
str r1,[r0]
@3.通过GPIOE_OTYPER:0x50006004寄存器设置PE8引脚为推挽输出模式 0x50006004[8]= 0
ldr r0,=0x50006004
ldr r1,[r0]
and r1,r1,#(~(0x1 << 8))
str r1,[r0]
@4.通过GPIOE_OSPEEDR:0x50006008寄存器设置PE8引脚为低速输出模式0x50006008[17:16]= 00
ldr r0,=0x50006008
ldr r1,[r0]
and r1,r1,#(~(0x3 << 16))
str r1,[r0]
@5.通过GPIOE_PUPDR:0x5000600C寄存器设置PE8引脚为禁止上下拉0x5000600C[17:16]= 00
ldr r0,=0x5000600C
ldr r1,[r0]
and r1,r1,#(~(0x3 << 16))
str r1,[r0]
loop:
bl LED1_ON
bl delay_1s
bl LED1_OFF
bl delay_1s
bl LED2_ON
bl delay_1s
bl LED2_OFF
bl delay_1s
bl LED3_ON
bl delay_1s
bl LED3_OFF
bl delay_1s
b loop
LED1_ON:
@1.通过GPIOE_ODR:0x50006014寄存器设置PE10引脚为输出高电平 0x50006014[10]= 1
ldr r0,=0x50006014
ldr r1,[r0]
orr r1,r1,#(0x1 << 10)
str r1,[r0]
mov pc,lr
LED2_ON:
@1.通过GPIOF_ODR:0x50007014寄存器设置PF10引脚为输出高电平 0x50007014[10]= 1
ldr r0,=0x50007014
ldr r1,[r0]
orr r1,r1,#(0x1 << 10)
str r1,[r0]
mov pc,lr
LED3_ON:
@1.通过GPIOE_ODR:0x50006014寄存器设置PE8引脚为输出高电平 0x50006014[8]= 1
ldr r0,=0x50006014
ldr r1,[r0]
orr r1,r1,#(0x1 << 8)
str r1,[r0]
mov pc,lr
LED1_OFF:
@1.通过GPIOE_ODR:0x50006014寄存器设置PE10引脚为输出低电平 0x50006014[10]= 0
ldr r0,=0x50006014
ldr r1,[r0]
and r1,r1,#(~(0x1 << 10))
str r1,[r0]
mov pc,lr
LED2_OFF:
@1.通过GPIOE_ODR:0x50007014寄存器设置PE10引脚为输出低电平 0x50007014[10]= 0
ldr r0,=0x50007014
ldr r1,[r0]
and r1,r1,#(~(0x1 << 10))
str r1,[r0]
mov pc,lr
LED3_OFF:
@1.通过GPIOE_ODR:0x50006014寄存器设置PE10引脚为输出低电平 0x50006014[8]= 0
ldr r0,=0x50006014
ldr r1,[r0]
and r1,r1,#(~(0x1 << 8))
str r1,[r0]
mov pc,lr
@ 大概1s的延时函数
delay_1s:
mov r3, #0x10000000
mm:
cmp r3, #0
subne r3, r3, #1
bne mm
mov pc, lr
.end
8.C语言实现小灯亮灭
a.C语言结构体的封装
1.在汇编语言中0x50000A28是一个地址,在C语言中如何表示0x50000A28是一个地址呢?
(volatile unsigned int*)0x50000A28
2.如何取地址0x50000A28中的值呢?
*(volatile unsigned int*)0x50000A28
3.将0x50000A28这个寄存器中的第4位置1,并且保证其他位不变?
*(volatile unsigned int*)0x50000A28 = (*(volatile unsigned int*)0x50000A28) | (0x1 << 4)
4.用宏定义#define,对寄存器进行封装
#define RCC_AHB4_ENSETR (*(volatile unsigned int*)0x50000A28)
RCC_AHB4_ENSETR |= (0x1 << 4);
5.用宏定义#define,对GPIOE寄存器进行封装
#define GPIOE_MODER (*(volatile unsigned int*)0x50006000)
#define GPIOE_OTYPER (*(volatile unsigned int*)0x50006004)
#define GPIOE_OSPEDDR (*(volatile unsigned int*)0x50006008)
#define GPIOE_PUPDR (*(volatile unsigned int*)0x5000600C)
#define GPIOE_ODR (*(volatile unsigned int*)0x50006014)
6.用结构体对GPIO控制器进行封装
typedef struct{
volatile unsigned int MODER; //00
volatile unsigned int OTYPER; //04
volatile unsigned int OSPEEDR; //08
volatile unsigned int PUPDR; //0C
volatile unsigned int IDR; //10
volatile unsigned int ODR; //14
}gpio_t;
#define GPIOE ((gpio_t*)0x50006000)
#define GPIOF ((gpio_t*)0x50007000)
b.gpio.h文件
#ifndef __GPIO_H__
#define __GPIO_H__
#define RCC_AHB4_ENSETR (*(volatile unsigned int*)0x50000A28)
typedef struct
{
volatile unsigned int MODER;
volatile unsigned int OTYPER;
volatile unsigned int OSPEEDR;
volatile unsigned int PUPDR;
volatile unsigned int IDR;
volatile unsigned int ODR;
}gpio_t;
#define GPIOE ((gpio_t*)0x50006000)
#define GPIOF ((gpio_t*)0x50007000)
void LED1_init();
void LED1_on();
void LED1_off();
void LED2_init();
void LED2_on();
void LED2_off();
void LED3_init();
void LED3_on();
void LED3_off();
#endif
c.gpio.c文件
#include "gpio.h"
void LED1_init()
{
RCC_AHB4_ENSETR |= (0x1 << 4);
GPIOE->MODER &= (~(0x3 << 20));
GPIOE->MODER |= (0x1 << 20);
GPIOE->OTYPER &= (~(0x1 << 10));
GPIOE->OSPEEDR &= (~(0x3 << 20));
GPIOE->PUPDR &= (~(0x3 << 20));
}
void LED1_on()
{
GPIOE->ODR |= (0x1 << 10);
}
void LED1_off()
{
GPIOE->ODR &=(~(0x1 << 10));
}
void LED2_init()
{
RCC_AHB4_ENSETR |= (0x1 << 5);
GPIOF->MODER &= (~(0x3 << 20));
GPIOF->MODER |= (0x1 << 20);
GPIOF->OTYPER &= (~(0x1 << 20));
GPIOF->OSPEEDR &= (~(0x3 << 20));
GPIOF->PUPDR &= (~(0x3 << 20));
}
void LED2_init()
{
RCC_AHB4_ENSETR |= (0x1 << 5);
GPIOF->MODER &= (~(0x3 << 20));
GPIOF->MODER |= (0x1 << 20);
GPIOF->OTYPER &= (~(0x1 << 20));
GPIOF->OSPEEDR &= (~(0x3 << 20));
GPIOF->PUPDR &= (~(0x3 << 20));
}
void LED2_on()
{
GPIOF->ODR |= (0x1 << 10);
}
void LED2_off()
{
GPIOF->ODR &=(~(0x1 << 10));
}
void LED3_init()
{
RCC_AHB4_ENSETR |= (0x1 << 4);
GPIOE->MODER &= (~(0x3 << 16));
GPIOE->MODER |= (0x1 << 16);
GPIOE->OTYPER &= (~(0x1 << 16));
GPIOE->OSPEEDR &= (~(0x3 << 16));
GPIOE->PUPDR &= (~(0x3 << 16));
}
void LED3_on()
{
GPIOE->ODR |= (0x1 << 8);
}
void LED3_off()
{
GPIOE->ODR &=(~(0x1 << 8));
}
d.main.c文件
#include "gpio.h"
extern void printf(const char *fmt, ...);
void delay_ms(int ms)
{
int i,j;
for(i = 0; i < ms;i++)
for (j = 0; j < 1800; j++);
}
int main()
{
LED1_init();
LED2_init();
LED3_init();
while(1)
{
LED1_on();
LED2_on();
LED3_on();
delay_ms(1000);
LED1_off();
LED2_off();
LED3_off();
delay_ms(1000);
}
return 0;
}
1.打开STM32CubeMx软件,创新新工程并找到下图对应的芯片
b.配置PE10/PF10/PE8,鼠标左键选择GPIO_Output(输出模式),右键设置Pin-Reservation里面的参数为Cortex-M4
c.查看下列参数列表的参数,无误后导出工程(注意各项操作)
d.代码编写
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10,GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10,GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10,GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10,GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8,GPIO PIN_SED);
HAL_Delay(500) ;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8,GPIO_PIN_RESET);
HAL_Delay(500);
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
//KEY2--->PF10
case GPIO_PIN_7:
HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
break;
//KEY3--->PE10
case GPIO_PIN_8:
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_10);
break;
//KEY1--->PE8
case GPIO_PIN_9:
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_8) ;
break;
}
}
e.调整拨码开关设置为M4核的启动方式(100)并调整仿真的选项,然后进行仿真