找回密码
 立即注册
楼主: 王昱顺

自研C语言编译器发布,STC IDE —— 面向STC32系列及AI8051U的C语言编译器,11/7更新

 火.. [复制链接]
已绑定手机

1

主题

8

回帖

1543

积分

金牌会员

积分
1543
发表于 2026-9-7 18:13:59 | 显示全部楼层
编译后自动改写 怎么关掉,撤销按钮根本没反应.

点评

暂时无法关掉,本质是给隐式提升写成显式提升,就算给关了内部也还是这样做的  详情 回复 发表于 2026-9-7 18:38
回复

使用道具 举报 送花

已绑定手机
已实名认证

148

主题

4104

回帖

1万

积分

超级版主

积分
11138
 楼主| 发表于 2026-9-7 18:38:08 | 显示全部楼层
天黑不*** 发表于 2026-9-7 18:13
编译后自动改写 怎么关掉,撤销按钮根本没反应.

暂时无法关掉,本质是给隐式提升写成显式提升,就算给关了内部也还是这样做的
回复

使用道具 举报 送花

8

主题

89

回帖

1057

积分

金牌会员

积分
1057
发表于 2026-9-8 08:40:44 | 显示全部楼层
搞个FAQ吧,需要设定头文件搜索目录吗?还是只能放在 root下?

点评

对于内置的头文件,直接引用即可 对于自己导入的头文件,通过相对路径引用即可,放在哪里都无所谓,只要相对路径写对了都可以引用到  详情 回复 发表于 2026-9-8 10:14
希望这个世界让我小装一次B
回复

使用道具 举报 送花

已绑定手机
已实名认证

148

主题

4104

回帖

1万

积分

超级版主

积分
11138
 楼主| 发表于 2026-9-8 10:14:37 | 显示全部楼层
Yang.*** 发表于 2026-9-8 08:40
搞个FAQ吧,需要设定头文件搜索目录吗?还是只能放在 root下?

对于内置的头文件,直接引用即可
对于自己导入的头文件,通过相对路径引用即可,放在哪里都无所谓,只要相对路径写对了都可以引用到
回复

使用道具 举报 送花

已绑定手机

1

主题

8

回帖

1543

积分

金牌会员

积分
1543
发表于 2026-9-8 17:17:18 | 显示全部楼层
王*** 发表于 2026-9-7 18:38
暂时无法关掉,本质是给隐式提升写成显式提升,就算给关了内部也还是这样做的 ...
  1. /*******************************************************************************
  2. *  文件名 : mian.c
  3. *  功能   : STC32G12K128 贪吃蛇游戏
  4. *  硬件   :
  5. *           P3.3~P3.7 接5个独立按键(按下为低电平)
  6. *           P0.0~P1.7 接16x16点阵行选 第1~8行(高电平有效)
  7. *           P2.0~P2.7 接16x16点阵行选 第9~16行(高电平有效)
  8. *           P1.3 接74HC595的SER(数据线)
  9. *           P1.0 接74HC595的SRCLK(移位时钟)
  10. *           P1.1 接74HC595的RCLK(锁存时钟)
  11. *           4个74HC595级联,第3个输出低8位列选,第4个输出高8位列选
  12. *           16x16共阴LED点阵: 行选高电平有效,列选低电平有效
  13. *  晶振   : 11.0592MHz
  14. *  编译   : Keil C251 5.39, 设备选 STC32G12K128
  15. *  注意   : 大数组用 "unsigned char xdata" 声明放在外部RAM
  16. *******************************************************************************/
  17. #include "stc32g.h"
  18. #include "intrins.h"
  19. /* ================== 按键引脚定义 ================== */
  20. sbit KEY_UP    = P3^7;   // 方向:上
  21. sbit KEY_DOWN  = P3^6;   // 方向:下
  22. sbit KEY_LEFT  = P3^5;   // 方向:左
  23. sbit KEY_RIGHT = P3^4;   // 方向:右
  24. sbit KEY_RESET = P3^3;   // 重新开始
  25. /* ================== 74HC595控制引脚 ================== */
  26. sbit HC_SER   = P1^3;    // 数据输入(SER)
  27. sbit HC_SRCLK = P1^0;    // 移位时钟(SRCLK)
  28. sbit HC_RCLK  = P1^1;    // 锁存时钟(RCLK)
  29. /* ================== 方向定义 ================== */
  30. #define DIR_UP    0
  31. #define DIR_DOWN  1
  32. #define DIR_LEFT  2
  33. #define DIR_RIGHT 3
  34. /* ================== 游戏区域大小 ================== */
  35. #define MAP_W     16      // 宽(列)16格
  36. #define MAP_H     16      // 高(行)16格
  37. #define MAX_LEN   32      // 蛇最大长度
  38. /* ================== 全局变量(大数组放xdata, 类型在前!) ================== */
  39. unsigned char xdata snake_x[MAX_LEN];   // 蛇身各节X坐标(0~15)
  40. unsigned char xdata snake_y[MAX_LEN];   // 蛇身各节Y坐标(0~15)
  41. unsigned char xdata disp_buf[16][2];    // 显示缓冲区[行][低/高8列]
  42. unsigned char snake_len;          // 当前蛇身长度
  43. unsigned char direction;          // 当前移动方向
  44. unsigned char new_direction;      // 待更新的方向
  45. unsigned char food_x;             // 食物X坐标
  46. unsigned char food_y;             // 食物Y坐标
  47. unsigned char move_count;         // 定时器中断计数
  48. bit           move_flag;          // 蛇移动标志
  49. bit           game_over;          // 游戏结束标志
  50. unsigned char random_seed;        // 伪随机数种子
  51. /* ================== 定时器0中断服务函数 ================== */
  52. /* 每50ms进一次中断, 中断20次=1秒, 蛇移动一格 */
  53. void TM0_Isr() interrupt 1
  54. {
  55.     move_count++;               // 中断计数+1
  56.     if (move_count >= 20)       // 50ms*20 = 1000ms = 1秒
  57.     {
  58.         move_count = 0;         // 清零计数
  59.         move_flag = 1;          // 置移动标志
  60.     }
  61. }
  62. /* ================== 延时函数(约1ms) ================== */
  63. void delay_ms(unsigned int ms)
  64. {
  65.     unsigned int i, j;
  66.     for (i = 0; i < ms; i++)
  67.     {
  68.         for (j = 0; j < 1000; j++)   // 大约1ms(11.0592MHz)
  69.         {
  70.             _nop_();
  71.         }
  72.     }
  73. }
  74. /* ================== 向74HC595发送16位列数据 ================== */
  75. void hc595_send(unsigned char col_low, unsigned char col_high)
  76. {
  77.     unsigned char i;
  78.    
  79.     /* 先发送高8位(最终进入第4个595,控制高8列) */
  80.     for (i = 0; i < 8; i++)
  81.     {
  82.         HC_SER = (col_high >> (7 - i)) & 0x01;
  83.         HC_SRCLK = 0;
  84.         _nop_();
  85.         HC_SRCLK = 1;
  86.         _nop_();
  87.     }
  88.    
  89.     /* 再发送低8位(最终进入第3个595,控制低8列) */
  90.     for (i = 0; i < 8; i++)
  91.     {
  92.         HC_SER = (col_low >> (7 - i)) & 0x01;
  93.         HC_SRCLK = 0;
  94.         _nop_();
  95.         HC_SRCLK = 1;
  96.         _nop_();
  97.     }
  98.    
  99.     /* 再发送2个字节0x00(给第1、2个595,不使用) */
  100.     for (i = 0; i < 16; i++)
  101.     {
  102.         HC_SER = 0;
  103.         HC_SRCLK = 0;
  104.         _nop_();
  105.         HC_SRCLK = 1;
  106.         _nop_();
  107.     }
  108.    
  109.     /* 锁存数据 */
  110.     HC_RCLK = 0;
  111.     _nop_();
  112.     HC_RCLK = 1;
  113.     _nop_();
  114. }
  115. /* ================== 行选输出 ================== */
  116. void row_select(unsigned char row)
  117. {
  118.     if (row < 8)
  119.     {
  120.         P0 = (unsigned char)(1 << row);       // 选中P1上的行(行1~8)
  121.         P2 = 0x00;                            // 清空P2行选
  122.     }
  123.     else
  124.     {
  125.         P2 = (unsigned char)(1 << (row - 8)); // 选中P2上的行(行9~16)
  126.         P0 = 0x00;                            // 清空P1行选
  127.     }
  128. }
  129. /* ================== 刷新显示一行 ================== */
  130. void display_row(unsigned char row)
  131. {
  132.     /* 列选低电平有效,取反后输出 */
  133.     hc595_send((unsigned char)~disp_buf[row][0], (unsigned char)~disp_buf[row][1]);
  134.     row_select(row);
  135. }
  136. /* ================== 刷新整个画面 ================== */
  137. void display_refresh(void)
  138. {
  139.     unsigned char row;
  140.     for (row = 0; row < 16; row++)
  141.     {
  142.         display_row(row);
  143.         delay_ms(1);   // 每行约1ms,16行约16ms
  144.     }
  145. }
  146. /* ================== 生成随机数 ================== */
  147. unsigned char random_byte(void)
  148. {
  149.     random_seed = (unsigned char)(random_seed * 17 + 13);
  150.     return random_seed;
  151. }
  152. /* ================== 生成食物 ================== */
  153. void generate_food(void)
  154. {
  155.     unsigned char x, y;
  156.     unsigned char i;
  157.     unsigned char ok;
  158.    
  159.     do
  160.     {
  161.         x = random_byte() & 0x0F;   // 0~15
  162.         y = random_byte() & 0x0F;   // 0~15
  163.         ok = 1;
  164.         
  165.         /* 检查是否被蛇身占据 */
  166.         for (i = 0; i < snake_len; i++)
  167.         {
  168.             if (snake_x[i] == x && snake_y[i] == y)
  169.             {
  170.                 ok = 0;
  171.                 break;
  172.             }
  173.         }
  174.     } while (ok == 0);
  175.    
  176.     food_x = x;
  177.     food_y = y;
  178. }
  179. /* ================== 更新显示缓冲区 ================== */
  180. void update_display(void)
  181. {
  182.     unsigned char i;
  183.    
  184.     /* 清空显示缓冲区 */
  185.     for (i = 0; i < 16; i++)
  186.     {
  187.         disp_buf[i][0] = 0x00;
  188.         disp_buf[i][1] = 0x00;
  189.     }
  190.    
  191.     /* 绘制蛇身 */
  192.     for (i = 0; i < snake_len; i++)
  193.     {
  194.         if (snake_x[i] < 8)
  195.         {
  196.             disp_buf[snake_y[i]][0] |= (unsigned char)(1 << snake_x[i]);
  197.         }
  198.         else
  199.         {
  200.             disp_buf[snake_y[i]][1] |= (unsigned char)(1 << (snake_x[i] - 8));
  201.         }
  202.     }
  203.    
  204.     /* 绘制食物 */
  205.     if (food_x < 8)
  206.     {
  207.         disp_buf[food_y][0] |= (unsigned char)(1 << food_x);
  208.     }
  209.     else
  210.     {
  211.         disp_buf[food_y][1] |= (unsigned char)(1 << (food_x - 8));
  212.     }
  213. }
  214. /* ================== 游戏初始化 ================== */
  215. void init_game(void)
  216. {
  217.     snake_len = 3;
  218.     snake_x[0] = 7;  snake_y[0] = 7;   // 蛇头
  219.     snake_x[1] = 6;  snake_y[1] = 7;   // 身体
  220.     snake_x[2] = 5;  snake_y[2] = 7;   // 尾巴
  221.    
  222.     direction = DIR_RIGHT;
  223.     new_direction = DIR_RIGHT;
  224.     random_seed = 0x5A;
  225.    
  226.     generate_food();
  227.     update_display();
  228. }
  229. /* ================== 扫描按键 ================== */
  230. void scan_keys(void)
  231. {
  232.     if (KEY_UP == 0)
  233.     {
  234.         delay_ms(10);
  235.         if (KEY_UP == 0)
  236.         {
  237.             if (direction != DIR_DOWN) new_direction = DIR_UP;
  238.             while (KEY_UP == 0);
  239.         }
  240.     }
  241.    
  242.     if (KEY_DOWN == 0)
  243.     {
  244.         delay_ms(10);
  245.         if (KEY_DOWN == 0)
  246.         {
  247.             if (direction != DIR_UP) new_direction = DIR_DOWN;
  248.             while (KEY_DOWN == 0);
  249.         }
  250.     }
  251.    
  252.     if (KEY_LEFT == 0)
  253.     {
  254.         delay_ms(10);
  255.         if (KEY_LEFT == 0)
  256.         {
  257.             if (direction != DIR_RIGHT) new_direction = DIR_LEFT;
  258.             while (KEY_LEFT == 0);
  259.         }
  260.     }
  261.    
  262.     if (KEY_RIGHT == 0)
  263.     {
  264.         delay_ms(10);
  265.         if (KEY_RIGHT == 0)
  266.         {
  267.             if (direction != DIR_LEFT) new_direction = DIR_RIGHT;
  268.             while (KEY_RIGHT == 0);
  269.         }
  270.     }
  271.    
  272.     if (KEY_RESET == 0)
  273.     {
  274.         delay_ms(10);
  275.         if (KEY_RESET == 0)
  276.         {
  277.             game_over = 0;
  278.             init_game();
  279.             while (KEY_RESET == 0);
  280.         }
  281.     }
  282. }
  283. /* ================== 蛇移动逻辑 ================== */
  284. void update_game(void)
  285. {
  286.     unsigned char new_x, new_y;
  287.     unsigned char i;
  288.    
  289.     direction = new_direction;
  290.    
  291.     new_x = snake_x[0];
  292.     new_y = snake_y[0];
  293.    
  294.     switch (direction)
  295.     {
  296.         case DIR_UP:    new_y--; break;
  297.         case DIR_DOWN:  new_y++; break;
  298.         case DIR_LEFT:  new_x--; break;
  299.         case DIR_RIGHT: new_x++; break;
  300.     }
  301.    
  302.     /* 穿墙处理: 撞墙从对面出来 */
  303.     if (new_y == 0xFF) new_y = 15;   // 先判断下溢 ← 必须先执行!
  304.                 if (new_x == 0xFF) new_x = 15;
  305.                 if (new_y >= MAP_H) new_y = 0;   // 再判断上溢
  306.                 if (new_x >= MAP_W) new_x = 0;
  307.    
  308.     /* 检查是否撞到自己 */
  309.     for (i = 1; i < snake_len; i++)
  310.     {
  311.         if (snake_x[i] == new_x && snake_y[i] == new_y)
  312.         {
  313.             game_over = 1;
  314.             return;
  315.         }
  316.     }
  317.    
  318.     /* 判断是否吃到食物 */
  319.     if (new_x == food_x && new_y == food_y)
  320.     {
  321.         /* 吃到食物: 整体后移, 新头插入 */
  322.         for (i = snake_len; i > 0; i--)
  323.         {
  324.             snake_x[i] = snake_x[i - 1];
  325.             snake_y[i] = snake_y[i - 1];
  326.         }
  327.         snake_x[0] = new_x;
  328.         snake_y[0] = new_y;
  329.         snake_len++;
  330.         
  331.         if (snake_len >= MAX_LEN)
  332.         {
  333.             game_over = 1;
  334.             return;
  335.         }
  336.         generate_food();
  337.     }
  338.     else
  339.     {
  340.         /* 没吃到食物: 去掉尾巴 */
  341.         for (i = snake_len; i > 0; i--)
  342.         {
  343.             snake_x[i] = snake_x[i - 1];
  344.             snake_y[i] = snake_y[i - 1];
  345.         }
  346.         snake_x[0] = new_x;
  347.         snake_y[0] = new_y;
  348.     }
  349.    
  350.     update_display();
  351. }
  352. /* ================== 硬件初始化 ================== */
  353. void init_hardware(void)
  354. {
  355.     P_SW2 |= 0x80;      // 使能访问XFR(扩展寄存器区)
  356.     WTST = 0x00;        // 程序代码等待参数设为最快
  357.    
  358.     /* P3: 按键输入(准双向) */
  359.     P3M0 = 0x00;
  360.     P3M1 = 0x00;
  361.    
  362.     /* P1: 行选输出(推挽) */
  363.     P0M0 = 0xFF;
  364.     P0M1 = 0x00;
  365.    
  366.     /* P2: 行选输出(推挽) */
  367.     P2M0 = 0xFF;
  368.     P2M1 = 0x00;
  369.    
  370.     /* P1: P1.2/P1.3/P1.4推挽输出 */
  371.     P1M0 = 0xFF;        // bit2,3,4 = 1
  372.     P1M1 = 0x00;
  373.    
  374.     /* 定时器0: 16位自动重装载, 12T模式 */
  375.     TMOD &= 0xF0;       // 清T0位
  376.     AUXR &= ~0x80;      // T0x12=0 → 12T模式
  377.    
  378.     /* 定时50ms: 初值=65536-46080=19456=0x4C00 */
  379.     TL0 = 0x00;
  380.     TH0 = 0x4C;
  381.    
  382.     TR0 = 1;            // 启动定时器0
  383.     ET0 = 1;            // 使能定时器0中断
  384.     EA = 1;             // 打开总中断
  385. }
  386. /* ================== 主函数 ================== */
  387. void main(void)
  388. {
  389.     init_hardware();
  390.     init_game();
  391.    
  392.     while (1)
  393.     {
  394.         display_refresh();    // 刷新显示
  395.         scan_keys();          // 扫描按键
  396.         
  397.         if (move_flag)        // 到了移动时间
  398.         {
  399.             move_flag = 0;
  400.             if (game_over == 0)
  401.             {
  402.                 update_game();
  403.             }
  404.         }
  405.     }
  406. }
复制代码
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;

显示就出问题了.

点评

看起来改的没啥问题? 强制转bit和&0x01的效果是完全一样的,可能是存在其他的问题?  详情 回复 发表于 2026-9-8 17:20
回复

使用道具 举报 送花

已绑定手机
已实名认证

148

主题

4104

回帖

1万

积分

超级版主

积分
11138
 楼主| 发表于 2026-9-8 17:20:49 | 显示全部楼层
天黑不*** 发表于 2026-9-8 17:17
HC_SER = (col_high >> (7 - i)) & 0x01;

HC_SER = (col_low >> (7 - i)) & 0x01;

看起来改的没啥问题? 强制转bit和&0x01的效果是完全一样的,可能是存在其他的问题?
回复

使用道具 举报 送花

已绑定手机

1

主题

8

回帖

1543

积分

金牌会员

积分
1543
发表于 2026-9-8 19:39:21 | 显示全部楼层
王*** 发表于 2026-9-8 17:20
看起来改的没啥问题? 强制转bit和&0x01的效果是完全一样的,可能是存在其他的问题? ...

问了STC AI给了这么一段

为什么加上 (bit) 后显示会出错?
根本原因:Keil C251 对 (bit) 转换的代码生成机制
在 STC32G(使用 Keil C251 编译)中,HC_SER 被定义为 sbit(可位寻址的位变量)。而 (bit) 是 Keil C251 的专用位类型。

当我们写:

HC_SER = (bit)(col_high >> (7 - i)) & 0x01;
📋
关键问题在于运算符优先级与 C251 的位变量处理方式:

根据 C 语言运算符优先级,(bit) 强制转换的优先级高于 &,所以实际的解析顺序是:

HC_SER = ((bit)(col_high >> (7 - i))) & 0x01;
📋
即先执行 (bit)(col_high >> (7 - i)),这会把右移的结果截断为一个 bit(0 或 1),然后再与 0x01 相与。

但问题不在这儿——因为 col_high >> (7-i) 的结果无论怎样,当 i 取 0~7 时,右移后提取的确实就是目标位,结果本来就是 0 或 1。

真正的问题在于 Keil C251 的编译器在生成 (bit) 转换代码时会使用"进位标志 C"作为中转:

C251 编译器对于 (bit) 类型转换,会生成类似这样的操作:先将表达式的值存入进位标志 C(通过进位标志传递),再从 C 取出给目标位变量。这个过程中如果 col_high 存放在 xdata(外部RAM)中,会涉及到:

从 xdata 读取 col_high(需要多时钟周期)
右移操作
将结果装载到进位标志
再从进位标志输出到 HC_SER
如果在第3步和第4步之间(进位标志装载/取出的过程中)恰好有其他中断或代码干扰了 PSW 的进位标志,或者编译器在优化时对位变量的处理不太理想,就可能导致输出数据错乱。

而原来的写法:

HC_SER = (col_high >> (7 - i)) & 0x01;
📋
编译器会把 & 0x01 的结果直接输出给 HC_SER,不经过额外的 (bit) 中间转换,生成的代码更直接、更高效,也更可靠。

验证一下:& 0x01 本身就足够产生 0/1 结果
col_high >> (7 - i) 右移后,我们只关心最低位,& 0x01 已经精确地提取出 0 或 1,这个结果赋给 sbit 类型是完美兼容的,完全不需要 (bit) 强制转换。

点评

STCIDE 目前并没有实现 bit 变量,只有 sbit 会被适配,就算是定义 bit 变量也会默认降级到 char 来实现,多余的运算会被优化掉 如果你这个程序不正常的话,可以打包一个工程,我来分析一下  详情 回复 发表于 2026-9-8 21:21
回复

使用道具 举报 送花

已绑定手机
已实名认证

148

主题

4104

回帖

1万

积分

超级版主

积分
11138
 楼主| 发表于 2026-9-8 21:21:36 | 显示全部楼层
天黑不*** 发表于 2026-9-8 19:39
问了STC AI给了这么一段

为什么加上 (bit) 后显示会出错?

STCIDE 目前并没有实现 bit 变量,只有 sbit 会被适配,就算是定义 bit 变量也会默认降级到 char 来实现,多余的运算会被优化掉
如果你这个程序不正常的话,可以打包一个工程上传上来,我来分析一下
回复

使用道具 举报 送花

已绑定手机

2

主题

21

回帖

1622

积分

金牌会员

积分
1622
发表于 2026-9-9 16:12:51 | 显示全部楼层
现在使用aicube生成的程序使用串口发送字符时会出现异常(以前是可以正常收发的),单独使用实例程序测试能正常收发
截图202609091610186999.jpg

点评

可能某次改动引入了回归问题,我排查一下  详情 回复 发表于 2026-9-9 16:16
回复

使用道具 举报 送花

已绑定手机
已实名认证

148

主题

4104

回帖

1万

积分

超级版主

积分
11138
 楼主| 发表于 2026-9-9 16:16:18 | 显示全部楼层
sion*** 发表于 2026-9-9 16:12
现在使用aicube生成的程序使用串口发送字符时会出现异常(以前是可以正常收发的),单独使用实例程序测试能 ...

可能某次改动引入了回归问题,我排查一下
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-14 09:48 , Processed in 0.079782 second(s), 92 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表