STM32实战:基于STM32F103的智能宠物喂食器(定时+定量)

文章目录

一、前言

1.1 技术背景

现代都市生活节奏快,很多养宠物的上班族经常面临无法按时喂食的困扰。智能宠物喂食器应运而生,它能够按照预设的时间和份量自动投放食物,让宠物主人即使不在家也能确保爱宠按时进食。

STM32F103系列微控制器凭借其丰富的外设接口、低功耗特性和高性价比,成为物联网智能硬件开发的理想选择。本项目将展示如何使用STM32F103实现一个功能完善的智能宠物喂食系统。

1.2 应用场景

  • 上班族家庭:工作日自动定时喂食,周末手动控制
  • 短期出差:设置多日喂食计划,远程监控进食情况
  • 多宠物家庭:精确控制每只宠物的食量
  • 宠物店/寄养中心:批量管理多个喂食器

1.3 本文目标

通过本教程,你将学会:

  • STM32F103的RTC实时时钟配置与使用
  • 步进电机驱动与控制算法
  • 重量传感器的校准与数据采集
  • 红外传感器的物体检测
  • OLED显示屏的图形界面开发
  • 按键与旋转编码器的人机交互设计
  • 低功耗待机模式实现

技术栈:

  • 硬件平台:STM32F103C8T6
  • 电机驱动:28BYJ-48步进电机 + ULN2003驱动板
  • 称重模块:HX711 + 5kg压力传感器
  • 显示模块:0.96寸I2C OLED (SSD1306)
  • 通信模块:ESP8266 WiFi模块(可选)
  • 输入设备:旋转编码器 + 按键
  • 传感器:红外对射传感器(检测食物余量)
  • 开发工具:STM32CubeIDE

二、环境准备

2.1 硬件清单

器件名称 型号/规格 数量 说明
主控芯片 STM32F103C8T6 1 Blue Pill开发板
步进电机 28BYJ-48 1 5V减速步进电机
电机驱动 ULN2003 1 步进电机驱动板
称重传感器 HX711模块 1 24位AD转换
压力传感器 5kg称重传感器 1 检测食物重量
OLED显示屏 0.96寸 I2C 1 SSD1306驱动
旋转编码器 EC11 1 带按键功能
红外传感器 对射式 1 检测食物余量
WiFi模块 ESP8266-01S 1 可选,远程控制
电源 5V/2A 1 系统供电

2.2 硬件连接图

PA0-PA3
PB12/PB13
PB6/PB7
PA8/PA9/PA10
PA11
PA2/PA3
STM32F103C8T6
28BYJ-48步进电机
HX711称重模块
OLED显示屏
旋转编码器
红外传感器
ESP8266 WiFi

引脚连接表:

STM32引脚 连接设备 功能说明
PA0-PA3 ULN2003 步进电机驱动
PB12 HX711 DT 称重数据
PB13 HX711 SCK 称重时钟
PB6 OLED SCL I2C时钟
PB7 OLED SDA I2C数据
PA8 编码器A相 旋转检测
PA9 编码器B相 方向检测
PA10 编码器按键 确认/菜单
PA11 红外传感器 食物检测
PA2/PA3 ESP8266 WiFi通信

三、核心实现

3.1 STM32CubeMX配置

时钟配置:

  • HSE Crystal/Ceramic Resonator
  • System Clock: 72MHz
  • RTC时钟源:LSE Crystal (32.768kHz)

外设配置:

  • RTC:使能日历功能
  • TIM2:1ms定时器,用于步进电机控制
  • TIM3:编码器模式,用于旋转编码器
  • I2C1:PB6(SCL), PB7(SDA),OLED通信
  • USART2:PA2(TX), PA3(RX),WiFi通信
  • GPIO
    • PA0-PA3:输出,步进电机
    • PB12:输入,HX711 DT
    • PB13:输出,HX711 SCK
    • PA11:输入,红外传感器
    • PA10:输入,编码器按键(外部中断)

3.2 主程序实现

📄 创建文件:Core/Src/main.c

c 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Smart Pet Feeder System
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "rtc.h"
#include "tim.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"

/* USER CODE BEGIN Includes */
#include "oled_driver.h"
#include "hx711_driver.h"
#include "stepper_motor.h"
#include "encoder.h"
#include "menu_system.h"
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */

/* Private defines -----------------------------------------------------------*/
#define FEED_INTERVAL_MS     60000    // 喂食间隔检查(1分钟)
#define MOTOR_SPEED_DELAY    2        // 电机步进延时(ms)
#define FOOD_THRESHOLD       50       // 食物不足阈值(克)

/* Private variables ---------------------------------------------------------*/
// 喂食计划结构体
typedef struct {
    uint8_t hour;
    uint8_t minute;
    uint16_t amount;      // 喂食量(克)
    uint8_t enabled;      // 是否启用
} FeedSchedule;

// 系统状态
volatile FeedSchedule schedule[4];    // 最多4个喂食时段
volatile uint8_t schedule_count = 0;
volatile uint8_t feeding_in_progress = 0;
volatile float current_weight = 0.0;
volatile uint8_t food_low_warning = 0;

// 显示缓冲区
char display_buffer[32];

/* USER CODE BEGIN PV */
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void Check_Feeding_Schedule(void);
static void Process_Feeding(uint16_t target_amount);
static void Update_Display(void);
static void Enter_LowPower_Mode(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */

/**
  * @brief  主函数入口
  */
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    
    MX_GPIO_Init();
    MX_RTC_Init();
    MX_TIM2_Init();
    MX_TIM3_Init();
    MX_I2C1_Init();
    MX_USART2_UART_Init();
    
    /* USER CODE BEGIN 2 */
    printf("\\r\\n===== Smart Pet Feeder =====\\r\\n");
    
    // 初始化OLED
    OLED_Init();
    OLED_Clear();
    OLED_ShowString(0, 0, "Pet Feeder", 16);
    OLED_ShowString(0, 2, "Initializing...", 8);
    HAL_Delay(1000);
    
    // 初始化HX711
    HX711_Init();
    HX711_Calibrate();  // 校准零点
    
    // 初始化步进电机
    Stepper_Init();
    
    // 初始化编码器
    Encoder_Init();
    
    // 初始化菜单系统
    Menu_Init();
    
    // 加载保存的喂食计划(从Flash或EEPROM)
    Load_Schedule();
    
    printf("System ready\\r\\n");
    OLED_Clear();
    /* USER CODE END 2 */
    
    /* Infinite loop */
    while (1)
    {
        /* USER CODE BEGIN 3 */
        
        // 读取当前重量
        current_weight = HX711_GetWeight();
        
        // 检测食物余量
        food_low_warning = HAL_GPIO_ReadPin(IR_SENSOR_GPIO_Port, IR_SENSOR_Pin);
        
        // 检查喂食计划
        if (!feeding_in_progress)
        {
            Check_Feeding_Schedule();
        }
        
        // 处理用户输入(编码器+按键)
        Menu_ProcessInput();
        
        // 更新显示
        Update_Display();
        
        // 低功耗处理
        if (!feeding_in_progress && !Menu_IsActive())
        {
            Enter_LowPower_Mode();
        }
        
        HAL_Delay(100);
    }
    /* USER CODE END 3 */
}

/**
  * @brief  检查喂食计划
  */
static void Check_Feeding_Schedule(void)
{
    RTC_TimeTypeDef sTime;
    RTC_DateTypeDef sDate;
    static uint8_t last_minute = 255;
    
    // 获取当前时间
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
    
    // 避免同一分钟重复喂食
    if (sTime.Minutes == last_minute)
    {
        return;
    }
    last_minute = sTime.Minutes;
    
    // 检查所有喂食计划
    for (uint8_t i = 0; i < schedule_count; i++)
    {
        if (schedule[i].enabled &&
            schedule[i].hour == sTime.Hours &&
            schedule[i].minute == sTime.Minutes)
        {
            printf("Starting scheduled feeding #%d\\r\\n", i + 1);
            Process_Feeding(schedule[i].amount);
            break;
        }
    }
}

/**
  * @brief  执行喂食过程
  * @param  target_amount: 目标喂食量(克)
  */
static void Process_Feeding(uint16_t target_amount)
{
    feeding_in_progress = 1;
    float start_weight = HX711_GetWeight();
    float target_total = start_weight - target_amount;
    
    printf("Feeding started: target %d grams\\r\\n", target_amount);
    
    // 显示喂食状态
    OLED_Clear();
    OLED_ShowString(0, 0, "Feeding...", 16);
    sprintf(display_buffer, "Target: %dg", target_amount);
    OLED_ShowString(0, 2, display_buffer, 8);
    
    // 启动步进电机
    Stepper_SetDirection(CW);  // 顺时针旋转
    
    while (feeding_in_progress)
    {
        current_weight = HX711_GetWeight();
        float dispensed = start_weight - current_weight;
        
        // 更新显示
        sprintf(display_buffer, "Dispensed: %dg", (int)dispensed);
        OLED_ShowString(0, 4, display_buffer, 8);
        
        // 检查是否达到目标量
        if (current_weight <= target_total || dispensed >= target_amount)
        {
            break;
        }
        
        // 检查食物是否充足
        if (food_low_warning)
        {
            printf("Warning: Food running low!\\r\\n");
            OLED_ShowString(0, 6, "Low Food!", 8);
        }
        
        // 步进电机转动一步
        Stepper_Step();
        HAL_Delay(MOTOR_SPEED_DELAY);
    }
    
    // 停止电机
    Stepper_Stop();
    
    // 显示完成
    OLED_Clear();
    OLED_ShowString(0, 0, "Feeding Done!", 16);
    sprintf(display_buffer, "Total: %dg", (int)(start_weight - current_weight));
    OLED_ShowString(0, 2, display_buffer, 8);
    HAL_Delay(3000);
    
    feeding_in_progress = 0;
    printf("Feeding completed\\r\\n");
}

/**
  * @brief  更新OLED显示
  */
static void Update_Display(void)
{
    RTC_TimeTypeDef sTime;
    RTC_DateTypeDef sDate;
    
    // 如果菜单激活,由菜单系统控制显示
    if (Menu_IsActive())
    {
        return;
    }
    
    // 获取当前时间
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
    
    // 第一行:时间
    sprintf(display_buffer, "%02d:%02d:%02d", sTime.Hours, sTime.Minutes, sTime.Seconds);
    OLED_ShowString(0, 0, display_buffer, 16);
    
    // 第二行:食物重量
    sprintf(display_buffer, "Food: %.1fg", current_weight);
    OLED_ShowString(0, 2, display_buffer, 8);
    
    // 第三行:下次喂食时间
    uint8_t next_feed = 255;
    for (uint8_t i = 0; i < schedule_count; i++)
    {
        if (schedule[i].enabled)
        {
            if (schedule[i].hour > sTime.Hours ||
                (schedule[i].hour == sTime.Hours && schedule[i].minute > sTime.Minutes))
            {
                next_feed = i;
                break;
            }
        }
    }
    
    if (next_feed != 255)
    {
        sprintf(display_buffer, "Next: %02d:%02d", schedule[next_feed].hour, schedule[next_feed].minute);
    }
    else
    {
        sprintf(display_buffer, "Next: --:--");
    }
    OLED_ShowString(0, 4, display_buffer, 8);
    
    // 第四行:状态指示
    if (food_low_warning)
    {
        OLED_ShowString(0, 6, "LOW FOOD!", 8);
    }
    else
    {
        OLED_ShowString(0, 6, "Status: OK", 8);
    }
}

/**
  * @brief  进入低功耗模式
  */
static void Enter_LowPower_Mode(void)
{
    // 关闭OLED显示以节省电量
    OLED_DisplayOff();
    
    // 进入睡眠模式,等待中断唤醒
    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
    
    // 唤醒后恢复显示
    OLED_DisplayOn();
}

/* USER CODE BEGIN 4 */

/**
  * @brief  编码器按键中断回调
  */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == ENCODER_BUTTON_Pin)
    {
        // 消抖
        HAL_Delay(20);
        if (HAL_GPIO_ReadPin(ENCODER_BUTTON_GPIO_Port, ENCODER_BUTTON_Pin) == GPIO_PIN_RESET)
        {
            Menu_ButtonPressed();
        }
    }
}

/* USER CODE END 4 */

/**
  * @brief System Clock Configuration
  */
void SystemClock_Config(void)
{
    // 系统时钟配置代码(由CubeMX生成)
    // ...
}

void Error_Handler(void)
{
    __disable_irq();
    while (1)
    {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
        HAL_Delay(100);
    }
}

3.3 HX711称重驱动

📄 创建文件:Core/Inc/hx711_driver.h

c 复制代码
#ifndef __HX711_DRIVER_H
#define __HX711_DRIVER_H

#include "main.h"

// HX711引脚定义
#define HX711_SCK_GPIO_Port   GPIOB
#define HX711_SCK_Pin         GPIO_PIN_13
#define HX711_DT_GPIO_Port    GPIOB
#define HX711_DT_Pin          GPIO_PIN_12

// 函数声明
void HX711_Init(void);
int32_t HX711_Read(void);
float HX711_GetWeight(void);
void HX711_Calibrate(void);
void HX711_SetScale(float scale);
void HX711_Tare(void);

#endif /* __HX711_DRIVER_H */

📄 创建文件:Core/Src/hx711_driver.c

c 复制代码
#include "hx711_driver.h"
#include "gpio.h"

// 校准参数
static float calibration_scale = 0.0035;  // 默认校准系数
static int32_t offset = 0;

/**
  * @brief  初始化HX711
  */
void HX711_Init(void)
{
    // SCK初始化为输出低电平
    HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET);
}

/**
  * @brief  读取HX711原始数据
  * @retval 24位ADC值
  */
int32_t HX711_Read(void)
{
    int32_t data = 0;
    
    // 等待DT变低(数据准备好)
    while (HAL_GPIO_ReadPin(HX711_DT_GPIO_Port, HX711_DT_Pin) == GPIO_PIN_SET);
    
    // 读取24位数据
    for (int8_t i = 0; i < 24; i++)
    {
        HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_SET);
        data = data << 1;
        HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET);
        
        if (HAL_GPIO_ReadPin(HX711_DT_GPIO_Port, HX711_DT_Pin) == GPIO_PIN_SET)
        {
            data++;
        }
    }
    
    // 第25个脉冲设置增益(128)
    HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET);
    
    // 转换为有符号数
    if (data & 0x800000)
    {
        data |= 0xFF000000;
    }
    
    return data;
}

/**
  * @brief  获取重量值(克)
  * @retval 重量值
  */
float HX711_GetWeight(void)
{
    int32_t raw = HX711_Read();
    return (float)(raw - offset) * calibration_scale;
}

/**
  * @brief  校准零点(去皮)
  */
void HX711_Calibrate(void)
{
    int32_t sum = 0;
    
    // 取10次平均值作为零点
    for (uint8_t i = 0; i < 10; i++)
    {
        sum += HX711_Read();
        HAL_Delay(10);
    }
    
    offset = sum / 10;
}

/**
  * @brief  设置校准系数
  * @param  scale: 校准系数(克/ADC值)
  */
void HX711_SetScale(float scale)
{
    calibration_scale = scale;
}

/**
  * @brief  去皮(当前重量设为0)
  */
void HX711_Tare(void)
{
    HX711_Calibrate();
}

3.4 步进电机驱动

📄 创建文件:Core/Inc/stepper_motor.h

c 复制代码
#ifndef __STEPPER_MOTOR_H
#define __STEPPER_MOTOR_H

#include "main.h"

// 旋转方向
#define CW    0   // 顺时针
#define CCW   1   // 逆时针

// 步进电机引脚
#define MOTOR_IN1_GPIO_Port   GPIOA
#define MOTOR_IN1_Pin         GPIO_PIN_0
#define MOTOR_IN2_GPIO_Port   GPIOA
#define MOTOR_IN2_Pin         GPIO_PIN_1
#define MOTOR_IN3_GPIO_Port   GPIOA
#define MOTOR_IN3_Pin         GPIO_PIN_2
#define MOTOR_IN4_GPIO_Port   GPIOA
#define MOTOR_IN4_Pin         GPIO_PIN_3

// 函数声明
void Stepper_Init(void);
void Stepper_SetDirection(uint8_t dir);
void Stepper_Step(void);
void Stepper_Stop(void);
void Stepper_RotateSteps(uint16_t steps, uint8_t dir);

#endif /* __STEPPER_MOTOR_H */

📄 创建文件:Core/Src/stepper_motor.c

c 复制代码
#include "stepper_motor.h"

// 28BYJ-48步进序列(4相8拍)
static const uint8_t step_sequence[8][4] = {
    {1, 0, 0, 0},
    {1, 1, 0, 0},
    {0, 1, 0, 0},
    {0, 1, 1, 0},
    {0, 0, 1, 0},
    {0, 0, 1, 1},
    {0, 0, 0, 1},
    {1, 0, 0, 1}
};

static uint8_t current_step = 0;
static uint8_t direction = CW;

/**
  * @brief  初始化步进电机
  */
void Stepper_Init(void)
{
    // 所有引脚初始化为低电平
    HAL_GPIO_WritePin(MOTOR_IN1_GPIO_Port, MOTOR_IN1_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_IN2_GPIO_Port, MOTOR_IN2_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_IN3_GPIO_Port, MOTOR_IN3_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_IN4_GPIO_Port, MOTOR_IN4_Pin, GPIO_PIN_RESET);
}

/**
  * @brief  设置旋转方向
  * @param  dir: CW(顺时针)或CCW(逆时针)
  */
void Stepper_SetDirection(uint8_t dir)
{
    direction = dir;
}

/**
  * @brief  执行一步
  */
void Stepper_Step(void)
{
    // 根据方向更新步数
    if (direction == CW)
    {
        current_step++;
        if (current_step >= 8) current_step = 0;
    }
    else
    {
        if (current_step == 0) current_step = 7;
        else current_step--;
    }
    
    // 设置引脚状态
    HAL_GPIO_WritePin(MOTOR_IN1_GPIO_Port, MOTOR_IN1_Pin, 
                      step_sequence[current_step][0] ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_IN2_GPIO_Port, MOTOR_IN2_Pin, 
                      step_sequence[current_step][1] ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_IN3_GPIO_Port, MOTOR_IN3_Pin, 
                      step_sequence[current_step][2] ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_IN4_GPIO_Port, MOTOR_IN4_Pin, 
                      step_sequence[current_step][3] ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

/**
  * @brief  停止电机(所有线圈断电)
  */
void Stepper_Stop(void)
{
    HAL_GPIO_WritePin(MOTOR_IN1_GPIO_Port, MOTOR_IN1_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_IN2_GPIO_Port, MOTOR_IN2_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_IN3_GPIO_Port, MOTOR_IN3_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_IN4_GPIO_Port, MOTOR_IN4_Pin, GPIO_PIN_RESET);
}

/**
  * @brief  旋转指定步数
  * @param  steps: 步数
  * @param  dir: 方向
  */
void Stepper_RotateSteps(uint16_t steps, uint8_t dir)
{
    Stepper_SetDirection(dir);
    for (uint16_t i = 0; i < steps; i++)
    {
        Stepper_Step();
        HAL_Delay(2);  // 2ms每步
    }
    Stepper_Stop();
}

四、测试验证

4.1 硬件测试

测试1:称重传感器校准

c 复制代码
void Test_Weight_Sensor(void)
{
    printf("Weight sensor test\\r\\n");
    
    // 零点校准
    HX711_Calibrate();
    printf("Zero calibrated\\r\\n");
    
    // 放置已知重量(如100g砝码)
    HAL_Delay(2000);
    
    // 读取并计算校准系数
    float weight = HX711_GetWeight();
    printf("Raw reading: %.2f\\r\\n", weight);
    
    // 校准系数 = 实际重量 / 读数
    float scale = 100.0 / weight;
    printf("Calibration scale: %.6f\\r\\n", scale);
}

测试2:步进电机测试

c 复制代码
void Test_Stepper_Motor(void)
{
    printf("Stepper motor test\\r\\n");
    
    // 顺时针旋转一圈(2048步)
    printf("Rotating CW...\\r\\n");
    Stepper_RotateSteps(2048, CW);
    HAL_Delay(1000);
    
    // 逆时针旋转一圈
    printf("Rotating CCW...\\r\\n");
    Stepper_RotateSteps(2048, CCW);
    
    printf("Motor test complete\\r\\n");
}

4.2 功能测试

测试3:喂食功能测试

  • 设置喂食量为50克
  • 验证实际出食量是否准确
  • 测试多次喂食的一致性

五、故障排查

5.1 常见问题

问题1:称重数据不稳定

原因分析:

  • 电源噪声干扰
  • 机械振动
  • 传感器安装不牢固

解决方案:

  • 使用独立稳压电源给HX711供电
  • 添加软件滤波算法
  • 加固传感器安装
c 复制代码
// 软件滤波:滑动平均
float GetFilteredWeight(void)
{
    static float buffer[10];
    static uint8_t index = 0;
    
    buffer[index] = HX711_GetWeight();
    index = (index + 1) % 10;
    
    float sum = 0;
    for (uint8_t i = 0; i < 10; i++)
    {
        sum += buffer[i];
    }
    return sum / 10.0;
}
问题2:电机堵转或异响

原因分析:

  • 食物卡住
  • 电机驱动电流不足
  • 步进序列错误

解决方案:

  • 添加堵转检测功能
  • 使用更大电流的驱动板
  • 检查步进序列配置

六、总结

6.1 核心知识点

  1. RTC实时时钟:实现精准的定时功能
  2. 步进电机控制:精确的定量投放控制
  3. 称重传感器:高精度的重量检测
  4. OLED图形界面:友好的用户交互
  5. 低功耗设计:延长电池续航时间

6.2 扩展方向

  • 摄像头监控:添加摄像头记录宠物进食情况
  • 语音播报:添加语音模块播放录音吸引宠物
  • 手机APP:开发配套APP远程控制
  • 多宠物识别:使用RFID识别不同宠物

6.3 学习资源

相关推荐
莎士比亚的文学花园1 天前
stm32——平衡小车
stm32·单片机·嵌入式硬件
Hello_Embed1 天前
STM32CubeIDE 创建第1个工程
stm32·单片机·嵌入式·ai编程
小麦嵌入式1 天前
FPGA入门(一):手把手教你用 Vivado 创建工程并仿真
stm32·单片机·嵌入式硬件·mcu·fpga开发·硬件架构·硬件工程
czwxkn1 天前
PCB设计-器件:2.电感
嵌入式硬件
佳木逢钺1 天前
从零开始:基于STM32H750的硬件设计与软件开发完整流程详解
stm32·单片机·嵌入式硬件
踏着七彩祥云的小丑1 天前
嵌入式——认识电子元器件——光电器件系列
单片机·嵌入式硬件
羽获飞1 天前
从零开始学嵌入式之STM32——31.高级定时器
stm32·单片机·嵌入式硬件
iCxhust2 天前
一块电路板的自觉
单片机·嵌入式硬件·嵌入式·微机原理
学习者1234567892 天前
Bootloader跳转APP代码流程
单片机·嵌入式硬件
ACP广源盛139246256732 天前
一芯搞定多屏高清@ACP#GSV1221 DP 1.4 MST 转 HDMI 1.4 高集成转换芯片
网络·人工智能·嵌入式硬件·计算机外设·电脑