【STM32单片机入门指南】:10步快速掌握STM32架构与原理
发布时间: 2024-07-01 20:52:49 阅读量: 104 订阅数: 65
嵌入式原理-STM32的芯片内部架构.pptx
![【STM32单片机入门指南】:10步快速掌握STM32架构与原理](https://img-blog.csdnimg.cn/5903670652a243edb66b0e8e6199b383.jpg)
# 1. STM32单片机概述
STM32单片机是意法半导体(STMicroelectronics)生产的一系列32位微控制器。它们基于ARM Cortex-M内核,具有高性能、低功耗和丰富的片上外设。STM32单片机广泛应用于工业控制、物联网、消费电子等领域。
STM32单片机的主要特点包括:
* **高性能:**基于ARM Cortex-M内核,主频高达216MHz,提供强大的计算能力。
* **低功耗:**采用先进的低功耗技术,支持多种低功耗模式,延长电池寿命。
* **丰富的片上外设:**集成各种外设,包括GPIO、定时器、UART、ADC、DAC等,满足不同的应用需求。
# 2. STM32单片机架构
STM32单片机架构是其内部结构和功能模块的集合,它决定了单片机的性能和功能。本章节将深入探讨STM32单片机的架构,包括其核心处理器、外设和内存系统。
### 2.1 ARM Cortex-M内核
STM32单片机采用ARM Cortex-M系列内核作为其核心处理器。Cortex-M内核是专为嵌入式系统设计的低功耗、高性能处理器,具有以下特点:
#### 2.1.1 Cortex-M内核架构
Cortex-M内核采用哈佛架构,具有独立的指令和数据存储器。其架构包括以下主要组件:
- **程序计数器(PC):**存储当前正在执行的指令的地址。
- **寄存器文件:**包含通用寄存器和特殊寄存器,用于存储数据和控制信息。
- **指令流水线:**提高指令执行效率,通过预取和解码指令来减少延迟。
- **异常处理单元(EHU):**处理中断和异常情况,确保系统稳定性。
#### 2.1.2 Cortex-M内核指令集
Cortex-M内核支持一系列指令,包括:
- **算术和逻辑指令:**用于执行基本算术和逻辑运算。
- **数据传输指令:**用于在寄存器、存储器和外设之间移动数据。
- **控制流指令:**用于改变程序执行流,包括跳转、分支和调用。
- **异常和中断指令:**用于处理中断和异常情况。
### 2.2 STM32外设
STM32单片机集成了丰富的片上外设,为各种应用提供了强大的功能。这些外设包括:
#### 2.2.1 GPIO(通用输入/输出)
GPIO外设提供数字输入和输出功能,允许单片机与外部设备进行交互。其主要特性包括:
- **可配置的引脚模式:**每个引脚可以配置为输入、输出、中断或模拟功能。
- **可编程中断:**引脚可以配置为在特定事件(例如上升沿或下降沿)时触发中断。
- **高驱动能力:**引脚可以提供高电流驱动能力,适合驱动LED、继电器等外部设备。
#### 2.2.2 定时器
定时器外设用于生成精确的时间间隔和脉冲。其主要特性包括:
- **多种定时器类型:**STM32单片机提供多种定时器类型,包括通用定时器、高级定时器和基本定时器。
- **可编程时基:**定时器可以配置为使用内部时钟或外部时钟源。
- **捕获和比较功能:**定时器可以捕获外部事件并与比较值进行比较,触发中断或生成输出脉冲。
#### 2.2.3 UART(通用异步收发器)
UART外设用于串行通信,允许单片机与外部设备交换数据。其主要特性包括:
- **可配置的波特率:**UART可以配置为使用不同的波特率,以适应各种通信需求。
- **数据格式:**UART支持多种数据格式,包括8位、9位和奇偶校验。
- **FIFO缓冲:**UART包含FIFO缓冲区,用于存储待发送或接收的数据,提高通信效率。
# 3. STM32单片机编程
### 3.1 C语言编程基础
**3.1.1 数据类型和变量**
C语言中,数据类型用于定义变量存储的数据类型,常见的数据类型包括:
- **整数类型:**int、short、long
- **浮点类型:**float、double
- **字符类型:**char
- **字符串类型:**char[]
变量用于存储数据,声明变量时需要指定数据类型和变量名,例如:
```c
int age = 25;
char name[] = "John Doe";
```
**3.1.2 运算符和表达式**
运算符用于对数据进行操作,表达式由运算符和操作数组成。C语言中常见的运算符包括:
- **算术运算符:**+、-、*、/、%
- **关系运算符:**==、!=、<、>、<=、>=
- **逻辑运算符:**&&、||、!
表达式用于计算值,例如:
```c
int sum = a + b;
if (age > 18) {
// ...
}
```
### 3.2 STM32 HAL库
**3.2.1 HAL库简介**
STM32 HAL(硬件抽象层)库是一组软件库,用于简化STM32单片机的编程。HAL库提供了对STM32外设的低级访问,同时隐藏了底层硬件的复杂性。
**3.2.2 GPIO HAL库使用**
GPIO HAL库用于配置和控制STM32的GPIO(通用输入/输出)引脚。使用GPIO HAL库配置GPIO引脚的步骤如下:
1. 初始化GPIO外设:
```c
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
```
2. 设置GPIO引脚电平:
```c
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
```
**3.2.3 定时器 HAL库使用**
定时器 HAL库用于配置和控制STM32的定时器外设。使用定时器 HAL库配置定时器的步骤如下:
1. 初始化定时器外设:
```c
TIM_HandleTypeDef htim;
htim.Instance = TIM2;
htim.Init.Prescaler = 64000;
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.Period = 1000;
HAL_TIM_Base_Init(&htim);
```
2. 启动定时器:
```c
HAL_TIM_Base_Start(&htim);
```
# 4. STM32单片机应用
本章节介绍STM32单片机的实际应用,包括LED控制、串口通信和定时器应用。
### 4.1 LED控制
#### 4.1.1 GPIO配置
LED控制需要配置GPIO(通用输入/输出)引脚。STM32单片机具有多个GPIO端口,每个端口包含多个GPIO引脚。
```c
// GPIO配置函数
void GPIO_Config(void) {
// 使能GPIOA时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 设置PA0引脚为输出模式
GPIOA->CRH &= ~(GPIO_CRH_MODE0);
GPIOA->CRH |= GPIO_CRH_MODE0_0;
}
```
**代码逻辑分析:**
* `RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;`:使能GPIOA时钟,确保GPIOA端口能够正常工作。
* `GPIOA->CRH &= ~(GPIO_CRH_MODE0);`:清除PA0引脚的模式位,将其设置为输出模式。
* `GPIOA->CRH |= GPIO_CRH_MODE0_0;`:设置PA0引脚的模式为输出模式。
#### 4.1.2 LED点亮和闪烁
```c
// LED点亮函数
void LED_On(void) {
// 设置PA0引脚为高电平
GPIOA->BSRR |= GPIO_BSRR_BS0;
}
// LED闪烁函数
void LED_Blink(void) {
while (1) {
// LED点亮100ms
LED_On();
HAL_Delay(100);
// LED熄灭100ms
GPIOA->BSRR |= GPIO_BSRR_BR0;
HAL_Delay(100);
}
}
```
**代码逻辑分析:**
* `GPIOA->BSRR |= GPIO_BSRR_BS0;`:设置PA0引脚为高电平,点亮LED。
* `HAL_Delay(100);`:延时100ms。
* `GPIOA->BSRR |= GPIO_BSRR_BR0;`:设置PA0引脚为低电平,熄灭LED。
### 4.2 串口通信
#### 4.2.1 UART配置
串口通信需要配置UART(通用异步收发器)外设。STM32单片机具有多个UART外设,每个UART外设包含多个UART通道。
```c
// UART配置函数
void UART_Config(void) {
// 使能UART1时钟
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
// 配置UART1波特率为115200
USART1->BRR = 0x082B;
// 配置UART1为8位数据位、无校验位、1个停止位
USART1->CR1 &= ~(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS);
}
```
**代码逻辑分析:**
* `RCC->APB2ENR |= RCC_APB2ENR_USART1EN;`:使能UART1时钟,确保UART1外设能够正常工作。
* `USART1->BRR = 0x082B;`:设置UART1波特率为115200。
* `USART1->CR1 &= ~(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS);`:配置UART1为8位数据位、无校验位、1个停止位。
#### 4.2.2 串口数据收发
```c
// 串口数据发送函数
void UART_SendData(uint8_t data) {
// 等待发送缓冲区为空
while (!(USART1->SR & USART_SR_TXE)) {}
// 发送数据
USART1->DR = data;
}
// 串口数据接收函数
uint8_t UART_ReceiveData(void) {
// 等待接收缓冲区不为空
while (!(USART1->SR & USART_SR_RXNE)) {}
// 接收数据
return USART1->DR;
}
```
**代码逻辑分析:**
* `while (!(USART1->SR & USART_SR_TXE)) {}`:等待发送缓冲区为空,确保数据可以正常发送。
* `USART1->DR = data;`:发送数据。
* `while (!(USART1->SR & USART_SR_RXNE)) {}`:等待接收缓冲区不为空,确保数据可以正常接收。
* `return USART1->DR;`:接收数据。
### 4.3 定时器应用
#### 4.3.1 定时器配置
定时器应用需要配置定时器外设。STM32单片机具有多个定时器外设,每个定时器外设包含多个定时器通道。
```c
// 定时器配置函数
void TIM_Config(void) {
// 使能TIM2时钟
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
// 配置TIM2为向上计数模式、预分频系数为1000、自动重装载值为1000
TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
TIM2->PSC = 1000;
TIM2->ARR = 1000;
}
```
**代码逻辑分析:**
* `RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;`:使能TIM2时钟,确保TIM2外设能够正常工作。
* `TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);`:配置TIM2为向上计数模式。
* `TIM2->PSC = 1000;`:设置TIM2的预分频系数为1000。
* `TIM2->ARR = 1000;`:设置TIM2的自动重装载值为1000。
#### 4.3.2 定时器中断处理
```c
// 定时器中断服务函数
void TIM2_IRQHandler(void) {
// 清除定时器中断标志位
TIM2->SR &= ~TIM_SR_UIF;
// 定时器中断处理代码
}
```
**代码逻辑分析:**
* `TIM2->SR &= ~TIM_SR_UIF;`:清除定时器中断标志位,表示中断已处理完毕。
* `// 定时器中断处理代码`:在此处编写定时器中断处理代码。
# 5. STM32单片机进阶**
**5.1 实时操作系统(RTOS)**
**5.1.1 RTOS简介**
实时操作系统(RTOS)是一种专为嵌入式系统设计的操作系统,它可以确保系统对事件的实时响应。RTOS提供了一组任务调度、同步和通信机制,使开发人员能够创建可靠且可预测的嵌入式系统。
**5.1.2 FreeRTOS使用**
FreeRTOS是一个流行的开源RTOS,它具有轻量级、可移植性和实时性等特点。使用FreeRTOS进行STM32单片机编程需要以下步骤:
1. 创建任务:任务是RTOS中的执行单元,它包含要执行的代码。
2. 创建队列:队列用于任务之间的通信和同步。
3. 创建信号量:信号量用于保护共享资源,防止多个任务同时访问同一资源。
4. 启动任务:任务通过调用vTaskStart()函数启动。
5. 调度任务:RTOS调度器负责根据任务优先级和状态调度任务。
**代码示例:**
```c
#include "FreeRTOS.h"
#include "task.h"
#include "queue.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;
}
```
**5.2 网络通信**
**5.2.1 以太网配置**
STM32单片机可以通过以太网接口与网络连接。以太网配置需要以下步骤:
1. 配置PHY芯片:PHY芯片是连接STM32单片机和以太网物理层的设备。
2. 配置MAC控制器:MAC控制器是STM32单片机中的以太网控制器。
3. 配置IP地址和子网掩码:IP地址和子网掩码用于标识STM32单片机在网络中的位置。
**5.2.2 TCP/IP协议栈使用**
TCP/IP协议栈是一组协议,用于在网络中传输数据。使用TCP/IP协议栈进行STM32单片机编程需要以下步骤:
1. 创建套接字:套接字是网络通信的端点。
2. 绑定套接字:将套接字绑定到特定的IP地址和端口号。
3. 监听套接字:监听套接字等待来自客户端的连接请求。
4. 接受连接:接受客户端的连接请求并创建一个新的套接字用于通信。
5. 发送和接收数据:通过套接字发送和接收数据。
**代码示例:**
```c
#include "lwip/sockets.h"
#include "lwip/netdb.h"
int main(void) {
// 创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 绑定套接字
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(8080);
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
// 监听套接字
listen(sockfd, 5);
// 接受连接
struct sockaddr_in cliaddr;
socklen_t clilen = sizeof(cliaddr);
int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);
// 发送和接收数据
char buf[1024];
while (1) {
int n = recv(connfd, buf, sizeof(buf), 0);
if (n > 0) {
send(connfd, buf, n, 0);
}
}
// 关闭套接字
close(sockfd);
close(connfd);
return 0;
}
```
0
0