- /*******************************************************************************
- * 文件名 : mian.c
- * 功能 : STC32G12K128 贪吃蛇游戏
- * 硬件 :
- * P3.3~P3.7 接5个独立按键(按下为低电平)
- * P0.0~P1.7 接16x16点阵行选 第1~8行(高电平有效)
- * P2.0~P2.7 接16x16点阵行选 第9~16行(高电平有效)
- * P1.3 接74HC595的SER(数据线)
- * P1.0 接74HC595的SRCLK(移位时钟)
- * P1.1 接74HC595的RCLK(锁存时钟)
- * 4个74HC595级联,第3个输出低8位列选,第4个输出高8位列选
- * 16x16共阴LED点阵: 行选高电平有效,列选低电平有效
- * 晶振 : 11.0592MHz
- * 编译 : Keil C251 5.39, 设备选 STC32G12K128
- * 注意 : 大数组用 "unsigned char xdata" 声明放在外部RAM
- *******************************************************************************/
-
- #include "stc32g.h"
- #include "intrins.h"
-
- /* ================== 按键引脚定义 ================== */
- sbit KEY_UP = P3^7; // 方向:上
- sbit KEY_DOWN = P3^6; // 方向:下
- sbit KEY_LEFT = P3^5; // 方向:左
- sbit KEY_RIGHT = P3^4; // 方向:右
- sbit KEY_RESET = P3^3; // 重新开始
-
- /* ================== 74HC595控制引脚 ================== */
- sbit HC_SER = P1^3; // 数据输入(SER)
- sbit HC_SRCLK = P1^0; // 移位时钟(SRCLK)
- sbit HC_RCLK = P1^1; // 锁存时钟(RCLK)
-
- /* ================== 方向定义 ================== */
- #define DIR_UP 0
- #define DIR_DOWN 1
- #define DIR_LEFT 2
- #define DIR_RIGHT 3
-
- /* ================== 游戏区域大小 ================== */
- #define MAP_W 16 // 宽(列)16格
- #define MAP_H 16 // 高(行)16格
- #define MAX_LEN 32 // 蛇最大长度
-
- /* ================== 全局变量(大数组放xdata, 类型在前!) ================== */
- unsigned char xdata snake_x[MAX_LEN]; // 蛇身各节X坐标(0~15)
- unsigned char xdata snake_y[MAX_LEN]; // 蛇身各节Y坐标(0~15)
- unsigned char xdata disp_buf[16][2]; // 显示缓冲区[行][低/高8列]
-
- unsigned char snake_len; // 当前蛇身长度
- unsigned char direction; // 当前移动方向
- unsigned char new_direction; // 待更新的方向
- unsigned char food_x; // 食物X坐标
- unsigned char food_y; // 食物Y坐标
- unsigned char move_count; // 定时器中断计数
- bit move_flag; // 蛇移动标志
- bit game_over; // 游戏结束标志
- unsigned char random_seed; // 伪随机数种子
-
- /* ================== 定时器0中断服务函数 ================== */
- /* 每50ms进一次中断, 中断20次=1秒, 蛇移动一格 */
- void TM0_Isr() interrupt 1
- {
- move_count++; // 中断计数+1
- if (move_count >= 20) // 50ms*20 = 1000ms = 1秒
- {
- move_count = 0; // 清零计数
- move_flag = 1; // 置移动标志
- }
- }
-
- /* ================== 延时函数(约1ms) ================== */
- void delay_ms(unsigned int ms)
- {
- unsigned int i, j;
- for (i = 0; i < ms; i++)
- {
- for (j = 0; j < 1000; j++) // 大约1ms(11.0592MHz)
- {
- _nop_();
- }
- }
- }
-
- /* ================== 向74HC595发送16位列数据 ================== */
- void hc595_send(unsigned char col_low, unsigned char col_high)
- {
- unsigned char i;
-
- /* 先发送高8位(最终进入第4个595,控制高8列) */
- for (i = 0; i < 8; i++)
- {
- HC_SER = (col_high >> (7 - i)) & 0x01;
- HC_SRCLK = 0;
- _nop_();
- HC_SRCLK = 1;
- _nop_();
- }
-
- /* 再发送低8位(最终进入第3个595,控制低8列) */
- for (i = 0; i < 8; i++)
- {
- HC_SER = (col_low >> (7 - i)) & 0x01;
- HC_SRCLK = 0;
- _nop_();
- HC_SRCLK = 1;
- _nop_();
- }
-
- /* 再发送2个字节0x00(给第1、2个595,不使用) */
- for (i = 0; i < 16; i++)
- {
- HC_SER = 0;
- HC_SRCLK = 0;
- _nop_();
- HC_SRCLK = 1;
- _nop_();
- }
-
- /* 锁存数据 */
- HC_RCLK = 0;
- _nop_();
- HC_RCLK = 1;
- _nop_();
- }
-
- /* ================== 行选输出 ================== */
- void row_select(unsigned char row)
- {
- if (row < 8)
- {
- P0 = (unsigned char)(1 << row); // 选中P1上的行(行1~8)
- P2 = 0x00; // 清空P2行选
- }
- else
- {
- P2 = (unsigned char)(1 << (row - 8)); // 选中P2上的行(行9~16)
- P0 = 0x00; // 清空P1行选
- }
- }
-
- /* ================== 刷新显示一行 ================== */
- void display_row(unsigned char row)
- {
- /* 列选低电平有效,取反后输出 */
- hc595_send((unsigned char)~disp_buf[row][0], (unsigned char)~disp_buf[row][1]);
- row_select(row);
- }
-
- /* ================== 刷新整个画面 ================== */
- void display_refresh(void)
- {
- unsigned char row;
- for (row = 0; row < 16; row++)
- {
- display_row(row);
- delay_ms(1); // 每行约1ms,16行约16ms
- }
- }
-
- /* ================== 生成随机数 ================== */
- unsigned char random_byte(void)
- {
- random_seed = (unsigned char)(random_seed * 17 + 13);
- return random_seed;
- }
-
- /* ================== 生成食物 ================== */
- void generate_food(void)
- {
- unsigned char x, y;
- unsigned char i;
- unsigned char ok;
-
- do
- {
- x = random_byte() & 0x0F; // 0~15
- y = random_byte() & 0x0F; // 0~15
- ok = 1;
-
- /* 检查是否被蛇身占据 */
- for (i = 0; i < snake_len; i++)
- {
- if (snake_x[i] == x && snake_y[i] == y)
- {
- ok = 0;
- break;
- }
- }
- } while (ok == 0);
-
- food_x = x;
- food_y = y;
- }
-
- /* ================== 更新显示缓冲区 ================== */
- void update_display(void)
- {
- unsigned char i;
-
- /* 清空显示缓冲区 */
- for (i = 0; i < 16; i++)
- {
- disp_buf[i][0] = 0x00;
- disp_buf[i][1] = 0x00;
- }
-
- /* 绘制蛇身 */
- for (i = 0; i < snake_len; i++)
- {
- if (snake_x[i] < 8)
- {
- disp_buf[snake_y[i]][0] |= (unsigned char)(1 << snake_x[i]);
- }
- else
- {
- disp_buf[snake_y[i]][1] |= (unsigned char)(1 << (snake_x[i] - 8));
- }
- }
-
- /* 绘制食物 */
- if (food_x < 8)
- {
- disp_buf[food_y][0] |= (unsigned char)(1 << food_x);
- }
- else
- {
- disp_buf[food_y][1] |= (unsigned char)(1 << (food_x - 8));
- }
- }
-
- /* ================== 游戏初始化 ================== */
- void init_game(void)
- {
- snake_len = 3;
- snake_x[0] = 7; snake_y[0] = 7; // 蛇头
- snake_x[1] = 6; snake_y[1] = 7; // 身体
- snake_x[2] = 5; snake_y[2] = 7; // 尾巴
-
- direction = DIR_RIGHT;
- new_direction = DIR_RIGHT;
- random_seed = 0x5A;
-
- generate_food();
- update_display();
- }
-
- /* ================== 扫描按键 ================== */
- void scan_keys(void)
- {
- if (KEY_UP == 0)
- {
- delay_ms(10);
- if (KEY_UP == 0)
- {
- if (direction != DIR_DOWN) new_direction = DIR_UP;
- while (KEY_UP == 0);
- }
- }
-
- if (KEY_DOWN == 0)
- {
- delay_ms(10);
- if (KEY_DOWN == 0)
- {
- if (direction != DIR_UP) new_direction = DIR_DOWN;
- while (KEY_DOWN == 0);
- }
- }
-
- if (KEY_LEFT == 0)
- {
- delay_ms(10);
- if (KEY_LEFT == 0)
- {
- if (direction != DIR_RIGHT) new_direction = DIR_LEFT;
- while (KEY_LEFT == 0);
- }
- }
-
- if (KEY_RIGHT == 0)
- {
- delay_ms(10);
- if (KEY_RIGHT == 0)
- {
- if (direction != DIR_LEFT) new_direction = DIR_RIGHT;
- while (KEY_RIGHT == 0);
- }
- }
-
- if (KEY_RESET == 0)
- {
- delay_ms(10);
- if (KEY_RESET == 0)
- {
- game_over = 0;
- init_game();
- while (KEY_RESET == 0);
- }
- }
- }
-
- /* ================== 蛇移动逻辑 ================== */
- void update_game(void)
- {
- unsigned char new_x, new_y;
- unsigned char i;
-
- direction = new_direction;
-
- new_x = snake_x[0];
- new_y = snake_y[0];
-
- switch (direction)
- {
- case DIR_UP: new_y--; break;
- case DIR_DOWN: new_y++; break;
- case DIR_LEFT: new_x--; break;
- case DIR_RIGHT: new_x++; break;
- }
-
- /* 穿墙处理: 撞墙从对面出来 */
- if (new_y == 0xFF) new_y = 15; // 先判断下溢 ← 必须先执行!
- if (new_x == 0xFF) new_x = 15;
- if (new_y >= MAP_H) new_y = 0; // 再判断上溢
- if (new_x >= MAP_W) new_x = 0;
-
- /* 检查是否撞到自己 */
- for (i = 1; i < snake_len; i++)
- {
- if (snake_x[i] == new_x && snake_y[i] == new_y)
- {
- game_over = 1;
- return;
- }
- }
-
- /* 判断是否吃到食物 */
- if (new_x == food_x && new_y == food_y)
- {
- /* 吃到食物: 整体后移, 新头插入 */
- for (i = snake_len; i > 0; i--)
- {
- snake_x[i] = snake_x[i - 1];
- snake_y[i] = snake_y[i - 1];
- }
- snake_x[0] = new_x;
- snake_y[0] = new_y;
- snake_len++;
-
- if (snake_len >= MAX_LEN)
- {
- game_over = 1;
- return;
- }
- generate_food();
- }
- else
- {
- /* 没吃到食物: 去掉尾巴 */
- for (i = snake_len; i > 0; i--)
- {
- snake_x[i] = snake_x[i - 1];
- snake_y[i] = snake_y[i - 1];
- }
- snake_x[0] = new_x;
- snake_y[0] = new_y;
- }
-
- update_display();
- }
-
- /* ================== 硬件初始化 ================== */
- void init_hardware(void)
- {
- P_SW2 |= 0x80; // 使能访问XFR(扩展寄存器区)
- WTST = 0x00; // 程序代码等待参数设为最快
-
- /* P3: 按键输入(准双向) */
- P3M0 = 0x00;
- P3M1 = 0x00;
-
- /* P1: 行选输出(推挽) */
- P0M0 = 0xFF;
- P0M1 = 0x00;
-
- /* P2: 行选输出(推挽) */
- P2M0 = 0xFF;
- P2M1 = 0x00;
-
- /* P1: P1.2/P1.3/P1.4推挽输出 */
- P1M0 = 0xFF; // bit2,3,4 = 1
- P1M1 = 0x00;
-
- /* 定时器0: 16位自动重装载, 12T模式 */
- TMOD &= 0xF0; // 清T0位
- AUXR &= ~0x80; // T0x12=0 → 12T模式
-
- /* 定时50ms: 初值=65536-46080=19456=0x4C00 */
- TL0 = 0x00;
- TH0 = 0x4C;
-
- TR0 = 1; // 启动定时器0
- ET0 = 1; // 使能定时器0中断
- EA = 1; // 打开总中断
- }
-
- /* ================== 主函数 ================== */
- void main(void)
- {
- init_hardware();
- init_game();
-
- while (1)
- {
- display_refresh(); // 刷新显示
- scan_keys(); // 扫描按键
-
- if (move_flag) // 到了移动时间
- {
- move_flag = 0;
- if (game_over == 0)
- {
- update_game();
- }
- }
- }
- }
复制代码 HC_SER = (col_high >> (7 - i)) & 0x01;
HC_SER = (col_low >> (7 - i)) & 0x01;
这两行被强行改成
HC_SER = (biat)(col_high >> (7 - i)) & 0x01;
HC_SER = (biat)(col_low >> (7 - i)) & 0x01;
显示就出问题了.
|