天天看点

学习STM32mini版(流水灯)

用STM32mini版写一个流水灯

今天,我用STM32mini版来写一个流水灯,自己的能力有限,是个小白,有不完美或者不对的的地方还望赐教。不喜勿喷。

学习一个新东西是一件很开心的事情,但是,自学一件从来没有接触过的事物,或许有点恶心。但是对于32单片机和51单片机的自学者来说,没有什么是比自己点亮流水灯更让人兴奋地了。确实,点亮了流水灯,剩下的无非就是学习其他硬件资源的控制方法。

本文接下来会介绍,流水灯的点亮方式和操作过程中遇到的问题及其解决办法。

为什么学习每一种板子都要从流水灯开始?因为点亮了流水灯,就足以表明学习者对GPIO口可以进行简单操作了,而且对后续模块学习的调试环节也有一定的指示作用。

本次实验用的是STM32mini来进行操作的(不管什么版本,基本操作都一样)。其电路图如图1-1所示。

学习STM32mini版(流水灯)
学习STM32mini版(流水灯)

要想点亮流水灯,就需要先点亮一个LED灯。

点亮一个LED灯

LED灯是怎样被点亮的呢?众所周知,LED都是单向导电的,简单来讲,在一个固定的通电方向上,只要LED中流过足够的电流,它就发光。现在就是不知道这个足够的电流是多少。那上面图中的LED接口电路来说,它是由右向左导通的,以LED0为例,当LED0右端PB5输出高电平时,电阻和LED两端的总电压为3.3V,那么就由欧姆定律很容易的就可以判断出LED0的电流不会超过3.3mA,因为LED0内部也是有电阻的,因此可以判断LED0发光时流经的电流是小于3.3mA的,一般为1~2mA就会发光。

现在的关键问题是什么呢?问题就是“如何实用程序来控制LED0的PB5输出高电平?”

控制PB5输出高电平的方法可以概述为:

1、找到PB口的控制寄存器,将其设置为输出模式;

2、找到PB口的数据寄存器,将该寄存器中控制PB5的控制位的值设置为1;

3、右端管脚就会输出高电平,相应的LED就会被点亮。

接下来就需要查看具体的PB口控制寄存器、PB口数据寄存器的具体地址以及使用方法。不同的处理器的操作方法都是相似的,不同的寄存器名字可能有所不同,各个寄存器的地址可能有所不同,这样就会使操作变得十分繁琐,为了解决这个问题ST公司的工程师已经把这些东西以固件库的形式提供给广大用户了,使用固件库,自学者只需要了解固件库提供的函数然后调用即可。(笔者将会在另一篇文章中来具体介绍固件库)

流水灯程序分析

尽管还没有介绍固件库函数,但是还是建议看完以下代码的分析。不用通篇理解只需要看一下库函数使用的具体例子即可。咱们日后会对程序段中使用到的函数进行具体的分析。

#include"stm32f10x_gpio.h"

#define Led1_On()    GPIO_SetBits(GPIOB,GPIO_Pin_5)
#define Led1_Off()   GPIO_ResetBits(GPIOB,GPIO_Pin_5)

#define Led2_On()    GPIO_SetBits(GPIOD,GPIO_Pin_6)
#define Led2_Off()   GPIO_ResetBits(GPIOD,GPIO_Pin_6)

#define Led3_On()    GPIO_SetBits(GPIOD,GPIO_Pin_3)
#define Led3_Off()   GPIO_ResetBits(GPIOD,GPIO_Pin_3)
           

第1行,既然使用了固件库中的函数,那么就需要包含库函数的头文件了。

第2~3行,实现对PB引脚的位置和复位操作,也就是点亮LED,熄灭LED。

第4~7行,实现对PD6、PD3引脚的位置和复位操作。

void LED_Init(void);
void Delay(__IO uint32_t nCount);
           

第8~9行声明了两个函数。

void Delay(unsigned int nCount)
{
    for(;nCount!=0;nCount--);
}
           

上述是一个延时函数,实现一定时间的延时。

void LED_Init(void)
{
    GPIO_InitTypeDef   GPIO_Structure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);

    GPIO_Structure.GPIO_Pin=GPIO_Pin_5;
    GPIO_Structure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_Structure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Iint(GPIOB,&GPIO_Sructure);
    
    GPIO_Structure.GPIO_Pin=GPIO_Pin_6;
    GPIO_Structure.GPIO_Pin=GPIO_Pin_3;
    GPIO_Iint(GPIOD,&GPIO_Sructure);
}
           

上述函数中只有三条语句没有讲解,其他语句相信都有似曾相识的感觉。

第10行,定义了一个GPIO——InitTypeDef类型的结构体变量GPIO_Structure,即通过该语句找到了“快递盒子”。

第13~15行,对结构体变量GPIO_Structure中的值进行了初始化,可以理解为向“盒子”里面填东西,当然填哪些东西是需要注意的。当然具体需要填什么,固件库已经给你定义好了。随着更加深入的学习会更加了解。

第16行,调用GPIO_Iint()函数进行“快递”,此时相当于“发送快递”了,剩下的就看函数的了。

第17和19行,类似于13~16行。

第16行,这行程序的意思初始化IO口的翻转速度,一个IO口可以实现时而输出高电平,时而输出低电平。但是涉及一个最大翻转速度的问题,这个函数就是对此定义的。

此外,我们对比第16、19行可以看出,GPIO_Iint()函数的第一个参数决定了“快递”的目的地地址,但是接收的方式可以有很多。

学习STM32mini版(流水灯)
int main(void)
{
   SystemInit();
   LED_Init();

   while(1)
   {
       led1_On();Led2_Off();Led3_Off();
       Delay(0x8FFFF);
       led1_Off();Led2_On();Led3_Off();
      
       Delay(0x8FFFF);
       led1_Off();Led2_Off();Led3_On();
       Delay(0x8FFFF);
   }
}
           

第20行,调用SystemInit()函数,又会有个疑问,这是个什么函数?这也是固件库中的函数。此函数主要是实现对处理器时钟的初始化工作。我们在这里主要记住:一般在主函数力需要首先调用该函数。就这一点就行了。

第21行,调用LED_Init()函数,进行初始化。

第22~28行,才是真正实现了流水灯的效果的函数。

笔者提问望读者评论

启动代码是如何工作的?

什么时候用main作为主函数名?

源程序

#include"stm32f10x_gpio.h"

#define Led1_On()    GPIO_SetBits(GPIOB,GPIO_Pin_5)
#define Led1_Off()   GPIO_ResetBits(GPIOB,GPIO_Pin_5)

#define Led2_On()    GPIO_SetBits(GPIOD,GPIO_Pin_6)
#define Led2_Off()   GPIO_ResetBits(GPIOD,GPIO_Pin_6)

#define Led3_On()    GPIO_SetBits(GPIOD,GPIO_Pin_3)
#define Led3_Off()   GPIO_ResetBits(GPIOD,GPIO_Pin_3)

void LED_Init(void);
void Delay(__IO uint32_t nCount);

void LED_Init(void)
{
    GPIO_InitTypeDef   GPIO_Structure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);

    GPIO_Structure.GPIO_Pin=GPIO_Pin_5;
    GPIO_Structure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_Structure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Iint(GPIOB,&GPIO_Sructure);
    
    GPIO_Structure.GPIO_Pin=GPIO_Pin_6;
    GPIO_Structure.GPIO_Pin=GPIO_Pin_3;
    GPIO_Iint(GPIOD,&GPIO_Sructure);
}

int main(void)
{
   SystemInit();
   LED_Init();

   while(1)
   {
       led1_On();Led2_Off();Led3_Off();
       Delay(0x8FFFF);
       led1_Off();Led2_On();Led3_Off();
      
       Delay(0x8FFFF);
       led1_Off();Led2_Off();Led3_On();
       Delay(0x8FFFF);
   }
}

void Delay(unsigned int nCount)
{
    for(;nCount!=0;nCount--);
}