【蓝桥杯】嵌入式编程_LED模块

目录

认识led原理图

分析GPIO口寄存器

理解时钟的作用

实操部分---利用hal库生成led点亮代码


认识led原理图

 (图来源:CT117E-M4产品手册.pdf)

VDD多半是单极器件的正(理解为电源 可以输出高电平 高电平为3.3v)

R为电阻 (可以看到图中 电阻值为0.3k)

那个三角形带箭头的是期间led灯(发光二几管)

最右右边的数字就是GPIO的引脚了 这个可以直接用编程语言控制的

什么情况下led灯点亮? 高电平为3.3v 低电平为0v 有电压差超过0.7v就会有电流通过 有电流通过led就会被点亮

电阻的作用? I=V/R 如果没有电阻电流无限大 led会烧坏 所以最好控制在20mA以内 以上图为例3.3v/0.3k=11mA 如此电流流过led灯 就会被点亮

·什么是共阴/共阳极发光二极管? 以上图为例 所有的led灯都接在了电源一端 所以上图是共阳极发光二极管 GPIO的引脚输出低电平led点亮

思考?什么情况下是高电平点亮led灯

*得出结论*

PA8-PA15 低电平点亮led灯

分析GPIO口寄存器

硬件编程本质就是关于寄存器的编程

操作硬件转化为操作地址 地址用寄存器分布

cpu管脚有很多可以使用的功能 也可以多个复用 需要用到那个功能就开启

思考 cpu管脚为什么要这样设计?一个管脚就一个功能行吗?

想一想我们这次的目的! 把PA8-PA15当做输出功能用 输出低电平 点亮led灯

编程思路

先找相关的寄存器

打开STM32G4系列微控制器参考手册.pdf

361页 9.4 GPIO registers

*注意***table 57给出各个GPIO的寄存器的偏移地址** 加上GPIO的基地址就可以找到这个寄存器的地址了

我们先一个一个的看 判断当前的寄存器是否与本次编程有关

 这个寄存器是有用的设置端口功能模式 我们应该找到PA8-PA15 将相应的位设置为01 (通用输出方式)

 接下来设置输出模式下的类型

通用推挽输出 直接输出高电平或者低电平

选择输出速度 一般情况下 low speed的就可以

上拉和下拉一般给输入用 这里没有关系 设置为00 No pull-up pull-down

 

ODR就是那个关键的寄存器了

当8到15位的值为1 PA8-PA15就会输出高电平

当8到15位的值为0 PA8-PA15就会输出低电平

剩下的寄存器就与点灯无关了 也就说设置这几个寄存器就好了

理解时钟的作用

在STM32芯片的中 当我们要使用到外设设备时(GPIO就算一个)必须开启相应的时钟 这个设备才能正常工作

你可以这样理解时钟 时钟总线就是用电的总电闸,哪一个家用设备要用电 就只需对应的输出电就行了 ,对应的用电有电压 时钟也有相应的频率。这样理解是不是好多了

先看看芯片手册内部框图 —— STM32G431RB数据手册.pdf

可以看到GPIO挂在了APB2总线上

那么 我们使能APB2 外设时钟使能寄存器 让GPIO能够工作

如何配置相关寄存器 可以参考STM32G4系列微控制器参考手册.pdf RCC那一章

实操部分---利用hal库生成led点亮代码

初学者先跟着步骤做一遍 先练一个感觉!

1,新建项目文件

打开STM32CubeMX file--->newproject---找到STM32G431RBTx的芯片 双击选中

 2,配置RCC时钟 ---clock configuration

 

初次调值 相关的总线统一设置80MHz 便于后面学习 80怎样得到的?计算过程 24/3=8 8*20/2=80

3,选择pc8~pc15的输出功能 另外开启PD2的输出功能(PD2为锁存器 作用是 控制pc8-pc15的改变)

4,配置生成文件 右上角点击生成代码

Application structure --basic--MDK-ARM v5--copy all used libraries ---generate peripherad initializa.....

5.进入keil5 调整配置

void MX_GPIO_Init(void)
{
​
  GPIO_InitTypeDef GPIO_InitStruct = {0};
​
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
​
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
​
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
​
  /*Configure GPIO pins : PC13 PC14 PC15 PC8
                           PC9 PC10 PC11 PC12 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
​
  /*Configure GPIO pin : PD2 */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
​
}

这里初始化配置有点问题 :PD2并未置高电平 所以GPIO的引脚8-13没有配置成默认的高高电平

我们准备这样修改

在代码 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);改成HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);

最后一行 增加代码 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);

6.编写一个控制led的函数

PC8-PC15 正好为8位数可以构成一个char型 我们可以让函数接收一个char 根据位数点亮或熄灭led灯

void Led_Input_Disp(unsigned char input)
{
​
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    //思路先将pc8~12置为高电平熄灭   锁存器PD2 置高电平 pc引脚写入后PD2置为低电平
    
//    * @param  GPIO_Pin specifies the port bit to be written.
//  *         This parameter can be any combinatio n of GPIO_PIN_x where x can be (0..15).
      HAL_GPIO_WritePin(GPIOC, input<<8, GPIO_PIN_RESET);
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    //输入数左移8位 低电平点亮  再次重复PD2操作
}

测试所写函数是否正确

while (1)
​
 {
​
  /* USER CODE END WHILE */
​
        Led_Input_Disp(0x88);
​
        HAL_Delay(500);
​
        Led_Input_Disp(0x00);
​
        HAL_Delay(500);     
​
  /* USER CODE BEGIN 3 */
​
 }

led全亮、短暂延时后 led量全灭 达到持续闪灭的现象

最终形成的led.c文件参考

#include "led.h"
​
void MX_GPIO_led_Init(void)
{
​
  GPIO_InitTypeDef GPIO_InitStruct = {0};
​
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
​
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
​
  /*Configure GPIO pin Output Level */
    
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
​
  /*Configure GPIO pins : PC13 PC14 PC15 PC8
                           PC9 PC10 PC11 PC12 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
​
  /*Configure GPIO pin : PD2 */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    
​
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
​
}
​
void Led_Input_Disp(unsigned char input)
{
    //思路先将pc8~12置为高电平熄灭   锁存器PD2 置高电平 pc引脚写入后PD2置为低电平
    //输入数左移8位 低电平点亮  再次重复PD2操作
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
//    * @param  GPIO_Pin specifies the port bit to be written.
//  *         This parameter can be any combinatio n of GPIO_PIN_x where x can be (0..15).
      HAL_GPIO_WritePin(GPIOC, input<<8, GPIO_PIN_RESET);
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
}
#ifndef __LED_H__
#define __LED_H__
​
#include "main.h" 
void MX_GPIO_led_Init(void);
void Led_Input_Disp(unsigned char input);
​
#endif

为了实现的代码直观的可读性 单独新建一个rcc.c文件 存放 函数 SystemClock_Config 后面的外设如果修改了时钟我们进行全部的覆盖就可以了

#include "rcc.h"
​
void SystemClock_Config(void)
{
  /*配置覆盖区*/
​
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}
​
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
​
  /* USER CODE END Error_Handler_Debug */
}
#ifndef __RCC_H__
#define __RCC_H__
#include "main.h" 
void SystemClock_Config(void);
​
#endif

注意 函数 void Error_Handler(void) 默认在main.c定义过了 这可以让其他外设自动生成的配置中要用这个函数 不至于报错误

猜你喜欢

转载自blog.csdn.net/shelter1234567/article/details/129093628