2.1 ARM微控制器是怎样构成的
ARM微控制器通常由处理器内核(如Cortex - M3或Cortex - M4)、片上外设(如定时器、串口、ADC等)、内存(包括Flash用于存储程序代码,SRAM用于数据存储)以及总线系统组成。处理器内核负责执行指令,片上外设实现与外部设备的交互,内存用于存储程序和数据,总线系统则负责在各个组件之间传输数据和控制信号。
2.2 开始时需要准备什么
2.2.1 开发组件
开发ARM微控制器通常需要以下组件:
- 编译器:将高级语言(如C)编写的代码转换为微控制器能够执行的机器语言。例如GCC(GNU Compiler Collection),它是一款常用的开源编译器。
- 调试器:用于查找和修复代码中的错误。例如OpenOCD,它支持多种调试接口(如JTAG、SWD)。
2.2.2 开发板
开发板是进行开发的硬件平台,它集成了ARM微控制器以及相关的外围电路,如电源电路、通信接口等。常见的开发板有STMicroelectronics的STM32系列开发板,方便开发者快速搭建开发环境。
2.2.3 调试适配器
调试适配器用于连接开发板和调试主机(如PC),实现调试器与微控制器之间的通信。例如,ST - Link就是STMicroelectronics为其STM32系列微控制器提供的调试适配器,支持JTAG和SWD调试接口。
2.2.4 软件设备驱动
软件设备驱动是控制微控制器片上外设的程序代码。例如,UART驱动程序用于实现串口通信,它负责配置UART外设的寄存器,实现数据的发送和接收。
2.2.5 例子
以一个简单的LED闪烁程序为例,假设使用STM32开发板:
#include "stm32f10x.h" // 包含对应芯片的头文件,定义了寄存器等
// 初始化LED GPIO口
void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct; // 定义GPIO初始化结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5; // 选择PA5引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 设置为推挽输出模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 设置输出速度
GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIOA
}
int main(void) {
LED_Init(); // 初始化LED
while (1) {
GPIO_SetBits(GPIOA, GPIO_Pin_5); // 点亮LED
for (volatile int i = 0; i < 500000; i++); // 简单延时
GPIO_ResetBits(GPIOA, GPIO_Pin_5); // 熄灭LED
for (volatile int i = 0; i < 500000; i++); // 简单延时
}
}
在这个例子中,LED_Init
函数用于初始化LED连接的GPIO口,这里体现了初始化模式,即将特定的GPIO口配置为所需的输出模式。main
函数中通过循环点亮和熄灭LED,使用了简单的轮询模式来控制LED闪烁。
2.2.6 文档和其他资源
开发过程中需要参考多种文档和资源:
- 芯片数据手册:详细描述微控制器的硬件特性,如引脚功能、寄存器配置等。
- 参考手册:提供更深入的技术细节,如指令集、系统架构等。
- 应用笔记:由芯片厂商提供,介绍如何在特定应用场景下使用微控制器。
2.2.7 其他设备
根据具体应用需求,可能还需要其他设备,如传感器用于数据采集,执行器用于控制外部设备等。
2.3 软件开发流程
- 需求分析:明确应用的功能需求,例如设计一个温度监测系统,需要确定测量范围、精度要求等。
- 设计:包括硬件设计(选择合适的微控制器和外围电路)和软件设计(确定软件架构、模块划分等)。例如,在温度监测系统中,选择带有ADC外设的微控制器用于采集温度传感器数据,软件设计上划分温度采集、数据处理和显示等模块。
- 编码:使用编程语言(如C)编写代码实现设计的功能。
- 调试:使用调试器查找和修复代码中的错误,确保程序按预期运行。
- 测试:对软件进行功能和性能测试,验证是否满足需求。
2.4 编译应用程序
以GCC编译器为例,编译过程通常包括以下步骤:
- 预处理:处理源代码中的预处理指令(如
#include
、#define
)。例如,#include "stm32f10x.h"
指令会将指定的头文件内容插入到源文件中。 - 编译:将预处理后的代码转换为汇编代码。编译器会对C语言代码进行语法和语义分析,生成对应的汇编指令。
- 汇编:将汇编代码转换为目标文件(.o文件),目标文件包含机器语言指令,但还未进行链接。
- 链接:将多个目标文件以及所需的库文件链接成可执行文件。链接过程会解决函数和变量的引用问题,将各个模块组合成一个完整的可执行程序。
2.5 软件流程
2.5.1 轮询
轮询是一种简单的软件流程,程序通过不断查询某个条件或状态来执行相应操作。例如,查询按键状态:
#include "stm32f10x.h"
void Button_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 设置为浮空输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
int main(void) {
Button_Init();
while (1) {
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0) { // 查询按键是否按下
// 执行按键按下后的操作
}
}
}
这里体现了轮询设计模式,程序不断检查按键状态,一旦检测到按键按下,就执行相应操作。这种模式简单直接,但会占用较多CPU资源,适用于对实时性要求不高且任务相对简单的场景。
2.5.2 中断驱动
中断驱动方式下,当特定事件发生时(如外部中断、定时器中断等),微控制器会暂停当前执行的任务,转而执行中断服务程序。例如,使用定时器中断实现定时功能:
#include "stm32f10x.h"
// 定时器初始化函数
void TIM3_Init(void) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能TIM3时钟
TIM_TimeBaseStructure.TIM_Period = 9999; // 设置自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler = 7199; // 设置预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 使能更新中断
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; // 选择TIM3中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; // 设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; // 设置子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3, ENABLE); // 使能定时器
}
// 定时器3中断服务函数
void TIM3_IRQHandler(void) {
if (TIM_GetITStatus(TIM3, TIM_IT_Update)!= RESET) {
// 执行定时任务
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 清除中断标志位
}
}
int main(void) {
TIM3_Init();
while (1) {
// 主循环可以执行其他任务
}
}
这里体现了中断驱动设计模式。通过定时器中断,在设定的时间间隔触发中断服务程序,执行定时任务。主循环可以继续执行其他任务,提高了CPU的利用率,适用于对实时性要求较高的场景。
2.5.3 多任务系统
多任务系统允许在一个微控制器上同时运行多个任务,每个任务可以看作是一个独立的程序。例如,使用FreeRTOS实时操作系统实现多任务:
#include "FreeRTOS.h"
#include "task.h"
// 任务1函数
void Task1(void *pvParameters) {
while (1) {
// 任务1的代码
vTaskDelay(pdMS_TO_TICKS(1000)); // 任务1延时1秒
}
}
// 任务2函数
void Task2(void *pvParameters) {
while (1) {
// 任务2的代码
vTaskDelay(pdMS_TO_TICKS(2000)); // 任务2延时2秒
}
}
int main(void) {
xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL); // 创建任务1
xTaskCreate(Task2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL); // 创建任务2
vTaskStartScheduler(); // 启动任务调度器
while (1) {
// 正常情况下不会执行到这里
}
}
这里体现了多任务设计模式。通过FreeRTOS,创建了两个任务Task1和Task2,每个任务有自己独立的执行逻辑和运行时间。任务调度器负责在不同任务之间进行切换,使得多个任务看似同时运行,提高了系统的并发处理能力,适用于复杂的应用场景。
2.6 C程序中的数据类型
在ARM微控制器开发中,常用的C数据类型包括:
- 基本数据类型:如
char
(字符型,通常占1字节)、short
(短整型,通常占2字节)、int
(整型,通常占4字节)、long
(长整型,通常占4字节或8字节)、float
(单精度浮点型,通常占4字节)、double
(双精度浮点型,通常占8字节)。 - 派生数据类型:如数组、指针、结构体、联合体等。数组用于存储多个相同类型的数据,指针用于存储变量的地址,结构体用于将不同类型的数据组合在一起,联合体则允许不同数据类型共享同一内存空间。
2.7 输入、输出和外设访问
通过微控制器的寄存器来访问外设。例如,访问GPIO口控制LED:
#include "stm32f10x.h"
int main(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟
GPIOA->CRL &= ~(0x0F << (4 * 5)); // 清除PA5的配置位
GPIOA->CRL |= (0x03 << (4 * 5)); // 设置PA5为推挽输出,50MHz
while (1) {
GPIOA->BSRR = GPIO_Pin_5; // 点亮LED
for (volatile int i = 0; i < 500000; i++);
GPIOA->BRR = GPIO_Pin_5; // 熄灭LED
for (volatile int i = 0; i < 500000; i++);
}
}
这里通过直接操作GPIO寄存器(如CRL
、BSRR
、BRR
)来配置GPIO口的模式并控制LED的亮灭,实现了对外设的访问。
2.8 微控制器接口
微控制器常见的接口包括:
- GPIO(通用输入输出口):用于连接外部设备,如LED、按键等,通过配置GPIO寄存器可以设置其输入或输出模式。
- UART(通用异步收发传输器):用于串行通信,如与PC进行串口通信,需要配置波特率、数据位、停止位等参数。
- SPI(串行外设接口):用于高速同步串行通信,常用于连接Flash、传感器等设备。
- I2C(集成电路总线):用于低速同步串行通信,常用于连接多个IC设备,如EEPROM、传感器等。
2.9 Cortex微控制器软件接口标准(CMSIS)
2.9.1 CMSIS简介
CMSIS(Cortex Microcontroller Software Interface Standard)是ARM公司为Cortex - M系列微控制器制定的软件接口标准,旨在提供统一的软件编程接口,提高软件的可移植性和可重用性。
2.9.2 CMSIS - Core所做的标准化
- 内核寄存器访问:提供了一组标准的函数和宏,用于访问Cortex - M内核的寄存器,如NVIC(Nested Vectored Interrupt Controller)寄存器,使不同厂商的微控制器在中断处理方面有统一的编程接口。
- 系统初始化:定义了系统初始化函数
SystemInit
,用于初始化微控制器的系统时钟、外设等,确保在不同微控制器上有一致的初始化流程。
2.9.3 CMSIS - Core的组织结构
CMSIS - Core主要包括以下几个部分:
- 内核头文件:定义了内核寄存器的结构体和访问函数,如
core_cm3.h
或core_cm4.h
,针对Cortex - M3和Cortex - M4内核。 - 启动文件:包含启动代码,用于初始化堆栈、调用
SystemInit
函数等,不同厂商的微控制器可能有不同的启动文件,但都遵循CMSIS标准。 - 系统头文件:定义了系统相关的配置和函数,如
system_stm32f10x.h
,针对特定厂商的微控制器系列。
2.9.4 如何使用CMSIS - Core
- 包含头文件:在源文件中包含相应的CMSIS头文件,如
#include "core_cm3.h"
(对于Cortex - M3内核)。 - 调用初始化函数:在程序开始时调用
SystemInit
函数进行系统初始化。 - 使用寄存器访问函数:通过CMSIS提供的函数和宏访问内核寄存器,例如使用
NVIC_SetPriority
函数设置中断优先级。
2.9.5 CMSIS的优势
- 可移植性:基于CMSIS编写的代码可以在不同厂商的Cortex - M微控制器上轻松移植,减少了软件移植的工作量。
- 可重用性:CMSIS提供的标准接口和函数可以被多个项目重用,提高了开发效率。
- 代码一致性:不同厂商的微控制器在使用CMSIS后,软件编程风格更加一致,便于开发人员学习和维护代码。
2.9.6 CMSIS的多个版本
CMSIS有多个版本,随着Cortex - M系列处理器的发展和新特性的加入,CMSIS也不断更新。每个版本在功能和兼容性上有所改进,例如支持新的内核特性、优化代码结构等,开发者需要根据所使用的微控制器和开发需求选择合适的CMSIS版本。
标签:LED,TIM,CMSIS,M4,嵌入式软件,Cortex,GPIO,void,微控制器 From: https://blog.csdn.net/qq_40844444/article/details/145049911