【STM32】时钟树和GPIO

1. 时钟树

  • 什么是时钟?

时钟是由电路产生的具有周期性的脉冲信号,相当于单片机的心脏,给单片机提供一个统一的信号。

要想使用单片机的外设必须开启相应的时钟。

HSE = 高速外部时钟

HSI = 高速内部时钟

LSI = 低速内部时钟

LSE = 低速外部时钟

  • 时钟树
  • 时钟树初始化代码
c 复制代码
#include "sys.h"

void stm32_clock_init(uint32_t plln)
{
    HAL_StatusTypeDef ret = HAL_ERROR;
    //定义晶振初始化结构体
    RCC_OscInitTypeDef rcc_osc_init = {0};
    //定义时钟初始化结构体
    RCC_ClkInitTypeDef rcc_clk_init = {0};
    
    //采用外部高速时钟
    rcc_osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    //设置时钟打开
    rcc_osc_init.HSEState = RCC_HSE_ON;
    //设置HSE预分频系数为1
    rcc_osc_init.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    //打开锁相环
    rcc_osc_init.PLL.PLLState = RCC_PLL_ON;
    //时钟来源选择HSE
    rcc_osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    //设置PLL倍频系数
    rcc_osc_init.PLL.PLLMUL = plln;
    //结构体写入
    ret = HAL_RCC_OscConfig(&rcc_osc_init);
    if(ret != HAL_OK){
        while(1);
    }
    
    //设置时钟种类
    rcc_clk_init.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
    //设置时钟来源为锁相环
    rcc_clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    //设置AHB分频系数为1
    rcc_clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1;
    //设置APB1分频系数为2
    rcc_clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
    //设置APB2分频系数为1
    rcc_clk_init.APB2CLKDivider = RCC_HCLK_DIV1;
    //结构体写入
    ret = HAL_RCC_ClockConfig(&rcc_clk_init, FLASH_LATENCY_2);
    if(ret != HAL_OK){
        while(1);
    }
}

2. GPIO

2.1 什么是GPIO?

  • GPIO是通用输入输出端口(General-purpose input/output)的英文简写,是所有的微控制器必不可少的外设之一,可以由STM32直接驱动从而实现与外部设备通信、控制以及采集和捕获的功能。
  • GPIO口可配置为多种输入输出模式,如输入浮空、输入上拉、输入下拉、模拟输入、开漏输出、开漏复用功能、推挽式输出以及推挽式复用功能等。
  • STM32单片机的GPIO被分为很多组,每组最多有16个引脚,不同型号的 MCU 的GPIO个数是不同的。
  • 引脚电平:0V~3.3V,部分引脚可容忍5V。

2.2 GPIO内部结构

2.3 GPIO工作模式


2.4 点灯实验

led.c

c 复制代码
#include "led.h"
#include "sys.h"

//初始化GBIO口函数
void led_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    
    //使能GPIOB时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    
    //调用GPIO初始化函数
    gpio_initstruct.Pin = GPIO_PIN_8;               //LED1对应引脚
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;     //推挽输出
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;   //上拉
    gpio_initstruct.Pull = GPIO_PULLUP;             //高速
    HAL_GPIO_Init(GPIOB, &gpio_initstruct);
    
    //关闭LED1
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
}

//点亮LED1的函数
void led1_on(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);   //拉低LED1引脚,点亮LED1
}


//熄灭LED1的函数

void led1_off(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);     //拉高LED1引脚,熄灭LED1
}

//翻转LED1的函数
void led1_toggle(void)
{
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);                   //翻转LED1引脚电平
}

led.h

c 复制代码
#ifndef __LED_H__
#define __LED_H__

//初始化GBIO口函数
void led_init(void);

//点亮LED1的函数
void led1_on(void);

//熄灭LED1的函数

void led1_off(void);

//翻转LED1的函数
void led1_toggle(void);

#endif 

main.c

c 复制代码
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */      
    //LED初始化
    led_init();
    
    //开灯
    led1_on();
    //灭灯
    led1_off();
    
    while(1)
    {
        led1_toggle();
        delay_ms(500);
    }
}

2.5 流水灯实验

led.c

c 复制代码
#include "led.h"
#include "sys.h"

//初始化GBIO口函数
void led_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    
    //使能GPIOB时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    
    //调用GPIO初始化函数
    gpio_initstruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;               //LED1,LED2对应引脚
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;     //推挽输出
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;   //上拉
    gpio_initstruct.Pull = GPIO_PULLUP;             //高速
    HAL_GPIO_Init(GPIOB, &gpio_initstruct);
    
    //关闭LED
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);
    
}

//点亮LED1的函数
void led1_on(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);   //拉低LED1引脚,点亮LED1
}


//熄灭LED1的函数

void led1_off(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);     //拉高LED1引脚,熄灭LED1
}

//翻转LED1的函数
void led1_toggle(void)
{
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);                   //翻转LED1引脚电平
}

//点亮LED2的函数
void led2_on(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);   //拉低LED2引脚,点亮LED2
}


//熄灭LED2的函数

void led2_off(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);     //拉高LED2引脚,熄灭LED2
}

//翻转LED2的函数
void led2_toggle(void)
{
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);                   //翻转LED2引脚电平
}

main.c

c 复制代码
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */      
    //LED初始化
    led_init();
    
    while(1)
    {
        led1_on();
        led2_off();
        delay_ms(500);
        led1_off();
        led2_on();
        delay_ms(500);
    }
}

2.5 按键实验

key.c

c 复制代码
#include "key.h"
#include "delay.h"

//初始化GPIO
void key_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    
    //使能GPIOA时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    //调用GPIO初始化函数
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;  //KEY1,KEY2对应引脚
    gpio_initstruct.Mode = GPIO_MODE_INPUT;         //输入
    gpio_initstruct.Pull = GPIO_PULLUP;             //上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;   //高速
    HAL_GPIO_Init(GPIOA, &gpio_initstruct);
}

//按键扫描函数
uint8_t key_scan(void)
{
    //检测按键1是否按下
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){
        //消抖
        delay_ms(10);
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){
            //如果确实按下,那么等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);
            //返回按键值
            return 1;
        }
    }
    
    //检测按键2是否按下
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET){
        //消抖
        delay_ms(10);
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET){
            //如果确实按下,那么等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);
            //返回按键值
            return 2;
        }
    }
    
    //返回默认值
    return 0;
}

key.h

c 复制代码
#ifndef __KEY_H__
#define __KEY_H__

#include "sys.h"

void key_init(void);
uint8_t key_scan(void);

#endif 

main.c

c 复制代码
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"
#include "key.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */      
    //LED初始化
    led_init();
    key_init();
    
    uint8_t key_num = 0;
    while(1)
    {
        key_num =key_scan();
        if(key_num == 1){
            led1_toggle();
        }
        if(key_num == 2){
            led2_toggle();
        }
    }
}
相关推荐
2401_888859719 小时前
STM32H733 MPU、AXI、FMC学习
java·开发语言·stm32·spring
深圳老胡9 小时前
STM32F4 OTA升级:单App与双App方案优缺点对比
笔记·stm32·单片机·代码规范
恒锐丰科技林技术员10 小时前
EG3112 半桥栅极驱动芯片解析与应用
经验分享·嵌入式硬件·硬件工程
mftang11 小时前
CAN总线控制段:位级结构、DLC编码、代际扩展与错误处理的系统性分析
单片机·嵌入式硬件·can总线·控制段·数据长度代码
Jason_zhao_MR19 小时前
Linux与实时控制如何兼得
linux·嵌入式硬件·机器人·工业控制
BSD_CGQ20 小时前
FSR传感器STM32 DMA高速采样工程实现(高精度、低CPU占用)
stm32·单片机·嵌入式硬件·压力传感器·源头工厂·柔性薄膜压力传感器·可变电阻压力传感器
芯岭技术郦1 天前
32 位 ARM® Cortex®-M0+ 内核MCU普冉MS32C001-C
单片机·嵌入式硬件
骑着毛驴数星星1 天前
STM32 CAN波特率与采样点计算,基于HAL库
stm32·单片机·嵌入式硬件
zhangrelay1 天前
Arduino-MEGA-ESP单片机理论课笔记02-硬件-2026
笔记·单片机·嵌入式硬件
艾芯微科技1 天前
钰泰 ETA5055V330DD1E|SOT-223 3.3V LDO,低压差、大电流线性稳压选型分享
网络·单片机·嵌入式硬件·集成测试·51单片机