嵌入式学习笔记

一、前置说明

RTOS学习铺垫

学习RTOS需掌握前置知识:链表、数组;
学习分为三个阶段:

  1. 会调用API
  2. 熟悉内部工作原理
  3. 优化修改

二、串口中断程序编写

1. CubeMX配置要点

  • 串口(UART)属于内部中断,无需配置EXTI(EXTI仅管理GPIO外部中断)
  • 核心配置方向:串口参数(波特率、数据位等)、GPIO引脚、中断优先级与使能
  • 具体流程图见飞书笔记

2. 核心代码解析

(1)串口初始化函数
//HAL库的串口初始化函数
void MX_USART1_UART_Init(void)
{
  /* USER CODE BEGIN USART1_Init 0 */
  /* USER CODE END USART1_Init 0 */
  /* USER CODE BEGIN USART1_Init 1 */
  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 9600;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;//8bit数据位
  huart1.Init.StopBits = UART_STOPBITS_1;//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;//16倍过采样
  if (HAL_UART_Init(&huart1) != HAL_OK)//初始化校验
  {
    Error_Handler();//初始化失败进入错误处理
  }
  /* USER CODE BEGIN USART1_Init 2 */
  /* USER CODE END USART1_Init 2 */
}
(2)串口GPIO与中断初始化
//串口的GPIO初始化
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */
  /* USER CODE END USART1_MspInit 0 */
    /* USART1时钟使能 */
    __HAL_RCC_USART1_CLK_ENABLE();//串口使能

    __HAL_RCC_GPIOA_CLK_ENABLE();//GPIOA时钟使能
    /**USART1 GPIO配置
    PA9     ------> USART1_TX
    PA10    ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;//收发引脚
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;//收发均是复用推挽输出(建议接收配置为浮空/上拉输入)
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//高速传输
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;//开启复用功能
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1中断配置 */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);//设置中断优先级
    HAL_NVIC_EnableIRQ(USART1_IRQn);//使能中断
  /* USER CODE BEGIN USART1_MspInit 1 */
  /* USER CODE END USART1_MspInit 1 */
  }
}

3. 串口中断关键函数与回调

(1)非阻塞发送函数 HAL_UART_Transmit_IT
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
  • 功能:启动中断驱动的UART发送,设置发送缓冲区/计数,使能TXE(发送数据寄存器空)中断,由中断逐字节发送
  • 特性:非阻塞,调用后立即返回,实际发送由中断完成
  • 返回值:HAL_OK/HAL_ERROR/HAL_BUSY
  • 调用示例:HAL_UART_Transmit_IT(&huart1,"xixixi",sizeof("xixixi"));(无超时时间)
(2)发送完成回调函数
//弱函数(用户可重写)
__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  UNUSED(huart);
  /* 需自定义逻辑时,在用户文件中重写该函数 */
}

//自定义重写示例
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart->Instance==USART1)//判断串口实例
  {
    i++;
    if(i>250){
      i=1;
    }
  }
}
  • 注意:串口发送完成后会自动关闭使能,需手动重新使能

三、定时器系统

1. 时钟基础概念

  • 时钟信号:有规律、稳定的周期性方波脉冲,用于计时/计数,决定程序运行速度(如F411最高100M,单条指令耗时1/100μs)
  • 核心参数:周期(T)、频率(f)、占空比(高电平占比)、上升沿/下降沿
  • 时钟源分类:
    • 高速:HSE(外部)、HSI(内部)→ 管理主频
    • 低速:LSE(外部)、LSI(内部)
    • 特殊:SysTick(内核)、TIM(片上外设)

2. SysTick(滴答定时器)

(1)核心特性
  • 归属:Cortex-M4内核,ARM官方开发

  • 类型:24位递减定时器,最大计数值2^24(16777216)

  • 作用:产生时基(通常1ms),为操作系统提供心跳,也可用于基础计时

  • 触发机制:设定初值使能后,每来1个时钟信号计数值-1;减至0触发异常,自动重装初值循环

    Systick流程图

(2)关键寄存器
  • CTRL:控制寄存器(使能、时钟源、中断使能、计数标志)
  • LOAD:重装载寄存器(存储计数初值)
  • VAL:当前值寄存器(存储当前计数值)
(3)HAL_Delay实现原理
#define HAL_MAX_DELAY      0xFFFFFFFFU   //最大延时值
typedef enum
{
  HAL_TICK_FREQ_10HZ         = 100U,
  HAL_TICK_FREQ_100HZ        = 10U,
  HAL_TICK_FREQ_1KHZ         = 1U,
  HAL_TICK_FREQ_DEFAULT      = HAL_TICK_FREQ_1KHZ //默认1KHz(1ms)
} HAL_TickFreqTypeDef;
HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT;

__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();//获取进入延时的初始时间
  uint32_t wait = Delay;

  /* 保证最小延时(防止Delay=0时无等待) */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);//加1ms,存在1ms误差
  }

  //死循环等待,直到当前时间-初始时间≥目标延时
  while((HAL_GetTick() - tickstart) < wait)
  {
  }
}
(4)SysTick中断触发周期配置
  • 初始化链路:main()HAL_Init()HAL_InitTick()HAL_SYSTICK_Config()
  • 配置示例:SystemCoreClock / (1000U /(uint32_t)uwTickFreq)(如SystemCoreClock=4000000UL时,计算得4000,即每4000个时钟周期触发一次中断,对应1ms)

3. TIM定时器(片上外设)

(1)核心特性
  • 类比闹钟,支持定时中断、计数外部脉冲、生成PWM(电机调速/LED调光等)

  • st、其他芯片厂商开发

  • 分类:高级定时器、通用定时器、基本定时器(按复杂度/功能扩展)

  • 位数决定计数上限

    定时器种类

  • 关键参数:

    • 计数器分辨率:0~65535(16位)
    • 计数类型:向上/向下/向上+向下计数
    • 预分频因子(PSC):16位寄存器(0~65535),0=不分频,1=2分频,以此类推(如16M时钟分频16得1M)
(2)CubeMX配置要点
  • 时钟来源:内部时钟
  • 预分频值、自动重装载值配置
  • 计数方式选择
  • NVIC中断优先级与使能
  • 通道选择(如需PWM)
  • 从动模式/触发方式(按需配置)
(3)实战:1S串口上报“我来了”

步骤:

  1. 配置串口(参考第二部分)
  2. 配置TIM定时器:
    • 设置预分频值、自动重装载值(实现1S定时)
    • 开启自动重装、NVIC中断使能
  3. 代码实现:
    • 调用函数开启定时器
    • 重写定时器中断回调函数
    • 在回调函数中调用HAL_UART_Transmit_IT发送“我来了”

4. 补充知识点

(1)枚举类型赋值规则
typedef enum {
    A = 1U  //1U:无符号1(减少CPU类型判断开销)
    B = 2UL //2UL:无符号长整型
    C = B   //继承B的值
    D       //未赋值,为前一个值+1(即3)
} name;    
  • 系统库常用U/UL:避免类型转换,提升调用效率
(2)关键外设缩写
  • SDIO:安全数字输入输出接口
  • SWDIO:串行调试输入输出接口
  • EXTI:外部中断控制器
  • NVIC:嵌套向量中断控制器
(3)volatile关键字
  • 作用:防止编译器优化,确保每次读取变量都从内存中获取(定时器/中断相关变量需加)
(4)总线挂载
  • TIM定时器分属APB1(低速)、APB2(高速)总线,可在芯片结构图中查看
  • 例:TIM1/TIM10共用一条中断线

四、待深入探究的问题

  1. 西风的按键消抖方法原理
  2. 串口硬件流控的具体含义与应用场景,NCOF,回顾飞书笔记
  3. 串口过采样的原理与作用
  4. huart->Instance的底层实现与作用
  5. HAL_Delay中“防0操作”的必用场景
  6. SysTick寄存器(CTRL/LOAD/VAL)的详细配置与解析
  7. TIM定时器不同类型(高级/通用/基本)的功能差异
  8. 回顾串口的cubemx配置
  9. 什么是ewarm——IAR
  10. 外部:SR状态寄存器
  11. 不定长串口接收

五、GPIO流程图

在05stm32实战的02点灯

点灯框架图
在通信笔记

通信框架图

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐