仿真图:
芯片/模块的特点:
AT89C52简介:
AT89C52是一款经典的8位单片机,是意法半导体(STMicroelectronics)公司生产的一系列单片机之一。它基于8051内核,并具有许多与其兼容的特性。
AT89C52的主要特点如下:
内部存储器:AT89C52具有8KB的闪存(Flash)存储器,可用于存储用户程序和数据。这些存储器的内容可以通过编程器进行编程和擦除。
RAM存储器:AT89C52配备了256字节的随机存取存储器(RAM),用于暂存数据和程序的变量。
外部扩展性:AT89C52支持多种外部扩展设备的连接,包括外部存储器(如RAM、EEPROM)和外设(如ADC、LCD、UART等),通过外部硬件连接,可以扩展单片机的功能和应用。
通用I/O引脚:AT89C52拥有32个可编程的通用输入/输出引脚,可用于连接外部设备和与其他芯片进行通信。
定时器/计数器:AT89C52内置了3个16位定时器/计数器和一个可编程的串行定时器/计数器。这些计时器/计数器可用于实现定时功能、生成脉冲信号、测量时间间隔等。0
串行通信:AT89C52支持串行通信接口,包括UART(串行异步通信)和SPI(串行外设接口),便于与其他设备进行数据通信和交互。
低功耗模式:AT89C52具有多种低功耗模式,如空闲模式和电源下模式,在不需要执行任务的时候可以将CPU进入低功耗状态以节省能量。
宽电源电压范围:AT89C52的工作电压范围通常为4.0V至5.5V,可以满足大多数应用需求。
ADC0832特点:
8位分辨率:ADC0832可以将模拟输入信号转换为8位数字输出。这意味着它可以将模拟信号划分为256个不同的离散电平,提供相对较低的分辨率。
双通道输入:ADC0832具有两个模拟输入通道,使其能够同时转换两个模拟信号。这对于需要同时测量多个信号的应用非常有用。
内部参考电压源:ADC0832提供了一个内部的参考电压源,它可以用作模拟输入信号的参考电压。这样可以简化外部电路设计,并提供更稳定和准确的参考电压。
串行输出:ADC0832通过串行接口(SPI或I2C)输出转换结果。这种串行输出形式使其与微控制器或其他数字设备的通信变得更加简单和方便。
低功耗:ADC0832具有较低的功耗特性,适合在低功耗应用中使用。
可编程时钟频率:ADC0832的转换速度可以通过控制输入时钟频率进行编程。这使得可以根据应用的需求调整转换速度,并平衡转换精度和速度。
内部自校准:ADC0832具有内部自校准电路,可以降低转换误差,并提供更准确的转换结果。
L9110特点:
双路驱动:L9110可以同时驱动两个直流电机,每个驱动通道最大电流可达800mA。这使得它非常适用于需要控制多个电机的应用。
低电压工作:L9110可以在较低的电源电压下工作,通常在2.5V至12V之间。这使得它适用于电池供电的低电压应用,如机器人、小型车辆等。
高效能:该芯片采用了双H桥驱动技术,具有较高的效率和较低的功耗。它可以提供高达15kHz的PWM(脉冲宽度调制)频率,以实现电机速度的精确控制。
内置保护功能:L9110具有过温保护和短路保护功能,可有效保护芯片和电机免受过载和短路等异常情况的损害。
引脚简单:L9110只需要几个引脚就可以实现电机的驱动,包括两个输入引脚控制电机的正反转,以及两个输出引脚连接电机。
主程序:
#include "reg52.h" //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "tlc0832.h"
unsigned char waterLevel = 1; // 水位,保存
sbit RELAY_IN = P2^1; // 进水阀控制端口
sbit RELAY_OUT = P2^2; // 排水阀控制端口
sbit RELAY_HEAT = P2^0; // 烘干
sbit MOTOR_A = P1^3; // 电机控制
sbit MOTOR_B = P1^4; // 电机控制
sbit LED1 = P1^7; // 速洗指示灯
sbit LED2 = P1^6; // 标准洗指示灯
sbit LED3 = P1^5; // 浸泡洗指示灯
sbit LED4 = P3^2; // 脱水指示灯
sbit LED5 = P3^3; // 烘干指示灯
sbit SEG_S1 = P2^6; // 数码管显示第一位公共端
sbit SEG_S2 = P2^7; // 数码管第二位显示控制公共端
sbit KEY_SWITCH = P3^4; // 洗衣机电源开关
sbit KEY_MODE = P3^5; // 洗衣机模式选择
sbit KEY_START = P3^6; // 启动按键
sbit BUZZER = P2^3; // 洗涤完报警
unsigned int time50ms, time1s_1, time5s, timeFlag, time1s; // 用于全局时钟定义
bit forwardFlag; // 电机,正反转标志位
unsigned char time[] = {20, 40, 80, 5, 20}; // 五个模式显示时间
unsigned char dis_seg[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f,
0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x00}; // 共阴数码管码表
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
TMOD |= 0x01;
TL0 = 0x00; //设置定时初始值
TH0 = 0x4C; //设置定时初始值 50ms
EA = 1; // 总中断打开
ET0 = 1; // 定时器中断打开
// TR0=1; //定时器开关打开
}
void delay(unsigned int t)
{
while (t--)
;
}
void WaterLevel_Ctrl()
{
switch (waterLevel)
{
case 1:
if (0xbe < ReadADC(AIN0_GND)) // 10*25 =250 //水位到了
{
TR0 = 1;
RELAY_IN = 1;
}
else //进水
{
TR0 = 0;
RELAY_IN = 0; //进水
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
case 2:
if (0x9e < ReadADC(AIN0_GND)) // 10*25 =250
{
TR0 = 1;
RELAY_IN = 1;
}
else
{
TR0 = 0;
RELAY_IN = 0;
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
case 3:
if (0x91 < ReadADC(AIN0_GND)) // 10*25 =250
{
TR0 = 1;
RELAY_IN = 1;
}
else
{
TR0 = 0;
RELAY_IN = 0;
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
case 4:
if (0x8a < ReadADC(AIN0_GND)) // 10*25 =250
{
TR0 = 1;
RELAY_IN = 1;
}
else
{
TR0 = 0;
RELAY_IN = 0;
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
case 5:
if (0x81 < ReadADC(AIN0_GND)) // 10*25 =250
{
TR0 = 1;
RELAY_IN = 1;
}
else
{
TR0 = 0;
RELAY_IN = 0;
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
case 6:
if (0x6e < ReadADC(AIN0_GND)) // 10*25 =250
{
TR0 = 1;
RELAY_IN = 1;
}
else
{
TR0 = 0;
RELAY_IN = 0;
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
case 7:
if (0x61 < ReadADC(AIN0_GND)) // 10*25 =250
{
TR0 = 1;
RELAY_IN = 1;
}
else
{
TR0 = 0;
RELAY_IN = 0;
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
case 8:
if (0x55 < ReadADC(AIN0_GND)) // 10*25 =250
{
TR0 = 1;
RELAY_IN = 1;
}
else
{
TR0 = 0;
RELAY_IN = 0;
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
case 9:
if (0x44 < ReadADC(AIN0_GND)) // 10*25 =250
{
TR0 = 1;
RELAY_IN = 1;
}
else
{
TR0 = 0;
RELAY_IN = 0;
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
case 10:
if (0x34 < ReadADC(AIN0_GND)) // 10*25 =250
{
TR0 = 1;
RELAY_IN = 1;
}
else
{
TR0 = 0;
RELAY_IN = 0;
RELAY_OUT = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
}
break;
}
// if(waterLevel*25<ReadADC(AIN0_GND)) // 10*25 =250
// {TR0=1;k1=1;}else{TR0=0;k1=0;RELAY_OUT=MOTOR_A=MOTOR_B=RELAY_HEAT=1;forwardFlag=0;}
// SendByte(ReadADC(AIN0_GND));
}
void Stop_Ctrl()
{ // SendByte(ReadADC(AIN0_GND));
if (ReadADC(AIN0_GND) < 0xe0)
{
TR0 = 1;
}
else
TR0 = 0;
}
/*------------------------------------------------
主程序
------------------------------------------------*/
// void InitUART (void)
//{
//
// SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收
// TMOD |= 0x20; // TMOD: timer 1, mode 2, 8-bit 重装
// TH1 = 0xF3; // TH1: 重装值 9600 波特率 晶振 11.0592MHz
// TR1 = 1; // TR1: timer 1 打开
// EA = 1; //打开总中断
// //ES = 1; //打开串口中断
// }
// void SendByte(unsigned char dat)
//{
// SBUF = dat;
// while(!TI);
// TI = 0;
//
// }
void main()
{
unsigned int modeFlag, dig_2, dig_1; // modeFlag用于计算模式
unsigned int sd = 0; // 蜂鸣器循环次数报警
KEY_SWITCH = KEY_MODE = KEY_START = 1; // 按键给高电平
Init_Timer0(); // 定时器初始化
// InitUART ();
dig_2 = dig_1 = 15;
while (1)
{ // SendByte(ReadADC(AIN0_GND));
if (KEY_SWITCH == 0)
{
delay(20000); // 按键延时去抖
dig_2 = dig_1 = 15;
while (KEY_SWITCH == 0); // 等待按键释放
while (1) //进入模式选择
{
stop: // 跳转介质为
if (KEY_MODE == 0)//模式选择
{
delay(20000);
while (KEY_MODE == 0);
modeFlag++; // 每次进入模式选择+
if (modeFlag == 6)
{
modeFlag = 1;
} // 当循环到6重新,跳动到第一个
switch (modeFlag) // 判断进入点亮相应,LED
{
case 1:
LED1 = 0;
LED2 = LED3 = LED4 = LED5 = 1;
break; // 点亮之后直接退出
case 2:
LED2 = 0;
LED1 = LED3 = LED4 = LED5 = 1;
break;
case 3:
LED3 = 0;
LED2 = LED1 = LED4 = LED5 = 1;
break;
case 4:
LED4 = 0;
LED2 = LED3 = LED1 = LED5 = 1;
break;
case 5:
LED5 = 0;
LED2 = LED3 = LED4 = LED1 = 1;
break;
}
dig_2 = time[modeFlag - 1] / 10; // 显示时间转换 25/10;
dig_1 = time[modeFlag - 1] % 10; // 显示时间转换 25%10;
// if(modeFlag==5){modeFlag=0;}
}
if (KEY_START == 0) // 判断,是否启动按键按下
{
delay(20000); // 延时去抖
switch (modeFlag) // 判断为哪一个模式,并,把时间给定时器
{ // 如果都不是,则为零
case 1: //速洗
time5s = 20;
timeFlag = 0;
break;
case 2: //标准洗
time5s = 40;
timeFlag = 0;
break;
case 3: //浸泡洗
time5s = 80;
timeFlag = 0;
break;
case 4: //脱水
time5s = 5;
timeFlag = 0;
break;
case 5: //烘干
time5s = 20;
timeFlag = 0;
break;
}
if (time5s == 0) // 判断如果启动时时间为零,则进入设置水位模式
{
while (1) // 死循环,一直在设置水位
{
if (KEY_START == 0) // 帮,启动按键再次按下时水加
{
delay(20000); // 简单延时去抖
waterLevel++; // ,变量加
if (waterLevel == 11)
waterLevel = 1; // 最高水位设置为10当再次达到11位变为1
while (KEY_START == 0); // 等待按键释放
}
SEG_S1 = 0;
SEG_S2 = 1; // 打开第一个数码管
P0 = dis_seg[waterLevel / 10]; // 进行数据处理并打印
delay(10); // 进行延时稳定
P0 = 0x00; // 萧影
SEG_S1 = 1;
SEG_S2 = 0;
P0 = dis_seg[waterLevel % 10];
delay(10);
P0 = 0x00;
if (KEY_SWITCH == 0)
{
delay(20000);
while (KEY_SWITCH == 0);
goto stop; //跳转回去
} // 如果当开关按下时跳转到前面,开机状态
}
}
while (KEY_START == 0); // 判断案件释放
TR0 = 1; // 打开定时器进行计数
while (1) // 死循环,用于判断整个流程完成
{
SEG_S1 = 0;
SEG_S2 = 1; // 数码管显示用于打印定时器时间
P0 = dis_seg[time5s / 10];
delay(10);
P0 = 0x00;
SEG_S1 = 1;
SEG_S2 = 0;
P0 = dis_seg[time5s % 10];
delay(10);
P0 = 0x00;
switch (modeFlag) // 判断模式
{
case 1: //速洗
switch (timeFlag)
{
case 0:
WaterLevel_Ctrl();
break;
case 1:
RELAY_IN = RELAY_OUT = RELAY_HEAT = 1;
forwardFlag = 1;
break;
case 7:
RELAY_OUT = 0;
RELAY_IN = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
Stop_Ctrl();
break;
case 8:
MOTOR_A = 0;
RELAY_IN = RELAY_OUT = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
break;
case 9:
WaterLevel_Ctrl();
break;
case 10:
RELAY_IN = RELAY_OUT = RELAY_HEAT = 1;
forwardFlag = 1;
break;
case 14:
RELAY_OUT = 0;
RELAY_IN = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
Stop_Ctrl();
break;
case 15:
MOTOR_A = 0;
RELAY_IN = RELAY_OUT = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
break;
}
break;
case 2: //标准洗
switch (timeFlag)
{
case 0:
WaterLevel_Ctrl();
break;
case 1:
RELAY_IN = RELAY_OUT = RELAY_HEAT = 1;
forwardFlag = 1;
break;
case 15:
RELAY_OUT = 0;
RELAY_IN = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
Stop_Ctrl();
break;
case 16:
MOTOR_A = 0;
RELAY_IN = RELAY_OUT = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
break;
case 17:
WaterLevel_Ctrl();
break;
case 18:
RELAY_IN = RELAY_OUT = RELAY_HEAT = 1;
forwardFlag = 1;
break;
case 30:
RELAY_OUT = 0;
RELAY_IN = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
Stop_Ctrl();
break;
case 31:
MOTOR_A = 0;
RELAY_IN = RELAY_OUT = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
break;
}
break;
case 3: //浸泡洗
switch (timeFlag)
{
case 0:
WaterLevel_Ctrl();
break;
case 1:
RELAY_IN = RELAY_OUT = RELAY_HEAT = MOTOR_A = MOTOR_B = 1;
break;
case 40:
RELAY_IN = RELAY_OUT = RELAY_HEAT = 1;
forwardFlag = 1;
break;
case 55:
RELAY_OUT = 0;
RELAY_IN = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
Stop_Ctrl();
break;
case 56:
MOTOR_A = 0;
RELAY_IN = RELAY_OUT = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
break;
case 57:
WaterLevel_Ctrl();
break;
case 58:
RELAY_IN = RELAY_OUT = RELAY_HEAT = 1;
forwardFlag = 1;
break;
case 70:
RELAY_OUT = 0;
RELAY_IN = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
Stop_Ctrl();
break;
case 71:
MOTOR_A = 0;
RELAY_IN = RELAY_OUT = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
break;
}
break;
case 4: //脱水
switch (timeFlag)
{
case 0:
RELAY_OUT = 0;
RELAY_IN = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
Stop_Ctrl();
break;
case 1:
MOTOR_A = 0;
RELAY_IN = RELAY_OUT = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
break;
}
break;
case 5: //烘干
switch (timeFlag)
{
case 0:
RELAY_OUT = 0;
RELAY_IN = MOTOR_A = MOTOR_B = RELAY_HEAT = 1;
forwardFlag = 0;
Stop_Ctrl();
break;
case 1:
RELAY_HEAT = 0;
RELAY_IN = RELAY_OUT = MOTOR_B = MOTOR_A = 1;
forwardFlag = 0;
break;
}
break;
}
if (time5s == 0)
{
P0 = P1 = P2 = P3 = 0xff;
TR0 = 0;
modeFlag = dig_2 = dig_1 = 0;
time50ms = time1s_1 = time5s = timeFlag = time1s = 0;
forwardFlag = 0;
KEY_SWITCH = 0;
break;
}
if (KEY_SWITCH == 0)
break;
}
}
SEG_S1 = 0;
SEG_S2 = 1;
P0 = dis_seg[dig_2];
delay(10);
P0 = 0x00;
SEG_S1 = 1;
SEG_S2 = 0;
P0 = dis_seg[dig_1];
delay(10);
P0 = 0x00;
if (KEY_SWITCH == 0)
{
delay(20000);
P0 = P1 = P2 = P3 = 0xff;
TR0 = 0;
modeFlag = dig_2 = dig_1 = 0;
time50ms = time1s_1 = time5s = timeFlag = time1s = 0;
forwardFlag = 0;
for (sd = 5; sd > 0; sd--)
{
delay(20000);
BUZZER = 1;
delay(20000);
BUZZER = 0;
}
BUZZER = 1;
break;
}
}
if (time5s == 0)
{
KEY_SWITCH = 1;
}
while (KEY_SWITCH == 0);
}
else //关闭
{
SEG_S1 = 0;
SEG_S2 = 1;
P0 = dis_seg[16];
delay(10);
P0 = 0x00;
SEG_S1 = 1;
SEG_S2 = 0;
P0 = dis_seg[16];
delay(14);
P0 = 0x00;
}
}
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 using 1
{
TL0 = 0x00; //设置定时初始值
TH0 = 0x4C; //设置定时初始值 50ms
time50ms++;
if (time50ms == 20)
{
time50ms = 0; // 用于下一次计算
if (forwardFlag == 1) //电机转动
{
time1s++;
if (time1s == 1) //正转
{
MOTOR_A = 1;
MOTOR_B = 0;
}
if (time1s == 2) //反转
{
MOTOR_A = 0;
MOTOR_B = 1;
time1s = 0;
}
}
//{MOTOR_A=1;MOTOR_B=0;}
time1s_1++;
if (time1s_1 == 5)
{
time1s_1 = 0;
time5s--; //倒计时
timeFlag++;
}
}
}
设计文件: