0 卖盘信息
BOM询价
您现在的位置: 首页 > 电子资讯 >基础知识 > STM32F407[3] 闪烁LED

STM32F407[3] 闪烁LED

来源: zhihu
2021-12-07
类别:基础知识
eye 7
文章创建人 拍明

原标题:STM32F407[3] 闪烁LED

  按照上一小节的内容,我们已经能点亮LED了。同样的,把它熄灭非常简单:把对应GPIO设置为低电平即可。回忆上次的内容,想一下那个单刀双掷开关,对吧?

  快速开始

  结合一下,我们可以得到这样的思路:

  PD12设置为高电平

  PD12设置为低电平

  执行步骤1,循环往复

  这样的话,我们的灯就会闪烁起来了。至少理论上是这样的。用于设置GPIO低电平的函数和设置高电平的函数用法类似:

  GPIO_ResetBits(GPIOD, GPIO_Pin_12);

  上面代码即可将PD12设置为低电平,来我们对比一下将PD12设置为高电平的写法:

  GPIO_SetBits(GPIOD, GPIO_Pin_12);

  可以很明显的感觉到,它们基本是一样的。我们把这两个代码组合一下,按照我们的思路,很容易写出:

  while (1)

  {

  GPIO_SetBits(GPIOD, GPIO_Pin_12);

  GPIO_ResetBits(GPIOD, GPIO_Pin_12);

  }

  这样的话,理论上PD12就会高低电平频繁切换,我们也就能看到LED闪烁起来了。如果你不知道如何组合代码可以参照下图:

  


  好,首先编译,然后下载,最后按下板子的复位键。看到灯闪了吗?

  

如果没问题的话......


  看到灯闪了吗?没有?至少我是没有(理论上来说还是可以看到灯亮起的)。

  看不到闪烁的原因?

  我们一步步的来。

  检查我们的思路,是否有误:循环切换PD12的高低电平,高电平时候LED亮,低电平的时候LED灭,因此可以实现闪烁

  思路,很显然没问题。其次,是板子烧掉了吗?比如没法输出低电平?我找来了一个简陋的示波器(啊啊其实是因为自己穷啊,压根不是因为别的),观察PD12的波形:

  

PD12的波形,纵向一格是1V,横向一格是0.1us


  很明显,虽然波形有很明显的变形,但是依旧是先高电平(表现在矩形波上升到最高,然后持平),然后切换为低电平(即波形和x轴重合)。这说明,PD12正如我们期望中的,先输出高电平,然后切换为低电平,然后再切换为高电平...即,芯片是正常的。

  注意了一点,横向的一格是0.1us,而高低电平切换一次(一个周期)的时间只有0.3us左右...

  稍微玩点游戏的读者应该知道,我们游戏一般是垂直同步在60帧,此时已经几乎不可能感觉得到卡顿了。也就是1/60 ≈ 16.667ms。而我们的LED闪烁频率是每秒钟闪烁三百万次以上...换句话说,人眼压根不可能看得到这个LED在闪。

  评论区

  @Rivers-Jin

  提醒,查证了下,LED的响应速度也确实也没有这么高,所以本身它也不见得反应不过来。

  解决方案

  总归,人眼看不到我们的LED在闪烁,那么我们延长高电平的时间,也延长低电平的时间不就好了?如此一来,思路就变成这样了:

  PD12设置为高电平

  等待一段时间

  PD12设置为低电平

  等待一段时间

  回到步骤1,循环往复

  那么现在主要问题就在于怎么等待了。对于单片机,它只有一个核心的一个CPU,因此可以用一个最简单的方法:等待的时候一直做点什么事情不就完事了,比如一个空循环,循环一百万次:

  for (int i = 0; i < 1000000; i += 1)

  {

  // nothing to do

  }

  我们把它插入到设置高电平完成后和设置低电平设置完成后:

  while (1)

  {

  GPIO_SetBits(GPIOD, GPIO_Pin_12);

  for (int i = 0; i < 1000000; i += 1)

  {

  // nothing to do

  }

  GPIO_ResetBits(GPIOD, GPIO_Pin_12);

  for (int i = 0; i < 1000000; i += 1)

  {

  // nothing to do

  }

  }

  整合好你的代码,下载到单片机上运行,应该可以看到LED快速闪烁起来了。如果没有看到,那么就把1000000改大一点,这样就会有更多的等待时间。

  我们再测一遍PD12的波形,可以看到高电平持续时间和低电平持续的时间明显长了很多,一个i周期大概有0.15秒:

  

PD12波形,纵向1V每格,横向50ms每格


  规范代码

  我们的延时部分是一致的,这意味着我们可以把它独立开来,形成一个单独的过程(函数)。例如这样:

  // 延时等待

  // Mcnt表示循环几百万次

  void delay(int Mcnt)

  {

  for (int i = 0; i < 1000000 * Mcnt; i += 1)

  {

  // nothing to do

  }

  }

  如此一来,我们就可以把我们的代码变得更加漂亮了。我给程序丰富了点功能,使得四个灯能轮番亮起来,您可以尝试优化这段程序,让它看起来没这么傻:

  // 延时等待

  // Mcnt表示循环几百万次

  void delay(int Mcnt)

  {

  for (int i = 0; i < 1000000 * Mcnt; i += 1)

  {

  // nothing to do

  }

  }

  int main(void)

  {

  // GPID时钟

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  GPIO_InitTypeDef gpioInitInfo;

  gpioInitInfo.GPIO_Pin = GPIO_Pin_12 // 要初始化的有12,13,14,15这四个

  + GPIO_Pin_13

  + GPIO_Pin_14

  + GPIO_Pin_15;

  gpioInitInfo.GPIO_Mode = GPIO_Mode_OUT; // 输出模式

  gpioInitInfo.GPIO_OType = GPIO_OType_PP, // 推挽输出

  gpioInitInfo.GPIO_PuPd = GPIO_PuPd_NOPULL; // 没有上下拉电阻

  gpioInitInfo.GPIO_Speed = GPIO_Speed_100MHz; // 高速模式

  GPIO_Init(GPIOD, &gpioInitInfo); // 初始化GPIO, 即PD12, PD13, PD14, PD15

  while (1) // 死循环做下面这些事情

  {

  GPIO_ResetBits(GPIOD, GPIO_Pin_12); // PD12低电平

  GPIO_SetBits(GPIOD, GPIO_Pin_13); // PD13高电平

  delay(1); // 等待一段时间

  GPIO_ResetBits(GPIOD, GPIO_Pin_13); // PD13低电平

  GPIO_SetBits(GPIOD, GPIO_Pin_14); // PD14高电平

  delay(1); // 等待一段时间

  GPIO_ResetBits(GPIOD, GPIO_Pin_14); // PD14低电平

  GPIO_SetBits(GPIOD, GPIO_Pin_15); // PD15高电平

  delay(1); // 等待一段时间

  GPIO_ResetBits(GPIOD, GPIO_Pin_15); // PD15低电平

  GPIO_SetBits(GPIOD, GPIO_Pin_12); // PD12高电平

  delay(1); // 等待一段时间

  }

  }

  如果运行成功,板子上的四个LED会轮番亮起熄灭。

  SUMMARY

  闪烁LED的思路

  人眼看不到那么快的闪烁,因此需要适当延迟。事实上对于电路也是,一些硬件反应不过来,我们也需要适当延迟

  未解决的问题

  似乎没有

  F.A.Q.

  想到/被问到再补充


责任编辑:David

【免责声明】

1、本文内容、数据、图表等来源于网络引用或其他公开资料,版权归属原作者、原发表出处。若版权所有方对本文的引用持有异议,请联系拍明芯城(marketing@iczoom.com),本方将及时处理。

2、本文的引用仅供读者交流学习使用,不涉及商业目的。

3、本文内容仅代表作者观点,拍明芯城不对内容的准确性、可靠性或完整性提供明示或暗示的保证。读者阅读本文后做出的决定或行为,是基于自主意愿和独立判断做出的,请读者明确相关结果。

4、如需转载本方拥有版权的文章,请联系拍明芯城(marketing@iczoom.com)注明“转载原因”。未经允许私自转载拍明芯城将保留追究其法律责任的权利。

拍明芯城拥有对此声明的最终解释权。

标签: STM32F407 闪烁LED

相关资讯