单片机寄存器如何开发?初识框架概念,点亮LED灯

  1. 初始框架

转述不利于理解,我们直接上图上操作,操作起来

下面图来自于我去年写的一个初学者按键点灯简洁的代码新手易于理解,易懂又可以看出效果

但是实际项目中不可能这么用这里边有很多坑。

这里采用之前的文章为切入点熟悉一下正常操作流程。。。

点这里跳转参考文章👍.

 #include "stm32f1xx_hal.h"
 #include "gpio.h"
 #define LED_R  GPIO_PIN_0;
 #define KEY_SW8  GPIO_PIN_13;
 #define LED_RR() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET)
 #define sw8  HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)
 void led_init(void)
 {
     GPIO_InitTypeDef gpiotypedef;
     __HAL_RCC_GPIOB_CLK_ENABLE();
     __HAL_RCC_GPIOC_CLK_ENABLE();
     gpiotypedef.Mode = GPIO_MODE_OUTPUT_OD;
     gpiotypedef.Pin = LED_R;
     gpiotypedef.Speed = GPIO_SPEED_FREQ_LOW;
     HAL_GPIO_Init(GPIOB,&gpiotypedef);
     LED_RR();
     
     gpiotypedef.Mode = GPIO_MODE_AF_INPUT;
     gpiotypedef.Pin = KEY_SW8;
     gpiotypedef.Pull = GPIO_PULLDOWN;
     HAL_GPIO_Init(GPIOC,&gpiotypedef);
 }
 ​

上述是GPIO初始化代码,配置结构体,传入结构体初始化,然后设置引脚的逻辑电平。

这是正常写法但是如果项目后加led灯你也要不停的在里边添加代码显得很麻烦

所以来看下图

这是stm32f411的一个工程

重构了GPIO结构体方便自己添加

下图结构体参数为GPIO总控、那个引脚、什么模式、以及上边的枚举类型时钟

image-20240625201959356

image-20240625202825357

LEDLISTMAX 这是一个宏来计算结构体大小,这是c语言知识不细说了

我们循环初始化结构体然后传入参数来利用HAL库底层帮我们做初始化后续这块代码不需要动

下边我把文件代码传上去先一个个看

 #define LEDLISTMAX sizeof(ledlist) / sizeof(LedInfo)
 ​
 /**
 ***********************************************************
 * @brief 初始化led为关闭
 * @param  
 * @return 
 ***********************************************************
 */
 void Led_Init(void)
 {
     
     for(uint8_t i = 0;i<LEDLISTMAX;i++)
     {
         switch(ledlist[i].clock)
         {
             case A:
                 __HAL_RCC_GPIOA_CLK_ENABLE();
                 break;
             case B:
                 __HAL_RCC_GPIOB_CLK_ENABLE();
                 break;
             case C:
                 __HAL_RCC_GPIOC_CLK_ENABLE();
                 break;
             default:
             break;
         }
         GPIO_InitTypeDef inittypedef;
         inittypedef.Pin = ledlist[i].pin;
         inittypedef.Mode = ledlist[i].mode;
         inittypedef.Speed = GPIO_SPEED_FREQ_LOW;
         HAL_GPIO_Init(ledlist[i].gpio,&inittypedef);
         HAL_GPIO_WritePin(ledlist[i].gpio, ledlist[i].pin, GPIO_PIN_RESET);
     }
 }

传入对应的序号,结构体数组0号成员就传入0,数组下标为1就传入1依次类推

这是反转电平函数

image-20240625203323493

这是置位高电平函数,以及低电平函数

image-20240625203546853

这是完整代码

 #include "hal_led.h"
 /**
 ***********************************************************
 * @brief 定义枚举类型的GPIO时钟
 * @param  0=A;1=B;C=2;D=3;
 * @return 
 ***********************************************************
 */
 typedef enum{
     A = 0,
     B,
     C,
 }GPIO_CLOCK;
 ​
 /**
 ***********************************************************
 * @brief 定义端口结构体类型
 * @param  
 * @return 
 ***********************************************************
 */
 typedef struct{
     GPIO_TypeDef      *gpio;  
         uint32_t       pin;
         uint32_t       mode;
         GPIO_CLOCK     clock;
 }LedInfo;
 ​
 LedInfo ledlist[] = {
      {GPIOB,GPIO_PIN_4,GPIO_MODE_OUTPUT_PP,B},
      //{GPIOB,GPIO_PIN_5,GPIO_MODE_OUTPUT_PP,B},
      
     
 };
 #define LEDLISTMAX sizeof(ledlist) / sizeof(LedInfo)
 ​
 /**
 ***********************************************************
 * @brief 初始化led为关闭
 * @param  
 * @return 
 ***********************************************************
 */
 void Led_Init(void)
 {
     
     for(uint8_t i = 0;i<LEDLISTMAX;i++)
     {
         switch(ledlist[i].clock)
         {
             case A:
                 __HAL_RCC_GPIOA_CLK_ENABLE();
                 break;
             case B:
                 __HAL_RCC_GPIOB_CLK_ENABLE();
                 break;
             case C:
                 __HAL_RCC_GPIOC_CLK_ENABLE();
                 break;
             default:
             break;
         }
         GPIO_InitTypeDef inittypedef;
         inittypedef.Pin = ledlist[i].pin;
         inittypedef.Mode = ledlist[i].mode;
         inittypedef.Speed = GPIO_SPEED_FREQ_LOW;
         HAL_GPIO_Init(ledlist[i].gpio,&inittypedef);
         HAL_GPIO_WritePin(ledlist[i].gpio, ledlist[i].pin, GPIO_PIN_RESET);
     }
 }
 /**
 ***********************************************************
 * @brief 反转Led
 * @param led编号
 * @return 
 ***********************************************************
 */
 void Led_toggle(uint8_t LedIndex)
 {
     if(LedIndex >= LEDLISTMAX)
     {
         return;
     }
     HAL_GPIO_TogglePin(ledlist[LedIndex].gpio, ledlist[LedIndex].pin);
 } 
 ​
 /**
 ***********************************************************
 * @brief 熄灭Led
 * @param led编号
 * @return 
 ***********************************************************
 */
 void Led_off(uint8_t LedIndex)
 {
     if(LedIndex >= LEDLISTMAX)
     {
         return;
     }
     HAL_GPIO_WritePin(ledlist[LedIndex].gpio, ledlist[LedIndex].pin,GPIO_PIN_RESET);
 }
 ​
 void Led_on(uint8_t LedIndex)
 {
     if(LedIndex >= LEDLISTMAX)
     {
         return;
     }
     HAL_GPIO_WritePin(ledlist[LedIndex].gpio, ledlist[LedIndex].pin,GPIO_PIN_SET);
 }

到时候只需在初始化结构体时候添加自己的结构体成员放到数组中即可,不过这种代码还是和底层代码混在一起并不是最高优的led驱动框架,真正的需要和底层硬件库解耦。

不过这种做基础的项目也够用了,有利于扩展和维护性。

  1. 寄存器驱动led

    寄存器的话代码比较少我们只需掌握指针既可以操作指定位置

     int a = 10;
     int *b = &a;
     //这样大家应该不陌生吧,标准指针指向变量
     //这里思考一下&a = 多少?
     //。。。
     //&a = 内存中某一块地址,所以*b = 这块地址
     //大家要有一个概念c语言地址,地址上有东西,地址 = 你家小区,你住在小区上这是俩个东西
     ​

    我们打开103的手册可以看到

    image-20240625204705569

image-20240625204751806

我们发现了有个偏移量的东西这是什么?

image-20240625205058598

所以我们来看这里

 //先应该定义一个指针
 //指向一块地址
 //配置为输出模式
 //从新指向一块地址
 //使能相应的GPIO
 //再次从新指向一块地址
 //然后利用(置位高低电平)
 uint8_t *temp;
 temp = (uint8_t *)(0x40010C00 + 0x00);
 *temp |= (1<<3);
 ​
 temp = (uint8_t *)(0x40021000 + 0x18);
 *temp |= (1<<3);
 ​
 temp = (uint8_t *)(0x40010C00 + 0x0C);
 *temp |= (1<<0);
 //这三步利用指针可以更改数据的道理,在你家小区里不同的人家中篡改他家东西你可以这么理解
 //你在疯狂作案所以小心被抓到,所以(谨慎行事!)
 ​
 //所以说寄存器点灯很简单这里我就不传手册图片了,大家可以自行看看地址思考一下

寄存器点灯代码量少没有函数掺杂执行效率高

但是不利于项目开发,周期太长你要不停的去对手册浪费时间

而现在芯片执行效率很快也就一行代码一个机器周期的时间而已

  • 22
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一份简单的使用寄存器点亮LED的实验报告。 实验目的: 了解单片机基本输入输出操作,掌握使用寄存器控制GPIO口输出高低电平,掌握使用按键控制LED亮灭。 实验器材: 1. STC89C52单片机开发板 2. LED 3. 按键开关 4. 杜邦线 实验步骤: 1. 将LED的正极接单片机的P1口,负极接单片机的GND口。 2. 将按键开关的一端接单片机的P3口,另一端接单片机的GND口。 3. 打开Keil C51开发环境,新建一个工程。 4. 在工程中编写以下代码: ```c #include <reg52.h> void delay(unsigned int xms) { unsigned int i, j; for (i = xms; i > 0; i--) for (j = 112; j > 0; j--); } void main() { P1 = 0xfe; // 将P1口电平置高,使LED亮起 while (1) { if (P3 == 0) { // 当按键按下时 delay(10); // 延时去抖动 if (P3 == 0) { // 再次检测按键状态 P1 = ~P1; // 取反P1口电平,使LED亮灭交替 while(!P3); // 等待按键松开 delay(10); // 延时去抖动 } } } } ``` 5. 编译、烧录程序到单片机,并将开发板上电。 6. 按下按键,LED会亮起;再次按下按键,LED会熄灭。按键可以控制LED的亮灭交替。 实验结果: 实验成功,LED可以通过按键控制亮灭交替。 实验总结: 本次实验主要是通过控制单片机GPIO口输出高低电平来控制LED的亮灭。在实验中,我们还学习了使用按键控制LED亮灭的方法,同时还掌握了去抖动的技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值