Interactive Tiles Code - Slave
This is a code for 8051 chip, which you have to use "keilC" to compile it. There might be some omissions in the code due to the error of web past function. Please go to this page to get the full code.
#include<REG52.H>
#include "math.h"
void delay05ms(unsigned char count); //宣告數學函數,才可以用floot(浮點)
void hsv_to_rgb(void);
void judge_type(void);
void sent(void);
sbit key_mode=P2^1;
sbit key_s=P2^2;
sbit key_touch=P2^0;
sbit PWM_R =P2^5;
sbit PWM_G =P2^6;
sbit PWM_B =P2^7;
unsigned char R_level,G_level,B_level,PWM_cnt=0,C_cnt=0,Sec=0,Sec3=0,half_S=0,d=0,cmd=0,mode=1,B_mode,judge=0,loc,no,ID,locx,locy,x,y,C_speed=2,temp,B_temp,info[6],k,j=0,n=0;
unsigned char
head,tail,lasted_H=0,damper=0,S_step=2,buffer;
int
H=0,Hc=0,Base=0,random=0;
idata int
S_counter=0,counter=0,R_counter=0,interval=0,DCK_counter=0;
float
v=0,s=1;
bit
spread=0,count_hold=0,hsv=1,check=0,direction=1,self=0,get=0,onoff_flag=0,turn_on=0,turn_off=0,black=1,type=0,reverse=0,finish=1,TxRx_done=0,circle=0,mid_hold=0;
bit
select=0,H_add=0,H_minus=0,touched=0,doubleclick=0,stateflag_mode=0,stateflag_s=0,black_mark=0,off_check=0,info_check=0,go=0,occupied=0,double_mode=0,food=0,slow=0;
bit
win=0,dead=0,blink=1,retard=0;
void Main(void){
SCON=0x50; /* SCON: mode 1, 8-bit UART, enable rcvr */
// PCON=0x07;
TMOD=0x22;
TH0=(256-125);
TL0=(256-125);
TH1=0xFD; /* TH1: reload value for 19200 baud @ 11.0592MHz */
TR0=1;
TR1=1;
EA=1;
ET0=1;
ES=1;
PS=1;
P0=0xff; //設定初始值
P1=0xff;
P2=0xff;
no=P1;
// key_touch=1; //初始值設定0會無法讀取touchkey
// key_end=1;
while(1)
{
if(H_add)
{
type=0;
Hc++;
if(Hc>359)
Hc=0;
hsv=1;
}
if(H_minus)
{
type=1;
Hc--;
if(Hc<0)
Hc=359;
hsv=1;
}
if(key_touch==1) //大於或小於3秒之觸壓
{
if(touched==0)
{
touched=1;
if(mode==5)
{
if(double_mode) //mode5雙人干擾模式
{
if(doubleclick==1)//第二次觸碰,時間未大於0.5秒,所以doubleclick還未被歸零
{
doubleclick=0; //動作完成,旗標歸零
if(black==0)
{
onoff_flag=1; //關掉module
turn_off=1;
hsv=1;
}
touched=0; //觸碰與記時相關旗標歸零
counter=0;
DCK_counter=0;
}
else
doubleclick=1;
}
}
else
{
if(doubleclick==1)//第二次觸碰,時間未大於0.5秒,所以doubleclick還未被歸零
{
doubleclick=0; //動作完成,旗標歸零
if(black==0)
{
onoff_flag=1; //關掉module
turn_off=1;
hsv=1;
}
touched=0; //觸碰與記時相關旗標歸零
counter=0;
DCK_counter=0;
}
else
doubleclick=1;
}
}
if(Sec>=2&&Sec<4)
{
if(mid_hold==0)
{
if(mode!=5)
{
s=0.65; //快速暗亮提示旗標
if(black)
{
v=0.1;
s=1;
}
}
mid_hold=1; //讓這個區間判別只進入一次
hsv=1;
}
}
if(Sec>=4)
{
if(count_hold==0)
{
if(mode!=5)
{
check=1; //快速暗亮提示旗標
if(black)
check=0;
s=1;
}
count_hold=1; //停止計時
hsv=1;
}
if(mode==4)
{
if(count_hold)
{
if(black==0)
{
slow=1;
buffer=S_step;
S_step=2;
type=0;
Hc++;
if(Hc>359)
Hc=0;
hsv=1;
}
}
}
}
}
else
{
if(touched)
{
if(Sec>=2&&Sec<4)
{
if(mode!=5)
{
S_step=buffer;
s=1;
cmd=28; //指改變點亮狀態模組
if(black)
{
cmd=1;
v=0;
}
sent();
delay05ms(1);
}
}
if(Sec>=4) //如果Sec大於2秒
{
if(mode!=5)
{
S_step=buffer;
cmd=0;
if(black)
{
cmd=1;
v=0;
}
sent();
delay05ms(1);
}
}
if(Sec<2) //key2被按下過且Sec小於1秒
{
switch(mode)
{
case 1: //黑色亂數顏色模式
if(black)
{
onoff_flag=1; //點亮
turn_on=1;
H=random;
Hc=H;
}
else //第一次啟動後的小於三秒之觸碰
{
interval=abs(Hc-random);
if(interval<20)
{
Hc=Hc+45;
if(Hc>359)
Hc=0;
}
else
Hc=random;
judge_type();
}
hsv=1;break; //進入變色副程式
case 2:
if(black)
{
onoff_flag=1; //點亮
turn_on=1;
}
type=0; //固定加色
Hc=Hc+45; //觸壓加色
if(Hc>=360)
Hc=Hc-360;
hsv=1;break; //進入變色副程式
case 3: //變色加色
if(black)
{
onoff_flag=1; //點亮
turn_on=1;
}
type=0;
Hc=Hc+80;
if(Hc>=360)
Hc=Hc-360;
hsv=1;break; //進入變色副程式
case 4: //回復模式
if(black)
{
onoff_flag=1; //點亮
turn_on=1;
}
slow=1
; S_step=1;
if(finish) //還沒觸碰過 ,fihish=1
Hc=Hc+90; //回復式加色
else
Hc=Hc+10;
if(Hc>=360)
Hc=Hc-360;
type=0;
finish=0; //回色程序啟動
reverse=0;
R_counter=0;
Sec3=0;
hsv=1;break; //進入變色副程式
case 5:
if(double_mode)
{
if(occupied==0)
{
if(food==0)
{
v=1;
black=0;
H=55;
Hc=55; //food color, yellow
occupied=1;
cmd=22; // inform other device food was set and where is it's location.
hsv=1;
sent();
delay05ms(1);
}
}
}
else
{
if(retard)
{}
else
{
retard=1;
cmd=22;
sent();
delay05ms(1);
}
}break;
default;break;
}
}
}
touched=0; //這一行要放後面,否不然無法進入if(touched)
Sec=0;
counter=0;
mid_hold=0;
count_hold=0;
}
if(info_check)
{
info_check=0;
head=info[0];
tail=info[5];
if(head==99&&tail==99)
get=1;
else
{
delay05ms(2);
n=0;j=0;
}
}
if(get)
{
get=0;
B_mode=info[1];
ID=info[2];
B_temp=info[3];
cmd=info[4];
if(cmd<2||cmd==28) //modules sent out info
{
food=0;win=0;dead=0;occupied=0,double_mode=0;
if(mode==5)
s=1;
mode=B_mode;
loc=ID;
temp=B_temp;
circle=0; //必須比Hc擷取前早一步關掉自動變色,以免曠散功能失效
C_speed=2;
Hc=temp*2+1; //mode3一得到Hc就會馬上變色所以改到後面spread後擷取
judge_type();
reverse=0; //一些基本參數歸零
finish=1;
R_counter=0;
Sec3=0;
locx=loc>>4; //取得接收之loc的X與Y數值
locy=loc&15;
x=no>>4; //取得no.之X與Y數值
y=no&15;
d=sqrt((locx-x)*(locx-x)+(locy-y)*(locy-y)); //計算距離
spread=1; //擴散旗標=1
}
else // master sents out cmd
{
switch(cmd)
{
case 2: //mode change
mode=B_mode; //全部把info[0]值毒回mpde
if(mode==3) //mode=3要把circle打開
spread=1;
if(select) //被選取者暗亮動作
{
check=1;
hsv=1;
}break;
case 3: //direction control
go=0;
if(no==ID) //被選取者輝度改變
{
select=1;
s=0.75;
if(black)
{
black_mark=1;
onoff_flag=1;
turn_on=1;
turn_off=0;
}
}
else
{
if(black_mark)
{
black_mark=0;
onoff_flag=1;
turn_off=1;
turn_on=0;
}
select=0;
s=1;
}
hsv=1; break;
case 4: //select control
go=0;
if(no==ID)
{
if(select==0)
{
select=1;
s=0.75;
if(black)
{
black_mark=1; // mark that the module is originally black
onoff_flag=1;
turn_on=1;
}
}
else
{
select=0;
s=1;
if(black_mark)
{
black_mark=0;
onoff_flag=1;
turn_off=1;
}
}
hsv=1;
}
break;
case 5: //lasted function-data sent out becon feedback to master
go=1; //在select狀況下按下lasted才會有go旗標,避免直接按下lasted又按方向鍵的bug
if(select)
{
if(black)
{
delay05ms(5);
cmd=25;
sent();
}
else
{
delay05ms(5);
cmd=6; //cmd=6在controller上沒實際功能
black_mark=0;
sent();
}
}
break;
case 6:
lasted_H=B_temp;
break;
case 7: // lasted function-Hc fetch
if(go)
{
if(no==ID)
{
select=1;
s=0.75;
Hc=lasted_H*2+1;
Base=Hc;
judge_type();
slow=0;
onoff_flag=1;
turn_on=1;
turn_off=0;
}
else
{
select=0;
s=1;
}
hsv=1;
}
break;
case 8: //H++
if(select)
{
H_add=1;
black_mark=0;
slow=0;
}
break;
case 9: //H--
if(select)
{
H_minus=1;
black_mark=0;
slow=0;
}
break;
case 10: //H state retro
if(select)
{
H_add=0;
H_minus=0;
Base=Hc;
}
break;
case 11: //enter
if(select)
{
delay05ms(1);
cmd=0;
black_mark=0;
if(black)
cmd=1;
sent();
}
break;
case 12: //turn_on-off
if(select)
{
if(black_mark)
{
black_mark=0;
check=1;
}
else
{
if(black)
{
onoff_flag=1;
turn_on=1;
turn_off=0;
}
else
{
onoff_flag=1;
turn_off=1;
turn_on=0;
off_check=1;
}
}
hsv=1;
}
break;
case 13: //end mode
if(no==83)
{
delay05ms(1);
cmd=0;
mode=0;
Hc=0;
Base=0;
check=1;
sent();
}
break;
case 14 : //game mode
food=0;win=0;dead=0;occupied=0,double_mode=0,s=1,R_counter=0;
if(no==ID)
{
delay05ms(1);
occupied=1;
cmd=1; //cmd=1這個指令本身即會把circle關掉
mode=5;
sent();
}
break;
case 15: //game mode, turn on light
if(no==ID)
{
v=1;
occupied=1;
black=0;
Hc=220;
H=Hc;
hsv=1;
}
break;
case 16: // game mode. thurn on light and food was reached
food=0;
if(no==ID)
{
v=1;
black=0;
occupied=1;
Hc=220;
H=Hc;
hsv=1;
}
break;
case 17: // game mode. 主機give food.
food=1;
if(no==ID)
{
v=1;
black=0;
occupied=1;
H=55; //food color
Hc=55;
hsv=1;
}
break;
case 18: //game mode. turn of light
if(no==ID)
{
v=0;
black=1;
occupied=0;
hsv=1;
}
break;
case 19:
if(double_mode)
double_mode=0;
else
double_mode=1;
break;
case 20:
win=1;
if(no==ID)
{
delay05ms(10);
cmd=1; //全部子機win=1,送出cmd=0全部進入快速變色勝利模式
sent();
check=1;
hsv=1;
}break;
case 21:
dead=1;break;
case 22: //子機give food
food=1; break;
case 25:
lasted_H=B_temp;
break;
case 26: // if black sent out cmd=25 ,and then feed back cmd=26
if(go)
{
if(no==ID)
{
select=1;
s=1;
Hc=lasted_H*2+1;
judge_type();
Base=Hc;
slow=0;
onoff_flag=1;
turn_on=0;
turn_off=1;
}
else
{
select=0;
s=1;
}
hsv=1;
}
break;
case 27:
if(S_step==2)
S_step=0;
else
S_step=2;break;
default:
break;
}
get=0;
}
}
if(dead)
{
hsv=1;
H=0;Hc=0;
if(blink)
v=1;
else
v=0;
}
if(spread)
{
Base=Hc; //一律把底色存下,用不用的到再說
slow=0;
if(d<=half_S) //判斷變色時間點
{
if(cmd==0)
{
if(black)
{
onoff_flag=1; //把未亮的模組點亮
turn_on=1;
}
}
if(cmd==1)
{
if(mode==5)
{
if(win)
{
C_speed=0; //如果有收到要進入mode3的指令在改回來C_speed=4
circle=1;
onoff_flag=1;
turn_on=1;
}
else
{
if(no==ID)
{
onoff_flag=1;
turn_on=1;
}
else
{
onoff_flag=1; //把module關掉
turn_off=1;
}
Hc=220; //新局cmd=14的起開始body color
}
}
else
{
onoff_flag=1; //把module關掉
turn_off=1;
}
cmd=0;
}
spread=0;
half_S=0;
S_counter=0;
if(mode==3)
circle=1;
else
circle=0;
judge_type();
hsv=1;
}
}
if(hsv)
hsv_to_rgb(); //轉換hsv
}
}
voidsent(void){
self=1;
if(mode==0) //把變色目標設成0並把這個值sent out
temp=Hc/2;
else
temp=H/2; //其他狀態把當下呈現顏色sent out
info[0]=99;
info[1]=mode;
info[2]=no;
info[3]=temp;
info[4]=cmd;
info[5]=99;
TI=1;
}
void judge_type(void){
if(Hc>H)
{
judge=Hc-H;
if(judge>180)
type=1;
else
type=0;
}
else
{
judge=H-Hc;
if(judge>180)
type=0;
else
type=1;
}
}
void delay05ms(unsigned char count) //時間延遲函式
{
int i,j;
for(i=0;i<count;i++)
for(j=0;j<40;j++);
}
void hsv_to_rgb(void)
{
float h,r,g,b; //r、g與b之值為h、s與v計算求得,同樣將其設為浮點變數。
float f, p, q, t; //f、p、q與t之值為h、s與v計算求得,同樣將其設為浮點變數。
unsigned char i; //為計算存放的一個暫存器
if(onoff_flag)
{
if(turn_on)
{
v=v+0.03;
if(v>1)
{
v=1;
black=0;
turn_on=0;
onoff_flag=0;
off_check=0;
}
}
if(turn_off)
{
if(off_check==0)
{
v=v-0.03;
if(v<0)
{
v=0;
black=1;
turn_off=0;
onoff_flag=0;
}
}
else
{
if(v>0.1)
v=v-0.03;
if(v<0.1)
{
black=1;
if(select==0)
off_check=0;
}
}
}
}
if(black)
check=0; //如果是黑的狀態,取消check
if(check)
{
if(direction)
{
v=v-0.04;
if(v<0.1)
direction=0;
}
else
{
v=v+0.04;
if(v>1)
{
v=1;
direction=1;
heck=0;
}
}
}
if(H!=Hc) //朝目標值加速變色
{
if(type) //type=1,逆轉變色
{
if(slow)
{
damper++;
if(damper>3) //S_step越大越慢
{
damper=0;
H=H-1;
}
}
else
H=H-1;
if(H<0)
H=359;
}
else //type=0
{
if(slow)
{
damper++;
if(damper>S_step) //S_step越大越慢
{
damper=0;
H=H+1;
}
}
else
H=H+1;
if(H>359)
H=0;
}
}
if(H==Hc)
{
type=0; //避免在自動變色mode加色方向與變色方向相反
if(mode==4)
{
if(finish==0) //變回原色動作未完成
reverse=1;
}
}
if(H==Hc)
{
hsv=0;
if(check)
hsv=1;
if(onoff_flag)
hsv=1;
}
h=H;
h/=60; //撰寫(2.1)式
i=H/60;
f = h - i; //撰寫(2.2)式
p = v * ( 1 - s ); //撰寫(2.3)式
q = v * ( 1 - s * f ); //撰寫(2.4)式
t = v * ( 1 - s * ( 1 - f )); //撰寫(2.5)式
switch(i) //判斷 i 座落範圍,撰寫(2.6)式
{
case 0:
r = v; g = t; b = p; break;
case 1:
r = q; g = v; b = p; break;
case 2:
r = p; g = v; b = t; break;
case 3:
r = p; g = q; b = v; break;
case 4:
r = t; g = p; b = v; break;
default:
r = v; g = p; b = q; break;
}
R_level=r*255;
G_level=g*255;
B_level=b*255; //將本為浮點的r、g與b之值放大到0~255的RGB色彩空間
}
void TxRx(void) interrupt 4
{
ES=0;
if(RI)
{
if(self==0)
{
if(n<6)
{
info[n]=SBUF;
n++;
}
if(n==6)
{
n=0;
info_check=1; //資料檢查
}
RI=0;
}
else
{
if(TxRx_done)
{
TxRx_done=0;
self=0;
info_check=1; //資料檢查
}
RI=0;
}
}
if(TI)
{
TI=0;
if(j<6)
{
SBUF=info[j];
j++;
for(k=0;k<3;k++)
{}
}
else
{
j=0;
TxRx_done=1;
}
}
ES=1;
}
void timer_PWM(void) interrupt 1 //30MGH 進中段20000次為1秒
{
if(mode==5&&double_mode==0)
{
if(retard)
{
DCK_counter++;
if(DCK_counter>1500) //約1/10秒
{
DCK_counter=0;
retard=0;
}
}
}
if(doubleclick) //離第一次觸碰0.25秒後doudleclick歸零
DCK_counter++;
if(DCK_counter>6500) //約1/3秒
{
doubleclick=0;
DCK_counter=0;
}
if(mode==1)
{
random++;
if(random>359)
random=0;
}
if(reverse)
{
R_counter++;
if(R_counter>10000)
{
R_counter=0;
Sec3++;
if(Sec3>3) //1.5S
{
type=1; //加色方向設回預設值
reverse=0; //倒轉旗標歸0
finish=1; //回色程序完成
Sec3=0;
R_counter=0;
Hc=Base; //時間buffer到後把底色存回變色目標
hsv=1;
}
}
}
else
{
if(dead)
R_counter++;
if(R_counter>6500) //0.5s
{
R_counter=0;
if(blink)
blink=0;
else
blink=1;
}
}
if(spread)
{
S_counter++;
if(S_counter>4000) //1/3秒的擴散
{
S_counter=0;
half_S++;
}
}
if(key_touch==1&&count_hold==0)
{
counter++;
if(counter>10000)
{
counter=0;
Sec++;
}
}
PWM_cnt++;
if(PWM_cnt==255)
{
if(circle) //自動變色
{
C_cnt++;
if(C_cnt>C_speed)
{
C_cnt=0;
Hc=Hc+1;
if(Hc>=360)
Hc=0;
hsv=1;
}
}
PWM_cnt=0;
}
if(R_level==0)
PWM_R=1;
else
{
if(R_level>=PWM_cnt)
PWM_R=0;
else
PWM_R=1;
}
if(G_level==0)
PWM_G=1;
else
{
if(G_level>=PWM_cnt)
PWM_G=0;
else
PWM_G=1;
}
if(B_level==0)
PWM_B=1;
else
{
if(B_level>=PWM_cnt)
PWM_B=0;
else
PWM_B=1;
}
}