romeo 发表于 2026-4-18 23:43:01

大四毕业设计,AI8051U单片机轻松帮我搞定毕设

转眼间大学生活已接近尾声,毕业设计成为我大学期间最后一次综合性实践。从最初确定课题、梳理方案,到一步步完成硬件搭建、程序编写、系统调试,整个过程充满挑战与成长。而在这段关键历程中,STC AI8051U 擎天柱核心功能板单片机凭借稳定可靠的性能、简洁易用的开发体验,以及丰富的学习资源,成为我顺利完成毕设的关键助力。
我的毕业设计题目是基于 AI8051U 单片机的宠物自动投料喂食器控制系统,主要实现定时定量喂食、手动应急投料、重量检测、OLED 状态显示等功能。系统涉及单片机控制、PWM 舵机驱动、HX711 称重采集、矩阵键盘输入、时钟模块等多个部分,对芯片的 IO 资源、定时器、稳定性都有一定要求。在芯片选型阶段,我曾担心普通单片机资源不足、驱动复杂、调试困难,而在老师的建议下,我选择了 STC AI8051U 擎天柱,事实证明,这一选择让我的整个设计过程事半功倍。
AI8051U 最打动我的一点是上手快、兼容性强、学习成本低。它基于经典增强型 8051 内核,与课堂所学知识高度契合,不需要重新学习复杂架构,让我能快速进入开发状态。同时,官方提供的例程、工具和文档非常完善,再加上论坛里大量实用教程和经验分享,让我在面对舵机驱动、称重采集、键盘消抖等难点时,总能找到清晰思路,少走了大量弯路。
在程序开发阶段,AI8051U 的优势更加明显。芯片拥有充足的 GPIO 口,可轻松连接键盘、OLED、舵机、称重传感器等模块,引脚分配灵活,布线简洁。多路定时器和 PWM 功能让 SG90 舵机控制更加精准,投料角度稳定,不会出现抖动、漏投或多投现象。在编写 HX711 称重程序时,AI8051U 的 IO 口响应速度快、时序稳定,数据采集准确,配合简单滤波即可实现可靠的定量检测。同时,芯片支持 USB 直接下载程序,调试方便快捷,大幅提高开发效率。
系统联调过程中,我遇到过定时不准、按键抖动、舵机干扰等问题,但 AI8051U 凭借稳定的中断系统、良好的抗干扰能力和灵活的配置方式,让这些问题都能快速解决。无论是时钟模块的掉电记忆功能,还是 OLED 屏幕的实时刷新显示,亦或是多模块协同工作,AI8051U 都表现得稳定可靠,确保整个喂食系统运行流畅。
回顾整个毕业设计过程,从方案设计到最终实现,STC AI8051U 擎天柱始终是我最可靠的伙伴。它性能够用、资料齐全、稳定性强、成本友好,特别适合本科生做毕业设计使用。它不仅帮我完成了课题要求,更让我在实践中巩固了嵌入式系统、单片机原理、硬件调试等专业知识,提升了工程实践能力。
在此,我衷心感谢指导老师的耐心帮助,也感谢 STC 提供如此优秀的单片机产品与学习生态。如果你也正在做单片机类毕业设计,纠结主控芯片,我真心推荐STC AI8051U 擎天柱,它简单、强大、靠谱,能帮你高效、顺利地完成毕业设计,轻松迈过大学最后一道关卡。
#ifndef __CONFIG_H__
#define __CONFIG_H__

#include "ai8051u.h"

#define MAIN_Fosc 40000000UL

// ==================== 引脚定义 ====================
sbit OLED_SCL = P2^4;
sbit OLED_SDA = P2^3;
#define OLED_ADDR    0x78

sbit HX711_DOUT = P1^0;
sbit HX711_SCK = P1^1;

sbit SG90 = P1^4;
sbit WATER_PUMP = P1^5;

sbit KEY_MODE = P3^2;      // 自动/手动切换 / 增加值
sbit KEY_SET = P3^3;       // 时间设置(短按)
sbit KEY_SYS_SET = P4^7;   // 系统设置进入按键(短按P4.7)

// ==================== 称重参数 ====================
#define HX711_GapValue       453.1f
#define HX711_SAMPLE_TIMES   3
#define HX711_MAOPI_TIMES    10

// ==================== 舵机参数 ====================
#define SERVO_PWM_0      16
#define SERVO_PWM_180    64

// ==================== 系统参数 ====================
extern unsigned int Weight_Threshold;      // 重量阈值(g)

// ==================== 水位参数 ====================
#define WATER_DRY_ADC         4
#define WATER_WET_ADC         46500
#define WATER_LOW_THRESHOLD   10
#define WATER_HIGH_THRESHOLD    90

// ==================== 时间设置参数 ====================
#define TIME_SET_MODE_NONE      0
#define TIME_SET_MODE_YEAR      1
#define TIME_SET_MODE_MONTH   2
#define TIME_SET_MODE_DAY       3
#define TIME_SET_MODE_HOUR      4
#define TIME_SET_MODE_MINUTE    5
#define TIME_SET_MODE_SECOND    6

// ==================== 状态机定义 ====================
#define STATE_IDLE      0
#define STATE_FEEDING   1
#define STATE_WAITING   2
#define STATE_RETURN    3

// ==================== 系统设置模式定义 ====================
#define SYS_SET_MODE_NONE       0
#define SYS_SET_MODE_TIME1      1   // 设置投喂时间1
#define SYS_SET_MODE_TIME2      2   // 设置投喂时间2
#define SYS_SET_MODE_TIME3      3   // 设置投喂时间3
#define SYS_SET_MODE_WEIGHT   4   // 设置重量阈值
#define SYS_SET_MODE_EXIT       5

// ==================== 时间设置子模式(用于时分切换)====================
#define TIME_SUB_MODE_HOUR      0
#define TIME_SUB_MODE_MINUTE    1

// ==================== 全局变量声明 ====================
extern float Weight_Maopi;
extern float Weight_Shiwu;
extern unsigned int Weight;
extern unsigned int Weight_g;

extern unsigned int year;
extern unsigned char month;
extern unsigned char day;
extern unsigned char hour;
extern unsigned char minute;
extern unsigned char second;

extern unsigned char Servo_State;
extern unsigned char Servo_Angle;
extern unsigned int Servo_Pulse_Count;

extern volatile unsigned int System_Time;
extern unsigned int Cycle_Timer;
extern unsigned int Motion_Timer;

extern bit Auto_Mode;
extern unsigned int Manual_Delay;
extern bit Manual_Trigger;
extern bit Key_Pressed;

extern unsigned int Water_ADC_Raw;
extern unsigned char Water_Percent;
extern unsigned char Water_Status;

extern unsigned char Time_Set_Mode;
extern unsigned char Set_Flash_Cnt;
extern bit Time_Set_Active;

// 系统参数设置相关变量
extern unsigned int Sys_Weight_Threshold;
extern unsigned char Sys_Set_Mode;
extern bit Sys_Set_Active;
extern unsigned char Sys_Feed_Hour;   // 存储三个投喂时间的小时(0-23)
extern unsigned char Sys_Feed_Minute;   // 存储三个投喂时间的分钟(0-59)
extern unsigned char Time_Sub_Mode;      // 当前调整小时还是分钟(仅系统设置界面有效)

// 投喂时间点(小时和分钟可调)
extern unsigned char feed_hour;
extern unsigned char feed_minute;
extern unsigned char feed_flag;         // 当天是否已投喂标志

#endif
* 文件名:adc.c
* 描述:ADC和水位传感器驱动(带突变保持功能)
*********************************************************************/
#include "../System/config.h"
#include "../System/delay.h"
#include "adc.h"

extern unsigned int Water_ADC_Raw;
extern unsigned char Water_Percent;
extern unsigned char Water_Status;

// 静态变量:用于滤波和突变保持
static unsigned int filter_buffer = {0};    // 滑动滤波缓冲区
static unsigned char filter_index = 0;
static unsigned int last_stable_adc = 0;       // 上一次稳定ADC值
static unsigned char last_stable_percent = 0;   // 上一次稳定百分比
static unsigned char jump_counter = 0;          // 突变计数器

// ==================== 滑动平均滤波 ====================
static unsigned int SlidingFilter(unsigned int new_value)
{
    unsigned char i;
    unsigned long sum = 0;
   
    filter_buffer = new_value;
    filter_index++;
    if(filter_index >= 5) filter_index = 0;
   
    for(i = 0; i < 5; i++)
    {
      sum += filter_buffer;
    }
   
    return (unsigned int)(sum / 5);
}

// ==================== 水位百分比计算 ====================
static unsigned char GetWaterPercent(unsigned int adc_raw)
{
    if(adc_raw <= WATER_DRY_ADC)
      return 0;
    else if(adc_raw >= WATER_WET_ADC)
      return 100;
    else
      return (unsigned char)((unsigned long)(adc_raw - WATER_DRY_ADC) * 100 / (WATER_WET_ADC - WATER_DRY_ADC));
}

// ==================== ADC单次读取 ====================
static unsigned int ADC_ReadValue(unsigned char channel)
{
    unsigned int adc_value;
    unsigned int timeout = 10000;
   
    P_SW2 |= 0x80;
   
    ADC_CONTR = 0x80 | (channel & 0x0F) | 0x40;
   
    while(!(ADC_CONTR & 0x20) && --timeout);
   
    if(timeout == 0) {
      P_SW2 &= ~0x80;
      return last_stable_adc;
    }
   
    ADC_CONTR &= ~0x20;
   
    adc_value = ADC_RES;
    adc_value <<= 8;
    adc_value |= ADC_RESL;
   
    P_SW2 &= ~0x80;
   
    return adc_value;
}

// ==================== ADC初始化 ====================
void ADC_Init(void)
{
    unsigned char i;
    unsigned int init_val;
   
    // 设置P1.6为高阻输入
    P1M1 |= 0x40;
    P1M0 &= ~0x40;
   
    // 开启扩展寄存器访问
    P_SW2 |= 0x80;
   
    ADCCFG = 0x0F;
    ADC_CONTR = 0x80;
   
    P_SW2 &= ~0x80;
   
    delay_ms(10);
   
    // 初始化滤波器
    init_val = ADC_ReadValue(6);
    for(i = 0; i < 5; i++)
    {
      filter_buffer = init_val;
    }
    last_stable_adc = init_val;
    last_stable_percent = GetWaterPercent(init_val);
}

// ==================== 水位传感器读取(突变保持版本)====================
void WaterSensor_Read(void)
{
    unsigned int raw_adc;
    unsigned int filtered_adc;
    unsigned char new_percent;
    unsigned char percent_change;
    static unsigned char last_percent = 0;
   
    // ========== 第1步:读取原始ADC值 ==========
    raw_adc = ADC_ReadValue(6);
   
    // ========== 第2步:滑动平均滤波 ==========
    filtered_adc = SlidingFilter(raw_adc);
   
    // ========== 第3步:计算当前水位百分比 ==========
    new_percent = GetWaterPercent(filtered_adc);
   
    // ========== 第4步:计算变化量 ==========
    if(new_percent > last_percent)
      percent_change = new_percent - last_percent;
    else
      percent_change = last_percent - new_percent;
   
    // ========== 第5步:突变检测与保持 ==========
    // 如果变化超过30%(触摸干扰),认为是突变
    if(percent_change > 30)
    {
      jump_counter++;
      // 连续3次突变才认为是真实变化,否则保持上次值
      if(jump_counter < 3)
      {
            // 保持上次值,忽略突变
            new_percent = last_percent;
            filtered_adc = last_stable_adc;
      }
      else
      {
            // 连续3次突变,认为是真实变化
            jump_counter = 0;
            last_stable_adc = filtered_adc;
            last_stable_percent = new_percent;
      }
    }
    else
    {
      // 正常变化,清零突变计数器
      jump_counter = 0;
      last_stable_adc = filtered_adc;
      last_stable_percent = new_percent;
    }
   
    // ========== 第6步:保存最终值 ==========
    Water_ADC_Raw = last_stable_adc;
    Water_Percent = last_stable_percent;
    last_percent = Water_Percent;
   
    // ========== 第7步:状态判断 ==========
    if(Water_Percent <= WATER_LOW_THRESHOLD)
      Water_Status = 0;   // 缺水
    else if(Water_Percent >= WATER_HIGH_THRESHOLD)
      Water_Status = 2;   // 充足
    else
      Water_Status = 1;   // 正常
} * 文件名:hx711.c
* 描述:HX711称重传感器驱动
*********************************************************************/
#include "../System/config.h"
#include "../System/delay.h"
#include "hx711.h"

extern float Weight_Maopi;
extern float Weight_Shiwu;

// 微秒级延时,给HX711通信提供时序
static void HX711_DelayUs(void)
{
    _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
}

// 读取HX711的24位AD原始值(称重传感器核心数据)
static unsigned long HX711_Read(void)
{
    unsigned long count = 0;
    unsigned char i;
   
    HX711_DOUT = 1;
    HX711_DelayUs();
    HX711_SCK = 0;
   
    while(HX711_DOUT);// 等待数据准备好
   
    // 读取24位数据
    for(i = 0; i < 24; i++)
    {
      HX711_SCK = 1;
      count <<= 1;
      HX711_DelayUs();
      HX711_SCK = 0;
      if(HX711_DOUT) count++;
      HX711_DelayUs();
    }
   
    HX711_SCK = 1;
    count ^= 0x800000;// 符号位处理
    HX711_DelayUs();
    HX711_SCK = 0;
   
    return count;
}

// 多次采样取平均值,让重量更稳定
static unsigned long HX711_ReadAverage(unsigned char times)
{
    unsigned long sum = 0;
    unsigned char i;
    for(i = 0; i < times; i++)
    {
      sum += HX711_Read();
      delay_ms(1);
    }
    return sum / times;
}

// 去皮(获取空盘子的重量值)
void Get_Maopi(void)
{
    Weight_Maopi = (float)HX711_ReadAverage(HX711_MAOPI_TIMES);
}

// 获取最终实际重量(克)
unsigned int Get_Weight(void)
{
    unsigned long adc;
    adc = HX711_ReadAverage(HX711_SAMPLE_TIMES);
   
    // 当前重量 - 去皮重量 = 实物重量
    if(adc > Weight_Maopi)
    {
      Weight_Shiwu = (float)(adc - Weight_Maopi);
      Weight_Shiwu = Weight_Shiwu / HX711_GapValue;// 转为克
      if(Weight_Shiwu < 0.2f) Weight_Shiwu = 0;      // 小重量清零
    }
    else
    {
      Weight_Shiwu = 0;
    }
   
    return (unsigned int)(Weight_Shiwu * 100);// 返回扩大100倍的重量值
}


romeo 发表于 2026-4-18 23:44:24

attach://136027.jpg
页: [1]
查看完整版本: 大四毕业设计,AI8051U单片机轻松帮我搞定毕设