⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cfk.c

📁 本程序为avr控制程序
💻 C
📖 第 1 页 / 共 2 页
字号:

/*-----------------------------------------------------------------------
函 数 名:         read_key_n
功    能:         读取按键,具有连发功能
输入参数:
注:  
    要每隔10ms调用一次,这样做是为了消抖
-----------------------------------------------------------------------*/
char read_key_n(void)
{
  static char key_state = 0, key_time = 0, key_buffer=0;
  char key_press, key_return = 0;
	
  key_press = key_mask & key_input;     // 读按键I/O 电平
  switch (key_state)
    {
      case key_state_0: 											// 按键初始态
        if (key_press != key_mask) key_state = key_state_1;     // 键被按下,状态转换到键确认态
        break;
      case key_state_1: 			  								// 按键确认态
	if (key_press != key_mask)
	  {
	    key_state = key_state_2;    // 按键仍按下,状态转换到计时1
	    key_buffer = key_press;
	    key_time = 0;       // 清另按键时间计数器
	  }
	else key_state = key_state_0;   // 按键已抬起,转换到按键初始态
        break;
      case key_state_2:
	if (key_press != key_buffer)
	  {
	    key_state = key_state_0;        // 按键已释放,转换到按键初始态
	    switch (key_buffer)
	      {
		case 0b11100000: key_return = 1; break; // 输出up
		case 0b11010000: key_return = 2; break; // 输出down
    		case 0b10110000: key_return = 3; break; // 输出left
		case 0b01110000: key_return = 4; break;	// 输出right
	      }
	  }
	else if (++key_time >= 30) 	// 按键时间计数
	  {
	    key_state = key_state_3; 	// 按下时间>0.3s,状态转换到计时2
	    key_time = 0; 										// 清按键计数器
	    switch (key_buffer)
	      {
	        case 0b11100000: key_return = 1; break;		// 长按up
		case 0b11010000: key_return = 2; break; 	// 长按down
    		case 0b10110000: key_return = 3; break;		// 长按left
		case 0b01110000: key_return = 4; break;		// 长按right
	      } 										
          }
	break;
      case key_state_3:
	if (key_press != key_buffer) key_state = key_state_0; 	//按键已释放,转换到按键初始态
	else
	  {
	    if (++key_time >= 20)  	// 按键时间计数
              {
		key_time = 0; 		// 按下时间>0.2s,清按键计数器
		switch (key_buffer)
		  {
		    case 0b11100000: key_return = 1; break;	// 长按up
		    case 0b11010000: key_return = 2; break;	// 长按down
                    case 0b10110000: key_return = 3; break;	// 长按left
		    case 0b01110000: key_return = 4; break;	// 长按right
		  }
	      }
	  }
	 break;
    }
    return key_return;
}



//--------------------------------方块主程序--------------------------------//
#define ulong  unsigned long
#define uint   unsigned int
#define uchar  unsigned char

//----------------俄罗斯方块函数定义----------------------------------------//
void fk_dot(uchar x,uchar y);          //显示1个方块点
void fk_cldot(uchar x,uchar y);        //清除1个方块点
void fk_show(void);                    //显示分数
void fk_reffk(void);                   //刷新方块
void fk_refnew(void);                  //刷新预览方块
void fk_refline(uchar yy);             //刷新1行背景
uchar  fk_chk(void);                   //冲突检查
void fk_new(void);                     //产生新方块
void fk_add(void);                     //方块合并

void fk_init(void);                    //方块初始化
void fk_move(unsigned char mode);      //移动方块

//--------------------------方块所需变量等定义--------------------------//
#define FULLMAP    0x03ff              /*方块Y向的掩码,一行10个方块*/
#define LINEMAX    21                  /*屏幕最高21行*/
uint fk_map[LINEMAX+4];                //背景映象
uchar  fk_x,fk_y,fk_r;                 //方块X坐标、Y坐标、方向
uchar fk_type;                         //方块形状
uchar  fk_oldx,fk_oldy,fk_oldr;        //方块上次X坐标、Y坐标、方向
uchar  fk_newtype,fk_newr;             //新方块形状、方向
static ulong int score;                //总分
bit fk_run;                            //方块运行状态  1-运行,0-停止
    
uint fk_mod[7][4][4]={            //方块模型号,4个方向,4行
    7,2,0,0,1,3,1,0,2,7,0,0,2,3,2,0,    //_|_
    2,3,1,0,3,6,0,0,2,3,1,0,3,6,0,0,    //_|~
    1,3,2,0,6,3,0,0,1,3,2,0,6,3,0,0,    //~|_
    1,1,3,0,4,7,0,0,3,2,2,0,7,1,0,0,    //|__
    3,1,1,0,1,7,0,0,2,2,3,0,7,4,0,0,    //__|
    1,1,1,1,15,0,0,0,1,1,1,1,15,0,0,0,  //____
    3,3,0,0,3,3,0,0,3,3,0,0,3,3,0,0     //田字
};
/*-----------------------------------------------------------------------
函 数 名:         fk_show
功    能:         显示分数
输入参数:
注:
-----------------------------------------------------------------------*/
void fk_show(void)
  {
    unsigned char i,tmp,num;
	unsigned int j;
	LCD_set_XY(42,0);       //设置坐标
	tmp=score;
	for (j=10000;j>=1;j/=10)    //取各位数字显示
	  {
	   num=tmp/j; 
	   tmp%=j;
	   for (i=0;i<8;i++)
		 LCD_write_byte(number[num][i],1);
	  }
  }

/*-----------------------------------------------------------------------  
函 数 名:         fk_reffk      
功    能:         刷新方块
输入参数:  
注:
-----------------------------------------------------------------------*/
void fk_reffk(void)
{
    uchar i,j;
    uchar temp;
    //----------------------------------------------//清除原来的方块
    for (i=0;i<4;i++)
    {
        temp=(fk_mod[fk_type][fk_oldr][i]);
        for (j=fk_oldx;j<fk_oldx+4;j++)
        {
            if(temp&0x01)
            {
                fk_cldot(j,fk_oldy+i);
            }
            temp>>=1;
        }
    }
    //----------------------------------------------//显示新的方块
    for (i=0;i<4;i++)
    {
        temp=(fk_mod[fk_type][fk_r][i]);
        for (j=fk_x;j<fk_x+4;j++)
        {
            if(temp&0x01)
            {
                fk_dot(j,fk_y+i);
            }
            temp>>=1;
        }
    }
    fk_oldx=fk_x;fk_oldy=fk_y;fk_oldr=fk_r;    //保存新方块位置
}

/*-----------------------------------------------------------------------  
函 数 名:         fk_refline   
功    能:         刷新1行背景
输入参数: yy      要刷新的行 
注:
-----------------------------------------------------------------------*/
void fk_refline(uchar yy) 
{
    uchar i;
    uint temp;
    if (yy>=1)
    {
        temp=fk_map[yy];
        for (i=0;i<10;i++)
        {
            if ((temp&0x01) !=0)
                fk_dot(i,yy);
            else
                fk_cldot(i,yy);
            temp >>= 1;
        }
    }
}

/*-----------------------------------------------------------------------  
函 数 名:         fk_refnew   
功    能:         刷新预览方块
输入参数:
注:
-----------------------------------------------------------------------*/
void fk_refnew(void)    
{
    uchar i;
    LCD_set_XY(35,0);
	for (i=0;i<4;i++)
    {
	    LCD_write_byte(smfk[fk_newtype][fk_newr][i], 1);
    }
}

/*-----------------------------------------------------------------------  
函 数 名:         fk_chk 
功    能:         冲突检查
输入参数:
注:
-----------------------------------------------------------------------*/
char fk_chk(void) 
{
    uchar i;
    char neq=0;
    for (i=0;i<4;i++)
    {
        if ( (((fk_mod[fk_type][fk_r][i])<<fk_x)+(fk_map[fk_y+i])) != (((fk_mod[fk_type][fk_r][i])<<fk_x)|(fk_map[fk_y+i])) )
            neq=1;
    }
    return neq ;
}

/*-----------------------------------------------------------------------  
函 数 名:         fk_new
功    能:         产生新方块
输入参数:
注:
-----------------------------------------------------------------------*/
void fk_new(void)                        
{
    srand(rand()+fk_x+fk_y+fk_r);
    fk_oldx=fk_x=4;
    fk_oldy=fk_y=LINEMAX;
    fk_type = fk_newtype;
    fk_oldr=fk_newr;
    fk_newtype = rand()%7;
    fk_newr=rand()%4;
    fk_refnew();       //刷新预览方块
    if (fk_run)
        fk_reffk();    //刷新显示
}

/*-----------------------------------------------------------------------  
函 数 名:         fk_add
功    能:         方块合并
输入参数:
注:
-----------------------------------------------------------------------*/
void fk_add(void) 
{
    uchar i,j;
    uchar full=0x00;
    uchar fulltemp;
    uchar fullline=0x00;
    for (i=0;i<4;i++)    //方块合并
    {
        fk_map[fk_y+i] |= (fk_mod[fk_type][fk_r][i])<<fk_x;
        full <<= 1;
        if ((fk_y+i >= 1) && (fk_map[fk_y+i] == 0xffff))        //满行
        {
            full |= 0x01;
        }
    }
    if (full != 0)        //有满行
    {
        fulltemp=full;
        for (i=fk_y;i<LINEMAX+4+fullline;i++)    //上面行下移
        {
            if ((i < LINEMAX+4)&&(fk_map[i-fullline]!=fk_map[i]))
            {
                fk_map[i-fullline]=fk_map[i];
                fk_refline(i-fullline);
            }
            if ((i >= LINEMAX+4)&&(fk_map[i-fullline]!=~FULLMAP))
            {
                fk_map[i-fullline]=~FULLMAP;    //背景映象
                fk_refline(i-fullline);
            }
            if ((fulltemp&0x08) != 0)
            {
                fullline++;
            }
            fulltemp <<= 1;
        }
        score+=fullline;
        fk_show();           //显示分数      
        fk_new();            //产生新方块
    }
    else
    {
        if (fk_y==LINEMAX)        //在最高位置碰撞且不能消行则游戏结束
            {
              #asm("cli")  //关中断
              LCD_clear();
              LCD_draw_bmp_pixel(15,0,32,44); 
              for (j=0;j<3;j++)
                {
                  delay_ms(700);
                  LCD_write_byte(0x0d, 0);
                  delay_ms(700);
                  LCD_write_byte(0x0c, 0);
                }
              fk_run=0;
              #asm("sei")
            }
        else
            fk_new();    //产生新方块
    }
}

/*-----------------------------------------------------------------------  
函 数 名:         fk_init
功    能:         方块初始化
输入参数:
注:
-----------------------------------------------------------------------*/
void fk_init(void)
{
    uchar i;
    LCD_clear();                     //LCD清屏
    fk_map[0]=0xffff;            //背景映象   
    for (i=1;i<LINEMAX+4;i++)
    {
        fk_map[i]=~FULLMAP;          //背景映象
        fk_refline(i);               //刷新1行背景
    }
    LCD_draw_top();                  //画右边的信息栏
    fk_run = 1;
    fk_show();                       //显示分数
    fk_new();                        //产生新方块
}

/*-----------------------------------------------------------------------  
函 数 名:         fk_move
功    能:         方块移动
输入参数: key     移动方向
注:
-----------------------------------------------------------------------*/
void fk_move(uchar key)
{
    switch(key)
    {
    case 2:        //下移到底
        while((fk_y>0)&&!(fk_chk()))     //一直下移直到冲突
        {
            fk_y--;
        }
        fk_y++;                //恢复到未冲突位置
        break;
    case 3:        //右移
        if (fk_run)                    //游戏中右移
        {
            if(fk_x<10)
            {
                fk_x++;
                if(fk_chk())
                    fk_x--;//有冲突取消操作
            }
        }
        break;
    case 4:        //左移
        if (fk_run)                        //游戏中左移
        {
            if(fk_x>0)
            {
                fk_x--;
                if(fk_chk())
                    fk_x++;//有冲突取消操作
            }
        }
        break;
    case 1:        //变形
        if (fk_run)                        //游戏中变形
        {
            fk_r++;
            if(fk_chk())
                fk_r--;                    //有冲突取消操作
            fk_r &= 0x03;
        }
        else                            //初始化时
        {
          fk_init();       
        }
        break;
    }
    if((fk_run)&& ((fk_x!=fk_oldx)||(fk_y!=fk_oldy)||(fk_r!=fk_oldr)) )    //方块的属性有变化就刷新
    {
        fk_reffk();    //刷新显示
    }
    rand();
} 
 
void main(void)
{
  char temp;
  OSCCAL=0x9d;                        // 8M系统内部时钟校准    
  PORTA=0x00;
  DDRA=0x00;
  
  //设置MCU的I/O口
  DDRB |= LCD_RST | LCD_DC | LCD_CE | SPI_MOSI | SPI_CLK;
  SPSR |= BIT(SPI2X);                 // 设置SPI时钟倍速
  SPCR |= BIT(SPE)|BIT(MSTR);		// 使能SPI接口,主机模式,4M时钟
 
  // T/C0 初始化
  TCCR0 = 0x0B; // 内部时钟,64 分频(4M/64=62.5KHz),CTC 模式
  TCNT0 = 0x00;
  OCR0 = 0x7C; // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  TIMSK = 0x02; // 允许T/C0 比较匹配中断
  
  LCD_init(); //初始化液晶  
  LCD_write_chinese_string(2,2,16,5,0,0); //显示LOGE
  delay_ms(3000);
  LCD_clear();  //LCD清屏
  LCD_draw_top();  //画右边的信息栏

  #asm("sei") // 开放全局中断
  
  while (1)
    { 
      if (key_10ms_ok)		   		  // 10ms 到
	{
          key_10ms_ok = 0;
	  temp = read_key_n();
	  if (temp!=0)           
	    fk_move(temp);              //有键按下
	}
      if (key_500ms_ok) 				  //0.5s  到
	{
	  key_500ms_ok=0;
	  if (fk_run)                    //自然下移
            {
              if (fk_y>0)
                {
                  fk_y--;
                  if (fk_chk())
                    {
                      fk_y++;        //有冲突取消操作,执行碰撞组合
                      fk_add();    //方块合并    
                    }
                }
              else                //方块到底也执行碰撞组合
                {
                  fk_add();        //方块合并
             	}
              if (fk_run) fk_reffk();         //刷新显示
            }
	}
    };
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -