【学习笔记】在STM32F103系列开发板上点亮LED的实例

学习的教程:杨桃电子《STM32入门100步》

使用的开发板:STM32_Mini

目录

板载LED原理图及LED点亮的条件

点亮LED需要注意的事:

有用到的几种设置GPIO状态的函数:

因此,led的初始化代码如下:

几种LED使用实例

第一种:LED常亮

第二种:LED闪烁

延时函数

第三种:呼吸灯

视觉暂留,亮度占空比

菜单切换

第四种:按键控制LED

配置KEY0

按键状态读取

无锁存

有锁存


板载LED原理图及LED点亮的条件

在开始之前,万年不变的就是配置LED需要使用的GPIO。在查看原理图得知,此开发板的LED0连接的引脚为PA8,需要置低电平(0),LED0才会点亮

点亮LED需要注意的事:

外围电路的不同,LED点亮的条件也不同,灯亮是因为两侧有电压差。此开发板的LED0是阴极(-)与PA8连接,阳极(+)与VCC3.3连接,那么,当PA8输出高电平时,LED两端无电压差,电流不流动,所以LED0不会点亮。反之,PA8输出低电平时,LED0被点亮。

同理可得,若LED0阴极接GND,正极接PA8,当PA8置高电平时,LED0也会亮,置于低电平时,LED0不会亮。

有用到的几种设置GPIO状态的函数:

  • GPIO_SetBits,设置指定的数据端口位
  • GPIO_ResetBits, 清除指定的数据端口位
  • GPIO_WriteBit, 设置或者清除指定的数据端口位

因此,led的初始化代码如下:

/*此为led.c的代码*/

#include "led.h"

void LED_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitTStruct;
	/*第一步,打开外设的时钟*/
    RCC_APB2PeriphClockCmd(LED0_GPIO_CLK, ENABLE);//A8
    /*第二步,配置外设初始化结构体*/	
	GPIO_InitTStruct.GPIO_Pin = LED0_GPIO_PIN;
	GPIO_InitTStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitTStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(LED0_GPIO_PORT,&GPIO_InitTStruct);
	/*第三步,调用外设初始化函数,把配置好的结构体成员写到寄存器里面*/
	GPIO_SetBits(LED0_GPIO_PORT,LED0_GPIO_PIN);//置高电平,LED初始状态为灭
 
}


/*此为led.h的代码*/

#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"

/* 定义LED连接的GPIO端口, 用户只需要修改下面的代码即可改变控制的LED引脚 */

#define LED0_GPIO_CLK  RCC_APB2Periph_GPIOA      /* GPIO端口时钟 */
#define LED0_GPIO_PORT GPIOA                     /* GPIO端口 */
#define LED0_GPIO_PIN  GPIO_Pin_8

#define LED0_OFF      GPIO_WriteBit(LED0_GPIO_PORT,LED0_GPIO_PIN,(BitAction)(1))
#define LED0_ON     GPIO_WriteBit(LED0_GPIO_PORT,LED0_GPIO_PIN,(BitAction)(0))

void LED_GPIO_Config(void);

#endif  /*__LED_H*/

几种LED使用实例

第一种:LED常亮

单独的点亮LED0

#include "stm32f10x.h"
#include "led.h"

int main(void)
 {
	 LED_GPIO_Config();
	 
	 while(1)
	 {
       LED0_ON;/*PA8输出低电平,led点亮*/
	 }
 }

第二种:LED闪烁

延时函数

在编写程序前,需要有一个延时函数。我是用的江协科技的Delay函数模块。

1-3 Delay函数模块 https://www.alipan.com/s/78wxYsgg8uG 点击链接保存,或者复制本段内容,打开「阿里云盘」APP

在前一种LED常亮的主函数中进行更改,添加了延时函数。

led灯点亮,延时一秒,熄灭,延时一秒,再点亮

#include "stm32f10x.h"
#include "led.h"
#include "Delay.h"

int main(void)
 {
	 LED_GPIO_Config();
	 
	 while(1)
	 {
       LED0_ON;/*PA8输出低电平,led点亮*/
       Delay_s(1);/*延时1s*/
       LED0_OFF;
       Delay_s(1);

	 }
 }

第三种:呼吸灯

视觉暂留,亮度占空比

(详见《STM32入门100步》P117)

在点亮部分的延时值为5us,熄灭500us时,在一个亮和灭的周期内,亮短熄灭长。由于视觉暂留现象,肉眼看到的LED亮度变更低。因此,通过延时值改变亮灭时间的占比,来改变LED的亮度。

LED 呼吸灯程序最终呈现的效果,就是刚刚实验所看到的呼吸灯效果。呼吸灯效果从过程上可拆分成两个部分:一是亮度逐渐变亮,二是亮度逐渐变暗

菜单切换

把不同功能的程序放入不同的菜单值判断中,通过改变菜单值来切换运行不同的程序。

在主函数的开头,定义了三个变量

uint8_t MENU;//菜单值

 uint16_t t,i;

/*变量t 是延时参数,t值增加,灯亮时间变长,则(501-t)是灯熄灭的时间*/

点亮和熄灭的一个周期总时长还是 501μ s,通过变量 t 的不断变化,就改变了 501μ s 中点亮和熄灭 LED 的时间,实现了占空比控制。

#include "stm32f10x.h"   // 相当于51单片机中的  #include <reg51.h>
#include "Delay.h"
#include "led.h"
#include <stdint.h>

int main(void)
{ 
	
	uint8_t MENU;
	uint16_t t,i;
	LED_GPIO_Config();
	MENU = 0;
	t = 1;
	while(1)
	{
	   if(MENU == 0) /*菜单0*/
		 {
			 for(i = 0;i < 10;i ++) /*目的:每循环10次,t的值才会加1*/
			 {
			   LED1_ON;
				 Delay_us(t);
				 LED1_OFF;
				 Delay_us(501 - t);
			 }
			 t ++;
			 if(t == 500)
			 {MENU = 1;}
		 }  
		 if(MENU == 1) /*菜单1*/
		 {
			 for(i = 0;i < 10;i ++)
			 {
			   LED1_ON;
				 Delay_us(t);
				 LED1_OFF;
				 Delay_us(501 - t);
			 }
			 t --;
			 if(t == 1)
			 {
                MENU = 0;
             }
		 }
	}
}

第四种:按键控制LED

通过原理图可知,KEY0连接的是PC1。在按键按下的时候,PC1接地,这个时候,I/O端口短接到电源负极。可以使用“GPIO_ReadInputDataBit”函数来读取I/O端口的电平状态。

所以,按下KEY0,低电平,松开KEY0,高电平。

配置KEY0

tips:当按键没有按下时需要让 I/O 端口保持在高电平。所以这里使用上拉电阻模式,即在按键没有被按下时让按键所连接的 I/O 端口没有连接 GND,是未接任何电路的悬空状态。设置为内部上拉电阻,I/O 端口则在悬空时仍保持高电平状态。当按键被按下时,I/O 端口与GND 短接,被 GND 强制变成低电平,单片机只要通过读取按键是高电平还是低电平,就能知道按键是否被按下。因为设置了 I/O 端口为上拉电阻输入模式。(详见《STM32入门100步》P121)

/*key.c*/

void KEY_GPIO_Config(void)
{
	
	GPIO_InitTypeDef  GPIO_InitStruct;
	/*开外设相关的时钟*/
	
	RCC_APB2PeriphClockCmd(KEY0_GPIO_CLK, ENABLE);
	
	//配置外设相关的结构体
	
	GPIO_InitStruct.GPIO_Pin = KEY0_GPIO_PIN |KEY1_GPIO_PIN;/*KEY1还没用到*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //输入,上拉电阻
	GPIO_Init(KEY0_GPIO_PORT,&GPIO_InitStruct);

    /*
	GPIO_Speed只针对IO端口在输出模式才有效
	*/
}


/*key.h*/

#include "stm32f10x.h"

/*KEY0 PC1  KEY1 PC13*/



#define KEY0_GPIO_CLK   RCC_APB2Periph_GPIOC
#define KEY0_GPIO_PORT  GPIOC
#define KEY0_GPIO_PIN   GPIO_Pin_1

#define KEY1_GPIO_CLK   RCC_APB2Periph_GPIOC
#define KEY1_GPIO_PORT  GPIOC
#define KEY1_GPIO_PIN   GPIO_Pin_13


#define digitalTOGGLE(p,i)   {p->ODR ^= i ;} 
//C语言知识点, ^ :两个数相 ^,相同的话为0,不同的话为1
#define LED0_TOGGLE           digitalTOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN) 
#define LED1_TOGGLE           digitalTOGGLE(LED1_GPIO_PORT,LED1_GPIO_PIN) 



void KEY_GPIO_Config(void);
uint8_t KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/*无锁存,按下亮*/
void KEY_ON_OFF(void);
/*有锁存*/
void KEY_Delay(void);

#endif /*__BSP_KEY_H*/

按键状态读取

有两种形式。

无锁存:按下就亮,松开就灭

有锁存:按一下亮,再按一下灭

无锁存

tips:if 语句里面调用了一个固件库函数 GPIO_ReadInputDataBit,也就是读取一个 I/O 端口的电平输入状态。此函数中有两个参数:第一个参数是使用哪个 I/O 端口组,第二个参数是端口号。那么 if 语句判断此 I/O 端口状态,如果读取到高电平(逻辑 1),表示 if 判断为真,则执行LED_OFF,把 LED 的 I/O 端口变成高电平,LED 熄灭;如果读取到低电平(逻辑 0),if 判断为假,则执行 else 里面的程序 LED_ON,将 LED 点亮。

void KEY_ON_OFF(void)
{
/*第一个方法*/
//	if(GPIO_ReadInputDataBit(KEY0_GPIO_PORT,KEY0_GPIO_PIN))/*读取按键的电平,返回值为输入端口管脚值,读取高电平为真,低电平为假*/
//		{
//	   LED0_OFF;
	  }else{
		   LED0_ON;
//		}
		
		/*新的方法*/
		GPIO_WriteBit(LED0_GPIO_PORT,LED0_GPIO_PIN,(BitAction)(GPIO_ReadInputDataBit(KEY0_GPIO_PORT,KEY0_GPIO_PIN)));/*没有按下是高电平,灯不亮*/
}

有锁存

/*有锁存*/
void KEY_Delay(void)
{
 if(!GPIO_ReadInputDataBit(KEY0_GPIO_PORT,KEY0_GPIO_PIN))/*读取按键的接口电平*/
 {
 Delay_ms(20);/*去抖动,我的按键卡死在消抖这里,删掉就可运行*/
	 if(!GPIO_ReadInputDataBit(KEY0_GPIO_PORT,KEY0_GPIO_PIN))/*再次读取按键的接口电平*/
	 {
		 GPIO_WriteBit(LED0_GPIO_PORT,LED0_GPIO_PIN,(BitAction)(1-GPIO_ReadOutputDataBit(LED0_GPIO_PORT,LED0_GPIO_PIN)));/*LED取反*/
		 while(!GPIO_ReadInputDataBit(KEY0_GPIO_PORT,KEY0_GPIO_PIN));/*判断按键是否松开*/
	 }
 }
}
 
 
/*
//STM32标准库提供了库函数GPIO_ReadInputDataBit来获取位状态
//该函数输入GPIO端口及引脚号
//函数返回该引脚的电平状态
//高电平返回1
//低电平返回0
*/

tips:先判断按键是否被按下,如果被按下则延时 20ms,再一次判断是否被按下,如果被按下则进行相对应的 LED 控制,最后等待按键被放开,只有按键被放开才退出程序。

这段程序我没运行成功,疑惑,以后再说

二进制控制灯的亮灭

使用的是PA0,PA1,高电平才会亮灯

GPIO初始化

#include "bsp_led.h"
void LED_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitTStruct;
    RCC_APB2PeriphClockCmd(GPIOA , ENABLE);
  	GPIO_InitTStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
	GPIO_InitTStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitTStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(LED0_GPIO_PORT,&GPIO_InitTStruct);

	GPIO_ResetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1);
}



具体的程序

void KEY_CON(void)
{
static uint8_t a;
if(!GPIO_ReadInputDataBit(KEY0_GPIO_PORT,KEY0_GPIO_PIN)){ 
			Delay_ms(20); /*我用了延时,程序动不了,你可以继续用*/
			if(!GPIO_ReadInputDataBit(KEY0_GPIO_PORT,KEY0_GPIO_PIN)){ 
				
				a++; 
				if(a>3)
				{
					a=0; 
				}
				GPIO_Write(GPIOA ,a); 
				while(!GPIO_ReadInputDataBit(KEY0_GPIO_PORT,KEY0_GPIO_PIN)); 
			}	
}
}

tips:定义的一个 8 位无符号变量。当按键确定被按下之后,便执行a++,也就是 a 的值加 1。初始状态下,变量 a 的值为 0,加 1 后为 1。下边使用了 GPIO_Write(GPIO,a),写入整组 I/O端口状态,写入的是 LEDPORT,也就是 PB 组端口,写入的值是变量 a,a 的值此时是 1,使得整组 16个 I/O 端口组中第 0 位(PA0)为 1,即 LED1 的状态为高电平点亮。当下一次按键被按下时,a 值又加1 等于 2,则 LED2 点亮;当下一次按键被按下时,a 再加 1 等于 3,在二进制数中,3 是 11,LED1 和LED2 同时点亮;当 a 值加到 4 时, if 语句发挥作用,判断 a 的值大于 3 则让 a 的值等于 0,再次写入就使得两个 LED 同时熄灭,也就实现了刚才实验的效果。

因为我没有加按键消抖,所以程序容易识别错误。

实现的视频

二进制点亮的效果

  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值