ARM单片机C语言怎么学?

99ANYc3cd6
预计阅读时长 21 分钟
位置: 首页 C语言 正文

ARM单片机C语言综合教程

第一章:引言与准备

1 什么是ARM单片机?

  • ARM (Advanced RISC Machines):是一种处理器架构,而不是一个具体的芯片公司,它定义了处理器的指令集、功能等“设计蓝图”。
  • RISC (Reduced Instruction Set Computer):精简指令集计算机,它的特点是指令数量少、执行速度快、效率高,与x86(复杂指令集,如你的电脑CPU)相对。
  • 单片机:将CPU、内存、定时器、I/O端口等集成在一块芯片上的微型计算机系统。
  • ARM单片机:采用了ARM架构的单片机,目前市面上最主流、最流行的就是ARM Cortex-M系列,例如STM32、NXP Kinetis、TI Tiva等。

为什么学习ARM单片机?

arm单片机c语言教程
(图片来源网络,侵删)
  • 市场占有率高:从消费电子到工业控制,ARM无处不在,就业需求大。
  • 性能与功耗平衡:Cortex-M系列在提供强大性能的同时,功耗控制得非常好,适合电池供电的设备。
  • 生态系统完善:有大量的开发工具、开源库、社区支持和学习资料。

2 开发环境搭建

要进行ARM单片机开发,你需要一套工具链,对于初学者,强烈推荐使用集成开发环境。

核心三要素:

  1. IDE (集成开发环境):编写、编译、调试代码的图形化软件。

    • 推荐:Keil MDK (ARM):老牌、稳定、文档齐全,非常适合初学者,有免费版(代码量限制)。
    • 推荐:STM32CubeIDE:ST官方推出的免费IDE,集成了代码生成器(CubeMX),非常强大。
    • 其他选项:IAR Embedded Workbench(商业,非常强大)、VS Code + PlatformIO(开源,灵活)。
  2. 编译器:将你写的C语言代码翻译成ARM CPU能理解的机器码。

    arm单片机c语言教程
    (图片来源网络,侵删)
    • ARMCC/ARMCLANG:Keil和STM32CubeIDE默认使用的编译器。
    • GCC (GNU Compiler Collection):开源,被广泛使用,例如在PlatformIO中。
  3. 调试器/下载器:将编译好的程序下载到单片机中,并可以进行在线调试。

    • ST-Link:ST公司官方的调试器,用于STM32单片机。
    • J-Link:SEGGER公司出品,支持多种ARM芯片,功能强大。
    • U-Link:Keil配套的调试器。

第一步:安装IDE和调试器驱动 以Keil MDK为例:

  1. 下载并安装Keil MDK(例如MDK523)。
  2. 安装对应的芯片包(例如STM32F1 Series Pack)。
  3. 安装ST-Link的USB驱动。

第二章:ARM Cortex-M核心概念

在学习C语言编程前,理解Cortex-M内核的几个关键特性至关重要。

1 寄存器

CPU通过寄存器与内存交互,Cortex-M内核有多个特殊功能寄存器,最核心的是:

arm单片机c语言教程
(图片来源网络,侵删)
  • 通用寄存器R0 ~ R15,用于临时存储数据、地址等。
  • 特殊功能寄存器
    • APSR (Application Program Status Register):应用程序状态寄存器,存放运算结果的标志(如进位、零、负等)。
    • PSR (Program Status Register):程序状态寄存器,包含APSR和中断优先级等。
    • SP (Stack Pointer):堆栈指针,指向栈顶。
    • PC (Program Counter):程序计数器,指向下一条要执行的指令地址。

2 存储器映射

ARM单片机内部有不同功能的存储区域,每个区域都有固定的地址。

  • 代码区:存放你的程序代码。
  • SRAM (静态随机存取存储器):存放全局变量、静态变量、堆栈,断电后数据丢失。
  • 寄存器区:控制所有外设(GPIO、串口、定时器等)的寄存器都集中在这里。
  • 片上Flash:用于程序存储,可以长期保存代码。
  • 外设区:虽然寄存器在寄存器区,但通常我们通过访问外设的“基地址 + 偏移量”来操作它们。

示例:STM32F103的GPIOA端口的寄存器基地址是 0x40010800,要操作GPIOA的输出数据寄存器(ODR),地址就是 0x4001080C

3 启动文件与系统初始化

当你按下复位键,单片机并不会直接运行你的main函数,它会先执行一段启动代码。

  • 启动文件:由汇编语言编写,完成以下工作:
    1. 设置堆栈指针。
    2. 将已初始化的全局变量从Flash复制到SRAM中。
    3. 清零未初始化的全局变量(BSS段)。
    4. 调用SystemInit()函数,配置系统时钟(将内部8MHz的时钟倍频到72MHz)。
    5. 调用main()函数,跳转到你的C语言主程序。

重要:你通常不需要修改启动文件,但需要理解它的存在。

4 中断与异常

这是ARM单片机的强大功能。

  • 异常:由内部事件引起,如系统复位、时钟故障。
  • 中断:由外部事件引起,如按键按下、串口收到数据。
  • NVIC (Nested Vectored Interrupt Controller):嵌套向量中断控制器,它是Cortex-M内核的一部分,负责管理所有的中断,可以设置中断的优先级、使能/失能中断。

第三章:ARM单片机C语言编程

这部分是核心,我们将结合STM32的HAL库(或标准外设库)来讲解。

1 点亮一个LED - GPIO操作

GPIO(General-Purpose Input/Output)是最基础的外设。

步骤:

  1. 使能GPIO时钟:ARM单片机为了省电,所有外设的时钟默认是关闭的,必须先开启对应GPIO端口的时钟。
    • RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 使能GPIOA时钟
  2. 配置GPIO模式:将引脚设置为输出模式(推挽、开漏等)。
    • GPIOA->CRL &= ~(0xF << 4*5); // 清空PA5的配置位
    • GPIOA->CRL |= (0x3 << 4*5); // 设置PA5为推挽输出模式
  3. 输出高低电平:通过设置或清除端口输出数据寄存器来控制引脚。
    • GPIOA->BSRR = (1 << 5); // PA5输出高电平
    • GPIOA->BRR = (1 << 5); // PA5输出低电平

现代方法:使用HAL库 STM32的HAL库封装了这些复杂的寄存器操作,代码更简洁、可移植性更好。

// 在 main.c 中
#include "main.h" // 包含了所有外设的头文件
void SystemClock_Config(void);
int main(void)
{
  // 1. HAL库初始化
  HAL_Init();
  // 2. 配置系统时钟
  SystemClock_Config();
  // 3. 初始化GPIO
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
  GPIO_InitStruct.Pin = GPIO_PIN_5; // 选择PA5引脚
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式
  GPIO_InitStruct.Pull = GPIO_NOPULL; // 不上下拉
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 调用HAL函数完成初始化
  while (1)
  {
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);   // PA5 = 1, LED亮
    HAL_Delay(500); // 延时500ms
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // PA5 = 0, LED灭
    HAL_Delay(500); // 延时500ms
  }
}

HAL库的优势:你只需要关心“做什么”,而不是“怎么做”,代码可读性极高。

2 串口通信 - UART

串口是单片机与PC或其他设备通信的常用方式。

步骤(HAL库):

  1. 使能时钟:使能GPIOA(用于TX, RX引脚)和USART1的时钟。
  2. 配置GPIO:将TX引脚(如PA9)设置为复用功能推挽输出,RX引脚(如PA10)设置为复用功能输入。
  3. 配置USART:设置波特率、数据位、停止位、校验位等。
  4. 初始化USART:调用HAL_UART_Init()
  5. 收发数据
    • 发送:HAL_UART_Transmit(&huart1, (uint8_t*)"Hello", 5, 100);
    • 接收:HAL_UART_Receive(&huart1, rx_buffer, 1, 100);

3 定时器与中断

定时器可以用于精确延时、产生PWM波、或周期性地执行任务。

步骤(HAL库 + 中断):

  1. 使能定时器时钟
  2. 配置定时器参数:设置预分频器、自动重装载值,来计算中断周期。
    • htim.Instance = TIM2;
    • htim.Init.Prescaler = 8000 - 1; // 8MHz / 8000 = 1kHz
    • htim.Init.Period = 1000 - 1; // 1kHz / 1000 = 1Hz (1秒中断一次)
  3. 使能定时器中断:在HAL_TIM_Base_Init之后,调用HAL_NVIC_SetPriorityHAL_NVIC_EnableIRQ来配置NVIC。
  4. 启动定时器HAL_TIM_Base_Start_IT(&htim2);
  5. 编写中断服务函数:HAL库会自动调用这个函数。
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
      if (htim->Instance == TIM2)
      {
        // 每隔1秒,翻转一次LED
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
      }
    }

第四章:进阶主题

1 DMA (Direct Memory Access)

作用:让数据在内存和外设之间直接传输,无需CPU参与,解放CPU,提高效率。 应用场景:高速数据采集(如ADC)、大量数据发送(如通过串口发送文件)。

2 FreeRTOS实时操作系统

作用:当一个任务变得复杂(需要同时处理按键、串口、定时器等多个事件),裸机编程会变得非常困难,RTOS可以帮你管理多个任务,让它们“看起来”在同时运行。 核心概念:任务、调度器、信号量、队列、互斥锁。


第五章:学习路径与资源推荐

1 推荐的学习路径

  1. 基础阶段

    • 掌握C语言基础(指针、结构体、位操作是重中之重)。
    • 学会点亮一个LED,控制蜂鸣器。
    • 学会使用串口打印信息,实现与PC的通信。
    • 学会使用定时器进行精确延时和中断。
    • 目标:完成一个“呼吸灯”项目。
  2. 进阶阶段

    • 学习使用ADC采集模拟信号(如电位器)。
    • 学习使用PWM控制舵机或电机转速。
    • 学习使用I2C、SPI等通信协议驱动OLED屏、传感器(如温湿度)。
    • 目标:完成一个“环境监测器”项目(显示温湿度)。
  3. 高级阶段

    • 学习使用DMA优化串口或ADC数据传输。
    • 学习移植和使用FreeRTOS,实现多任务并发。
    • 学习低功耗模式,延长电池寿命。
    • 目标:完成一个复杂的综合项目,如“智能小车”或“无线遥控器”。

2 推荐资源

  • 开发板
    • 正点原子:教程和配套资料极其丰富,非常适合新手入门。
    • 野火:同样提供非常棒的教程和开发板。
    • ST官方:可以购买Nucleo系列开发板,价格便宜,自带ST-Link调试器。
  • 在线教程
    • B站/YouTube:搜索“STM32入门”、“正点原子”、“野火”,有大量视频教程。
    • ST官方网站:提供数据手册、参考手册、应用笔记和例程,是最终的技术权威。
  • 书籍
    • 《STM32库开发实战指南》- 野火/正点原子
    • 《Cortex-M3权威指南》- Joseph Yiu (如果对底层原理感兴趣)

学习ARM单片机C语言是一个“理论+实践”相结合的过程,不要害怕寄存器,因为HAL库已经帮你处理了大部分复杂性,但理解底层原理(时钟、中断、存储器映射)会让你在遇到问题时更有底气。

动手!动手!再动手! 从点亮第一个LED开始,一步步搭建你的项目,这是最快的学习方式,祝你学习顺利!

-- 展开阅读全文 --
头像
大一C语言程序设计笔记,如何高效入门?
« 上一篇 前天
织梦自定义表单权限如何精细设置?
下一篇 » 前天

相关文章

取消
微信二维码
支付宝二维码

目录[+]