历史上的今天
返回首页

历史上的今天

今天是:2024年09月13日(星期五)

正在发生

2021年09月13日 | STM8S自学笔记-003 GPIO输出:点亮LED灯 and 跑马灯特效

2021-09-13 来源:eefocus

点亮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 %drn", 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****/

推荐阅读

史海拾趣

Acculin Inc公司的发展小趣事

Acculin Inc深知人才是企业发展的核心。为了吸引和留住优秀人才,公司建立了完善的培训体系,并为员工提供了良好的晋升机会。此外,公司还注重团队建设,通过举办各种团建活动活动增强员工之间的凝聚力。这些举措使得Acculin在人才竞争激烈的市场中保持了优势。

Datatronic公司的发展小趣事

随着环保意识的提高,Datatronic公司开始探索绿色发展的道路。公司注重节能减排和资源循环利用,通过改进生产工艺和使用环保材料等方式降低对环境的影响。同时,公司还积极推广绿色产品和技术,引导客户树立绿色消费观念。这些努力使得Datatronic公司在环保方面取得了显著成效,赢得了社会的广泛赞誉。

益升华(Essentra)公司的发展小趣事

在电子产品的保护领域,益升华(Essentra)公司一直走在行业前列。多年前,公司研发团队发现市场上缺乏一种既轻便又耐用的塑料保护盖。于是,他们投入大量资源进行研发,经过数百次的试验和改进,最终成功开发出一种新型的塑料保护盖,它不仅具备优异的抗冲击性和耐磨损性,还能有效隔绝外界环境中的静电和尘埃。这一创新产品迅速获得市场的认可,为益升华(Essentra)公司带来了可观的收益。

Hasco Relays and Electronics International Corp公司的发展小趣事

随着时间的推移,Harris公司逐渐与国防工业建立了紧密的联系。在二战及随后的冷战时期,Harris为军事机构提供了大量的通信设备和技术支持,包括雷达系统、导航系统以及加密通信设备等。这些技术不仅帮助军队在战场上保持高效的通信能力,还极大地提升了国家的国防安全水平。Harris在国防领域的卓越表现,进一步巩固了其在电子行业中的领先地位。

EA Elektro-Automatik公司的发展小趣事

近年来,中国市场对EA Elektro-Automatik来说变得越来越重要。公司高层认识到了中国市场的巨大潜力和重要性,并制定了在中国市场继续投资和实现增长的明确计划。EA Elektro-Automatik的代表在多个场合与中国政府和行业领导进行交流和合作,努力拓展中国市场。目前,中国市场已经占据EA Elektro-Automatik全球业务的相当一部分份额,并有望在未来继续保持增长。

Aeroflex Metelics / Hi-Rel Components公司的发展小趣事

近年来,中国市场对EA Elektro-Automatik来说变得越来越重要。公司高层认识到了中国市场的巨大潜力和重要性,并制定了在中国市场继续投资和实现增长的明确计划。EA Elektro-Automatik的代表在多个场合与中国政府和行业领导进行交流和合作,努力拓展中国市场。目前,中国市场已经占据EA Elektro-Automatik全球业务的相当一部分份额,并有望在未来继续保持增长。

问答坊 | AI 解惑

过滤口罩常见使用问题

问题1:是不是越小的粉尘,越难被口罩过滤呢?   解答:一般而言,我们会以为越小的粉尘越难被过滤,但这是个似是而非的观念,以过滤理论而言,主要有五种过滤粉尘的方法:(1)布郎运动[Brownian Diffusion]-对越小的粒子,效应越强。(2)拦 ...…

查看全部问答>

LCD图形取模

请问下大家,LCD图形取模都用的是哪些软件啊?介绍下啊。…

查看全部问答>

我自己的USB2.0仿真器烧写经验-三恒星

DSP烧写方法 1、TMS320LF24xx, TMS320LF28xx:   利用CCS里面自带的flash burn插件,很容易烧写。   不必专门编程,只要输入.out文件即可。 2、TMS320C5x   需要自己手工编写BootLoader程序,和烧写flash ...…

查看全部问答>

SAA7113 不能产生LLC信号

我用SAA7113对视频信号进行A/D转换,芯片输入时钟采用晶振产生,波形正常,可是LLC管脚怎么也出不来信号,一直为低电平。电路图是按照datasheet上给的。求教原因。…

查看全部问答>

sfilter编译问题ntifs.h

我建了一个工程然后把sfilter.c加进来,编译的时候老是有如下的错误: C:\\WINDDK\\2600.1106\\INC\\DDK\\WXP\\ntddk.h(23) : fatal error C1189: #error :  Compiler version not supported by Windows DDK queue.c C:\\WINDDK\\2600 ...…

查看全部问答>

有人做过WHQL认证吗?

我的NDIS中间层驱动要在64位Windows 7上使用,是不是必须要有WHQL认证?怎么才能取得这个认证?…

查看全部问答>

1602字符lcd问题,急

相信不少人都调试过吧! 那个忙检测到底怎么实现,读时序是怎么样的,主要是 E 脚的时序, 所以我现在都是用一段delay来了事, 看过厂商的文档了觉得有错误,他的时序图和后面的文字描述以及后面的示例代码好像有矛盾。 文档上说,E下降沿开始 ...…

查看全部问答>

【新发布的应用笔记】STM32F10xxxLCD驱动固件

AN2656 - STM32F10xxx LCD glass driver firmwareIntroductionThis application note describes a technique for driving liquid crystal displays (L ...…

查看全部问答>

请教一个 关于时钟发生器的问题

大家好: 最近在看时钟发生器,我是新手,看的是ADI公司的AD9517,文档介绍说时钟发生器,可以采用外部VCO输入,我想问下,这个外部VCO输入是不是通过CLK管脚输入的。 还有就是PLL的1路差分或2路单端基准输入基准监控功能,有什么作用。 还有就 ...…

查看全部问答>