STM8S自学笔记-003 GPIO输出:点亮LED灯 and 跑马灯特效
【修订记录】
1、20181226,第一版
2、20210315,错别字修正,简化文字表述
3、20210321,错误修正
4、20210808,将应用层代码与底层代码分离,增加目录
点亮LED
点亮一个LED灯,应该是大多数单片机教程的第一步。这是最简单的一步。
GPIO初始化函数:GPIO_Init()
通常,要对LED所在的单片机的LED引脚 Px(y) 进行:
模式设置
①输出模式
②哪一种输出方式)
电平设置
③高/低电平
才能够点亮LED。看上去,至少也要三个语句,方能实现对LED的控制;但是,在STM8S中,只要一个句子就可以实现!
//假设该LED是灌电流方式
GPIO_Init( GPIOC , GPIO_PIN_3 , GPIO_MODE_OUT_PP_LOW_SLOW );
来分析上面的句子:
-
它调用了库函数stm8s_gpio.c中的GPIO初始化函数-GPIO_Init(),该函数可将指定的引脚配置为你想要的状态。函数的入口有三个参数:GPIOx, GPIO_Pin, GPIO_Mode
-
GPIOx:GPIO分组
-
GPIO_Pin:PIN编号
-
GPIO_Mode:模式配置,包含引脚模式、速度、电平、中断
短短一句话完成了所有的设置,言简意赅。
GPIO电平操作库函数:GPIO_WriteHigh()、GPIO_WriteLow()、GPIO_WriteReverse()
如果要在点亮LED之后熄灭它呢,你可以写成:
GPIO_Init( GPIOC , GPIO_PIN_3 , GPIO_MODE_OUT_PP_HIGH_SLOW );
这样做,的确是熄灭了LED,但在改变IO电平的同时还把IO再次执行了初始化,后者是无用的,还浪费CPU程序资源。
我们需要新的办法,来加快只改变输出电平的操作。而库函数里也的确有这样的函数:
GPIO_WriteHigh( GPIOC , GPIO_PIN_3 ); //PC3输出高电平
GPIO_WriteLow( GPIOC , GPIO_PIN_3 ); //PC3输出低电平
GPIO_WriteReverse( GPIOC ,GPIO_PIN_3 ); //PC3输出电平取反
进入倒函数内部,你会发现这三个函数只操作了GPIOC->ODR(输出寄存器)。
LED控制代码
在《STM8S自学笔记-002 STM8初上手和开发环境的建立》中,我有介绍自己用的开发板。上面有三个LED灯,从左到右依次接在PC3,PC4和PD2上。我用宏定义给他们编了号,方便后续的开发,包含Drv_GPIO.c和Drv_GPIO.h。
新建源文件【Drv _GPIO.c】
/**
******************************************************************************
* @file Drv_GPIO.c
* @author Elsa
* @version V1.0.0
* @date 7-August-2021
* @brief
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "Drv_GPIO.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief Initializes the LEDx according to the specified parameters.
* @param LED_MAP : This parameter contains the pin number
* @retval None
*/
void LED_Init(uint8_t LED_MAP)
{
if (LED_MAP & LED1) GPIO_Init(LED1_GPIO, LED1_GPIO_PIN, GPIO_MODE_OUT_PP_LOW_SLOW); //LED1 ON
if (LED_MAP & LED2) GPIO_Init(LED2_GPIO, LED2_GPIO_PIN, GPIO_MODE_OUT_PP_LOW_SLOW); //LED2 ON
if (LED_MAP & LED3) GPIO_Init(LED3_GPIO, LED3_GPIO_PIN, GPIO_MODE_OUT_PP_LOW_SLOW); //LED3 ON
}
/**
* @brief Light on the specified LEDs.
* @param LED_MAP : This parameter contains the pin number
* @retval None
*/
void LED_On(uint8_t LED_MAP)
{
if (LED_MAP & LED1) GPIO_WriteLow(LED1_GPIO, LED1_GPIO_PIN);
if (LED_MAP & LED2) GPIO_WriteLow(LED2_GPIO, LED2_GPIO_PIN);
if (LED_MAP & LED3) GPIO_WriteLow(LED3_GPIO, LED3_GPIO_PIN);
}
/**
* @brief Light off the specified LEDs.
* @param LED_MAP : This parameter contains the pin number
* @retval None
*/
void LED_Off(uint8_t LED_MAP)
{
if (LED_MAP & LED1) GPIO_WriteHigh(LED1_GPIO, LED1_GPIO_PIN);
if (LED_MAP & LED2) GPIO_WriteHigh(LED2_GPIO, LED2_GPIO_PIN);
if (LED_MAP & LED3) GPIO_WriteHigh(LED3_GPIO, LED3_GPIO_PIN);
}
/**
* @brief Blink the specified LEDs.
* @param LED_MAP : This parameter contains the pin number
* @retval None
*/
void LED_Reverse(uint8_t LED_MAP)
{
if (LED_MAP & LED1) GPIO_WriteReverse(LED1_GPIO, LED1_GPIO_PIN);
if (LED_MAP & LED2) GPIO_WriteReverse(LED2_GPIO, LED2_GPIO_PIN);
if (LED_MAP & LED3) GPIO_WriteReverse(LED3_GPIO, LED3_GPIO_PIN);
}
/**
* @brief Control the specified LEDs.
* @param LED_MAP : This parameter contains the pin number
* @retval None
*/
void LED_Control(uint8_t LED_MAP)
{
if (LED_MAP & LED1) GPIO_WriteLow(LED1_GPIO, LED1_GPIO_PIN);
else GPIO_WriteHigh(LED1_GPIO, LED1_GPIO_PIN);
if (LED_MAP & LED2) GPIO_WriteLow(LED2_GPIO, LED2_GPIO_PIN);
else GPIO_WriteHigh(LED2_GPIO, LED2_GPIO_PIN);
if (LED_MAP & LED3) GPIO_WriteLow(LED3_GPIO, LED3_GPIO_PIN);
else GPIO_WriteHigh(LED3_GPIO, LED3_GPIO_PIN);
}
新建头文件【Drv _GPIO.h】
/**
******************************************************************************
* @file Drv_GPIO.h
* @author ANNA
* @version V1.0.0
* @date 03-August-2021
* @brief This file contains the headers of the Drv_GPIO.c
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __DRV_GPIO_H
#define __DRV_GPIO_H
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Exported types ------------------------------------------------------------*/
/* Exported defines ----------------------------------------------------------*/
//Maps of LEDx
#define LED(n) ((uint8_t)(0x01<<(uint8_t)(n-1)))
#define LED1 LED(1)
#define LED2 LED(2)
#define LED3 LED(3)
//GPIO Definition of LEDx
#define LED1_GPIO_PIN GPIO_PIN_3
#define LED2_GPIO_PIN GPIO_PIN_4
#define LED3_GPIO_PIN GPIO_PIN_2
#define LED1_GPIO GPIOC
#define LED2_GPIO GPIOC
#define LED3_GPIO GPIOD
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
void LED_Init(uint8_t LED_MAP);
void LED_On(uint8_t LED_MAP);
void LED_Off(uint8_t LED_MAP);
void LED_Reverse(uint8_t LED_MAP);
void LED_Control(uint8_t LED_MAP);
#endif
跑马灯
跑马灯原理
其实跑马灯真么什么好说的。想实现这个效果,你至少要有三个LED,而且它们在物理上要排成一行,这样看的才明显。
实现的原理也很简单:
- 只开第一个LED;
- 只开第二个LED;
- 只开第三个LED;
- 返回1 。
为了方便肉眼观察,还需要在1、2、3步的尾部各追加一个延时函数。
简单的延时函数如下:
#define Delay(n) while(n--)
跑马灯代码
源文件【main.c】的内容
/**
******************************************************************************
* @file main.c
* @author Annakin
* @version V1.0.0
* @date 21-March-2018
* @brief
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define Delay(n) while(n--)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void Easy_Delay(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Main program.
* @param None
* @retval None
*/
void main(void)
{
LED_Init(LED1 | LED2 | LED3);
while (1)
{
LED_Control(LED1);
Easy_Delay();
LED_Control(LED2);
Easy_Delay();
LED_Control(LED3);
Easy_Delay();
}
}
void Easy_Delay(void)
{
uint16_t i = 60000;
Delay(i);
}
#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(u8* file, u32 line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
源文件【main.h】的内容
#ifndef __MAIN_H
#define __MAIN_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
#include "stm8s_it.h"
#include "Drv_GPIO.h"
/* Exported types ------------------------------------------------------------*/
/* Exported defines ----------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
#endif
/***************************************************************END OF FILE****/
更完备的延时函数,它们和时钟系统有关系,让我们一起期待《STM8S自学笔记-004 时钟》和《STM8S自学笔记-005 精准延时》。