【STM32单片机入门秘籍】:从小白到大师,快速掌握STM32
发布时间: 2024-07-04 15:25:26 阅读量: 97 订阅数: 34
![STM32](https://wiki.st.com/stm32mpu/nsfr_img_auth.php/2/25/STM32MP1IPsOverview.png)
# 1. STM32单片机简介
STM32单片机是意法半导体(STMicroelectronics)公司推出的基于ARM Cortex-M内核的高性能微控制器系列。它以其卓越的性能、丰富的外设和广泛的应用而闻名。
STM32单片机广泛应用于工业控制、医疗设备、汽车电子、物联网等领域。其强大的处理能力、丰富的通信接口和低功耗特性使其成为嵌入式系统开发的理想选择。
# 2. STM32单片机硬件基础
### 2.1 STM32单片机架构
#### 2.1.1 Cortex-M内核
STM32单片机采用ARM Cortex-M系列内核,具有低功耗、高性能的特点。Cortex-M内核采用哈佛架构,具有独立的指令和数据总线,提高了指令执行效率。
Cortex-M内核包含多个寄存器组,包括通用寄存器、控制寄存器和状态寄存器。通用寄存器用于存储数据和地址,控制寄存器用于控制内核的行为,状态寄存器用于指示内核的状态。
#### 2.1.2 外设总线和中断系统
STM32单片机的外设总线包括APB总线、AHB总线和AXI总线。APB总线用于连接低速外设,AHB总线用于连接高速外设,AXI总线用于连接高性能外设。
STM32单片机的中断系统支持多级中断,每个中断源都可以配置自己的优先级。中断系统可以根据优先级对中断进行排序,并自动执行中断处理程序。
### 2.2 STM32单片机外设
#### 2.2.1 GPIO接口
GPIO接口(通用输入/输出接口)是STM32单片机最基本的输入/输出接口。GPIO接口可以配置为输入、输出或模拟功能。
GPIO接口具有可编程的引脚功能,可以配置为推挽输出、开漏输出、上拉输入或下拉输入。GPIO接口还支持中断功能,可以检测引脚状态的变化。
#### 2.2.2 定时器
STM32单片机有多个定时器外设,可以用于生成脉冲、测量时间和产生PWM信号。定时器可以配置为不同的模式,包括定时器模式、计数器模式和PWM模式。
定时器具有可编程的时钟源和分频器,可以产生不同的时钟频率。定时器还支持中断功能,可以检测定时器事件的发生。
#### 2.2.3 ADC和DAC
ADC(模数转换器)可以将模拟信号转换为数字信号,DAC(数模转换器)可以将数字信号转换为模拟信号。ADC和DAC外设可以用于测量和产生模拟信号。
ADC外设具有可编程的分辨率和采样率,可以实现不同的精度和速度。DAC外设具有可编程的输出电压范围和精度,可以产生不同的模拟信号。
**表格:STM32单片机外设汇总**
| 外设 | 功能 | 特性 |
|---|---|---|
| GPIO | 通用输入/输出 | 可编程引脚功能,支持中断 |
| 定时器 | 脉冲生成、时间测量、PWM | 可编程时钟源和分频器,支持中断 |
| ADC | 模数转换 | 可编程分辨率和采样率 |
| DAC | 数模转换 | 可编程输出电压范围和精度 |
**代码块:GPIO接口配置为输出模式**
```c
/* 使能GPIOB时钟 */
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
/* 配置PB0为输出模式 */
GPIOB->CRH &= ~(GPIO_CRH_MODE0);
GPIOB->CRH |= GPIO_CRH_MODE0_0;
```
**逻辑分析:**
* RCC->APB2ENR |= RCC_APB2ENR_IOPBEN:使能GPIOB时钟。
* GPIOB->CRH &= ~(GPIO_CRH_MODE0):清除PB0引脚的模式位。
* GPIOB->CRH |= GPIO_CRH_MODE0_0:将PB0引脚配置为输出模式。
**mermaid流程图:GPIO接口配置流程**
```mermaid
sequenceDiagram
participant GPIOB
participant RCC
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN
GPIOB->CRH &= ~(GPIO_CRH_MODE0)
GPIOB->CRH |= GPIO_CRH_MODE0_0
```
# 3.1 STM32单片机编程环境
#### 3.1.1 Keil MDK
Keil MDK(Microcontroller Development Kit)是ARM公司推出的集成开发环境(IDE),专门用于ARM Cortex-M系列单片机的开发。它包含了编译器、调试器、仿真器等一系列工具,为开发者提供了全面的开发平台。
Keil MDK具有以下特点:
- **支持多种ARM Cortex-M内核:**支持Cortex-M0、M0+、M3、M4、M7等多种内核,覆盖了STM32单片机的全系列产品。
- **丰富的调试功能:**提供单步调试、断点调试、变量监视等多种调试功能,帮助开发者快速定位和解决程序中的问题。
- **强大的仿真器:**内置仿真器,可以模拟STM32单片机的运行,方便开发者在不使用实际硬件的情况下进行程序调试和验证。
- **代码生成效率高:**采用ARM Compiler 6编译器,代码生成效率高,可以生成高效、紧凑的代码。
- **丰富的第三方库支持:**支持多种第三方库,如CMSIS、HAL库等,方便开发者快速开发应用程序。
#### 3.1.2 IAR Embedded Workbench
IAR Embedded Workbench是IAR Systems公司推出的集成开发环境(IDE),也专门用于ARM Cortex-M系列单片机的开发。它同样包含了编译器、调试器、仿真器等一系列工具,与Keil MDK相比,它具有以下特点:
- **代码优化能力强:**IAR Embedded Workbench的编译器具有强大的代码优化能力,可以生成高效、紧凑的代码,在性能方面具有优势。
- **调试功能强大:**提供单步调试、断点调试、变量监视等多种调试功能,还支持代码覆盖率分析,帮助开发者全面了解程序的执行情况。
- **支持多种第三方库:**支持多种第三方库,如CMSIS、HAL库等,方便开发者快速开发应用程序。
- **图形化界面友好:**IAR Embedded Workbench的图形化界面友好,操作直观,上手容易。
总体来说,Keil MDK和IAR Embedded Workbench都是功能强大的STM32单片机编程环境,开发者可以根据自己的喜好和需求进行选择。
# 4. STM32 单片机实战项目
### 4.1 STM32 单片机 LED 闪烁
#### 4.1.1 原理分析
LED 闪烁是最基本的 STM32 单片机实战项目,其原理非常简单。通过控制 GPIO 引脚的电平,可以控制 LED 的亮灭。具体来说,当 GPIO 引脚电平为高电平时,LED 点亮;当 GPIO 引脚电平为低电平时,LED 熄灭。
#### 4.1.2 代码实现
```c
#include "stm32f10x.h"
int main() {
// 初始化 GPIOC 时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
// 配置 GPIOC13 为输出模式
GPIOC->CRH &= ~GPIO_CRH_MODE13;
GPIOC->CRH |= GPIO_CRH_MODE13_0;
while (1) {
// 点亮 LED
GPIOC->BSRR = GPIO_BSRR_BS13;
// 延时 500ms
for (int i = 0; i < 500000; i++) {
__NOP();
}
// 熄灭 LED
GPIOC->BSRR = GPIO_BSRR_BR13;
// 延时 500ms
for (int i = 0; i < 500000; i++) {
__NOP();
}
}
}
```
**代码逻辑分析:**
1. 初始化 GPIOC 时钟,使能 GPIOC 外设。
2. 配置 GPIOC13 为输出模式,用于控制 LED。
3. 进入无限循环,不断点亮和熄灭 LED。
4. `GPIOC->BSRR = GPIO_BSRR_BS13`:设置 GPIOC13 为高电平,点亮 LED。
5. `GPIOC->BSRR = GPIO_BSRR_BR13`:设置 GPIOC13 为低电平,熄灭 LED。
6. `for` 循环用于延时,控制 LED 的闪烁频率。
### 4.2 STM32 单片机按键检测
#### 4.2.1 原理分析
按键检测也是一个常见的 STM32 单片机实战项目。通过检测 GPIO 引脚的电平,可以判断按键是否被按下。具体来说,当按键按下时,GPIO 引脚电平为低电平;当按键松开时,GPIO 引脚电平为高电平。
#### 4.2.2 代码实现
```c
#include "stm32f10x.h"
int main() {
// 初始化 GPIOA 时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 配置 GPIOA0 为输入模式
GPIOA->CRL &= ~GPIO_CRL_MODE0;
GPIOA->CRL |= GPIO_CRL_MODE0_0;
while (1) {
// 检测按键是否按下
if ((GPIOA->IDR & GPIO_IDR_IDR0) == 0) {
// 按键按下,执行相应操作
// ...
}
}
}
```
**代码逻辑分析:**
1. 初始化 GPIOA 时钟,使能 GPIOA 外设。
2. 配置 GPIOA0 为输入模式,用于检测按键。
3. 进入无限循环,不断检测按键是否按下。
4. `(GPIOA->IDR & GPIO_IDR_IDR0) == 0`:判断 GPIOA0 引脚电平是否为低电平,如果为低电平,则表示按键按下。
5. 如果按键按下,执行相应的操作(如打印信息、控制 LED 等)。
### 4.3 STM32 单片机 UART 通信
#### 4.3.1 原理分析
UART 通信是 STM32 单片机中常用的通信方式。通过 UART 接口,可以与其他设备进行数据收发。UART 通信需要使用两个 GPIO 引脚,一个用于发送数据(TX),另一个用于接收数据(RX)。
#### 4.3.2 代码实现
```c
#include "stm32f10x.h"
int main() {
// 初始化 GPIOA 时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 配置 GPIOA9 为 TX 引脚
GPIOA->CRH &= ~GPIO_CRH_MODE9;
GPIOA->CRH |= GPIO_CRH_MODE9_1;
// 配置 GPIOA10 为 RX 引脚
GPIOA->CRH &= ~GPIO_CRH_MODE10;
GPIOA->CRH |= GPIO_CRH_MODE10_1;
// 初始化 USART1
USART1->BRR = 0x0683; // 波特率 9600
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE; // 使能发送和接收
while (1) {
// 发送数据
USART1->DR = 'A';
// 等待发送完成
while ((USART1->SR & USART_SR_TXE) == 0) {
__NOP();
}
// 接收数据
while ((USART1->SR & USART_SR_RXNE) == 0) {
__NOP();
}
uint8_t data = USART1->DR;
// 处理接收到的数据
// ...
}
}
```
**代码逻辑分析:**
1. 初始化 GPIOA 时钟,使能 GPIOA 外设。
2. 配置 GPIOA9 为 TX 引脚,GPIOA10 为 RX 引脚。
3. 初始化 USART1,设置波特率和使能发送和接收。
4. 进入无限循环,不断发送和接收数据。
5. `USART1->DR = 'A'`:发送字符 'A'。
6. `while ((USART1->SR & USART_SR_TXE) == 0)`:等待发送完成。
7. `while ((USART1->SR & USART_SR_RXNE) == 0)`:等待接收完成。
8. `uint8_t data = USART1->DR`:读取接收到的数据。
9. 处理接收到的数据(如打印信息、控制 LED 等)。
# 5.1 STM32单片机RTOS编程
### 5.1.1 RTOS概述
**RTOS(实时操作系统)**是一种专为嵌入式系统设计的操作系统,它提供了任务调度、同步和通信等基本功能,使开发者能够创建复杂的实时应用程序。
RTOS的核心组件包括:
- **任务:**执行特定功能的独立代码块。
- **调度程序:**负责管理任务的执行顺序,确保实时响应。
- **同步机制:**用于协调任务之间的访问共享资源,防止冲突。
- **通信机制:**用于任务之间交换数据和消息。
### 5.1.2 FreeRTOS移植
FreeRTOS是广泛使用的开源RTOS,可移植到各种嵌入式平台,包括STM32单片机。
移植FreeRTOS到STM32单片机需要以下步骤:
1. **创建FreeRTOS配置:**根据STM32单片机的具体型号和外设配置FreeRTOS。
2. **移植内核:**将FreeRTOS内核移植到STM32单片机的架构和外设。
3. **移植驱动程序:**为STM32单片机的外设编写FreeRTOS兼容的驱动程序。
4. **创建任务:**创建任务并配置其优先级、堆栈大小和其他属性。
5. **创建同步机制:**使用FreeRTOS提供的同步机制,如互斥锁和信号量,协调任务之间的访问共享资源。
**代码示例:**
```c
#include "FreeRTOS.h"
#include "task.h"
// 任务1
void task1(void *pvParameters) {
while (1) {
// 执行任务1的代码
vTaskDelay(100);
}
}
// 任务2
void task2(void *pvParameters) {
while (1) {
// 执行任务2的代码
vTaskDelay(200);
}
}
int main(void) {
// 创建任务1
xTaskCreate(task1, "Task1", 128, NULL, 1, NULL);
// 创建任务2
xTaskCreate(task2, "Task2", 128, NULL, 2, NULL);
// 启动调度程序
vTaskStartScheduler();
return 0;
}
```
0
0