STM32F1库函数版本章节1 LED灯学习

       以下只是个人学习的要点和个人观点,若整理的知识要点有问题,可以提出来,一起学习进步,嘻嘻嘻。

       自毕业一年以后,我和我的一位学长住在了一起,最近和他探讨学习中,我被他喷的一无是处,作为一个嵌入式开发工程师,我的底子太薄了,所以我要重新学习单片机。

        我们就从最简单的程序开始把,点亮一个LED灯。

        看一下正点原子的程序:

#include "sys.h"
#include "delay.h"
#include "led.h"
 
 int main(void)
 {    
    delay_init();        //延时函数初始化      
    LED_Init();              //初始化与LED连接的硬件接口
    while(1)
    {
        LED0=0;
        LED1=1;
        delay_ms(300);     //延时300ms
        LED0=1;
        LED1=0;
        delay_ms(300);    //延时300ms
    } 
 }

        这个程序非常简单,但是我I们要重视,打好底子是最重要的,不要想着实现了就可以,要明白是怎么实现更重要,这会提高你解决复杂程序的效率,最重要的是,你要多敲代码,不懂多敲几遍,学习是循序渐进的过程,知识无穷尽,进一寸有一寸的欢喜。

#include  “”这是加载一个库文件,是官方或者你个人编写好的库,这个库的大概内容就是将一些重复并复杂的操作集成后,直接做成库文件调用,极大的节省了开发的时间。

这里面sys.h文件,这个是系统头文件。delay.h----延时库文件。led.h----点亮LED灯的头文件。  

单片机是怎么执行的我现在不大明白,但是我知道程序是直接从主函数main直接执行,顺序往下,为什么加while,如果不加单片机执行一遍就结束了么,还是说会执行完重新开始,再次从头开始。等我测试一下。

while应该就是要把你想要一直重复的工作放在里面,在main函数里面开头到while的区间中,就是你要进行的初始化配置,这就好比人的一生,父母孕育你的过程,只需要一遍,这叫初始化,等你乖乖落地,吃饭学习睡觉,不停地循环,这是while循环。总不能你父母孕育出来你就是让你吃一顿饭吧,然后就不要了,再养一个。是吧。

我们来看一下函数delay_init(); 点开之后

               
//初始化延迟函数
//当使用OS的时候,此函数会初始化OS的时钟节拍
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟
void delay_init()
{
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);    //选择外部时钟  HCLK/8
    fac_us=SystemCoreClock/8000000;                //为系统时钟的1/8  
    fac_ms=(u16)fac_us*1000;                    //非OS下,代表每个ms需要的systick时钟数   

}            

里面实际就进行了三个操作,选择一下时钟,然后进行微妙和毫秒的计数值的赋值。
打开SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);    //选择外部时钟  HCLK/8

我们就可以看到(记得追溯一下参数源头,这里就不讲了。)

/**
  * @brief  Configures the SysTick clock source.
  * @param  SysTick_CLKSource: specifies the SysTick clock source.
  *   This parameter can be one of the following values:
  *     @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
  *     @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.
  * @retval None
  */
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
  if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  {
    SysTick->CTRL |= SysTick_CLKSource_HCLK;
  }
  else
  {
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
  }
}

可以看出这个就是官方的一个函数,它先是检查一下参数,然后是那种时钟模式,就将那种时钟模式赋予给了SysTick的CTRL参数,我们看一下CTRL到底是啥

/** @addtogroup CMSIS_CM3_SysTick CMSIS CM3 SysTick
  memory mapped structure for SysTick
  @{
 */
typedef struct
{
  __IO uint32_t CTRL;                         /*!< Offset: 0x00  SysTick Control and Status Register */
  __IO uint32_t LOAD;                         /*!< Offset: 0x04  SysTick Reload Value Register       */
  __IO uint32_t VAL;                          /*!< Offset: 0x08  SysTick Current Value Register      */
  __I  uint32_t CALIB;                        /*!< Offset: 0x0C  SysTick Calibration Register        */
} SysTick_Type;
可以看到CTRL  就是系统时钟控制和状态寄存器的位置,给这个寄存器赋值,然后就决定了系统时钟是什么状态。

然后fac_us = SystemCoreClock/8000000;                //为系统时钟的1/8    我们看一下这SystemCoreClock参数是啥。

#elif defined SYSCLK_FREQ_72MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< System Clock Frequency (Core Clock) */

我们可以看出这是一个代表72MHZ的数字,这个就说明主频为72MHZ,如果主频不是,记得要改哦。fac_ms那就不用看了,然后,我看下一个函数LED_Init();


//初始化PB5和PE5为输出口.并使能这两个口的时钟            
//LED IO初始化
void LED_Init(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
     
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);     //使能PB,PE端口时钟
    
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                 //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);                     //根据设定参数初始化GPIOB.5
 GPIO_SetBits(GPIOB,GPIO_Pin_5);                         //PB.5 输出高

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                 //LED1-->PE.5 端口配置, 推挽输出
 GPIO_Init(GPIOE, &GPIO_InitStructure);                       //推挽输出 ,IO口速度为50MHz
 GPIO_SetBits(GPIOE,GPIO_Pin_5);                          //PE.5 输出高 
}
这其实就是一个简单的IO口配置,第一句,定义了一个结构体变量,我们看一下里面有什么,


/** 
  * @brief  GPIO Init structure definition  
  */

typedef struct
{
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;
只有三个参数,分别是GPIO引脚,速度和模式。

然后通过操作打开了系统时钟,因为时钟是所有引脚工作的动力源,你必须要跟他请求进行分配时钟进行干活,就好比小时候跟爸妈要钱买吃的。

让我看看这个函数里面

/**
  * @brief  Enables or disables the High Speed APB (APB2) peripheral clock.
  * @param  RCC_APB2Periph: specifies the APB2 peripheral to gates its clock.
  *   This parameter can be any combination of the following values:
  *     @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
  *          RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
  *          RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
  *          RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
  *          RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
  *          RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
  *          RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11     
  * @param  NewState: new state of the specified peripheral clock.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  if (NewState != DISABLE)
  {
    RCC->APB2ENR |= RCC_APB2Periph;
  }
  else
  {
    RCC->APB2ENR &= ~RCC_APB2Periph;
  }
}

可一个看到APB2下面有这个么多小弟,每次进行操作都要检查一下参数对不对,就是看看是不是自己的小弟,然后使能和不使能,将小弟名字发过去。

哈哈哈哈,你发现没,这就是单片机,太神奇了。

紧接着下面我们把GPIO结构体里面定义赋完了,然后我们再次进行下一步操作,GPIO_Init();这是什么东东,我们再次进入他的身体里面看看。

/**
  * @brief  Initializes the GPIOx peripheral according to the specified
  *         parameters in the GPIO_InitStruct.
  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param  GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
  *         contains the configuration information for the specified GPIO peripheral.
  * @retval None
  */
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  uint32_t tmpreg = 0x00, pinmask = 0x00;
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  
  
/*---------------------------- GPIO Mode Configuration -----------------------*/
  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
  { 
    /* Check the parameters */
    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
    /* Output mode */
    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
  }
/*---------------------------- GPIO CRL Configuration ------------------------*/
  /* Configure the eight low port pins */
  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
  {
    tmpreg = GPIOx->CRL;
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = ((uint32_t)0x01) << pinpos;
      /* Get the port pins position */
      currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        /* Clear the corresponding low control register bits */
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits */
        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << pinpos);
        }
        else
        {
          /* Set the corresponding ODR bit */
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
          {
            GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
          }
        }
      }
    }
    GPIOx->CRL = tmpreg;
  }

这次比较多,意思大概是把GPIO的赋的参数全部传给单片机的GPIO寄存器,那么这个GPIO算配置完成了。

那么后面的延时后定义都很简单啦,那么我们正式扒开了LED控制的所有面纱,它是不是你中意的哪一个呢。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值