STM32:从入门到精通,解锁单片机开发奥秘:10步掌握STM32开发,成为单片机开发高手
发布时间: 2024-07-03 00:16:06 阅读量: 60 订阅数: 54
![STM32:从入门到精通,解锁单片机开发奥秘:10步掌握STM32开发,成为单片机开发高手](https://img-blog.csdnimg.cn/c3437fdc0e3e4032a7d40fcf04887831.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiN55-l5ZCN55qE5aW95Lq6,size_20,color_FFFFFF,t_70,g_se,x_16)
# 1. STM32简介与基础**
STM32是意法半导体(STMicroelectronics)推出的32位微控制器系列,以其高性能、低功耗和丰富的外设而闻名。STM32广泛应用于工业控制、物联网、医疗电子等领域。
本章将介绍STM32的基本概念,包括其架构、内核、外设和开发工具。我们将从STM32的起源和发展历程开始,逐步深入了解其硬件和软件特性。通过本章的学习,读者将对STM32有一个全面的认识,为后续的开发奠定基础。
# 2. STM32开发环境搭建与程序结构
### 2.1 开发环境搭建
**1. 安装Keil MDK**
Keil MDK(Microcontroller Development Kit)是ARM官方提供的集成开发环境(IDE),专用于ARM Cortex-M系列单片机开发。下载并安装Keil MDK,选择对应STM32系列的版本。
**2. 安装STM32CubeMX**
STM32CubeMX是一款图形化配置工具,可简化STM32外设配置和代码生成过程。下载并安装STM32CubeMX,选择对应STM32系列的版本。
**3. 配置开发板**
将STM32开发板连接到计算机,在STM32CubeMX中选择开发板型号,配置时钟、外设等参数。
### 2.2 程序结构分析
**1. 主函数**
STM32程序的入口点为`main()`函数,其格式如下:
```c
int main(void)
{
// 程序代码
return 0;
}
```
**2. 系统初始化**
系统初始化通常在`main()`函数中进行,包括:
- 时钟配置
- 外设初始化
- 中断使能
**3. 主循环**
主循环是程序的无限循环,通常用于处理事件、数据采集或控制任务。
```c
while (1)
{
// 主循环代码
}
```
**4. 中断服务函数**
中断服务函数是响应中断请求而执行的代码段,通常用于处理特定事件。
```c
void SysTick_Handler(void)
{
// 中断服务函数代码
}
```
**5. 库函数**
STM32标准库提供了丰富的函数,可用于简化外设操作、数据处理等任务。
**6. 用户代码**
用户代码是开发人员编写的特定于应用程序的代码,用于实现具体功能。
# 3. STM32外设编程
### 3.1 GPIO编程
GPIO(通用输入/输出)是STM32微控制器上最基本的I/O外设,用于控制外部设备和读取外部信号。
#### GPIO寄存器
GPIO外设由一系列寄存器控制,包括:
- **GPIOx_MODER**:模式寄存器,配置引脚的模式(输入、输出、模拟等)。
- **GPIOx_OTYPER**:输出类型寄存器,配置引脚的输出类型(推挽、开漏)。
- **GPIOx_OSPEEDR**:输出速度寄存器,配置引脚的输出速度(低速、中速、高速)。
- **GPIOx_PUPDR**:上拉/下拉寄存器,配置引脚的上拉/下拉电阻。
- **GPIOx_IDR**:输入数据寄存器,读取引脚的输入状态。
- **GPIOx_ODR**:输出数据寄存器,设置引脚的输出状态。
#### GPIO编程步骤
1. **时钟配置:**启用GPIO外设的时钟。
2. **引脚配置:**配置引脚的模式、输出类型、输出速度和上拉/下拉电阻。
3. **读/写操作:**读取引脚的输入状态或设置引脚的输出状态。
#### 代码示例
```c
// 配置GPIOA的第5个引脚为输出模式
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER &= ~(GPIO_MODER_MODE5);
GPIOA->MODER |= GPIO_MODER_MODE5_0;
// 设置GPIOA的第5个引脚为高电平
GPIOA->ODR |= GPIO_ODR_OD5;
// 读取GPIOA的第5个引脚的输入状态
uint8_t input_state = GPIOA->IDR & GPIO_IDR_ID5;
```
### 3.2 定时器编程
定时器是STM32微控制器上用于生成精确时间间隔或脉冲的I/O外设。
#### 定时器寄存器
定时器外设由一系列寄存器控制,包括:
- **TIMx_CR1**:控制寄存器,控制定时器的启动、停止、复位等。
- **TIMx_PSC**:预分频寄存器,配置定时器的时钟预分频值。
- **TIMx_ARR**:自动重装载寄存器,配置定时器的重装载值。
- **TIMx_CNT**:计数器寄存器,存储定时器的当前计数值。
- **TIMx_CCR1**:捕获/比较寄存器1,用于生成输出比较脉冲。
#### 定时器编程步骤
1. **时钟配置:**启用定时器外设的时钟。
2. **定时器配置:**配置定时器的预分频值、重装载值、计数模式等。
3. **输出比较配置:**配置输出比较通道,生成输出比较脉冲。
4. **定时器启动:**启动定时器。
#### 代码示例
```c
// 配置TIM2为向上计数模式,时钟预分频为1000
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->PSC = 1000;
TIM2->ARR = 1000;
TIM2->CR1 |= TIM_CR1_CEN;
// 配置TIM2的通道1为输出比较模式,比较值设为500
TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
TIM2->CCR1 = 500;
```
### 3.3 串口通信编程
串口通信是STM32微控制器上用于与其他设备进行异步串行通信的I/O外设。
#### 串口寄存器
串口外设由一系列寄存器控制,包括:
- **USARTx_CR1**:控制寄存器,控制串口的启动、停止、复位等。
- **USARTx_BRR**:波特率寄存器,配置串口的波特率。
- **USARTx_SR**:状态寄存器,指示串口的当前状态。
- **USARTx_DR**:数据寄存器,用于发送和接收数据。
#### 串口编程步骤
1. **时钟配置:**启用串口外设的时钟。
2. **串口配置:**配置串口的波特率、数据位、停止位、奇偶校验等。
3. **数据传输:**发送和接收数据。
#### 代码示例
```c
// 配置USART1为8位数据位、1个停止位、无奇偶校验
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
USART1->CR1 &= ~(USART_CR1_M | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE);
USART1->CR1 |= USART_CR1_M_1;
USART1->BRR = 9600;
// 发送数据
USART1->DR = 'A';
// 接收数据
uint8_t received_data = USART1->DR;
```
# 4. STM32高级编程
### 4.1 中断编程
#### 中断概念
中断是一种硬件机制,当特定事件发生时,会暂停当前程序执行,转而执行中断服务程序(ISR)。中断处理完成后,程序将继续从中断发生点继续执行。
#### 中断类型
STM32支持多种中断类型,包括:
- **外部中断:**由外部引脚触发,如按钮按下或外部设备中断。
- **内部中断:**由内部外设触发,如定时器溢出或串口接收数据。
- **NMI中断:**非屏蔽中断,在任何情况下都会被触发。
#### 中断优先级
每个中断都有一个优先级,优先级高的中断会在优先级低的中断之前被处理。STM32支持多达32个优先级等级。
#### 中断编程步骤
1. **配置中断控制器:**设置中断优先级、使能中断。
2. **编写中断服务程序:**定义ISR函数,处理中断事件。
3. **使能中断:**在中断控制器中使能中断。
```c
// 使能外部中断线0
EXTI->IMR |= EXTI_IMR_MR0;
// 配置中断优先级为1
NVIC_SetPriority(EXTI0_IRQn, 1);
// 中断服务程序
void EXTI0_IRQHandler(void) {
// 清除中断标志位
EXTI->PR |= EXTI_PR_PR0;
// 执行中断处理逻辑
// ...
}
```
### 4.2 DMA编程
#### DMA概念
直接内存访问(DMA)是一种硬件机制,允许外设直接与内存进行数据传输,无需CPU参与。这可以显著提高数据传输效率。
#### DMA通道
STM32支持多个DMA通道,每个通道可以连接一个外设和一个内存区域。
#### DMA传输模式
DMA支持多种传输模式,包括:
- **单次传输:**一次传输指定数量的数据。
- **循环传输:**连续传输数据,直到传输完成或DMA被禁用。
- **乒乓传输:**使用两个缓冲区交替传输数据,提高传输效率。
#### DMA编程步骤
1. **配置DMA控制器:**设置传输模式、源地址、目标地址、传输长度。
2. **启动DMA传输:**启动DMA控制器开始传输。
3. **等待传输完成:**轮询DMA控制器状态寄存器,等待传输完成。
```c
// 配置DMA传输
DMA1_Channel1->CCR |= DMA_CCR_DIR_0; // 从外设到内存
DMA1_Channel1->CPAR = (uint32_t)buffer; // 目标地址
DMA1_Channel1->CMAR = (uint32_t)&USART1->DR; // 源地址
DMA1_Channel1->CNDTR = 100; // 传输长度
// 启动DMA传输
DMA1_Channel1->CCR |= DMA_CCR_EN;
// 等待传输完成
while ((DMA1_Channel1->CCR & DMA_CCR_TC) == 0) {}
```
### 4.3 实时操作系统(RTOS)应用
#### RTOS概念
实时操作系统(RTOS)是一种软件平台,为嵌入式系统提供任务调度、同步和通信等功能。它可以提高系统的实时性和可靠性。
#### FreeRTOS
FreeRTOS是STM32常用的RTOS之一,它是一个轻量级、开源、免费的RTOS。
#### RTOS编程步骤
1. **创建任务:**定义任务函数和任务参数。
2. **创建队列:**用于任务间通信。
3. **启动任务:**启动RTOS调度器,开始执行任务。
```c
// 创建任务
TaskHandle_t task1Handle;
xTaskCreate(task1, "Task1", 128, NULL, 1, &task1Handle);
// 创建队列
QueueHandle_t queueHandle = xQueueCreate(10, sizeof(int));
// 启动任务
vTaskStartScheduler();
// 任务1函数
void task1(void *pvParameters) {
while (1) {
int data;
xQueueReceive(queueHandle, &data, portMAX_DELAY);
// 处理数据
// ...
}
}
```
# 5. STM32项目实战
### 5.1 LED闪烁程序
**目标:**编写一个程序,使STM32开发板上连接的LED灯闪烁。
**步骤:**
1. **配置GPIO:**
- 将LED连接到STM32开发板上的GPIO引脚。
- 在代码中配置该GPIO引脚为输出模式。
2. **循环闪烁LED:**
- 在一个无限循环中,执行以下操作:
- 设置GPIO引脚为高电平,使LED亮起。
- 延时一段时间。
- 设置GPIO引脚为低电平,使LED熄灭。
- 延时一段时间。
**代码示例:**
```c
#include "stm32f10x.h"
int main() {
// 配置GPIO
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
GPIOC->CRH &= ~GPIO_CRH_MODE13;
GPIOC->CRH |= GPIO_CRH_MODE13_0;
while (1) {
// LED亮起
GPIOC->BSRR = GPIO_BSRR_BS13;
// 延时
for (int i = 0; i < 1000000; i++);
// LED熄灭
GPIOC->BSRR = GPIO_BSRR_BR13;
// 延时
for (int i = 0; i < 1000000; i++);
}
}
```
### 5.2 定时器延时程序
**目标:**编写一个程序,使用STM32的定时器实现延时功能。
**步骤:**
1. **配置定时器:**
- 选择一个定时器并配置其时钟源和分频系数。
- 设置定时器的重装载值和计数方向。
2. **启动定时器:**
- 使能定时器并开始计数。
3. **等待定时器溢出:**
- 在一个循环中,检查定时器的溢出标志位。
- 当溢出标志位被置位时,延时结束。
**代码示例:**
```c
#include "stm32f10x.h"
int main() {
// 配置定时器
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->CR1 &= ~TIM_CR1_DIR;
TIM2->PSC = 7200 - 1;
TIM2->ARR = 1000 - 1;
// 启动定时器
TIM2->CR1 |= TIM_CR1_CEN;
// 等待定时器溢出
while ((TIM2->SR & TIM_SR_UIF) == 0);
// 清除溢出标志位
TIM2->SR &= ~TIM_SR_UIF;
}
```
### 5.3 串口通信程序
**目标:**编写一个程序,使用STM32的串口进行通信。
**步骤:**
1. **配置串口:**
- 选择一个串口并配置其波特率、数据位、停止位和校验位。
2. **发送数据:**
- 使用串口发送函数发送数据到串口缓冲区。
3. **接收数据:**
- 使用串口接收函数从串口缓冲区接收数据。
**代码示例:**
```c
#include "stm32f10x.h"
int main() {
// 配置串口
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
USART1->BRR = 0x341;
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE;
// 发送数据
USART1->DR = 'H';
while ((USART1->SR & USART_SR_TXE) == 0);
// 接收数据
while ((USART1->SR & USART_SR_RXNE) == 0);
char data = USART1->DR;
}
```
0
0