【STM32】F103ZET6开发板—-笔记01

一、简述

1.1什么是STM32

STM32 是 STMicroelectronics(ST)的一系列 32 位微控制器,其基于 ARM架构 Cortex-M 系列的处理器内核设计。它们广泛应用于各种嵌入式系统,如物联网设备、汽车电子、工业自动化等领域。

ARM(Advanced RISC Machine)是一种低功耗、低成本、高性能的处理器架构。

“ST” 是指制造商 STMicroelectronics 的缩写。 “M” 表示其是基于 ARM 的 Cortex-M 系列核心。 “32” 则代表其为 32 位微控制器 (简称MCU)

STM32F103ZET6 ARM Cortex-M3系列(基础型, 主频: 72M(时钟的工作频率)), Z (144引脚), E (Flash 闪存 512K字节) , T( 封装性: LQFP), 6 (温度范围: -40 ~ 85)。

1.2 STM32最小系统

用最小的电路组成的可以工作的单片机叫做最小系统。

stm32f103zet6 最小系统有 5 部分组成(电源电路、时钟电路、boot 电路、下载/调试接口、复位电路)

电源供电: USB方式(USB, CH340 调试串口),最高5V电压

时钟电路: 内部时钟源(低速 LSI、高速 HSI)、外部时钟(低速 LSE 、高速 HSE)

boot 电路: 引导电路(BT1, BT0, 通过跳帽方式确定, 出厂默认即可)

下载/调试接口: ST下载器进行程序的下载(JTAG/SWD), CH340 USB串口调试

复位电路: RST按键

1.3固件库使用说明

对于MCU开发方式:汇编语言 C语言

stm32 单片机:(汇编+C语言)

实际开发编程过程中使用的方法:

  • 配置 MCU 中的某个功能模块的寄存器,进行操作

  • 使用 ST 官方提供的固件库驱动操作, 推荐使用 ST 官方提供了 STM32cubemx 软件,图形化配置与开发。

  • 常用的固件库:

    Standard Peripheral Library (SPL): ST Microelectronics 最初为其 STM32 微控制器系列发布的固件库。此库包含了一些方便的 C 函数,可以直接控制 STM32 的各种外设,通常称为标准库。

    STM32Cube: ST Microelectronics 自 2015 年以来开始推广的一种新的固件库。
    STM32Cube 包括一个嵌入式软件平台和一个独立的集成开发环境。嵌入式软件平台包括一个硬件抽象层(HAL),该层为 STM32 的各种外设提供通用的 API,并且还包含一些中间件组件(如 FreeRTOS,USB 库,TCP/IP 库等)。STM32Cube 的集成开发环境(STM32CubeIDE)则包含了代码生成器,它可以生成基于 STM32Cube HAL 的初始化代码。

    LL (Low Layer) Drivers: LL 库是 STM32Cube 库的一部分,为高级用户提供了一个硬件抽象层的替代方案。LL 库提供了一组低级 API,可以让用户直接访问 STM32 外设的寄存器。这些 API 比 HAL 更加高效,但是需要更深入的硬件知识。

    使用kill5和cubeMX软件

    二、stm32启动

    3.1系统架构

    总线矩阵(Bus Matrix): 总线矩阵主要用于在多个主设备(如 CPU、DMA 等)和从设备(内存和外设)之间进行数据的路由和管理。通过 总线矩阵,主设备可以同时(并行)地访问从设备。

    DMA 总线(DMA Bus): DMA,全称 Direct Memory Access,是一种让某些硬件子系统在内存和外设之间直接传输数据,而无需处理器参与的技术。在 STM32 中,DMA 总线主要用于 DMA 控制器和内存以及需要使用 DMA 服务的外设(如 USART、SPI、ADC 等)之间的数据传输。

    ICode 总线(ICode Bus/IBus): ICode 总线是一个专门用于 CPU 从 Flash 内存中取指令的总线。这条总线专门优化了指令的取得,以提高 CPU 的 性能。专门用于从 Flash 内存或者其他指令存储器中获取指令,支持 CPU 以最优化的方式取指。该总线用于把指 令从存储器传输到处理器核心,以便执行,主要面向读操作。

    DCode 总线(DCode Bus/DBus): DCode 总线是一个专门用于 CPU 访问数据的总线,可以从 Flash 内存或系统内存中读取数据。用于 CPU 核心的数据访问,包括对 Flash 内存和 RAM 的读写。使数据可以并行地(与指令访问操作并行)从存储器中读取或写入。

    3.2存储器的架构

    闪存:512KB 主存SRAM

    程序存储器、数据存储器、寄存器和输入输出端口(外设)被组织在同一个 4GB 的线性地址空间内。可访问的存储器空间被分成 8 个主要块,每个块为 512MB。

    3.3 stm32启动方式

    跳帽:

    BOOT0/BOOT1: 0 启动方式从 Flash 中启动

    3.4启动文件过程

    从汇编主程序开始中的复位处理(上电之后或按RST键进行的处理过程):

    选择 SystemInit 系统初始化, 再调用 __main函数执行核心应用程序。

    SystemInit 的主要目的是进行系统级别的初始化,包括配置内部硬件和设置系统的运行环境。

    __main函数:

    负责完成初始化 C 环境、设置堆栈、清零全局和静态变量等,并最终调用用户定义的 main 函数

    四、stm32 系统时钟

    4.1 系统时钟的时钟源

    三种不同的时钟源可被用来驱动系统时钟(SYSCLK): HSI 振荡器时钟(高速系统内部时钟)、 HSE 振荡器 时钟(高速系统外部时钟)和 PLL 时钟(锁相环时钟)。

    以上三种时钟都有以下 2 种二级时钟源:

    1. 40kHz 低速内部 RC (LSI),可以用于驱动独立看门狗和通过程序选择驱动 RTC。RTC 用于从停机/待机模式下自动唤醒系统。

    2. 32.768kHz 低速外部晶体也可用来通过程序选择驱动 RTC(RTC CLK)。

    当不被使用时,任一个时钟源都可被独立地启动或关闭,由此优化系统功耗。

    PLL 是 Phase-Locked Loop(相位锁定环)的简称,是一种控制系统的结构,常用于电子通信设备中。在微控制器和嵌入式系统中,PLL 被用作时钟系统的一部分,能够生成频率比输入时钟(通常是内部的低速时钟或者外部的 晶体振荡器提供的时钟)更高的时钟信号。

    五、stm32 通用输入输出

    STM32 Pin引脚 144个

    通用输入输出 : GPIO(112个) , 分为A, B, C,D, E, F, G 七个组, 每一个组分16个索引。如GPIOE5 -> PE5

    5.1 GPIO 框图

    保护二极管: IO 引脚上下两边两个二极管用于防止引脚外部过高、过低的电压输入,当引脚电压高于 VDD_FT 时,上方的二极 管导通,当引脚电压低于 VSS 时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁。

    上拉、下拉电阻: 控制引脚默认状态的电压,开启上拉的时候引脚默认电压为高电平,开启下拉的时候引脚默认电压为低电平。

    TTL 施密特/肖特基触发器: 基本原理是当输入电压高于正向阈值电压,输出为高;当输入电压低于负向阈值电压,输出为低;IO 口信号经过 触发器后,模拟信号转化为 0 和 1 的数字信号。

    P-MOS 管和 N-MOS 管: 信号由 P-MOS 管和 N-MOS 管,依据两个 MOS 管的工作方式,使得 GPIO 具有“推挽输出”和“开漏输出”的模 式。P-MOS 管高电平导通,低电平关闭; N-MOS 低电平导通,高电平关闭。

    5.2 GPIO 的八种工作模式

    输入四种: 浮空输入, 上拉输入、下拉输入, 模拟输入

    输出四种: 推挽输出、开漏输出、复用推挽输出、复用开漏输出

    5.2.1 浮空输入 GPIO_MODE_IN_FLOATING

    浮空输入模式下,I/O 端口的电平信号直接进入输入数据寄存器。MCU 直接读取 I/O 口电平,I/O 的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的,低功耗。

    5.2.2 上拉输入 GPIO_MODE_IPU(In Pull Up)

    IO 内部接上拉电阻,此时如果 IO 口外部没有信号输入或者引脚悬空,IO 口默认为高电平。 如果 I/O 口输入低电平,那么引脚就为低电平,MCU 读取到的就是低电平。

    应用场景:钳位电平、增强驱动能力、抗干扰。可以用来检测外部信号;例如按键等

    5.2.3 下拉输入 GPIO_Mode_IPD(In Pull Down)

    IO 内部接下拉电阻,此时如果 IO 口外部没有信号输入或者引脚悬空,IO 口默认为低电平 如果 I/O 口输入高电平,那么引脚就为高电平,MCU 读取到的就是高电平,可以用来检测外部信号; 例如按键等;

    5.2.4 模拟输入 GPIO_MODE_AIN(Analog Input)

    当 GPIO 引脚用于 ADC 采集电压的输入通道时,用作"模拟输入"功能,此时信号不经过施密特触发器,直接进入 ADC 模块,并且输入数据寄存器为空 ,CPU 不能在输入数据寄存器上读到引脚状态。 当 GPIO 用于模拟功能时,引脚的上、下拉电阻是不起作用的,这个时候即使配置了上拉或下拉模式,也不会影响 到模拟信号的输入输出。 除了 ADC 和 DAC 要将 IO 配置为模拟通道之外其他外设功能一律要配置为复用功能模式,应用 ADC 模拟输 入,或者低功耗下省电。

    5.2.5 推挽输出 GPIO_Mode_Out_PP(out push—pull)

    在推挽输出模式时,N-MOS 管和 P-MOS 管都工作,如果我们控制输出为 0,低电平,则 P-MOS 管关闭,N-MOS管导通,使输出低电平,I/O 端口的电平就是低电平,若控制输出为 1 高电平,则 P-MOS 管导通 N-MOS 管关闭,输出高电平,I/O 端口的电平就是高电平,外部上拉和下拉的作用是控制在没有输出时 IO 口电平,此时施密特触发器是打开的,即输入可用,通过输入数据寄存器 GPIOx_IDR 可读取 I/O 的实际状态。I/O 口的电平一定是输出的电平,一般应用在输出电平为 0 和 3.3 伏而且需要高速切换开关状态的场合。

    5.2.6 开漏输出 GPIO_Mode_Out_OD(out open drain)

    在开漏输出模式时,只有 N-MOS 管工作,如果我们控制输出为 0,低电平,则 P-MOS 管关闭,N-MOS 管导通, 使输出低电平,I/O 端口的电平就是低电平,若控制输出为 1 时,高电平,则 P-MOS 管和 N-MOS 管都关闭,输出指令就不会起到作用,此时 I/O 端口的电平就不会由输出的高电平决定,而是由 I/O 端口外部的上拉或者下拉决定。 如果没有上拉或者下拉 IO 口就处于悬空状态。并且此时施密特触发器是打开的,即输入可用,通过输入数据寄存器 GPIOx_IDR 可读取 I/O 的实际状态。I/O 口的电平不一定是输出的电平。一般应用在 I2C、SMBUS 通讯等需要"线与"功能的总线电路中。

    5.2.7 复用推挽输出 GPIO_AF_PP(alternate function open push—pull)

    GPIO 复用为其他外设(如 I2C),输出数据寄存器 GPIOx_ODR 无效;输出的高低电平的来源于其它外设,施密特 触发器打开,输入可用,通过输入数据寄存器可获取 I/O 实际状态,除了输出信号的来源改变,其他与推挽输出功 能相同。应用于片内外设功能(I2C 的 SCL,SDA)等

    5.2.8 复用开漏输出 GPIO_AF_OD(alternate function open drain)

    GPIO 复用为其他外设,输出数据寄存器 GPIOx_ODR 无效;输出的高低电平的来源于其它外设,施密特触发器打 开,输入可用,通过输入数据寄存器可获取 I/O 实际状态,除了输出信号的来源改变 其他与开漏输出功能相同。 应用于片内外设功能(TX1,MOSI,MISO.SCK.SS)等。

    六、NVIC 中断

    6.1 NVIC 介绍

    NVIC(Nest Vector Interrupt Controller)嵌套中断向量控制器,作用是管理中断嵌套,核心任务是管理中断优先级。

    特点:

    1. 68 个可屏蔽中断通道(不包含 16 个 Cortex-M3 的中断线)

    2. 16 个可编程的优先等级(使用了二进制 4 位中断优先级)

    3. 低延迟的异常和中断处理

    4. 电源管理控制

    5. 系统控制寄存器的实现

    NVIC 给每个中断赋予抢占优先级和响应(子)优先级

    关系如下:

    1. 拥有较高抢占优先级的中断可以打断抢占优先级较低的中断

    2. 若两个抢占优先级的中断同时挂起,则优先执行响应优先级较高的中断

    3. 若两个挂起的中断优先级都一致,则优先执行位于中断向量表中位置较高的中断

    4. 响应优先级不会造成中断嵌套,也就是说中断嵌套是由抢占优先级决定的

    6.2 HAL中断API

    void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);
    void HAL_NVIC_SetPriority(IRQn_Type IRQn,
    uint32_t PreemptPriority,
    uint32_t SubPriority);

    HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
    __HAL_GPIO_EXTI_GET_IT(GPIO_PIN_x);
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_x);
    void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);

    处理中断函数,需要自己依据中断线定义:

    void 中断线_IRQHandler(void){ }

    在main()函数下方定义即可。

    6.2 示例
    示例1: 按键点灯

    GPIO配置:

    static void MX_GPIO_Init(void)
    {
     ?GPIO_InitTypeDef GPIO_InitStruct = {0};
    /* USER CODE BEGIN MX_GPIO_Init_1 */
    /* USER CODE END MX_GPIO_Init_1 */
    ?
     ?/* GPIO Ports Clock Enable */
     ?__HAL_RCC_GPIOE_CLK_ENABLE(); ?//D1 PE5,  PE3按键 Key1
    ?
     ?/*Configure GPIO pin Output Level */
     ?HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET); ?// 0
    ?
    ?
     ?/*Configure GPIO pin : PE5 */
     ?GPIO_InitStruct.Pin = GPIO_PIN_5;
     ?GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; ?// 推挽输出 P-MOS/N-MOS
     ?GPIO_InitStruct.Pull = GPIO_NOPULL;
     ?GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; ?// GPIO_SPEED_FREQ_LOW == MODE: 10  10MHz
     ?HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    ?
    ?
        
        /* 配置GPIO pin: PE3 Key1 */
        GPIO_InitStruct.Pin = GPIO_PIN_3;
     ?GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
     ?GPIO_InitStruct.Pull = GPIO_NOPULL;
     ?GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     ?HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    ?
    /* USER CODE BEGIN MX_GPIO_Init_2 */
    /* USER CODE END MX_GPIO_Init_2 */
    }
    

    main函数的设置中断优先级和开启中断

    /* 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 */
     ? ?// 1. 设置中断的优先级 
        HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
        // 2. 开启中断
        HAL_NVIC_EnableIRQ(EXTI3_IRQn);
     ?/* USER CODE END 2 */
    

    中断处理函数:

    // 3. 定义中断处理程序
    void EXTI3_IRQHandler(void){
     ?// 1) 定义变量 用于统计按下产生的中断次数
     ?static int n=0;
        // 2) 获取PE3中断状态: SET 1, RESET 0
        if( __HAL_GPIO_EXTI_GET_IT(GPIO_PIN_3) != GPIO_PIN_RESET){
            n++;
            // 3) 防止抖动
            //if( __HAL_GPIO_EXTI_GET_IT(GPIO_PIN_3) != GPIO_PIN_RESET && n >= 5){
             ? ?// 4) 处理中断产生的效果 PE5灯亮/灭
                if( HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_5) == GPIO_PIN_RESET){
                     HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET);
                }else{
                     HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET);
                }
                
                n = 0;
            //}
            __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); // 清除中断状态
        }
        
        HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3); ?// 继续请求GPIO E3的中断处理
    }
    
    示例2: 按键控制蜂鸣器

    在示例1的基本之上, 将PF0使能并初始化,在main函数的while循环中:

    // 2. 开启中断
        HAL_NVIC_EnableIRQ(EXTI3_IRQn);
     ?/* USER CODE END 2 */
     ?/* Infinite loop */
     ?/* USER CODE BEGIN WHILE */
     ?while (1)
      {
            // 当灯亮时,Beep响起来
     ? ?while( !HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_5) ){
             ? HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);
                 HAL_Delay(2);
                 HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);
                 HAL_Delay(2);
            }
     ? ?/* USER CODE BEGIN 3 */
      }
    

    作者:m0_74825003

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【STM32】F103ZET6开发板—-笔记01

    发表回复