ARM实现LED灯亮灭

cortex-A7芯片实现LED灯亮灭

步骤:

1.观察LED灯的丝印,三个小灯名字叫LED1,LED2,LED3,并观察拓展板,找到三个小灯对应的电路图费,分析电路图可得知三个小灯的工作原理为引脚写高电平,灯点亮,引脚写低电平,灯熄灭。

ARM实现LED灯亮灭_第1张图片

2.知道了小灯扩展板上的名称,去芯片的资源扩展板J1上去寻找小灯对应的管脚,分别为

LED1----->PE10  

LED2----->PF10

LED3----->PE8

3.了解SOC(stm32mp157a)芯片的框图

ARM实现LED灯亮灭_第2张图片

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控制器工作。

ARM实现LED灯亮灭_第3张图片

6.分析GPIO章节

        a.分析GPIO的框图

ARM实现LED灯亮灭_第4张图片

         b.分析13.3.3章节了解I/O端口控制寄存器的作用,通过分析可得知

                GPIOx_MODER为GPIO模式寄存器(设置输出模式)

ARM实现LED灯亮灭_第5张图片

                GPIOx_OTYPER为GPIO输出类型寄存器(设置为推挽/开漏模式)

ARM实现LED灯亮灭_第6张图片

                GPIOx_OSPEEDR为GPIO输出速度寄存器(设置为输出速率)

ARM实现LED灯亮灭_第7张图片

                GPIOx_PUPDR为GPIO是否需要上下拉电阻

ARM实现LED灯亮灭_第8张图片

                GPIOx_ODR为GPIO为输出数据寄存器(输出高低电平,实现LED灯点亮熄灭)

ARM实现LED灯亮灭_第9张图片

        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;
}

cortex-M4芯片实现LED的亮灭

1.打开STM32CubeMx软件,创新新工程并找到下图对应的芯片

ARM实现LED灯亮灭_第10张图片

b.配置PE10/PF10/PE8,鼠标左键选择GPIO_Output(输出模式),右键设置Pin-Reservation里面的参数为Cortex-M4

ARM实现LED灯亮灭_第11张图片

ARM实现LED灯亮灭_第12张图片

 

c.查看下列参数列表的参数,无误后导出工程(注意各项操作)

ARM实现LED灯亮灭_第13张图片

 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)并调整仿真的选项,然后进行仿真

你可能感兴趣的:(arm,单片机,stm32)