美文网首页
《嵌入式-STM32开发指南》第二部分 基础篇 - 第1章 GP

《嵌入式-STM32开发指南》第二部分 基础篇 - 第1章 GP

作者: BruceOu | 来源:发表于2020-09-16 23:34 被阅读0次

    1.1 GPIO流水灯硬件电路分析

    发光二极管是属于二极管的一种,具有二级管单向导电特性,即只有在正向电压(二极管的正极接正,负极接负)下才能导通发光。PB0引脚接发光二极管(LED1)的正极,所以PB0引脚输出高电平LED1亮,PB0引脚输出低电平LED1熄灭,,LED2,LED3同理。

    图1 LED电路图

    在上一章,我们知道STM32的引脚有8中模式,我们要点亮LED,显然是输出模式,那么则要将PB0、PG6、PG7设置为普通输出模式,那么是是开漏输出,还是推挽输出呢?或者都可以。为了使得LED点亮,我们只需要将PB0、PG6、PG7输出为高电平,斌企鹅需要输出电流,则需要将其设置为推挽输出,因为如果是开漏输出,则不会有电流,LED就不会点亮。好了,就到这里吧,我们使用STM32Cube新建工程。

    1.2 STM32Cube新建工程

    关于如何使用使用STM32Cube新建工程在前文已经讲解过了,这里直说配置GPIO部分内容。本文要实现流水灯,其实输出为初始化设置为高电平还是低电平都可以,因为流水灯需要不断反转。

    1.首先进行系统配置

    Debug模式选择可以选择其他模式,默认选择No debug,Timebase Source选择SysTick,关于Timebase Source在后文会详细讲解。

    图2系统配置

    2.时钟配置,外部高速时钟

    图3

    配置系统时钟配置72MHz,APB1总线配置36MHz。默认高速时钟是使用内部(HSI),而且CPU时钟配置的比较低。以我选择的STM32F103,外部8M晶振为例(如下图)。

    图4

    3.GPIO初始化配置

    我们将PB0、PG6、PG7配置输出模式(高电平、低电平均可)、输出速率、上/下拉等,默认即可。

    图5 GPIO初始化

    4.工程生成设置

    图6

    其他默认即可。最后点击“生成代码”即可生成代码。

    图7生成代码

    1.3 GPIO流水灯实现与代码分析

    1.3.1 流水灯实现

    我们要实现流水灯,需要在主函数添加一下代码。

    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    
    HAL_Delay(500);
    
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    
    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
    
    HAL_Delay(500);
    
    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
    
    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
    
    HAL_Delay(500);
    
    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
    
    图8

    1.3.2流水灯代码分析

    在分析代码前,先看看流水灯编程流程:

    1>使能GPIO端口时钟;

    2>初始化GPIO引脚,即为GPIO初始化结构体赋值,并调用相应初始化函数完成初始化配置;

    3>根据实际需求控制流水灯。

    STM32采用固件库开发,代码比较多,因此,我们在看一个实际工程时,只需从主函数开始,好了,接下来,笔者就带领大家一步一步看看流水灯是怎么实现的。笔者先贴出主函数代码。

    int main(void)
    
    {
    
     /* USER CODE BEGIN 1 */
    
     /* USER CODE END 1 */
    
     /* MCU Configuration--------------------------------------------------------*/
    
     /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    
     HAL_Init();
    
     /* USER CODE BEGIN Init */
    
     /* USER CODE END Init */
    
     /* Configure the system clock */
    
     SystemClock_Config();
    
     /* USER CODE BEGIN SysInit */
    
     /* USER CODE END SysInit */
    
     /* Initialize all configured peripherals */
    
     MX_GPIO_Init();
    
     /* USER CODE BEGIN 2 */
    
     /* USER CODE END 2 */
    
     /* Infinite loop */
    
     /* USER CODE BEGIN WHILE */
    
     while (1)
    
     {
    
     /* USER CODE END WHILE */
    
     HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    
     HAL_Delay(500);
    
     HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    
     HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
    
     HAL_Delay(500);
    
     HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
    
     HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
    
     HAL_Delay(500);
    
     HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
    
     /* USER CODE BEGIN 3 */
    
     }
    
     /* USER CODE END 3 */
    
    }
    

    注释部分不用管,我们只看代码。

    1.复位所有硬件

    HAL_Init()函数为复位所有硬件,这个就不细说了。

    HAL_StatusTypeDef HAL_Init(void)
    
    {
    
     /* Configure Flash prefetch */
    
    #if (PREFETCH_ENABLE != 0)
    
    #if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \
    
     defined(STM32F102x6) || defined(STM32F102xB) || \
    
     defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \
    
     defined(STM32F105xC) || defined(STM32F107xC)
    
     /* Prefetch buffer is not available on value line devices */
    
     __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
    
    #endif
    
    #endif /* PREFETCH_ENABLE */
    
     /* Set Interrupt Group Priority */
    
     HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
    
     /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
    
     HAL_InitTick(TICK_INT_PRIORITY);
    
     /* Init the low level hardware */
    
     HAL_MspInit();
    
     /* Return function status */
    
     return HAL_OK;
    
    }
    

    2.时钟初始化函数

    SystemClock_Config()函数用于时钟初始化,也就是通过STM32Cube实现。

    图9时钟配置

    时钟初始化函数如下:

    void SystemClock_Config(void)
    
    {
    
     RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    
     RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
     /** Initializes the RCC Oscillators according to the specified parameters
    
     * in the RCC_OscInitTypeDef structure.
    
     */
    
     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    
     RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    
     RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    
     RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    
     RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    
     RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    
     RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    
     if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    
     {
    
     Error_Handler();
    
     }
    
     /** Initializes the CPU, AHB and APB buses clocks
    
     */
    
     RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
    
     |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    
     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    
     RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    
     RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    
     RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
     if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    
     {
    
     Error_Handler();
    
     }
    
    }
    

    RCC_OscInitTypeDef结构体类型定义时钟来源和系统时钟生成配置,就是图9中的配置,本例程使用外部8MHz晶振,通过PLL锁相环9倍频后得到72M系统时钟。

    RCC_ClkInitTypeDef结构体类型定义总线时钟配置,一般选择使能系统时钟、AHB、APB1和APB2总线时钟,其中只有APB1总线时钟36MHz,其他都为72MHz。

    HAL_RCC_ClockConfig函数就是HAL定义的一个系统滴答定时器初始化配置函数,通过这个函数得到延时效果。

    2.GPIO初始化函数

    MX_GPIO_Init()函数用于LED的GPIO初始化,代码如下:

    static void MX_GPIO_Init(void)
    
    {
    
     GPIO_InitTypeDef GPIO_InitStruct = {0};
    
     /* GPIO Ports Clock Enable */
    
     __HAL_RCC_GPIOB_CLK_ENABLE();
    
     __HAL_RCC_GPIOG_CLK_ENABLE();
    
     /*Configure GPIO pin Output Level */
    
     HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    
     /*Configure GPIO pin Output Level */
    
     HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
    
     /*Configure GPIO pin : PB0 */
    
     GPIO_InitStruct.Pin = GPIO_PIN_0;
    
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    
     GPIO_InitStruct.Pull = GPIO_NOPULL;
    
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
     /*Configure GPIO pins : PG6 PG7 */
    
     GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    
     GPIO_InitStruct.Pull = GPIO_NOPULL;
    
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    
     HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
    
    }
    

    以上就是LED的初始化函数,初始化GPIO有个重要的结构体GPIO_InitTypeDef,先看看该结构体。

    typedef struct
    
    {
    
     uint32_t Pin; /*!< Specifies the GPIO pins to be configured.
    
     This parameter can be any value of @ref GPIO_pins_define */
    
     uint32_t Mode; /*!< Specifies the operating mode for the selected pins.
    
     This parameter can be a value of @ref GPIO_mode_define */
    
     uint32_t Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
    
     This parameter can be a value of @ref GPIO_pull_define */
    
     uint32_t Speed; /*!< Specifies the speed for the selected pins.
    
     This parameter can be a value of @ref GPIO_speed_define */
    
    } GPIO_InitTypeDef;
    
    • Pin:引脚编号选择,一个GPIO有16个引脚可选,参数可选有:GPIO_PIN_0、….、GPIO_PIN_15和GPIO_PIN_ALL。很多时候我们可以使用或运算进行选择:GPIO_PIN_0| GPIO_PIN_4。

    • Mode:引脚模式选择,在前文笔者已经介绍了引脚有8中工作模式,根据外设选择相应模式。

    表1GPIO引脚工作模式
    • Pull:上下拉,用于输入模式,可选:GPIO_NOPULL不上下拉;GPIO_PULLUP:使能下拉;GPIO_PULLDOWN使能下拉;

    • Speed:引脚速度,可选:GPIO_SPEED_FREQ_LOW:低速(2MHz);中速(10MHz);高速(50MHz)。

    在初始化代码中,还有一个重要的函数HAL_GPIO_WritePin()。HAL_GPIO_WritePin()函数为3个LED灯时钟初始化状态,这里设置为低电平,所以初始化状态3个LED都是暗的。

    4.流水灯实现

    在前文已经贴出了流水灯的相应代码。

    while (1)
    
    {
    
     /* USER CODE END WHILE */
    
     HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    
     HAL_Delay(500);
    
     HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    
     HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
    
     HAL_Delay(500);
    
     HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
    
     HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
    
     HAL_Delay(500);
    
     HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
    
     /* USER CODE BEGIN 3 */
    
    }
    

    HAL_GPIO_TogglePin函数用于GPIO电平反转,HAL_Delay用于延时,单位是毫秒,以此不断将LED1、LED2、LED3关灭,这就是实现流水灯的效果。

    1.4实验现象

    将编译好的程序下载到板子中,可以看到三个LED灯不同地闪烁。


    代码获取方式
    1.关注公众号[嵌入式实验楼]
    2.在公众号回复关键词[STM32F1]获取资料

    欢迎访问我的网站:
    BruceOu的哔哩哔哩
    BruceOu的主页
    BruceOu的博客
    CSDN博客
    简书

    相关文章

      网友评论

          本文标题:《嵌入式-STM32开发指南》第二部分 基础篇 - 第1章 GP

          本文链接:https://www.haomeiwen.com/subject/xkskyktx.html