【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();
        }
    }
}
相关推荐
DS小龙哥5 小时前
基于STM32F103C8T6的智能家居健康环境监测系统
stm32·嵌入式硬件·智能家居
小白嘎嘎6 小时前
CAN总线学习
单片机·嵌入式硬件·嵌入式
STC_USB_CAN_80516 小时前
TF卡,SD卡:【Ai8051U】FatFs+SD+W25Q测试, AiCube
单片机·嵌入式硬件·51单片机
夜月yeyue7 小时前
嵌入式 Linux 启动流程详解 (以 ARM + U-Boot 为例)
linux·单片机·udp·嵌入式·uboot·bootloard
半夜吃早餐7 小时前
【STM32HAL-----NRF24L01】
c语言·开发语言·stm32·单片机·嵌入式硬件
TheBszk7 小时前
FOC学习路线
单片机·嵌入式硬件
清风6666669 小时前
基于STM32单片机的家庭医护血氧体温血压吃药监测APP系统
stm32·单片机·嵌入式硬件·毕业设计·课程设计
三佛科技-187366133979 小时前
单片机和PLC有哪些区别?揭秘单片机MCU的常见应用
单片机·嵌入式硬件
CC呢12 小时前
基于单片机汽车防撞系统设计
stm32·单片机·嵌入式硬件·汽车