、、、、、、、2022年11月17日。。。。。。改
#include "STC15W0XX.H"
typedef unsigned char BYTE;
typedef unsigned int WORD;
//-----------------------------------------------
//最后一个 L 表示强制长整形,无论前面的数值是多大多小,固定长度为长整形。 具体字节数取决于编译器。
//#define FOSC 11059200L // 晶振设置,默认使用11.0592MHz
//#define T1MS (65536-FOSC/1000) //1T模式 ,定时 1毫秒
//#define T1MS (65536-FOSC/12/1000) //12T模式
/*
它的意思是,定时器实现1毫秒定时,求定时器的初值。
因为定时器计数65536后,就会清零,想实现特定时间定时,就要自己计算起点,也叫做初值
因为1个机器周期等于12个时钟周期,因此FOSC/12,得到的是一个机器周期的频率,
也是1秒内定时器计数的个数,再除以1000,就是1毫秒内定时器计数的个数。
想让定时器在这些个数之后清零,就要设置起点为65536-该个数。
这样就得到了65536-FOSC/12/1000
同理,想设置5毫秒定时器,65536-5*FOSC/12/1000
这样得到,想设置t毫秒定时器,65536-t*FOSC/12/1000
注意,定时器有上限,最大为65536*FOSC/12毫秒,因为一个机器周期为FOSC/12毫秒,定
时器计数最多65536次,就会溢出,从0开始计数。
---------上面是12T的模式说法----------------
------->
概括的说
假如频率 5.5692MHZ
则1S计数 5569200个数
那么1ms 计数 5569200/1000 =5569.2 个~~5569个
另外,定时器计数最大数 -> 65536 后,就会清零
所以,TH0 TL0 计数器初值 = 65536-5569=59967
------->
---------------------------------------------------------------------
第2种方法:
#define FOSC 11059200L //晶振的频率
TH=(65536-time*FOSC /12)/256
TL=(65536-time*FOSC /12)%256
time就是假设要延时的100ms(要取100000us)
FOSC 是晶振频率
注意:定时器一定要考虑晶振的频率,因为单片机最小的中断时间和频率有关系。
例如:
6MHz晶振对应的时间范围是:512us --- 16.384ms --- 131.072ms
因此,在设置时间前,一定要考虑晶振和定时器的关系。
*/
//-----------------------------------------------
//sfr P3 = 0xB0; 如果不写头文件,就要单独这样写了
//sbit 自定义名 = 寄存器名
//问题:为啥要用2个IO口检测开关门的状态呢?
sbit LED1_Open = P3^1;
sbit LED2_Close = P3^0;
sbit Door_CloseVolt = P3^4;
sbit Door_OpenVolt = P3^5;
sbit Check_Batvolt = P3^3;
BYTE Door_flag; //定义一个标志位,0 无动作,1 门打开,2门关闭
BYTE Batvlot_low_flag; //定义电池电压低判断位 ,0 不是低压(正常电压),1 暂时假设是低压(需再次判断),2 确定是低压
//WORD count;
//-----------------------------------------------
//延时函数
void Delay1ms() //@5.5296MHz
{
BYTE i, j;
// _nop_();
// _nop_();
i = 6;
j = 93;
do
{
while (--j);
} while (--i);
}
void Delay200ms() //@5.5296MHz
{
unsigned char i, j, k;
// _nop_();
// _nop_();
i = 5;
j = 52;
k = 195;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay2000ms() //@5.5296MHz
{
unsigned char i, j, k;
// _nop_();
// _nop_();
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//----------------------------------------------
void main (void)
{
//IO口配置
//初始化,对所有IO口配置成准双向口
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
/* IO口配置成准双向口
Pn Pn.7 Pn.6 Pn.5 Pn.4 Pn.3 Pn.2 Pn.1 Pn.0
PnM1 0 0 0 0 0 0 0 0
PnM0 0 0 0 0 0 0 0 0
//方法1:总体配置
//P3.0 配置成开漏,P3.1 配置成推挽输出
P3M1 = 0x01; //0000 0001
P3M0 = 0x03; //0000 0011
方法2:单独配置
P3.0 单独配置成开漏 (不考虑其他引脚)
P3M1 = 0000 0001
P3M0 = 0000 0001
-----------------
初始
P3M1 = 0000 0000
P3M0 = 0000 0000
然后
P3M1 |= 0x01
P3M1 = (P3M1 | 0x01)
0000 0000
或 0000 0001
--------------
0000 0001
P3M0 |= 0x01
P3M0 = (P3M0 | 0x01)
0000 0000
或 0000 0001
--------------
0000 0001
//P3.0 单独配置成开漏
P3M1 |= 0x01;
P3M0 |= 0x01;
*************************
P3.1 单独配置成推挽输出 (不考虑其他引脚)
P3M1 = 0000 0000
P3M0 = 0000 0010
然后
P3M1 &=(~0x02)
P3M1 = (P3M1 & (~0x02))
0x02取反
0000 0010
取反
--------------
1111 1101
再与
0000 0000
与 1111 1101
--------------
0000 0000
P3M0 |= 0x02
P3M0 = (P3M0 | 0x02)
0000 0000
或 0000 0010
--------------
0000 0010
//P3.2 单独配置成推挽输出
P3M1 &=(~0x02);
P3M0 |= 0x02;
*/
//初始化
//这里使用方法1
//方法1:总体配置
//P3.0 配置成开漏,P3.1 配置成推挽输出
P3M1 = 0x00; //0000 0000
P3M0 = 0x03; //0000 0011
/*------------------------------------------
//定时器配置
AUXR |= 0x80; //定时器0为1T模式(快) ,AUXR,辅助寄存器,BIT7置1,1I模式、置0,12T模式
// AUXR &= (~0x80); //定时器0为12T模式
// AUXR &= 0x7f;
TMOD = 0x00; //设置定时器为模式0(16位自动重装载)
//TH0 TL0 = 65536-(5569200/12) = 59967 = EA3F
TL0 = T1MS; //赋初值的低八位,给TL0 3F
TH0 = T1MS >> 8; //右移八位,就是把他的高八位取出来给TH0 EA
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
*/
//------------------------------------------
//初始化
//外部中断1配置
IT1 = 0; //设置INT1的中断类型 (1:仅下降沿 0:上升沿和下降沿)
EX1 = 1; //使能INT1中断
//外部中断2配置
INT_CLKO |= 0x10; //(EX2 = 1)使能INT2中断
//外部中断3配置
INT_CLKO |= 0x20; //(EX3 = 1)使能INT3中断
//开总中断
EA = 1;
//初始化
//-------------------------------------------------------
//两个灯,上电亮一秒,再熄灭
LED1_Open = 1; // 初始化配置 开门灯开
LED2_Close = 1; // 初始化配置 关门灯开
Delay2000ms();
LED1_Open = 0; // 初始化配置 开门灯关
LED2_Close = 0; // 初始化配置 关门灯关
Door_CloseVolt = 1; // 初始化配置 关门信号高电平
Door_OpenVolt = 1; // 初始化配置 开门信号高电平
Check_Batvolt = 1; // 初始化配置 电池电压正常,高电平
//初始化
//--------------------------------------------------------------------
//Door_flag 是个互斥事件,不会同时发送
Door_flag = 0; // 初始化配置 门标志位 无动作
Batvlot_low_flag = 0; //初始化配置 电池电压状态, 正常,不是低压
// count = 0;
// 通过读取IO口状态,判断打开灯
while(1)
{
if(Door_flag == 1) //表示门打开
{
//LED1_Open = 1;
Delay1ms();
if(Door_OpenVolt == 0)
{
LED1_Open = 1;
Delay200ms();
LED1_Open = 0;
}
Door_flag = 0;
}
if(Door_flag == 2) //表示门关闭
{
//LED2_Close = 1;
Delay1ms();
if(Door_CloseVolt == 0)
{
LED1_Open = 1;
Delay200ms();
LED1_Open = 0;
}
Door_flag = 0;
}
if(Batvlot_low_flag == 1) //表示P3.3临时低压,触发INT1外部中断,进入此再次判断
{
Delay200ms();
if(Check_Batvolt == 0) //延时后,确认P3.3低压,即电池进入低压状态
{
Batvlot_low_flag = 2; //表示真的低压
}
else
{
Batvlot_low_flag = 0; //表示不是低压,还是正常电压
}
}
if(Batvlot_low_flag == 2)
{
LED2_Close = 1;
Delay200ms();
Delay200ms();
LED2_Close = 0;
Delay200ms();
Delay200ms();
}
//循环检测P3.4,P3.5口电压
//先判断是否开门,P3.5脚是否接地
/* if(Door_Open == 0) //根据原理图,开门,Door_open IO口 变成低电平
{
Delay1ms();
if(Door_Open == 0)
{
LED1_Open = 1;
}
}
else
{
LED1_Open = 0;
}
//再判断是否关门,P3.4脚是否接地
if(Door_Close == 0) //根据原理图,开门,Door_open IO口 变成低电平
{
Delay1ms();
if(Door_Close == 0)
{
LED2_Close = 1;
}
}
else
{
LED2_Close = 0;
}
*/ }
}
//-----------------------------------------------
//这个芯片,外部中断2,3,4 只支持下降沿
//中断函数
/* Timer0 interrupt routine */
/*
void tm0_isr() interrupt 1
{
count++;
if(count > 999)
{
count = 0;
LED2 = ! LED2; //将测试口取反
}
}
*/
//-----------------------------------------------
//-----------------------------------------------
//中断服务程序
//中断服务程序
void exint1() interrupt 2 //INT1中断入口-->电池低压检测
{
Batvlot_low_flag = 1; //INT1外部中断触发,假设电池低压情况发生
//这时候,需要进入主循环进程再次检测
}
void exint2() interrupt 10 //INT2中断入口-->关门
{
Door_flag = 2;
// LED1_Open = 0;
// LED2_Close = 1;
}
void exint3() interrupt 11 //INT3中断入口-->开门
{
Door_flag = 1;
//LED1_Open = 1;
// LED2_Close = 0;
}