• STM32使用寄存器点灯实验


    寄存器点灯实验

    操作过程

    使能IO口时钟配置寄存器RCC_APB2ENR

    初始化IO口模式,配置寄存器GPIOx_CRH/CRL

    操作IO口,输出高低电平,配置寄存器GPIOx_ODR或者BSRR/BRR。

    APB2 外设时钟使能寄存器(RCC_APB2ENR)

    STM32中文参考手册6.3RCC寄存器描述的6.3.7小节可以看到该寄存器的使用说明

    在这里插入图片描述

    因为使用的是GPIOA端口组,所以使能IOPAEN位,该位置1则IO端口A时钟开启

    端口配置低寄存器(GPIOx_CRL) (x=A…E)

    在中文参考手册的8.2节可以找到GPIO寄存器相关配置寄存器的描述
    在这里插入图片描述

    因为开发板上的PA1连接到了LED灯,所以对CNF1和MODE1进行初始化,MODE1初始化为11,设置为输出模式,速度为50MHz,CNF1初始化为00,设置为通用推挽输出模式

    因为没有用到更高的引脚位,所以端口配置高寄存器(GPIOx_CRH) 并不用配置

    端口输出数据寄存器(GPIOx_ODR)

    在这里插入图片描述

    往ODR寄存器的ODR1位写入0,则PA1引脚输出低电平,LED灯被点亮

    端口位设置/清除寄存器(GPIOx_BSRR) ,端口位清除寄存器(GPIOx_BRR)

    也可以使用这两个寄存器,因为是PA1输出低电平LED灯才被点亮,所以这两个寄存器都有效

    如果LED灯是引脚输出高电平才能被点亮,那就只有端口位设置/清除寄存器(GPIOx_BSRR)的设置功能才能输出高电平,BRR寄存器不行

    在这里插入图片描述

    在这里插入图片描述

    程序

    参照手册搭建好寄存器的工程模板后,新建LED.h和LED.c文件,开始编写代码

    LED.h

    在头文件中要添加函数声明,因为写了多种初始化方法,所以这些函数都要添加声明

    #ifndef __LED_H__
    #define __LED_H__
    
    //宏定义,LED_Init_3,LED_Init_4
    #define IOPAEN                  0x01<<2
    #define CNF1_AND_MODE1          ((u32)0x0F<<4)
    #define OUT_MODE_PP			   ((u32)0x03<<4)
    #define ODR1                    ((u16)0x01<<1)
    #define BSRR_BR1                ((u32)0x01<<17)
    #define BRR_BR1                 ((u16)0x01<<1)
    
    void LED_Init_1(void);
    void LED_Init_2(void);
    void LED_Init_3(void);
    void LED_Init_4(void);
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    LED.c

    分别用三种不同的写法实现点亮LED灯,方法一是直接往寄存器写入十六进制,方法二是用移位的方法初始化寄存器,但这两种方法的数值第一眼看去不好理解,不看参考手册的话很难知道0xFFF4是初始化什么,(u16)0x01<<2也是一样

    所以推荐使用第三种方法,用宏定义,先在LED.h头文件中定义好数值,然后使用时直接调用宏名即可,可以让人一眼就看出初始化的是哪个位

    第四种方法是使用BSRR或BRR寄存器对PA1进行赋值,一样能使LED灯点亮

    #include "LED.h"
    #include "stm32f10x.h"
    
    /**
      * @name 	LED_Init_1
      * @brief	LED初始化-寄存器(写法1)
      * @param	None
      * @retval	None
      */
    void LED_Init_1()
    {
    	//初始化APB2上GPIOA的时钟
    	RCC->APB2ENR |= 0xFFF4;
    
      //GPIOA端口配置低寄存器
      //4 ~ 7配置的是PA1,所以先将这4位清零
      GPIOA->CRL &= 0xFFFFFF0F;
    
      //然后MODE1初始化为11,CNF1初始化为00,设置为通用推挽输出模式
      GPIOA->CRL |= 0xFFFFFF3F;
    
      //配置端口输出数据寄存器,将ODR1置0,输出低电平,点亮LED
      GPIOA->ODR &= 0xFFFD;
    }
    
    /**
      * @name 	LED_Init_2
      * @brief	LED初始化-寄存器(写法2)
      * @param	None
      * @retval	None
      */
    void LED_Init_2()
    {
      //初始化APB2上GPIOA的时钟
      RCC->APB2ENR |= ((u16)0x01<<2);
    
      //GPIOA端口配置低寄存器
      //4 ~ 7配置的是PA1,所以先将这4位清零
      GPIOA->CRL &= ~((u32)0x0F<<4);
    
      //然后MODE1初始化为11,CNF1初始化为00,设置为通用推挽输出模式
      GPIOA->CRL |= ((u32)0x03<<4);
    
      //配置端口输出数据寄存器,将ODR1置0,输出低电平,点亮LED
      GPIOA->ODR &= ~((u16)0x01<<1);
    }
    
    /**
      * @name 	LED_Init_3
      * @brief	LED初始化-寄存器(写法3)
      * @param	None
      * @retval	None
      */
    void LED_Init_3()
    {
    	//初始化APB2上GPIOA的时钟
    	RCC->APB2ENR |= IOPAEN;
    
    	//GPIOA端口配置低寄存器
    	//4 ~ 7配置的是PA1,所以先将这4位清零
    	GPIOA->CRL &= ~CNF1_AND_MODE1;
    
    	//然后MODE1初始化为11,CNF1初始化为00,设置为通用推挽输出模式
    	GPIOA->CRL |= OUT_MODE_PP;
    
    	//配置端口输出数据寄存器,将ODR1置0,输出低电平,点亮LED
    	GPIOA->ODR &= ~ODR1;
    }
    
    
    /**
      * @name 	LED_Init_4
      * @brief	LED初始化-寄存器(测试BSRR寄存器和BRR寄存器)
      * @param	None
      * @retval	None
      */
    void LED_Init_4()
    {
      //初始化APB2上GPIOA的时钟
    	RCC->APB2ENR |= IOPAEN;
    
    	//GPIOA端口配置低寄存器
    	//4 ~ 7配置的是PA1,所以先将这4位清零
    	GPIOA->CRL &= ~CNF1_AND_MODE1;
    
    	//然后MODE1初始化为11,CNF1初始化为00,设置为通用推挽输出模式
    	GPIOA->CRL |= OUT_MODE_PP;
    
    	//配置端口输出数据寄存器,将ODR1置0,输出低电平,点亮LED
    	//GPIOA->ODR &= ~ODR1;
    
      //配置端口位设置/清除寄存器(GPIOx_BSRR) 31-16位置1则对应的ODR位清0,LED点亮
      //GPIOA->BSRR |= BSRR_BR1;
    
      //配置端口位清除寄存器(GPIOx_BRR) 15-0位置1则对应的ODR位清0,LED点亮
      GPIOA->BRR |= BRR_BR1;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    main.c

    主函数中引入LED.h头文件后,直接调用LED初始化函数即可

    #include "LED.h"
    
    int main()
    {
    	//LED_Init_1();
    	//LED_Init_2();
    	//LED_Init_3();
    	LED_Init_4();
    	while(1)
    	{
    		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    多种规格尺寸可定制羧基化聚苯乙烯-二乙烯基苯聚合物微球PS-DVB-COOH
    小型k8s
    linux篇【7】:进程程序替换
    MySQL DDL执行方式-Online DDL介绍
    名窑讲坛:钧瓷“神、奇、妙、绝”四大特色之“妙”——纹路
    7.SpringEL使用正则表达式
    Nodejs 第十六章(ffmpeg)
    车载多媒体没法显示歌词的解决办法 —— 修改 LRC 文件的编码格式为 UTF-8
    Selenium基础 — Selenium中的expected_conditions模块(一)
    【脏读、脏写、不可重复读、幻读】数据库数据并发产生的问题
  • 原文地址:https://blog.csdn.net/weixin_46251230/article/details/126603022