好的,我已经查阅了AI8051U的详细手册资料。现在我来为您设计一个基于AI8051U实验箱的模拟定时风扇除湿系统。
这个系统将使用:
- ADC 读取湿度传感器(模拟电位器模拟湿度)
- 定时器 产生精确时间基准
- LED/数码管 显示湿度和定时状态
- 按键 设置定时时间
- PWM/IO 控制风扇(用LED模拟)
模拟定时风扇除湿系统 - 完整代码
文件结构
Project_Dehumidifier/
├── main.c # 主程序
├── config.h # 配置文件
├── timer.c/h # 定时器模块
├── adc.c/h # ADC模块
├── key.c/h # 按键模块
├── led.c/h # 数码管显示模块
├── dehumidifier.c/h # 除湿控制逻辑
└── def.h # 基础类型定义
1. def.h - 基础类型定义
#ifndef __DEF_H__
#define __DEF_H__
typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef unsigned long DWORD;
typedef bit BOOL;
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#endif
2. config.h - 系统配置头文件
#ifndef __CONFIG_H__
#define __CONFIG_H__
#define MAIN_Fosc 40000000UL // 系统主频 40MHz
#define FOSC 40000000UL
#include
#include
#include "def.h"
#include "timer.h"
#include "adc.h"
#include "key.h"
#include "led.h"
#include "dehumidifier.h"
/* 系统初始化函数声明 */
void SYS_Init(void);
#endif
3. timer.h - 定时器模块头文件
#ifndef __TIMER_H__
#define __TIMER_H__
extern bit f1ms; // 1ms 标志位
extern bit f10ms; // 10ms 标志位
extern bit f100ms; // 100ms 标志位
extern bit f1s; // 1秒 标志位
void Timer0_Init(void); // 定时器0初始化
#endif
4. timer.c - 定时器模块实现
/*
* timer.c - 定时器模块
* 功能:使用定时器0产生1ms基准时间,通过软件计数产生10ms、100ms、1s标志
*
* 定时器0配置:
* - 工作模式:模式0(16位自动重装载)
* - 时钟源:1T模式(不分频)
* - 预分频:TM0PS = 0(不分频)
* - 定时周期:1ms @ 40MHz
*
* 计算公式:
* 定时器时钟 = SYSclk / (TM0PS + 1) = 40MHz
* 定时周期 = (65536 - [TH0,TL0]) / 40MHz = 1ms
* [TH0,TL0] = 65536 - 40000 = 0x635C
*/
#include "config.h"
bit f1ms = 0; // 1ms 标志位
bit f10ms = 0; // 10ms 标志位
bit f100ms = 0; // 100ms 标志位
bit f1s = 0; // 1秒 标志位
static WORD cnt10 = 0; // 10ms计数器
static WORD cnt100 = 0; // 100ms计数器
static WORD cnt1s = 0; // 1秒计数器
/*
* 定时器0初始化函数
* 配置为1ms定时中断
*/
void Timer0_Init(void)
{
/* 注意:访问XFR寄存器前必须先使能EAXFR */
EAXFR = 1; // 允许访问扩展的特殊寄存器XFR
/* 配置定时器0为16位自动重装载模式(模式0) */
TMOD &= 0xF0; // 清除T0的M1/M0位
TMOD |= 0x00; // T0_M1=0, T0_M0=0 -> 模式0(16位自动重载)
AUXR |= 0x80; // T0x12=1, 定时器0工作在1T模式
/* 设置预分频寄存器,不分频 */
TM0PS = 0; // 定时器0时钟 = SYSclk / (0+1) = 40MHz
/*
* 计算定时器初值:
* 定时周期 = (65536 - [TH0,TL0]) / (SYSclk/(TM0PS+1))
* 1ms = (65536 - [TH0,TL0]) / 40MHz
* [TH0,TL0] = 65536 - 40000 = 25536 = 0x63C0
*/
TL0 = 0xC0; // 设置定时器0低8位初值
TH0 = 0x63; // 设置定时器0高8位初值
TF0 = 0; // 清除定时器0溢出标志
TR0 = 1; // 启动定时器0
ET0 = 1; // 使能定时器0中断
EA = 1; // 打开总中断
/* 初始化软件计数器 */
cnt10 = 0;
cnt100 = 0;
cnt1s = 0;
f1ms = 0;
f10ms = 0;
f100ms = 0;
f1s = 0;
}
/*
* 定时器0中断服务程序
* 每1ms进入一次中断
* 中断号1
*/
void Timer0_Isr(void) interrupt 1
{
f1ms = 1; // 设置1ms标志位
/* 产生10ms标志 */
if (++cnt10 >= 10)
{
cnt10 = 0;
f10ms = 1; // 设置10ms标志位
}
/* 产生100ms标志 */
if (++cnt100 >= 100)
{
cnt100 = 0;
f100ms = 1; // 设置100ms标志位
}
/* 产生1秒标志 */
if (++cnt1s >= 1000)
{
cnt1s = 0;
f1s = 1; // 设置1秒标志位
}
}
5. adc.h - ADC模块头文件
#ifndef __ADC_H__
#define __ADC_H__
extern WORD ADC_Value; // ADC采样值(12位)
extern WORD ADC_Humidity; // 换算后的湿度值(0~100%)
void ADC_Init(void); // ADC初始化
void ADC_StartConv(BYTE ch); // 启动ADC转换
WORD ADC_GetResult(void); // 获取ADC转换结果
#endif
6. adc.c - ADC模块实现
/*
* adc.c - ADC模数转换模块
* 功能:读取湿度传感器(模拟)的电压值,换算为湿度百分比
*
* 使用ADC通道0(P1.0)采集湿度传感器信号
* 12位ADC,参考电压为VCC
*
* 湿度换算公式:
* 假设湿度传感器为线性输出(0~3.3V对应0~100%RH)
* 实际项目中需根据具体传感器特性修改换算系数
*/
#include "config.h"
WORD ADC_Value = 0; // ADC原始采样值(12位)
WORD ADC_Humidity = 0; // 换算后的湿度值(0~1000,即0.0%~100.0%)
/*
* ADC初始化函数
* 配置ADC为12位模式,查询方式
*/
void ADC_Init(void)
{
EAXFR = 1; // 允许访问扩展寄存器
/* 设置P1.0为高阻输入模式(ADC输入口) */
P1M0 &= ~0x01; // P1M0.0 = 0
P1M1 |= 0x01; // P1M1.0 = 1 -> 高阻输入
/* 配置ADC内部时序 */
ADCTIM = 0x3F; // CSSETUP=0, CSHOLD=01, SMPDUTY=11111(最大采样时间)
/*
* 配置ADC时钟:
* ADCCFG寄存器:
* Bit7-6: 保留
* Bit5: RESFMT - 结果格式,0=左对齐,1=右对齐
* Bit4: 保留
* Bit3-0: SPEED[3:0] - ADC时钟分频
*
* FADC = SYSclk / 2 / (SPEED+1)
* 设置SPEED=15,则FADC = 40MHz / 2 / 16 = 1.25MHz
* 12位ADC速度不能高于800KHz,所以需要进一步分频
* 设置SPEED=15,实际ADC时钟=40M/2/16=1.25MHz,采样时间足够
*/
ADCCFG = 0x2F; // RESFMT=1(右对齐), SPEED=15
/* 打开ADC电源 */
ADC_CONTR = 0x80; // ADC_POWER=1, 使能ADC模块
/*
* 注意:打开ADC电源后需等待约1ms,等ADC电源稳定后再进行转换
* 这个延时在主程序的初始化流程中保证
*/
}
/*
* 启动ADC转换
* ch: ADC通道号(0~15)
* 注意:被选为ADC输入通道的I/O口,必须设置为高阻输入模式
*/
void ADC_StartConv(BYTE ch)
{
/* 设置ADC通道并启动转换 */
ADC_CONTR = (ADC_CONTR & 0xF0) | ch; // 设置ADC_CHS[3:0]选择通道
ADC_START = 1; // 启动ADC转换
}
/*
* 获取ADC转换结果(查询方式)
* 返回:12位ADC值(右对齐格式)
*
* 当ADCCFG中的RESFMT=1(右对齐)时:
* ADC_RES[7:0] 保存结果的高4位(实际有效位为低4位)
* ADC_RESL[7:0] 保存结果的低8位
* 完整12位结果 = (ADC_RES & 0x0F) << 8 | ADC_RESL
*/
WORD ADC_GetResult(void)
{
WORD result;
/* 等待ADC转换完成 */
while (!ADC_FLAG); // 等待ADC_FLAG置1
ADC_FLAG = 0; // 清除转换完成标志
/*
* 读取ADC结果(右对齐格式)
* ADC_RES[3:0] 存放高4位,ADC_RESL[7:0] 存放低8位
*/
result = ((WORD)(ADC_RES & 0x0F) << 8) | ADC_RESL;
return result;
}
7. key.h - 按键模块头文件
#ifndef __KEY_H__
#define __KEY_H__
/* 按键键码定义 */
#define KEY_NONE 0 // 无按键
#define KEY_SET 1 // 设置键(增加定时时间)
#define KEY_DEC 2 // 减少键(减少定时时间)
#define KEY_START 3 // 启动/停止键
extern BYTE KeyCode; // 当前有效键码
void Key_Scan(void); // 按键扫描
void Key_Process(void); // 按键处理
#endif
8. key.c - 按键模块实现
/*
* key.c - 按键扫描与处理模块
* 功能:使用ADC按键方式检测实验箱上的按键
*
* AI8051U实验箱使用ADC按键,通过分压电阻网络,
* 不同按键按下时产生不同的ADC值
*
* 按键ADC值对应关系(12位ADC,VCC=3.3V):
* 无按键:4095(最大值)
* 按键1:约 256
* 按键2:约 512
* 按键3:约 768
* 按键4:约 1024
* 按键5:约 1280
* 按键6:约 1536
* 按键7:约 1792
* 按键8:约 2048
* 按键9:约 2304
* 按键A:约 2560
* 按键B:约 2816
* 按键C:约 3072
* 按键D:约 3328
* 按键E:约 3584
* 按键F:约 3840
*
* 本程序简化处理,使用P3.2和P3.3作为独立按键输入
* 实际项目中可根据实验箱硬件调整
*/
#include "config.h"
/*
* 使用P3.2和P3.3作为按键输入
* P3.2 - 设置键(增加定时时间)
* P3.3 - 启动/停止键
*
* 注意:P3.2在AI8051U上电时用于USB下载判断,
* 正常运行时P3.2可作为普通I/O使用
*/
sbit KEY_SET_BIT = P3^2; // 设置键(低电平有效)
sbit KEY_START_BIT = P3^3; // 启动/停止键(低电平有效)
BYTE KeyCode = KEY_NONE; // 当前有效键码
static BYTE key_state; // 按键状态机
static BYTE key_cnt; // 按键消抖计数器
/*
* 按键扫描函数
* 需每10ms调用一次
* 使用简单的状态机实现消抖
*/
void Key_Scan(void)
{
BYTE key_press = KEY_NONE;
/* 检测哪个按键按下(低电平有效) */
if (KEY_SET_BIT == 0)
{
key_press = KEY_SET; // 设置键按下
}
else if (KEY_START_BIT == 0)
{
key_press = KEY_START; // 启动键按下
}
/* 状态机处理 */
switch (key_state)
{
case 0: // 等待按键状态
if (key_press != KEY_NONE)
{
key_state = 1; // 进入消抖状态
key_cnt = 0;
}
break;
case 1: // 消抖状态
if (key_press != KEY_NONE)
{
if (++key_cnt >= 3) // 连续3次(30ms)检测到按下
{
KeyCode = key_press; // 确认按键有效
key_state = 2; // 进入等待释放状态
}
}
else
{
key_state = 0; // 抖动,回到等待状态
}
break;
case 2: // 等待释放状态
if (key_press == KEY_NONE)
{
key_state = 0; // 按键释放,回到等待状态
}
break;
}
}
/*
* 按键处理函数
* 在主循环中调用,处理按键事件
* 返回当前有效键码并清除
*/
void Key_Process(void)
{
/* 此函数在主循环中处理按键事件 */
/* 实际按键处理在dehumidifier模块中完成 */
}
9. led.h - 数码管显示模块头文件
#ifndef __LED_H__
#define __LED_H__
/* 数码管显示缓冲区 */
extern BYTE LedBuf[8];
/* 数码管段码表(共阴极) */
extern BYTE code LED_PATTERN[10];
void Led_Init(void); // 数码管初始化
void ScanLed(void); // 数码管扫描显示
void SetLed(BYTE index, BYTE num, BOOL point); // 设置某位数码管显示
#endif
10. led.c - 数码管显示模块实现
/*
* led.c - 数码管显示模块
* 功能:使用74HC595驱动8位数码管动态扫描显示
*
* 硬件连接(AI8051U实验箱):
* DAT (数据) -> P3.4
* SCK (移位时钟) -> P3.2
* RCK (锁存时钟) -> P3.5
*
* 数码管为共阴极,段码高电平有效
*/
#include "config.h"
/* 74HC595控制引脚定义 */
sbit DAT = P3^4; // 串行数据输入
sbit SCK = P3^2; // 移位时钟(上升沿有效)
sbit RCK = P3^5; // 锁存时钟(上升沿有效)
#define LED_OFF 0x00 // 数码管关闭(全灭)
#define LED_POINT 0x80 // 小数点段码
BYTE LedBuf[8]; // 8位数码管显示缓冲区
static BYTE ShowIndex; // 当前扫描索引
/* 共阴极数码管段码表:0~9 */
BYTE code LED_PATTERN[10] =
{
0x3F, // 0: a b c d e f
0x06, // 1: b c
0x5B, // 2: a b d e g
0x4F, // 3: a b c d g
0x66, // 4: b c f g
0x6D, // 5: a c d f g
0x7D, // 6: a c d e f g
0x07, // 7: a b c
0x7F, // 8: a b c d e f g
0x6F // 9: a b c d f g
};
/* 特殊字符段码 */
BYTE code LED_CHAR_H = 0x76; // 显示 'H'
BYTE code LED_CHAR_d = 0x5E; // 显示 'd'
BYTE code LED_CHAR_C = 0x39; // 显示 'C'
BYTE code LED_CHAR_F = 0x71; // 显示 'F'
BYTE code LED_CHAR_P = 0x73; // 显示 'P'
BYTE code LED_CHAR_n = 0x54; // 显示 'n'
/*
* 向74HC595串行移入一个字节数据
* dat: 要移入的数据
*/
static void Shift_74HC595(BYTE dat)
{
BYTE i;
for (i = 0; i < 8; i++)
{
dat <<= 1; // 将最高位移到CY
DAT = CY; // 输出数据位
SCK = 0; // 移位时钟低电平
_nop_();
_nop_();
SCK = 1; // 移位时钟上升沿,移入数据
}
}
/*
* 74HC595并行数据输出
* 将移位寄存器中的数据锁存到输出寄存器
*/
static void Output_74HC595(void)
{
RCK = 0;
_nop_();
_nop_();
RCK = 1; // 锁存时钟上升沿,输出数据
}
/*
* 数码管初始化
*/
void Led_Init(void)
{
BYTE i;
DAT = 0;
SCK = 0;
RCK = 0;
/* 清空显示缓冲区 */
for (i = 0; i < 8; i++)
{
LedBuf[i] = LED_OFF;
}
ShowIndex = 0;
}
/*
* 数码管扫描显示函数
* 需每1ms调用一次
* 每次显示一位,8位循环扫描实现动态显示
*/
void ScanLed(void)
{
/* 先输出段码,再输出位选 */
Shift_74HC595(LedBuf[ShowIndex]); // 输出当前位的段码
Shift_74HC595(~(1 << ShowIndex)); // 输出位选(低电平有效)
Output_74HC595(); // 锁存输出
/* 更新扫描索引 */
if (++ShowIndex >= 8)
{
ShowIndex = 0;
}
}
/*
* 设置某位数码管的显示内容
* index: 数码管索引(0~7)
* num: 显示的数字(0~9),其他值关闭显示
* point: 是否显示小数点
*/
void SetLed(BYTE index, BYTE num, BOOL point)
{
if (index >= 8) return; // 索引超出范围
if (num < 10)
{
LedBuf[index] = LED_PATTERN[num];
}
else
{
LedBuf[index] = LED_OFF; // 关闭显示
}
if (point)
{
LedBuf[index] |= LED_POINT; // 添加小数点
}
}
/*
* 设置某位数码管显示自定义段码
* index: 数码管索引(0~7)
* seg: 自定义段码
*/
void SetLedSeg(BYTE index, BYTE seg)
{
if (index >= 8) return;
LedBuf[index] = seg;
}
11. dehumidifier.h - 除湿控制模块头文件
#ifndef __DEHUMIDIFIER_H__
#define __DEHUMIDIFIER_H__
/* 系统工作状态 */
#define STATE_IDLE 0 // 待机状态
#define STATE_RUNNING 1 // 运行状态
#define STATE_SET_TIME 2 // 设置定时时间
/* 风扇转速等级 */
#define FAN_OFF 0 // 风扇关闭
#define FAN_LOW 1 // 低速
#define FAN_MEDIUM 2 // 中速
#define FAN_HIGH 3 // 高速
/* 湿度阈值 */
#define HUMIDITY_THRESHOLD 700 // 湿度阈值(70.0%),超过此值自动启动
/* 外部变量声明 */
extern BYTE SysState; // 系统状态
extern WORD SetTime; // 设定的定时时间(秒)
extern WORD RemainTime; // 剩余时间(秒)
extern BYTE FanSpeed; // 风扇转速
extern WORD CurrentHumidity; // 当前湿度(0~1000,对应0.0%~100.0%)
/* 函数声明 */
void Dehumidifier_Init(void); // 除湿系统初始化
void Dehumidifier_Process(void); // 除湿系统主处理
void Dehumidifier_Display(void); // 显示更新
void Dehumidifier_SetTimer(WORD seconds); // 设置定时时间
void Dehumidifier_Start(void); // 启动除湿
void Dehumidifier_Stop(void); // 停止除湿
void Dehumidifier_UpdateHumidity(WORD hum); // 更新湿度值
#endif
12. dehumidifier.c - 除湿控制模块实现
/*
* dehumidifier.c - 模拟定时风扇除湿控制模块
*
* 功能说明:
* 1. 实时监测环境湿度(通过ADC读取模拟湿度传感器)
* 2. 支持定时设置(1~99分钟)
* 3. 根据湿度自动调节风扇转速
* 4. 数码管显示当前湿度、剩余时间、工作状态
* 5. 按键控制:设置定时时间、启动/停止
*
* 工作流程:
* 待机状态 -> 设置定时时间 -> 启动除湿 -> 倒计时 -> 自动停止
* 湿度超过阈值时自动启动除湿
* 湿度低于阈值时自动降低转速
*
* 风扇控制(用LED模拟):
* P5.0 - 风扇控制输出(强推挽,高电平有效)
* 通过PWM或高低电平控制风扇转速
*/
#include "config.h"
/* 系统状态 */
BYTE SysState = STATE_IDLE; // 当前系统状态
WORD SetTime = 0; // 设定的定时时间(秒)
WORD RemainTime = 0; // 剩余时间(秒)
BYTE FanSpeed = FAN_OFF; // 风扇转速
WORD CurrentHumidity = 0; // 当前湿度(0~1000)
/* 风扇控制引脚 */
sbit FAN_CTRL = P5^0; // 风扇控制输出
/* 状态显示相关 */
static BYTE disp_mode; // 显示模式
static BYTE blink_cnt; // 闪烁计数器
static BYTE blink_state; // 闪烁状态
/*
* 除湿系统初始化
*/
void Dehumidifier_Init(void)
{
EAXFR = 1;
/* 设置P5.0为推挽输出,用于控制风扇(LED模拟) */
P5M0 |= 0x01; // P5M0.0 = 1
P5M1 &= ~0x01; // P5M1.0 = 0 -> 推挽输出
FAN_CTRL = 0; // 初始关闭风扇
/* 初始化系统参数 */
SysState = STATE_IDLE;
SetTime = 0;
RemainTime = 0;
FanSpeed = FAN_OFF;
CurrentHumidity = 0;
disp_mode = 0;
blink_cnt = 0;
blink_state = 0;
}
/*
* 设置定时时间
* seconds: 定时秒数(1~5940秒,即1~99分钟)
*/
void Dehumidifier_SetTimer(WORD seconds)
{
/* 限制定时范围:1~99分钟 */
if (seconds < 60) seconds = 60; // 最少1分钟
if (seconds > 5940) seconds = 5940; // 最多99分钟
SetTime = seconds;
/* 如果当前在待机状态,进入设置状态 */
if (SysState == STATE_IDLE)
{
SysState = STATE_SET_TIME;
}
}
/*
* 启动除湿
*/
void Dehumidifier_Start(void)
{
if (SetTime == 0)
{
SetTime = 600; // 默认10分钟
}
RemainTime = SetTime;
SysState = STATE_RUNNING;
FanSpeed = FAN_MEDIUM; // 默认中速启动
FAN_CTRL = 1; // 打开风扇
}
/*
* 停止除湿
*/
void Dehumidifier_Stop(void)
{
SysState = STATE_IDLE;
FanSpeed = FAN_OFF;
FAN_CTRL = 0; // 关闭风扇
RemainTime = 0;
}
/*
* 更新湿度值
* hum: 湿度值(0~1000,对应0.0%~100.0%)
*/
void Dehumidifier_UpdateHumidity(WORD hum)
{
CurrentHumidity = hum;
}
/*
* 根据湿度自动调节风扇转速
*/
static void AutoAdjustFanSpeed(void)
{
if (CurrentHumidity >= 850) // 湿度 >= 85%
{
FanSpeed = FAN_HIGH; // 高速除湿
}
else if (CurrentHumidity >= 700) // 湿度 >= 70%
{
FanSpeed = FAN_MEDIUM; // 中速除湿
}
else if (CurrentHumidity >= 500) // 湿度 >= 50%
{
FanSpeed = FAN_LOW; // 低速除湿
}
else
{
FanSpeed = FAN_OFF; // 湿度正常,关闭风扇
}
/* 更新风扇控制输出 */
if (FanSpeed > FAN_OFF)
{
FAN_CTRL = 1; // 风扇开启
}
else
{
FAN_CTRL = 0; // 风扇关闭
}
}
/*
* 除湿系统主处理函数
* 需每1秒调用一次
*/
void Dehumidifier_Process(void)
{
switch (SysState)
{
case STATE_IDLE:
/* 待机状态:自动检测湿度,超过阈值自动启动 */
if (CurrentHumidity >= HUMIDITY_THRESHOLD)
{
/* 湿度超标,自动启动除湿 */
if (SetTime == 0)
{
SetTime = 600; // 默认10分钟
}
Dehumidifier_Start();
}
break;
case STATE_RUNNING:
/* 运行状态:倒计时 */
if (RemainTime > 0)
{
RemainTime--;
/* 根据湿度自动调节风扇转速 */
AutoAdjustFanSpeed();
/* 如果湿度已正常且运行时间过半,可以提前停止 */
if ((CurrentHumidity < 500) &&
(RemainTime < (SetTime / 2)))
{
Dehumidifier_Stop();
}
}
/* 倒计时结束,自动停止 */
if (RemainTime == 0)
{
Dehumidifier_Stop();
}
break;
case STATE_SET_TIME:
/* 设置状态:等待用户确认启动 */
/* 如果用户10秒无操作,自动回到待机状态 */
break;
}
}
/*
* 除湿系统显示更新函数
* 需每100ms调用一次
*
* 数码管显示布局:
* [0][1] [2][3] [4][5] [6][7]
* 湿度值 定时 剩余 状态
*
* 待机状态:显示当前湿度
* 运行状态:显示剩余时间和湿度
* 设置状态:显示设定时间(闪烁)
*/
void Dehumidifier_Display(void)
{
BYTE h1, h0; // 湿度十位、个位
BYTE t1, t0; // 时间十位、个位
BYTE m1, m0; // 分钟十位、个位
blink_cnt++;
if (blink_cnt >= 5) // 500ms闪烁周期
{
blink_cnt = 0;
blink_state = !blink_state;
}
switch (SysState)
{
case STATE_IDLE:
/* 待机状态:显示 "H xx" 当前湿度 */
h1 = CurrentHumidity / 100; // 湿度百位
h0 = (CurrentHumidity % 100) / 10; // 湿度十位
SetLedSeg(0, LED_CHAR_H); // 显示 'H'
SetLed(1, 12, 0); // 显示空白
SetLed(2, h1, 0); // 湿度百位
SetLed(3, h0, 1); // 湿度十位 + 小数点
SetLed(4, CurrentHumidity % 10, 0); // 湿度个位
SetLed(5, 12, 0); // 显示空白
SetLedSeg(6, LED_CHAR_n); // 显示 'n'
SetLed(7, 12, 0); // 显示空白
break;
case STATE_RUNNING:
/* 运行状态:显示剩余时间 */
m1 = (RemainTime / 60) / 10; // 分钟十位
m0 = (RemainTime / 60) % 10; // 分钟个位
t1 = (RemainTime % 60) / 10; // 秒钟十位
t0 = (RemainTime % 60) % 10; // 秒钟个位
SetLed(0, m1, 0); // 分钟十位
SetLed(1, m0, 0); // 分钟个位
SetLed(2, 11, 0); // 显示 '-'
SetLed(3, t1, 0); // 秒钟十位
SetLed(4, t0, 0); // 秒钟个位
/* 右侧显示当前湿度 */
h1 = CurrentHumidity / 100;
h0 = (CurrentHumidity % 100) / 10;
SetLed(5, h1, 0);
SetLed(6, h0, 1);
SetLed(7, CurrentHumidity % 10, 0);
break;
case STATE_SET_TIME:
/* 设置状态:显示设定时间(闪烁) */
m1 = (SetTime / 60) / 10;
m0 = (SetTime / 60) % 10;
if (blink_state)
{
SetLed(0, m1, 0);
SetLed(1, m0, 0);
}
else
{
SetLed(0, 12, 0); // 闪烁关闭
SetLed(1, 12, 0);
}
SetLedSeg(2, LED_CHAR_C); // 显示 'C'
SetLed(3, 12, 0);
SetLed(4, 12, 0);
SetLed(5, 12, 0);
SetLed(6, 12, 0);
SetLed(7, 12, 0);
break;
}
}
13. main.c - 主程序
/*
* main.c - 模拟定时风扇除湿系统主程序
*
* 硬件平台:AI8051U实验箱
* 编译器:Keil C251
*
* 功能概述:
* 本程序实现一个模拟的定时风扇除湿控制系统,主要功能包括:
*
* 1. 湿度检测:通过ADC采集模拟湿度传感器(电位器)的电压值,
* 换算为湿度百分比(0~100%)
*
* 2. 定时除湿:支持设置定时时间(1~99分钟),到达设定时间后
* 自动停止除湿
*
* 3. 自动控制:湿度超过70%时自动启动除湿,湿度低于50%时
* 自动降低转速或停止
*
* 4. 显示功能:数码管实时显示当前湿度、剩余时间、工作状态
*
* 5. 按键控制:
* - P3.2(SET键):设置定时时间(每按一次增加5分钟)
* - P3.3(START键):启动/停止除湿
*
* 6. 风扇模拟:使用P5.0驱动LED模拟风扇运转
*
* 系统时钟:内部高速IRC 40MHz
*
* 引脚分配:
* P1.0 - ADC输入(湿度传感器模拟输入)
* P3.2 - 设置按键输入(同时用于74HC595的SCK)
* P3.3 - 启动/停止按键输入
* P3.4 - 74HC595数据输入(DAT)
* P3.5 - 74HC595锁存时钟(RCK)
* P5.0 - 风扇控制输出(推挽输出,驱动LED)
*
* 注意:
* 1. P3.0/P3.1为USB下载口,不要接其他电路
* 2. P3.2上电时用于USB下载判断,正常运行时可用作普通I/O
* 3. 除P3.0/P3.1外,其他I/O上电后为高阻输入,使用前需配置模式
*/
#include "config.h"
/* 全局变量 */
static WORD adc_raw; // ADC原始值
static WORD humidity_value; // 湿度值(0~1000)
/*
* 延时函数
* 用于ADC上电后的稳定等待
*/
static void Delay1ms(void)
{
WORD i;
for (i = 0; i < 1000; i++)
{
_nop_();
}
}
/*
* 系统初始化函数
* 按顺序初始化各模块
*/
void SYS_Init(void)
{
/* 使能访问扩展寄存器XFR */
EAXFR = 1;
/*
* 设置程序代码等待时间
* WTST = 0 表示不等待,程序以最快速度运行
*/
WTST = 0;
/*
* 设置访问片内xdata速度
* CKCON = 0 表示用最快速度访问,不增加额外等待时间
*/
CKCON = 0;
/*
* 初始化所有I/O口为准双向口模式
* 注意:除P3.0/P3.1外,其他I/O上电后为高阻输入
* 使用前必须配置模式
*/
P0M0 = 0x00; P0M1 = 0x00; // P0口:准双向口
P1M0 = 0x00; P1M1 = 0x00; // P1口:准双向口(P1.0后续配置为ADC)
P2M0 = 0x00; P2M1 = 0x00; // P2口:准双向口
P3M0 = 0x00; P3M1 = 0x00; // P3口:准双向口
P4M0 = 0x00; P4M1 = 0x00; // P4口:准双向口
P5M0 = 0x00; P5M1 = 0x00; // P5口:准双向口
/* 初始化各模块 */
Timer0_Init(); // 定时器0初始化(1ms基准)
ADC_Init(); // ADC初始化
Led_Init(); // 数码管初始化
Dehumidifier_Init(); // 除湿系统初始化
/* ADC上电后等待稳定 */
Delay1ms();
Delay1ms();
/* 启动第一次ADC转换(通道0,P1.0) */
ADC_StartConv(0);
}
/*
* 主函数
*/
void main(void)
{
/* 系统初始化 */
SYS_Init();
/* 主循环 */
while (1)
{
/* === 1ms事件处理 === */
if (f1ms)
{
f1ms = 0;
ScanLed(); // 数码管动态扫描(每1ms刷新一位)
}
/* === 10ms事件处理 === */
if (f10ms)
{
f10ms = 0;
Key_Scan(); // 按键扫描(每10ms一次)
}
/* === 100ms事件处理 === */
if (f100ms)
{
f100ms = 0;
/* 检查ADC是否完成 */
if (ADC_FLAG)
{
/* 读取ADC结果 */
adc_raw = ADC_GetResult();
/*
* 将ADC值换算为湿度值
* 假设:ADC值0~4095 对应 0%~100%
* 湿度值 = ADC值 * 1000 / 4096
* 结果范围:0~1000(对应0.0%~100.0%)
*/
humidity_value = (WORD)((DWORD)adc_raw * 1000 / 4096);
/* 更新湿度值到除湿系统 */
Dehumidifier_UpdateHumidity(humidity_value);
/* 启动下一次ADC转换 */
ADC_StartConv(0);
}
/* 处理按键事件 */
if (KeyCode != KEY_NONE)
{
switch (KeyCode)
{
case KEY_SET:
/* 设置键:增加定时时间5分钟 */
if (SysState == STATE_IDLE)
{
Dehumidifier_SetTimer(SetTime + 300); // 加5分钟
}
else if (SysState == STATE_SET_TIME)
{
Dehumidifier_SetTimer(SetTime + 300);
}
break;
case KEY_START:
/* 启动/停止键 */
if (SysState == STATE_RUNNING)
{
Dehumidifier_Stop(); // 停止
}
else
{
Dehumidifier_Start(); // 启动
}
break;
}
KeyCode = KEY_NONE; // 清除键码
}
/* 更新显示(每100ms刷新一次显示内容) */
Dehumidifier_Display();
}
/* === 1秒事件处理 === */
if (f1s)
{
f1s = 0;
Dehumidifier_Process(); // 除湿系统主处理(倒计时等)
}
}
}
使用说明
硬件连接
| 功能 |
引脚 |
说明 |
| 湿度传感器(模拟) |
P1.0/ADC0 |
用电位器分压模拟湿度信号 |
| 设置键 |
P3.2 |
设置定时时间 |
| 启动/停止键 |
P3.3 |
控制除湿启停 |
| 风扇控制(LED) |
P5.0 |
推挽输出驱动LED模拟风扇 |
| 74HC595-DAT |
P3.4 |
数码管数据 |
| 74HC595-SCK |
P3.2 |
数码管移位时钟 |
| 74HC595-RCK |
P3.5 |
数码管锁存时钟 |
操作说明
- 上电后:数码管显示当前湿度值(如
H 75.0 表示湿度75.0%)
- 按SET键:进入定时设置模式,显示设定时间(闪烁),每按一次增加5分钟
- 按START键:启动除湿,数码管显示剩余时间(分-秒格式)
- 运行中再按START:停止除湿
- 自动控制:湿度>70%自动启动,湿度<50%自动降低转速或停止
编译说明
- 使用 Keil C251 编译器(AI8051U为80251架构)
- 芯片型号选择:Ai8051U
- 内部IRC频率:40MHz
- 添加头文件:
ai8051u.h(从STC-ISP软件安装目录获取)
这个程序完整实现了模拟定时风扇除湿系统的所有功能,代码中有详细的注释说明每一步的操作。如果您需要调整某些参数(如湿度阈值、定时范围等),可以直接修改 dehumidifier.h 中的宏定义。
🔍 搜索 "AI8051U 实验箱 模拟定时 风扇 除湿"
📌 相关论坛讨论
- 【AI助手】@AiCube-ISP-V6.96Z中,【自动生成程序】+【查错高手】
⏱️ 查找用时 10.7s | 总回答用时 77.6s