积分赛——光敏控制多功系统设计
竞赛板配置:
将IAP15F2K61S2单片机内部振荡器频率设定为12MHz。
键盘工作模式跳线J5配置为矩阵键盘(KBD)模式。
扩展方式跳线J13配置为IO模式。
硬件框图
图1 系统硬件框图
功能描述
3.1 功能概述
1)通过PCF8591采集光敏电阻电压值。
2)通过数码管、按键完成题目要求的数据显示、界面切换、参数设置功能。
3)通过LED指示灯完成题目要求的输出指示功能。
4)通过继电器模拟开发板外的功率器件。
3.2 性能要求
1)按键动作响应时间:≤0.2.秒。
2)指示灯动作响应时间:≤0.1秒。
3)继电器响应时间:≤0.2秒。
3.3 显示功能
1)欢迎界面
欢迎界面如图2所示,显示内容固定为(HELLO)。
图2 欢迎界面
2)工作界面
工作界面如图3所示,显示内容包括标识符(C)、剩余时间组成。剩余时间固定由两位数码管显示,显示不足位数时高位(左侧)数码管熄灭。
图3 工作界面
**剩余时间的初始值为当前设置的时间参数,倒计时过程中从该值递减至0。当时间参数修改后,剩余时间将同步更新为新的参数值。
3)设置界面
设置界面如图4所示,显示内容包括标识符(E)、时间参数组成。时间参数数值范围为(5~30),显示不足位数时高位(左侧)数码管熄灭。
图4 设置界面
4)显示要求
按照题目要求的格式和切换方式设计
数码管显示无重影、闪烁、过暗、亮度不均匀等严重影响显示效果的缺陷。
3.5 按键功能
1、功能说明
使用S4完成界面切换与设置功能。
1)S4:定义为“多功能”按键。
在“欢迎界面”时,定义为“切换”按键,按下S4按键,切换到“设置界面”。
在“设置界面”时,定义为“加”按键,按下S4按键,“时间参数”增加5。
2、按键要求
1)按键应做好消抖处理,避免出现一次按键动作导致功能多次触发。
2)按键动作不影响数码管显示等其他功能。
3.6 工作模式
①当光敏电阻处于被遮挡状态时,自动切换到“工作界面”,开始倒计时,同时打开继电器。
②在倒计时过程中,若光敏电阻的遮挡被移开,则立即停止计时并关闭继电器,在“工作界面”继续停留3秒,显示剩余时间。若在这3秒内光敏电阻重新被遮挡,则再次打开继电器并继续计时;若未被遮挡则返回“欢迎界面”。准备下一次工作。
③在倒计时结束后(为0),无论光敏电阻是否被遮挡,均停止计时并关闭继电器,在“工作界面”继续停留3秒,之后返回“欢迎界面”。准备下一次工作。
④在“设置界面”无操作3秒后,自动返回“欢迎界面”。
3.7 LED指示灯功能
1、界面指示灯
1)L1:在“欢迎界面”下,指示灯L1点亮,否则指示灯L1熄灭。
2)L2:在“工作界面”下,指示灯L2点亮,否则指示灯L2熄灭。
3)L3:在“设置界面”下,指示灯L3点亮,否则指示灯L3熄灭。
2、其余试题未涉及的指示灯均处于熄灭状态。
初始状态
请严格按照以下要求设计作品的上电初始状态。
1)处于欢迎界面。
2)默认时间参数为5。
代码
other.h
#ifndef __OTHER_H__
#define __OTHER_H__
#include <STC15F2K60S2.H>
#include "intrins.h"
#define LINE 1.5 //判断光敏电阻是否被遮挡的电压底线
sbit sda=P2^1;
sbit scl=P2^0;
sbit s4=P3^3;
extern unsigned char time_remain;//剩余时间
extern unsigned char time_init;//时间参数
extern unsigned char Seg_Buff[8];//数码管缓存
extern unsigned char keyval;//按键标志
extern unsigned char UI;//界面选择标志,1为欢迎界面,2为工作界面,3为设置界面
extern float num_adc;//光敏电阻电压值
//other.c
void init74hc138(unsigned char n);//74hc138译码器选通
void no_relay(void);//关闭继电器
void relay(void);//打开继电器
void init(void);//系统初始化
void led(void);//LED功能
//seg.c
void Seg_Loop(void);//数码管刷新函数
void seg_ui();//界面显示选择
//key.c
void Key_Loop(void);//按键刷新函数
//iic.c
unsigned char r_adc(unsigned char addr);//AD转换函数
#endif
main.c
#include "other.h"
bit flag_seg=0;
bit flag_key=0;
bit flag_adc=0;
bit flag_time=0;//倒计时开始标志位
void Timer0_Init(void) //100微秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x50; //设置定时初始值
TH0 = 0xFB; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
}
void Timer1_Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
EA = 1;
}
void main(){
init();
Timer0_Init();
Timer1_Init();
num_adc=(float)r_adc(0x01)*5.0/255;
while((int)(num_adc*100)<(int)(LINE*100))
num_adc=(float)r_adc(0x01)*5.0/255;
while(1){
led();
if(flag_seg){
flag_seg=0;
seg_ui();
Seg_Loop();
}
if(flag_key){
flag_key=0;
Key_Loop();
}
if(flag_adc){
flag_adc=0;
num_adc=(float)r_adc(0x01)*5.0/255;//0x01即选择AIN1通道
}
if((int)(num_adc*100)<(int)(LINE*100)){
UI=2;//切换为工作模式
relay();//打开继电器
flag_time=1;
}else{
flag_time=0;
}
}
}
void Timer0_Isr(void) interrupt 1
{
static unsigned char count1=0;//数码管定时刷新
static unsigned char count2=0;//按键定时扫描
static unsigned int count3=0;//AD转换
count1++;count2++;count3++;
if(count1==2){
count1=0;
flag_seg=1;
}
if(count2==50){
count2=0;
flag_key=1;
}
if(count3==1000){//0.1s进行一次AD转换
count3=0;
flag_adc=1;
}
}
void Timer1_Isr(void) interrupt 3
{
static unsigned int count4=0;
static unsigned int count5=0;
static unsigned int count6=0;
static unsigned int count7=0;
if(flag_time){
count5=0;
count4++;
if(count4==1000){//定时1s
count4=0;
if(time_remain>0)
time_remain--;
}
}else if(time_remain>0){
count4=0;
count5++;
if(count5==3000){//定时3s
count5=0;
no_relay();
UI=1;
time_remain=time_init;
}
}else{
count4=0;
count5=0;
}
if(time_remain==0){
no_relay();
count6++;
if(count6==3000){
count6=0;
flag_time=0;
UI=1;
time_remain=time_init;
}
}else{
count6=0;
}
if(UI==3&&keyval==0){
count7++;
if(count7==3000){
count7=0;
UI=1;
}
}else{
count7=0;
}
}
other.c
#include "other.h"
unsigned char UI=1;
unsigned char time_init=5;
unsigned char time_remain=5;
float num_adc;
//74hc138译码器选通
void init74hc138(unsigned char n){
P2=(P2&0x1f)|(n<<5);
P2&=0x1f;
}
//系统初始化
void init(void){
P0=0x00;
init74hc138(5);//关闭蜂鸣器和继电器
P0=0xff;
init74hc138(4);//熄灭LED小灯
UI=1;
}
//LED功能
void led(void){
switch(UI){
case 1://欢迎界面L1亮
P0=0xfe;init74hc138(4);P0=0xff;break;
case 2://工作界面L2亮
P0=0xfd;init74hc138(4);P0=0xff;break;
case 3://设置界面L3亮
P0=0xfb;init74hc138(4);P0=0xff;break;
}
}
//打开继电器
void relay(void){
P0=0x10;
init74hc138(5);
P0=0xff;
}
//关闭继电器
void no_relay(void){
P0=0x00;
init74hc138(5);
P0=0xff;
}
seg.c
#include "other.h"
code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0xc6, //C 10
0x86, //E 11
0x89, //H 12
0xC7, //L 13
0xff //熄灭 14
};
unsigned char Seg_Buff[8]={14,14,14,14,14,14,14,14};
void seg(unsigned char addr,unsigned char num){
P0=0xff; //消隐
init74hc138(7);
P0=0x01<<addr;
init74hc138(6);
P0=Seg_Table[num];
init74hc138(7);
}
void Seg_Loop(void){
static unsigned char i=0;
seg(i,Seg_Buff[i]);
i++;
if(i==8)i=0;
}
void seg_u1(void){
Seg_Buff[7]=14;
Seg_Buff[6]=14;
Seg_Buff[5]=14;
Seg_Buff[4]=0; //O
Seg_Buff[3]=13;//L
Seg_Buff[2]=13;//L
Seg_Buff[1]=11;//E
Seg_Buff[0]=12;//H
}
void seg_u2(void){
Seg_Buff[7]=time_remain%10;
if(time_remain<10)
Seg_Buff[6]=14;
else
Seg_Buff[6]=time_remain/10;
Seg_Buff[5]=14;
Seg_Buff[4]=14;
Seg_Buff[3]=14;
Seg_Buff[2]=14;
Seg_Buff[1]=14;
Seg_Buff[0]=10;//C
}
void seg_u3(void){
Seg_Buff[7]=time_init%10;
if(time_init==5)
Seg_Buff[6]=14;
else
Seg_Buff[6]=time_init/10;
Seg_Buff[5]=14;
Seg_Buff[4]=14;
Seg_Buff[3]=14;
Seg_Buff[2]=14;
Seg_Buff[1]=14;
Seg_Buff[0]=11;//E
}
void seg_ui(){
switch(UI){
case 1:seg_u1();break;
case 2:seg_u2();break;
case 3:seg_u3();break;
}
}
key.c
#include "other.h"
unsigned char keyval,keyold,keyup,keydown;
unsigned char Key_Scan(void){
static unsigned char key_cnt = 0;
unsigned char temp=0;
P44=0;
if(s4==0){
key_cnt++;
if(key_cnt >= 20){ // 消抖处理,20ms
key_cnt = 20;
//在欢迎界面按下,temp=1表示切换到设置界面
if(UI==1)temp=1;
//在设置界面按下,temp=2表示时间参数增加5
if(UI==3)temp=2;
}
}else{
key_cnt = 0;
}
return temp;
}
void Key_Loop(void){
keyval=Key_Scan();
keydown=keyval&(keyold^keyval);
keyup=~keyval&(keyold^keyval);
if(keyval==1&&keyold!=1){UI=3;}
if(keyval==2&&keyold!=2){
time_init+=5;
if(time_init==35)time_init=5;
time_remain=time_init;
}
keyold=keyval;
}
iic.c
#include "other.h"
#define DELAY_TIME 5
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
while(n--);
}
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
void I2CSendAck(unsigned char ackbit)
{
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
}
unsigned char r_adc(unsigned char addr){
unsigned char temp;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
temp=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return temp;
}