【蓝桥杯】【嵌入式组别】第三节:LED灯的点亮

1.LED电路原理

打开《CT117E-M4产品手册》,在第11页可以看到LED灯的电路原理图:
在这里插入图片描述

图中所示的属于LED共阳接法,LED负极接低电平则LED点亮。
所以如何将LED的负极赋值为低电平呢?就需要看74HC573这个锁存器的用法。
锁存器一边接的是LED灯的负极一端,而另一边是单片机的PC8~PC15端口。
而为什么不直接将单片机的PC8~PC15端口接到LED灯的负极一端呢?是因为在这个开发板上,PC8-PC15端口还在LCD的驱动方面起着作用,如下图。所以这几个端口有多个复用功能,无法直接连接到LED灯的负极。
在这里插入图片描述

所以点亮LED灯需要用到这几个端口的复用功能。

74HC573锁存器相当于“门锁”,PD2是打开“门锁”的“钥匙”;PD2为高电平时,D和Q的电平相同,也就是可以将D端的数据传到Q端。PD2是低电平时,Q的电平保持,D端电平变化并不会影响到D端。
OE管脚是芯片的使能管脚,把OE管脚接地则可以使芯片处于工作状态。

所以如果想让LED1点亮,LED2熄灭,则先将PC1赋值为低电平,PC2赋值为高电平,然后将PD2赋值为高电平(也就是打开门锁),则此时可以将D端的数据传入到Q端,然后即使关闭门锁。从而实现点亮LED1,熄灭LED2的操作。

2.操作锁存器的原则

在打开锁存器前,需要保持PC8-PC15数据的稳定;在关闭锁存器后,才可以改变数据。
所以必须先让PC口输出数据控制LED,再打开锁存器(PD2高电平),再关闭锁存器(PD2低电平),让Q端数据保持稳定。

3.程序设计(CubeMX与keil)

1)程序设计步骤:

  • 从【赛场资源】里复制一份程序作为【模板】;一份作为【编程工程】(【模板】作为STM32CubeMX生成代码的工程;【编程工程】作为自己编写代码的工程,并从【模板】里移植代码)
  • 设置LED相关的GPIO为【推挽输出】模式;(PC8~PC15和PD2)
  • STM32CubeMX设置将每个外设单独生成.c和.h文件,并生成代码;
  • 下载程序时,需要设置Debug-Flash Download-添加stm32G4的下载算法;(下载程序,查看LCD显示是否正常)
  • 编写led.c和led.h文件,并添加到工程中,编写LED_Control函数用于控制LED灯模块
  • 在main.c添加led.h,并调用LED_Control函数,完成LED控制

2)实际操作

赛场资源包一共会提供两个工程文件,一个是基于HAL库的,一个是基于LL库的,里边都包含液晶显示屏的驱动例程(因为这个编写比较难,所以一般都会提供),我们一般使用的是HAL库。
在这里插入图片描述

我们复制两份HAL库的工程文件到我们创建的文件夹,一份作为模板工程,一份作为编程工程。分别命名为programming和template
在这里插入图片描述

由于LED灯编程比较简单,本次可以直接使用编程工程进行stm32cube的代码生成。

首先打开programming工程文件的cube文件:
在这里插入图片描述

打开后会弹出让更新固件包的提示框,因为我们用的是1.20版本的固件包,而最新的是1.40版本的,但是为了和比赛所用的保持一致,我们最好保持不变,仍旧用1.20版本的固件包,所以选择continue即可。
在这里插入图片描述

打开工程文件后我们需要设置PC8~PC15和PD2为推挽输出模式,但是打开后会发现PC8-PC15已经设置为推挽输出模式了,因为液晶屏幕的初始化需要用到这些端口,所以我们只需要设置PD2为输出模式即可。
在这里插入图片描述

最终界面应该如下所示:
在这里插入图片描述

然后点击左边栏的System Core下边的GPIO选项,可以查看每一个GPIO设置的什么模式,通过查看其中的“GPIO mode”一栏可以看到每一个都默认配置的是推挽输出功能。
在这里插入图片描述

而旁边的“GPIO output level”这一栏显示的是管脚一上电会被赋予的电平高低值,这个保持默认即可,无需改动。
在这里插入图片描述

右边的“GPIO-pull up/pull down”一栏显示的是是否配置上拉下拉电阻。由于我们用的是推挽输出模式,所以不用配置上下拉电阻。
在这里插入图片描述

点到RCC部分发现使用的是外部晶振,也已经配置好了。
在这里插入图片描述

时钟树也是配置好的,就都保持默认即可。
在这里插入图片描述

接下来来到工程配置界面,将IDE改成keilV5。在code generator中将“生成.c/.h文件”这个选项勾上。
在这里插入图片描述
在这里插入图片描述

然后生成代码。
在这里插入图片描述

然后进入工程文件:
首先点击“Rebuild”,,查看有没有编译错误。发现没有编译错误之后可以编写自己的文件。
在这里插入图片描述

我们尽量实现模块化编程,所以将led的功能单独放到“led.c”和“led.h”文件中。
点击此处的“新建文件”,新建文件之后点击“保存”:
在这里插入图片描述

在programming 工程的src目录下保存该文件,文件名为"led.c"。
在这里插入图片描述

以相同的操作在programming 工程的Inc目录下添加“led.h”文件。
在这里插入图片描述

在keil工程中添加"led.c"文件。(双击“Application/User”选项,找到Src路径,选中相应文件,点击添加)

在这里插入图片描述
之后就可以开始"led.c"与"led.h"文件的编写了。
有两种写法:

①led.h文件:

#ifndef __led_H
#define __led_H//这两句话,还有最后一句的endif,是头文件的基本格式,作用是防止某些宏定义的重复定义
#include "main.h"
void LED_Control(uint16_t led_ctrl);//对led.c中定义的函数进行声明
#endif

①led.c文件:

#include "led.h"
//传入的参数之所以类型是uint16_t ,是因为GPIO_PIN_X的数据类型都是uint16_t 。
void LED_Control(uint16_t led_ctrl)
{
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15|GPIO_PIN_14|GPIO_PIN_13|GPIO_PIN_12|GPIO_PIN_11|GPIO_PIN_10|GPIO_PIN_9|GPIO_PIN_8,GPIO_PIN_SET);
		//上面一句作用是用“HAL_GPIO_WritePin”函数将所有位都置为高电平
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
	    //通过开关锁存器将高电平从D端输送到Q端,并保持。这里实现的功能是将所有led灯熄灭
		HAL_GPIO_WritePin(GPIOC,led_ctrl,GPIO_PIN_RESET);
		//具体把哪一位置为低电平,由传入特定的参数而定
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
		//把特定位的led灯点亮
}

②led.h:

#ifndef __led_H
#define __led_H//这两句话,还有最后一句的endif,是头文件的基本格式,作用是防止某些宏定义的重复定义
#include "main.h"
void LED_Control(u8 led_ctrl);//对led.c中定义的函数进行声明
#endif

②led.c:

#include "led.h"
void LED_Control(u8 led_ctrl)
{
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15|GPIO_PIN_14|GPIO_PIN_13|GPIO_PIN_12|GPIO_PIN_11|GPIO_PIN_10|GPIO_PIN_9|GPIO_PIN_8,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
	
	HAL_GPIO_WritePin(GPIOC,led_ctrl<<8,GPIO_PIN_RESET);
	//因为u8的位数就是0x01,0x02这样,但是GPIO_PIN_X的位数是0x0100这样的,所以我们需要把我们的u8进行移位,就可以得到u16的数了。例如:0x01<<8=0x0100=GPIO_Pin_8.
	//输入0x55是间隔点亮
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

然后编写main.c文件:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "led.h" //此处一定要记得添加自己编写的led.h头文件,因为里边包含LED_Control函数的声明,不包含的话编译器找不到此函数,会报错
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */
	
	LCD_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	
	LCD_Clear(Blue);
	LCD_SetBackColor(Blue);
	LCD_SetTextColor(White);
	
	LCD_DisplayStringLine(Line0, (uint8_t *)"                    ");
	LCD_DisplayStringLine(Line1, (uint8_t *)"                    ");
	LCD_DisplayStringLine(Line2, (uint8_t *)"      LCD Test      ");
	LCD_DisplayStringLine(Line3, (uint8_t *)"                    ");
	LCD_DisplayStringLine(Line4, (uint8_t *)"                    ");
	
	LCD_SetBackColor(White);
	LCD_SetTextColor(Blue);

	LCD_DisplayStringLine(Line5, (uint8_t *)"                    ");
	LCD_DisplayStringLine(Line6, (uint8_t *)"       HAL LIB      ");
	LCD_DisplayStringLine(Line7, (uint8_t *)"                    ");
	LCD_DisplayStringLine(Line8, (uint8_t *)"         @80        ");
	LCD_DisplayStringLine(Line9, (uint8_t *)"                    ");
	
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    //自己真正编写的部分都要写在“USER CODE BEGIN”后边,此处只有一句话,功能是点亮led8
		LED_Control(GPIO_PIN_15);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
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 */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

编译无错之后就可以准备下载了。
最后需要配置一下debug下载算法才能下载到板子上:
首先选择用“CMSIS-DAP Debugger”
在这里插入图片描述

之后点击"Settings":
在这里插入图片描述

最后点击“下载”,即可将代码下载到板子上。最后可以看到板子的led8是亮的,其他led都是处于熄灭状态,则该项目就编写成功了。

如果有想要工程文件的小伙伴可以留言,我看有没有人要,有人要的话我就传一下。

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兜兜里有好多糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值