📄 iopic18.c
字号:
// 将指定棋盘格子(含格式内的棋子)反相显示
// (当选定待移动棋子但未走动时,通过反复反相显示形成闪烁效果)
//-----------------------------------------------------------------
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 + -