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

📄 iopic18.c

📁 单片机c语言程序设计100例--基于PIC+PROTEUS
💻 C
📖 第 1 页 / 共 2 页
字号:
// 将指定棋盘格子(含格式内的棋子)反相显示
// (当选定待移动棋子但未走动时,通过反复反相显示形成闪烁效果)
//-----------------------------------------------------------------
void panel_invert(BYTE loc[], BYTE flag)
{ 
   BYTE char_code;
   //文本区首地址为0x2000,每个棋盘格子由4x4=16个字符(16字节)铺成,
   //每行有8列棋盘格子,占16x8=128字节.
   //下面的语句根据位置loc得到平铺指定格子底色的字符在DDRAM中的起始地址
   WORD addr = 0x2000 + loc[0] * 128 + loc[1] * 4;
   //偶数行奇数列,奇数行偶数列为黑格子,否则为白格子(& 0x01可得到1/0[奇/偶])
   if ((loc[0] & 0x01) ^ (loc[1] & 0x01))
   {  //黑格子反相(flag为1)时用编码为0x00的字符铺底
      //否则(flag为0)还原时用编码为0x80的自定义字符"■"铺底
      char_code = flag ? 0x00 : 0x80;
   }
   else
   {  //白格子反相(flag为1)时用编码为0x80的自定义字符"■"铺底
      //否则(flag为0)还原时用编码为0x00的内置字符(无色)铺底
      char_code = flag ? 0x80 : 0x00; 
   }
   //用编码为0x00或0x80的全白或全黑字符重新对指定格子铺底色
   //每个格子需要铺4行字符
   for (INT i = 0; i < 4; i++)
   {  //设置显示DDRAM地址
      lcd_wrcmd2(LCD_ADDRESS, addr);
      //每行铺4个编码为0x00或0x80的字符
      for (INT j = 0; j < 4; j++) lcd_wrcmd1(LCD_WRITEINC, char_code);
      //铺完一行后,addr指向下一行的DDRAM地址
      //(由于棋盘每格有4列字符,共8列,故定位到下一行同一列的地址需要+32)
      //(该值与所设置的文本区宽度:LCD_TEXTAREA,32也相对应)
      addr += 32;
   }
}

//-----------------------------------------------------------------
// 检测液晶状态寄存器(STA0~STA7)
//-----------------------------------------------------------------  
void lcd_status_check(BYTE STA_mask)
{
    BYTE status; TRISD = 0xFF; //PORTD设为输入,读取状态寄存器
    do
    {   //发送读状态寄存器字节命令
        PORTA = LCD_STATUS; asm("nop");
        //从PORTD读取状态寄存器字节,保存到status变量
        //随后禁止LCD操作(禁止读/写,禁止片选,C/D设为1) 
        status = PORTD; PORTA = LCD_DONE;
        //与掩码相与时为0x00则继续读状态
    } while ((status & STA_mask) == 0x00); 
} 
   
//-----------------------------------------------------------------
// LCD清屏
//-----------------------------------------------------------------
void lcd_cls()
{
   lcd_wrcmd(LCD_DISPLAY + 0x00);   //关闭显示
   lcd_wrcmd2(LCD_ADDRESS, 0x0000); //LCD RAM地址指针设为0x0000
   lcd_wrcmd(LCD_AUTOWRITE);        //发送数据自动写命令(RAM地址自动递增)
   for (INT i = 0; i < 0x2400; i++) //
   {  
      lcd_status_check(0x08);       //数据自动写就绪(DAWRDY)标志位为0则等待
      PORTD = 0x00; TRISD = 0x00;   //向PORTD端口写全0
      PORTA = LCD_DATA;             //在PORTA端口使能写数据(C/D=0,WR=0,CE=0,RD=1)
      PORTA = LCD_DONE;             //完成后禁止操作
   }    
   lcd_wrcmd(LCD_AUTORESET);        //自动读/写复位(退出自动读/写方式)
   lcd_wrcmd(LCD_DISPLAY + 0x0C);   //设置显示模式(启用图形/文本显示)
}

//-----------------------------------------------------------------
// 将img指针所指向的棋子图形点阵数据中的num个字节写入LCD的addr地址显示
//-----------------------------------------------------------------  
void lcd_blit(WORD addr, const BYTE *img, BYTE num)
{ 
   lcd_wrcmd2(LCD_ADDRESS,addr);//设置显示DDRAM地址为addr
   lcd_wrcmd(LCD_AUTOWRITE);    //设置自动写(DDRAM地址自动递增)
   while (num--)                //共发送num个字节
   { 
      lcd_status_check(0x08);   //检测LCD状态寄存器中的STA3,等待自动写就绪
      //向PORTD端口输出显示字节
      PORTD = *img++;  TRISD = 0; 
      //PORTA端口使能写后结束操作
      PORTA = LCD_DATA; PORTA = LCD_DONE;
   }
   lcd_wrcmd(LCD_AUTORESET);   //自动写复位(停止自动写)
}

//-----------------------------------------------------------------
// 写无参数LCD命令
//-----------------------------------------------------------------
void lcd_wrcmd(BYTE cmd)
{  
   lcd_status_check(0x01);     //检测LCD状态寄存器中的STA0,等待指令读写状态位就绪
   PORTD = cmd; TRISD = 0;     //命令字节送PORTD端口
   PORTA = LCD_COMMAND;        //写命令
   PORTA = LCD_DONE;           //禁止操作
}

//-----------------------------------------------------------------
// 写带单字节参数的LCD命令
//-----------------------------------------------------------------
void lcd_wrcmd1(BYTE cmd, BYTE data)
{
   lcd_status_check(0x02);     //检测LCD状态寄存器中的STA1,等待数据读写状态位就绪
   PORTD = data; TRISD = 0x00; //参数送PORTD端口 
   PORTA = LCD_DATA;           //写参数数据
   PORTA = LCD_DONE;           //禁止操作
   lcd_status_check(0x01);     //检测LCD状态寄存器中的STA0,等待指令读写状态位就绪
   PORTD = cmd;  TRISD = 0x00; //命令字节送PORTD端口
   PORTA = LCD_COMMAND;        //写命令
   PORTA = LCD_DONE;           //禁止操作
 }

//-----------------------------------------------------------------
// 写带字参数(两字节)LCD命令
//-----------------------------------------------------------------
void lcd_wrcmd2 (BYTE cmd, WORD arg)
{  
   lcd_status_check(0x02);     //检测LCD状态寄存器中的STA1,等待数据读写状态位就绪
   PORTD = arg & 0xFF;TRISD = 0x00; //参数D1送PORTD端口   
   PORTA = LCD_DATA;           //写参数数据D1
   PORTA = LCD_DONE;           //禁止操作
   lcd_status_check(0x02);     //检测LCD状态寄存器中的STA1,等待数据读写状态位就绪  
   PORTD = arg >> 8;  TRISD = 0x00; //参数D2送PORTD端口    
   PORTA = LCD_DATA;           //写参数数据D2
   PORTA = LCD_DONE;           //禁止操作
   lcd_status_check(0x01);     //检测LCD状态寄存器中的STA0,等待指令读写状态位就绪
   PORTD = cmd;  TRISD = 0x00; //命令字节送PORTD端口
   PORTA = LCD_COMMAND;        //写命令
   PORTA = LCD_DONE;           //禁止操作
}

//-----------------------------------------------------------------
// 输出提示音,提示yourmove
//-----------------------------------------------------------------
void sound_yourmove()
{ 
   tone(100, 100);
}   
//-----------------------------------------------------------------
// 棋子被捕获时所输出的声音
//-----------------------------------------------------------------
void sound_capture()
{ 
   tone(50, 100); tone(75, 75); tone(100, 50); sleep(200);
}
//-----------------------------------------------------------------
// 棋子无效移动时所输出的声音
//-----------------------------------------------------------------
void sound_illegal()
 { 
    tone(400, 100);
 }
//-----------------------------------------------------------------
// 通过T0定时器,按指定周期和时长输出声音
//-----------------------------------------------------------------
void tone(WORD period, WORD cycles)
{
   LATC = 0x03;                 //RC0,RC1初始输出11(0x03)
   T0CON = 0x04;                //T0定时器关,设16位模式,1/32分频
   while (cycles--)
   { 
      TMR0H = -period >> 8;     //设置TMR0定时初值
      TMR0L = -period & 0xFF;
      TMR0IF = 0;               //中断标志位请0
      TMR0ON = 1;               //启动定时器
      while (TMR0IF == 0);     //等待T0溢出
      TMR0ON = 0;               //停止定时器
      LATC ^= 0x03;             //RC0,RC1两脚输出11,00,11,00,驱动扬声器输出
   }
 }

//-----------------------------------------------------------------
// 按键扫描函数,无键按下时返回0xFF
//-----------------------------------------------------------------
BYTE scankeypad()
{  
   BYTE r,c,tmp,key = 0xFF;
   //扫描8x8按键矩阵(相当于本例的触摸屏的8x8=64个格子)
   for (c = 0; c < 8; c++)
   {  //在相应的列上设置低电平,然后读取行状态tmp
      //由于使用了3-8译码器,输出000~111时
      //实际输出的列字节为111111110,11111101,...01111111(仅有一位为0)
      PORTE = c; sleep(1); tmp = PORTB;
      //查看变为低电平的行,根据行号r与列号c,得出当前按键序号(0~63)
      for (r = 0; r < 8; ++r)
      { 
          if ((tmp & (1 << r)) == 0) { key = r * 8 + c;  goto done; }
      }
   }
   done: return key;
}

//-----------------------------------------------------------------
// 睡眠函数
//-----------------------------------------------------------------
void sleep(INT msecs)
{ 
    while (msecs--)
    {
      TMR0L = -32;              //设置TMR0定时初值
      TMR0IF = 0;               //TMR0溢出中断标志位清0
      T0CON = 0xC6;             //T0定时器设为8位模式(T08BIT),启动(TMR0ON)
      while (TMR0IF == 0);      //等待定时器溢出      
      TMR0ON = 0;               //定时器关
    }
}

//-----------------------------------------------------------------
// 字符输出函数
//-----------------------------------------------------------------
void putch(char value)
{ 
   if (value == '\n') value = '\r';
   TXREG = value; while (!TRMT);//向串口输出一字节,等待发送结束
}

⌨️ 快捷键说明

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