本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:STM32F103固件函数库由意法半导体提供,为基于ARM Cortex-M3内核的STM32F101和STM32F103系列微控制器提供开发资源。用户手册旨在帮助初学者和开发者理解和应用STM32F103系列芯片。该系列MCU具有高性能、低功耗特性,并内置丰富外设接口。固件库包含预编译C语言函数,分为HAL和LL库,简化跨系列代码移植和提供高效硬件访问。手册内容包括初始化、外设驱动、内存管理、中断和异常处理、RTOS支持、调试工具、应用示例和性能优化。开发者通过这份手册可以学习STM32F103 MCU的操作和高级功能,提升开发效率。
STM32F103固件函数库用户手册(中文).zip

1. STM32F103微控制器概述

STM32F103微控制器是ST公司生产的一款基于ARM Cortex-M3处理器的高性能32位微控制器,广泛应用于各种嵌入式系统和物联网项目。它的设计旨在提供成本效益高且性能强大的解决方案,以支持从简单的应用到复杂的系统控制任务。

1.1 STM32F103的功能特点

  • 处理器核心 :内置ARM Cortex-M3 32位RISC核心,最大工作频率为72MHz。
  • 存储器容量 :支持多种存储选项,包括闪存、SRAM以及EEPROM。
  • 丰富的外设接口 :包括多个UART、I2C、SPI、CAN、USB接口,为各种外设的接入提供了便利。
  • 模拟接口 :集成高精度的模拟数字转换器(ADC)和数字模拟转换器(DAC)。
  • 电源管理 :低功耗模式支持,如睡眠模式和待机模式,以降低功耗。

1.2 STM32F103的应用领域

由于其灵活的性能和丰富的外设接口,STM32F103微控制器在众多领域中都有应用,如工业控制、医疗设备、消费电子、物联网设备和汽车电子等。其在执行实时任务时的高效率和可靠性,加上成本效益,使其成为了嵌入式开发者的首选之一。

接下来的章节将会深入介绍STM32F103的固件函数库、系统初始化与配置、内存管理、中断处理机制等关键主题,帮助开发者全面掌握如何高效使用STM32F103微控制器进行项目开发。

2. 固件函数库介绍与分类

STM32F103微控制器的开发离不开固件函数库的支持。本章节将详细介绍固件函数库的基本结构、如何搭建开发环境以及分类和特点。

2.1 固件函数库的基本结构

2.1.1 库文件组成与模块划分

固件函数库由一系列的源代码文件、头文件以及预处理器定义组成,它们共同提供了对STM32F103微控制器硬件的抽象和封装。库文件通常根据硬件模块进行划分,如GPIO、ADC、UART、TIM等,便于开发者按需调用。

在源代码文件中,实现了与硬件相关的寄存器操作,开发者可以通过更高级别的函数调用来控制硬件。头文件则提供了函数的声明和必要的宏定义,确保代码的可读性和易用性。

2.1.2 HAL库与LL库的特点与区别

STM32F103微控制器的固件库主要分为两部分:硬件抽象层(HAL)库和低层(LL)库。

  • HAL库 提供了一组标准的API,用于不同的STM32系列。它抽象了底层硬件细节,让开发者可以使用统一的接口来操作不同的硬件资源。HAL库适用于需要快速开发的应用场景,降低了学习和使用STM32的门槛。

  • LL库 提供更接近硬件的函数,没有HAL库那样复杂和抽象,允许开发者直接操作寄存器。LL库适用于对性能有严格要求或者需要精细控制硬件的场景。

在选择使用HAL库还是LL库时,开发者需要根据项目的具体需求和开发周期来决定。

2.2 开发环境搭建与配置

2.2.1 集成开发环境(IDE)的选择与安装

要开发STM32F103微控制器,首先需要搭建一个合适的集成开发环境(IDE)。目前较为流行的选择有Keil MDK-ARM、IAR Embedded Workbench以及开源的Eclipse-based IDEs,如Eclipse配合GNU ARM Embedded Toolchain。

选择IDE时应考虑其性能、扩展性、社区支持和是否易于使用。以Keil MDK-ARM为例,它支持直接导入固件库,提供了代码编辑、编译、调试一体化的解决方案。

2.2.2 固件库的下载、导入与配置方法

安装好IDE后,接下来需要下载并导入对应的固件库。STM32F103的固件库可以从ST官网免费下载。下载后,通常包含一个工程模板和库文件。

  • 导入固件库 :在IDE中创建一个新项目,并按照提供的步骤将固件库文件导入到项目目录中。通常需要配置包括但不限于源文件路径、头文件路径和库文件路径。

  • 配置方法 :在项目设置中指定微控制器型号、晶振频率、优化选项等。确保在编译之前所有必要的库文件都已经添加到项目中,并且配置正确。

2.2.2.1 Keil MDK-ARM导入步骤示例

  1. 打开Keil uVision并创建一个新项目。
  2. 在弹出的“选择设备”对话框中,搜索并选择STM32F103系列的微控制器。
  3. 指定项目保存位置,并创建一个新项目。
  4. 在项目浏览器中右键点击“Target 1”,选择“Manage Project Items”。
  5. 在弹出的对话框中选择“User”,然后点击“Add”按钮来导入库文件。
  6. 选择下载好的固件库文件夹,然后点击“Add”。
  7. 在项目设置中配置系统时钟、处理器时钟和内存设置。
  8. 完成以上步骤后,就可以开始编写代码并编译项目了。

通过以上步骤,开发环境就搭建好了,接下来可以开始编写自己的程序,使用STM32F103提供的各种外设功能了。

3. 系统初始化与配置

3.1 系统时钟配置与管理

3.1.1 内部与外部时钟源设置

STM32F103微控制器提供了多种时钟源,包括内部高速时钟(HSI)、外部高速时钟(HSE)、外部低速时钟(LSE)和内部低速时钟(LSI)。系统时钟(SYSCLK)可以在这些时钟源之间进行选择和切换。

#include "stm32f10x.h"

void RCC_Configuration(void) {
    // 启动外部高速时钟
    RCC_HSICmd(ENABLE);
    while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);

    // 尝试切换到外部高速时钟
    RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
    while (RCC_GetSYSCLKSource() != 0x01);

    // 如果需要,也可以配置PLL和其它时钟设置
}

int main(void) {
    // 初始化RCC
    RCC_Configuration();

    // 以下是系统时钟配置后的代码逻辑...
    while (1) {
        // 应用程序的主体逻辑
    }
}

分析:代码中首先启用了内部高速时钟(HSI),待其稳定后,尝试将系统时钟切换到外部高速时钟(HSE)。RCC_SYSCLKConfig()函数用于系统时钟的配置,RCC_GetSYSCLKSource()函数检查当前系统时钟源。

3.1.2 系统时钟树的配置与优化

系统时钟树的配置包括主时钟源的选择、时钟分频器的配置等。正确的时钟树配置是确保系统运行稳定性和性能优化的关键。

void CLK_Configuration(void) {
    // 配置APB2时钟为HSE的2分频,也就是HSE的一半
    RCC_PCLK2Config(RCC_HCLK_Div2);
    // 配置APB1时钟为HSE的2分频,也就是HSE的一半
    RCC_PCLK1Config(RCC_HCLK_Div2);
    // 配置AHB时钟(HCLK)为HSE的1分频,即HSE
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    // 配置高速时钟域(PLCK)为HSE的9分频
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    // 启动PLL
    RCC_PLLCmd(ENABLE);
    // 等待PLL稳定
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    // 切换系统时钟源到PLL
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    // 等待PLL成为系统时钟源
    while (RCC_GetSYSCLKSource() != 0x08);
}

int main(void) {
    // 初始化时钟配置
    CLK_Configuration();

    // 接下来是系统时钟配置后的代码逻辑...
    while (1) {
        // 应用程序的主体逻辑
    }
}

分析:RCC_PCLK1Config()和RCC_PCLK2Config()函数用于配置APB1和APB2时钟域的分频器,RCC_HCLKConfig()函数用于配置AHB时钟域。RCC_PLLConfig()函数用于配置PLL并设置PLL的乘数和源时钟。RCC_PLLCmd()函数用于启用或禁用PLL。RCC_SYSCLKConfig()函数用于切换系统时钟源到PLL。

3.2 中断向量与优先级配置

3.2.1 中断向量表的查看与修改

STM32F103的中断向量表是一个在启动时由链接器脚本定义的数据结构,包含了指向中断服务例程(ISR)的指针。

#define VECT_TAB_OFFSET  0x0 // 向量表偏移量,默认为0

void NVIC_Configuration(void) {
    // 假设修改优先级分组为Group1,抢占优先级占3位,响应优先级占5位
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    // 配置中断优先级,这里以外部中断EXTI0为例
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; // 响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

int main(void) {
    // 初始化中断配置
    NVIC_Configuration();

    // 接下来是中断向量配置后的代码逻辑...
    while (1) {
        // 应用程序的主体逻辑
    }
}

分析:代码使用NVIC_PriorityGroupConfig()函数配置了中断优先级分组。NVIC_InitTypeDef结构体定义了中断通道、优先级和使能状态。NVIC_Init()函数用于将这些设置应用到中断控制器上。

3.2.2 中断优先级与抢占策略的设置

中断优先级分为抢占优先级和响应优先级。抢占优先级决定了中断处理的先后顺序,响应优先级则在抢占优先级相同的情况下决定中断处理的顺序。

void EXTI_Configuration(void) {
    EXTI_InitTypeDef EXTI_InitStructure;

    // 连接EXTI Line0到PA0引脚
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

    // 配置EXTI Line0的触发条件为下降沿触发
    EXTI_InitStructure.EXTI_Line = EXTI_Line0;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    // 其它EXTI配置...
}

int main(void) {
    // 初始化外部中断
    EXTI_Configuration();

    // 接下来是外部中断配置后的代码逻辑...
    while (1) {
        // 应用程序的主体逻辑
    }
}

分析:在EXTI_Configuration()函数中,通过GPIO_EXTILineConfig()函数连接EXTI Line0到GPIOA的第0个引脚。EXTI_InitTypeDef结构体用于设置中断触发条件(下降沿触发),EXTI_Init()函数将这些设置应用到外部中断控制器上。注意,这里并没有改变中断的优先级,而是设置了中断触发条件。

3.3 系统时钟与中断配置的整合

在实际应用中,时钟配置与中断配置往往紧密相关,因为中断服务例程的执行效率直接受到时钟系统状态的影响。

// 完整的配置示例
int main(void) {
    // 初始化时钟配置
    CLK_Configuration();

    // 初始化中断配置
    NVIC_Configuration();
    EXTI_Configuration();

    // 主循环,等待中断触发
    while (1) {
        // 应用程序的主体逻辑
    }
}

分析:在主函数中,我们首先配置系统时钟,然后设置中断优先级和配置外部中断。通过时钟系统的优化配置,确保了在中断发生时,CPU能够及时响应并执行中断服务例程,同时保证系统的稳定性和运行效率。通过结合本章节内容,可以根据具体的应用场景设计出高效的时钟系统和中断响应策略。

4. 外设驱动使用与控制

外设驱动的使用与控制是嵌入式系统开发中的核心部分。STM32F103作为一款广泛使用的32位微控制器,其丰富的外设资源和灵活的驱动配置能力让它在各种应用中大放异彩。在本章节中,我们将深入探讨如何使用和控制STM32F103的外设,包括基本输入输出端口GPIO、串行通信接口UART/I2C/SPI,以及模拟与数字信号处理。

4.1 基本输入输出端口GPIO操作

GPIO(General-Purpose Input/Output)端口是微控制器最基本的外围接口,几乎所有的外设功能都离不开它。STM32F103的GPIO端口支持多种模式和特性,本节将介绍GPIO模式与特性,并提供一些高级控制技巧和实例。

4.1.1 GPIO模式与特性介绍

STM32F103的每个GPIO引脚都可以被配置为不同的模式来满足特定的应用需求。常见的GPIO模式有输入模式、输出模式、模拟模式和特殊功能模式。

  • 输入模式下,GPIO可以配置为上拉、下拉、浮空或者模拟输入。
  • 输出模式下,GPIO可以被配置为推挽输出或开漏输出。
  • 在模拟模式下,GPIO引脚可以直接连接到内部的模拟外设,如ADC和DAC。
  • 特殊功能模式则用于特定的外设功能,例如时钟输出、I2C、SPI等。

GPIO的特性还包括速度配置(低速、中速、高速)、上拉/下拉电阻配置,以及外部中断功能等。

4.1.2 GPIO的高级控制技巧与实例

在STM32F103的GPIO使用中,高级控制技巧可以大幅提高应用的性能和灵活性。一个典型的高级控制技巧是利用GPIO的外部中断功能来响应外部事件,实现低延迟的事件处理。

例如,下面的代码展示了如何配置GPIO的外部中断:

void EXTI0_IRQHandler(void) {
  if(EXTI->PR & (1<<0)) {    // 检查是否为EXTI Line0中断
    // 执行中断处理逻辑
    EXTI->PR = (1<<0);       // 清除中断标志位
  }
}

int main(void) {
  // 配置GPIO引脚为输入模式,并启用内部上拉
  // GPIOx->PUPDR |= (1<<GPIO_PUPDR_PUPD0_Pos); // 详细配置根据需要设定
  // 连接EXTI Line0到GPIO0
  SYSCFG->EXTICR[0] &= ~(0xf << (4 * 0)); // 清除旧的设置
  SYSCFG->EXTICR[0] |= (0x1 << (4 * 0));   // 连接到GPIOA
  // 配置NVIC
  NVIC_SetPriority(EXTI0_IRQn, 2); // 设置优先级
  NVIC_EnableIRQ(EXTI0_IRQn);      // 使能中断
  // 配置EXTI Line0
  EXTI->IMR |= (1<<0);   // 启用中断请求
  EXTI->EMR &= ~(1<<0);  // 禁止事件请求
  EXTI->FTSR |= (1<<0);  // 使用上升沿触发
  EXTI->RTSR &= ~(1<<0); // 不使用下降沿触发
  // ... 其他初始化代码 ...
  while(1) {
    // 主循环代码
  }
}

在这个例子中,我们配置了PA0引脚为外部中断输入,并将EXTI Line0的中断服务程序设置为 EXTI0_IRQHandler 。当中断发生时,会调用该中断服务程序,执行相应的逻辑处理。这表明STM32F103的GPIO不仅用于简单的信号输入输出,还支持复杂的事件触发机制,能够满足多种应用场景的需求。

GPIO配置参数表

参数 描述 可选值 默认值
Mode 输入/输出/模拟/特殊功能模式 INPUT, OUTPUT, ANALOG, ALT(Function) INPUT
Configuration 输入配置(上拉/下拉/浮空/模拟),输出配置(推挽/开漏) PULL_UP, PULL_DOWN, NO_PULL, PUSH_PULL, OPEN_DRAIN NO_PULL
Output Speed 输出速度(低速、中速、高速) LOW, MEDIUM, HIGH MEDIUM
Interrupt 中断配置(上升沿/下降沿/双边沿触发,或禁用中断) RISING, FALLING, RISING_FALLING, DISABLE DISABLE

GPIO操作流程图

graph LR
A[开始配置GPIO] --> B[设置GPIO模式]
B --> C[配置输出速度]
C --> D[选择是否配置中断]
D --> E[设置中断触发条件]
E --> F[配置中断优先级]
F --> G[启用中断]
G --> H[编写中断服务程序]

在本节中,我们深入了解了STM32F103的GPIO端口的功能和高级配置技巧。通过实际的代码示例和配置流程,我们展示了如何有效地利用这些特性来实现高效和灵活的硬件控制。在下一节中,我们将继续探索STM32F103的串行通信接口,了解如何通过这些接口实现数据的高效传输。

5. 内存管理与程序数据操作

5.1 内存分配与管理策略

内存管理是嵌入式系统开发中的关键环节,涉及内存的高效使用和数据操作的优化。在STM32F103微控制器上,合理管理内存资源对于系统的稳定性和响应速度有着直接影响。

5.1.1 动态内存分配与释放

动态内存管理通常用于程序运行时根据需求分配和释放内存空间。在C语言中, malloc , calloc , realloc free 函数是动态内存管理的核心。

#include <stdlib.h>

int *array;
size_t array_size = 100;

// 动态分配内存
array = (int*)malloc(array_size * sizeof(int));

// 检查内存分配是否成功
if (array == NULL) {
    // 错误处理
}

// 使用完毕后释放内存
free(array);

在STM32F103中,如果不注意内存分配,可能会导致内存泄漏或堆栈溢出。因此,在使用动态内存时,必须确保每个 malloc 都有对应的 free ,避免内存泄漏。

5.1.2 内存缓冲区的管理与优化

为了提高数据处理效率,需要合理管理内存缓冲区。例如,在处理串行数据时,可以使用环形缓冲区来存储接收到的数据,从而减少数据拷贝的开销。

#define BUFFER_SIZE 256

char buffer[BUFFER_SIZE];
uint8_t head = 0;
uint8_t tail = 0;

void enqueue(char data) {
    buffer[head] = data;
    head = (head + 1) % BUFFER_SIZE;
}

char dequeue() {
    if (head != tail) {
        char data = buffer[tail];
        tail = (tail + 1) % BUFFER_SIZE;
        return data;
    }
    return -1; // 缓冲区为空
}

5.2 数据结构与算法的实现

在嵌入式系统中,数据结构和算法的选择对程序性能有着决定性作用。STM32F103这样的资源受限设备上,必须更加注重空间和时间的优化。

5.2.1 常用数据结构在STM32F103上的应用

在STM32F103微控制器上,由于资源限制,通常不会使用复杂的数据结构。数组和链表是最基本且广泛使用的数据结构。

typedef struct Node {
    int data;
    struct Node *next;
} Node;

void append(Node **head, int data) {
    Node *new_node = (Node*)malloc(sizeof(Node));
    new_node->data = data;
    new_node->next = NULL;

    if (*head == NULL) {
        *head = new_node;
    } else {
        Node *current = *head;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = new_node;
    }
}

5.2.2 算法的实现与性能考量

在实现算法时,开发者应该尽量考虑其时间复杂度和空间复杂度。例如,在排序算法中,快速排序通常比冒泡排序要高效,尤其是在处理大量数据时。

void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pivotIndex = partition(arr, low, high);
        quickSort(arr, low, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, high);
    }
}

int partition(int arr[], int low, int high) {
    int pivot = arr[high];
    int i = low - 1;
    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[high]);
    return i + 1;
}

在选择和实现算法时,务必考虑到程序的实际需求和资源限制,以确保程序的性能和稳定性。

注意:本章节深入探讨了STM32F103微控制器的内存管理及数据操作。对于内存管理,介绍了动态内存分配和内存缓冲区管理的策略。在数据结构与算法的实现部分,本章节分析了在资源受限的环境中如何合理选择数据结构和实现高效算法。这些内容对于提高嵌入式程序的性能至关重要。在接下来的章节中,我们将继续深入探讨如何优化程序性能,以及如何利用高级的数据结构和算法实现具体的应用。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:STM32F103固件函数库由意法半导体提供,为基于ARM Cortex-M3内核的STM32F101和STM32F103系列微控制器提供开发资源。用户手册旨在帮助初学者和开发者理解和应用STM32F103系列芯片。该系列MCU具有高性能、低功耗特性,并内置丰富外设接口。固件库包含预编译C语言函数,分为HAL和LL库,简化跨系列代码移植和提供高效硬件访问。手册内容包括初始化、外设驱动、内存管理、中断和异常处理、RTOS支持、调试工具、应用示例和性能优化。开发者通过这份手册可以学习STM32F103 MCU的操作和高级功能,提升开发效率。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐