嵌入式开发入门:C语言在STM32项目中的实战应用

🎓博主介绍:精通 C、Python、Java、JavaScript 等编程语言,具备全栈开发能力。日常专注于分享编程干货、算法解析、项目实战经验,以及前沿技术动态。让我们一起在技术的道路上不断探索,共同成长!
在这里插入图片描述

嵌入式开发入门:C 语言在 STM32 项目中的实战应用

一、引言

嵌入式系统在当今科技领域无处不在,从智能家居到工业自动化,从汽车电子到医疗设备,嵌入式技术都发挥着至关重要的作用。STM32 系列微控制器作为 ARM Cortex - M 内核的经典代表,以其高性能、低功耗、丰富的外设等特点,成为嵌入式开发的热门选择。而 C 语言凭借其高效、灵活和可移植性,成为了 STM32 开发的首选编程语言。本文将带领大家走进嵌入式开发的世界,详细介绍 C 语言在 STM32 项目中的实战应用。

二、STM32 开发环境搭建

2.1 硬件准备

2.1.1 STM32 开发板

常见的 STM32 开发板有 STM32F103 系列、STM32F407 系列等。以 STM32F103C8T6 开发板为例,它具有丰富的 GPIO 引脚、串口、SPI、I2C 等外设接口,适合初学者进行基础实验和项目开发。

2.1.2 调试工具

常用的调试工具是 ST - Link 或 J - Link 仿真器,用于将程序下载到开发板并进行调试。

2.2 软件准备

2.2.1 开发工具

可以选择 Keil MDK(Microcontroller Development Kit)作为开发环境,它是专门为 ARM 微控制器设计的集成开发环境,支持 C、C++ 等编程语言,具有强大的代码编辑、编译、调试功能。可以从 Keil 官方网站(https://www.keil.com/)下载并安装。

2.2.2 固件库

STM32 官方提供了标准外设库和 HAL(Hardware Abstraction Layer)库。标准外设库是早期的开发库,对硬件的控制更加底层;HAL 库则是后来推出的抽象层库,使用更加方便,易于移植。可以从 STM32 官方网站(https://www.st.com/)下载所需的固件库。

三、C 语言基础回顾

3.1 变量与数据类型

在 C 语言中,常见的数据类型有 int(整数)、float(浮点数)、char(字符)等。例如:

#include <stdio.h>

int main() {
    int num = 10;
    float f = 3.14;
    char ch = 'A';
    printf("整数: %d, 浮点数: %f, 字符: %c\n", num, f, ch);
    return 0;
}

3.2 函数与指针

函数是一段具有特定功能的代码块,指针是存储变量内存地址的变量。例如:

#include <stdio.h>

// 函数定义
int add(int a, int b) {
    return a + b;
}

int main() {
    int num1 = 3, num2 = 5;
    int result = add(num1, num2);
    int *p = &num1;
    printf("两数之和: %d, 指针指向的值: %d\n", result, *p);
    return 0;
}

四、STM32 项目实战:点亮 LED 灯

4.1 项目需求分析

点亮 LED 灯是嵌入式开发的入门项目,通过控制 STM32 的 GPIO(通用输入输出)引脚输出高低电平,来控制 LED 灯的亮灭。

4.2 代码实现步骤

4.2.1 配置 GPIO 引脚

在 STM32 中,需要先对 GPIO 引脚进行初始化配置,包括选择引脚、设置引脚模式等。以下是使用 HAL 库进行 GPIO 初始化的代码示例:

#include "stm32f1xx_hal.h"

// 定义 LED 引脚
#define LED_PIN GPIO_PIN_13
#define LED_PORT GPIOC

// 系统时钟配置
void SystemClock_Config(void);
// GPIO 初始化
static void MX_GPIO_Init(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();

  while (1)
  {
    // 点亮 LED
    HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET);
    HAL_Delay(1000);  // 延时 1 秒
    // 熄灭 LED
    HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET);
    HAL_Delay(1000);  // 延时 1 秒
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** 初始化 RCC 振荡器 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** 初始化 RCC 时钟 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO 端口时钟使能 */
  __HAL_RCC_GPIOC_CLK_ENABLE();

  /* 配置 GPIO 引脚 */
  GPIO_InitStruct.Pin = LED_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
}
4.2.2 控制 LED 灯亮灭

使用 HAL_GPIO_WritePin 函数来控制 GPIO 引脚的输出电平,从而实现 LED 灯的亮灭控制。GPIO_PIN_RESET 表示输出低电平,GPIO_PIN_SET 表示输出高电平。

4.2.3 延时函数的使用

使用 HAL_Delay 函数来实现延时功能,控制 LED 灯亮灭的时间间隔。

4.3 代码编译与下载

4.3.1 编译代码

在 Keil MDK 中,打开项目文件,点击编译按钮(“Build”),Keil 会对代码进行编译和链接,生成可执行文件(.hex 或 .bin 文件)。

4.3.2 下载程序

将 ST - Link 仿真器与开发板连接,在 Keil MDK 中点击下载按钮(“Download”),将生成的可执行文件下载到 STM32 开发板中。下载完成后,开发板上的 LED 灯将按照程序设定的逻辑进行亮灭闪烁。

五、STM32 项目进阶:串口通信

5.1 项目需求分析

串口通信是嵌入式系统中常用的通信方式,通过串口可以实现开发板与计算机或其他设备之间的数据传输。本项目将实现 STM32 开发板通过串口向计算机发送数据。

5.2 代码实现步骤

5.2.1 配置串口

使用 HAL 库对串口进行初始化配置,包括选择串口、设置波特率、数据位、停止位等。以下是串口初始化的代码示例:

#include "stm32f1xx_hal.h"

UART_HandleTypeDef huart1;

// 系统时钟配置
void SystemClock_Config(void);
// GPIO 初始化
static void MX_GPIO_Init(void);
// 串口初始化
static void MX_USART1_UART_Init(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  char *message = "Hello, Serial Communication!\r\n";
  while (1)
  {
    // 通过串口发送数据
    HAL_UART_Transmit(&huart1, (uint8_t *)message, strlen(message), HAL_MAX_DELAY);
    HAL_Delay(1000);  // 延时 1 秒
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** 初始化 RCC 振荡器 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** 初始化 RCC 时钟 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_USART1_UART_Init(void)
{
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_GPIO_Init(void)
{
  __HAL_RCC_GPIOA_CLK_ENABLE();
}
5.2.2 发送数据

使用 HAL_UART_Transmit 函数向串口发送数据,该函数的参数包括串口句柄、数据缓冲区指针、数据长度和超时时间。

5.2.3 接收数据(可选)

如果需要接收计算机发送的数据,可以使用 HAL_UART_Receive 函数,该函数的使用方法与 HAL_UART_Transmit 类似。

5.3 串口调试

使用串口调试助手(如 SecureCRT、串口调试精灵等),将计算机与 STM32 开发板通过串口线连接,设置好波特率等参数,即可在串口调试助手中看到开发板发送的数据。

六、总结

通过以上两个实战项目,我们了解了 C 语言在 STM32 项目中的基本应用,从简单的 GPIO 控制到串口通信,逐步掌握了 STM32 开发的基本流程和方法。在实际开发中,还可以结合更多的外设和功能,如 ADC(模拟 - 数字转换)、定时器、SPI、I2C 等,开发出更加复杂和实用的嵌入式系统。希望本文能为嵌入式开发初学者提供一些帮助,让大家在嵌入式开发的道路上迈出坚实的一步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值