04、GPIO外设(四):HAL库代码示例



本章源代码链接:

链接: link

1、点亮LED

实验要求:点亮LED
在这里插入图片描述

①RCC_Init.c文件的代码如下:

/****************************************************/
/*****************此文件是配置时钟源函数****************/
/****************************************************/

#include "RCC_Init.h"

/**
 * 将时钟源配置配置为HSI,且AHB,ABP1和APB2的时钟频率到达最大值64MHz,32MHz,64MHz
 * HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruct)
 * HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t FLatency)
 * 
 */
void HSI_RCC_Init(void)
{
    /* 1、配置振荡器HSI和PLL */
    /* 1.1、配置振荡器HSI */
    RCC_OscInitTypeDef CC_OscInitStruct;
    CC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;           //选择HSI振荡器作为时钟源
    CC_OscInitStruct.HSIState = RCC_HSI_ON;                             //开启HSI振荡器
    CC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;  //HSI微调
    /* 1.2、配置PLL */
    CC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;                        //PLL的倍频系数
    CC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;            //选择分频后的HSI
    CC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;                         //开启PLL
    HAL_RCC_OscConfig(&CC_OscInitStruct);
    
    /* 2、配置系统时钟 */
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | 
                                  RCC_CLOCKTYPE_HCLK | 
                                  RCC_CLOCKTYPE_PCLK1 | 
                                  RCC_CLOCKTYPE_PCLK2;                  //需要配置的总线时钟
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;           //系统时钟的输入源
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;                  //系统时钟的分频系数
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;                   //APB1的分频系数
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;                   //APB2的分频系数
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);           //传入配置的结构体指针
                                                                        //配置Flash的2个等待周期
}

/**
 * 将时钟源配置配置为HSE,且AHB,ABP1和APB2的时钟频率到达最大值72MHz,36MHz,72MHz
 */
void HSE_RCC_Init(void)
{
    /* 1、配置振荡器HSE和PLL */
    RCC_OscInitTypeDef CC_OscInitStruct;
    CC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;       //选择HSE振荡器作为时钟源
    CC_OscInitStruct.HSEState = RCC_HSE_ON;                         //开启HSE:8MHz
    CC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;          //HSE的预分配系数:1分频
    CC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;                     //PLL的倍频系数:  9倍频
    CC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;             //选择HSE作为PLL的来源
    CC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;                     //开启PLL
    HAL_RCC_OscConfig(&CC_OscInitStruct);
    
    /* 2、配置系统时钟 */
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK |             
                                  RCC_CLOCKTYPE_HCLK |              
                                  RCC_CLOCKTYPE_PCLK1 |          
                                  RCC_CLOCKTYPE_PCLK2;               //需要配置的总线时钟
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;        //系统时钟的输入源:    PLL
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;               //系统时钟的分频系数:  1分频
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;                //APB1的分频系数:      2分频
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;                //APB2的分频系数:      1分频
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);        //配置Flash的2个等待周期
}

②RCC_Init.h文件的代码如下:

#ifndef __RCC_Init_H
#define __RCC_Init_H
#include "stm32f1xx_hal.h"

void HSI_RCC_Init(void);    //选择内部高速时钟源
void HSE_RCC_Init(void);    //选择外部高速时钟源

#endif

③LED.c文件的代码如下:

#include "LED.h"

/**
 * LED引脚初始化
 */
 /* 定义数组,想要添加引脚向里面添加即可 */
uint16_t GPIO_A[] = {PA0,PA1,PA2,PA3};
static uint8_t GPIONum = sizeof(GPIO_A)/sizeof(GPIO_A[0]);
void LED_Init(void)
{
    /* 1、开启GPIOA的时钟 */
   __HAL_RCC_GPIOA_CLK_ENABLE();                //这里使用的时宏,宏就是直接操作寄存器,常用于开关
    
    /* 2、对GPIOA0进行配置 */
    GPIO_InitTypeDef GPIO_Init;
    for(uint8_t i = 0; i < GPIONum; i++)
    {
        GPIO_Init.Pin = GPIO_PIN_0;                 //选择PA0
        GPIO_Init.Mode = GPIO_MODE_OUTPUT_PP;       //选择通用推挽输出
                                                    //若使用通用开漏输出,则为GPIO_MODE_OUTPUT_OD
        GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;     //最大输出速度50MHz
        HAL_GPIO_Init(GPIOA, &GPIO_Init);
    }
}

/**
 * 点亮LED
 * PAx:PA0~PA3
 */
void LED_ON(uint16_t PAx)
{
    /* 点亮LED,PAx引脚输出高电平 */
    HAL_GPIO_WritePin(GPIOA, PAx, GPIO_PIN_SET);
}

/**
 * 熄灭LED
 * PAx:PA0~PA3
 */
void LED_OFF(uint16_t PAx)
{
    /* 熄灭LED,PAx引脚输出低电平 */
    HAL_GPIO_WritePin(GPIOA, PAx, GPIO_PIN_RESET);
}

/**
 * 翻转LED
 * PAx:PA0~PA3
 */
void LED_Turn(uint16_t PAx)
{
    /* 翻转引脚PAx */
    HAL_GPIO_TogglePin(GPIOA, PAx);
}

④LED.h文件的代码如下:

#ifndef __LED_H
#define __LED_H
#include "stm32f1xx_hal.h"

#define PA0 GPIO_PIN_0
#define PA1 GPIO_PIN_1
#define PA2 GPIO_PIN_2
#define PA3 GPIO_PIN_3

void LED_Init(void);
void LED_ON(uint16_t PAx);
void LED_OFF(uint16_t PAx);
void LED_Turn(uint16_t PAx);

#endif

⑤Delay.c文件的代码如下:(定时器章节进行讲解)

#include "Delay.h"

/**
 * DWT的CYCCNT寄存器的初始化
 */
void DelayInit(void)
{
    /* 1、关闭TRCENA寄存器 */
    CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
    
    /* 2、打开TRCENA寄存器 */
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    
    /* 3、关闭CYCCNT计数功能 */
    DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
    
    /* 4、打开CYCCNT计数功能 */
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    
    /* 5、CYCCNT计数清零 */
    DWT->CYCCNT = 0;
}

/**
 * 微妙延时函数
 * CYCCNT寄存器每隔(1/72MHz)s中的数值+1
 */
void Delay_us(uint32_t nUs)
{
    uint32_t tickStart = DWT->CYCCNT;   //记录一开始CYCCNT寄存器的值
    
    /* 将nUs转换为CYCCNT寄存器对应的值*/
    //每隔(1000000/SystemCoreClock)us,寄存器的值+1。每隔1us,寄存器的值 + (SystemCoreClock / 1000000)
    uint32_t nUsToTick;
    nUsToTick = nUs * (SystemCoreClock / 1000000);
    
    /* 延时等待 */ 
    while ((DWT->CYCCNT - tickStart) < nUsToTick);
}

/**
 * 毫秒延时
 */
void Delay_ms(uint32_t nMs)
{
    while (nMs--)
    {
        Delay_us(1000);
    }
}

/**
 * 秒延时
 */
void Delay_s(uint16_t s)
{
    while (s--)
    {
        Delay_ms(1000);
    }
}

⑥Delay.h文件的代码如下:

#ifndef __Delay_H
#define __Delay_H
#include "stm32f1xx_hal.h"

void DelayInit(void);
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint16_t s);

#endif

⑦main.c文件的代码如下:

#include "RCC_Init.h"
#include "LED.h"

int main(void)
{
    HAL_Init();         //初始化
    HSE_RCC_Init();     //配置时钟树,配置为最高频率
    LED_Init();         //PA0~PA3引脚初始化
    LED_ON(PA0);        //点亮LED0
    
    while(1) 
    {
        
    }
}

2、LED闪烁

实验要求:LED每隔1s亮灭
在这里插入图片描述

⑤main.c文件的代码如下:

#include "RCC_Init.h"
#include "LED.h"
#include "Delay.h"

int main(void)
{
    HAL_Init();         //初始化
    HSE_RCC_Init();     //配置时钟树,配置为最高频率
    LED_Init();         //PA0~PA3引脚从初始化
    DelayInit();        //延时初始化
    
    while(1) 
    {
        LED_Turn(PA0);
        Delay_ms(500);
    }
}

3、LED流水灯

在这里插入图片描述
⑤main.c文件的代码如下:

#include "RCC_Init.h"
#include "LED.h"
#include "Delay.h"

extern uint16_t GPIO_A[];
int main(void)
{
    HAL_Init();         //初始化
    HSE_RCC_Init();     //配置时钟树,配置为最高频率
    LED_Init();         //PA0~PA3引脚从初始化
    DelayInit();        //延时初始化
    
    while(1) 
    {
        for(uint8_t i = 0; i < 4; i++)
        {
           LED_ON(GPIO_A[i]);           //点亮
           LED_OFF(GPIO_A[(i+3)%4]);    //熄灭
           Delay_ms(500);
        }
    }
}

4、按键控制LED

在这里插入图片描述

①Key.c文件的代码如下:

#include "Key.h"

/**
 * Key1引脚PB0的初始化
 */
void Key_Init(void)
{
    /* 1、开启GPIOB的时钟 */
     __HAL_RCC_GPIOB_CLK_ENABLE();              //这里使用的时宏,宏就是直接操作寄存器,常用于开关
    
    /* 2、对引脚工作模式进行配置:上拉输入模式 */
    GPIO_InitTypeDef GPIO_Init;
    GPIO_Init.Pin = GPIO_PIN_0;                 //选择PB0
    GPIO_Init.Pull = GPIO_PULLUP;               //上拉模式
    GPIO_Init.Mode = GPIO_MODE_INPUT;           //选择输入模式
    HAL_GPIO_Init(GPIOB, &GPIO_Init);
}

/**
 * 检测按键是否按下
 */
uint8_t Key_Num(void)
{
    uint8_t num = 0;
    if(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0))                //如果按键按下
    {
        Delay_ms(10);                                       //延时消抖
        if(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0))            //按键真的按下
        {
            while(!!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0));   //等待按键松开
            Delay_ms(10);                                   //延时消抖
            num = 1;
        }
    }
    return num;
}

②Key.h文件的代码如下:

#ifndef __Key_H
#define __Key_H
#include "stm32f1xx_hal.h"
#include "Delay.h"

void Key_Init(void);
uint8_t Key_Num(void);

#endif

③main.c文件的代码如下:

#include "RCC_Init.h"
#include "LED.h"
#include "Key.h"

int main(void)
{
    HAL_Init();         //初始化
    HSE_RCC_Init();     //配置时钟树,配置为最高频率
    LED_Init();         //PA0~PA3引脚从初始化
    Key_Init();
    
    while(1) 
    {
         if(Key_Num() == 1)
        {
            LED_Turn(PA0);
        }
    }
}

5、蜂鸣器

在这里插入图片描述

😀蜂鸣器模块的IO引脚输入低电平时,蜂鸣器响;IO引脚输入高电平时,蜂鸣器不响。
图蜂鸣器IO连接着单片机的PC1引脚,PC1输出低电平,蜂鸣器响,输出高电平,蜂鸣器不响

①Buzzer.c文件的代码如下:

#include "Buzzer.h"

/**
 * 蜂鸣器引脚的初始化
 */
void Buzzer_Init(void)
{
    /* 1、开启GPIOA的时钟 */
   __HAL_RCC_GPIOC_CLK_ENABLE();                //这里使用的时宏,宏就是直接操作寄存器,常用于开关
    
    /* 2、对引脚工作模式进行配置:通用推挽输出 */
    GPIO_InitTypeDef GPIO_Init;
    GPIO_Init.Pin = GPIO_PIN_1;                 //选择PC1
    GPIO_Init.Mode = GPIO_MODE_OUTPUT_PP;       //选择通用推挽输出
                                                //若使用通用开漏输出,则为GPIO_MODE_OUTPUT_OD
    GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;     //最大输出速度50MHz
    HAL_GPIO_Init(GPIOC, &GPIO_Init);

}

/**
 * 蜂鸣器响
 */
void Buzzer_ON(void)
{
    /* PC1输出低电平 */
   HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
}

/**
 * 蜂鸣器不响
 */
void Buzzer_OFF(void)
{
    /* PC1输出高电平 */
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);
}

②Buzzer.h文件的代码如下:

#ifndef __Buzzer_H
#define __Buzzer_H
#include "stm32f1xx_hal.h"

void Buzzer_Init(void);
void Buzzer_ON(void);
void Buzzer_OFF(void);

#endif

③main.c文件的代码如下:

#include "RCC_Init.h"
#include "Buzzer.h"
#include "Delay.h"

int main(void)
{
    HAL_Init();         //初始化
    HSE_RCC_Init();     //配置时钟树,配置为最高频率
    Buzzer_Init();
    DelayInit();
    
    while(1) 
    {
        Buzzer_ON();    //响
        Delay_ms(200);
        Buzzer_OFF();   //不响
        Delay_ms(200);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值