找回密码
 立即注册
楼主: vccdufyg

滑动图标问题。

[复制链接]

49

主题

611

回帖

5448

积分

荣誉版主

积分
5448
发表于 2026-10-16 15:00:18 | 显示全部楼层
大*** 发表于 2026-10-16 14:32
根据上面第二点思路

不用缓存也可以实现图标的滑动,只是在眼力非常好的人看来,可能会有略微迟滞感。

这个效果没有使用缓存,可以根据这个思路,把将数据发给屏幕的部分替换成改成写进缓存的
这里用到的几条关键代码,一部分让AI助手进行了优化和添加注释

图标数组部分:
  1. /* 测试图标:32x32实心方块 */
  2. const unsigned char code IconsBlock[128]={
  3.         0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  4.         0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  5.         0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  6.         0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  7. };
  8. /* 图标0:'Finger1' */
  9. const unsigned char code Icon0[128] = {
  10.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xEF,0x01,0x01,0x01,0x02,0x1C,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  11.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0xC0,0x20,0x21,0x7F,0xC0,0x00,0x00,0x00,0xFE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  12.     0x00,0x00,0x00,0x00,0x00,0x3C,0xF6,0x82,0x82,0x87,0x7D,0x30,0x40,0x47,0x3C,0x38,0x24,0xC3,0x42,0x42,0x44,0x05,0x07,0x0C,0x08,0x90,0x60,0x00,0x00,0x00,0x00,0x00,
  13.     0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x1C,0x20,0x40,0x82,0x82,0x82,0x84,0xC0,0x4C,0x83,0x80,0x80,0x40,0x40,0x20,0x10,0x08,0x06,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
  14. };
  15. /* 图标1:'Finger2' */
  16. const unsigned char code Icon1[128] = {
  17.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x01,0x01,0x01,0x06,0xFC,0xE0,0x30,0x10,0x10,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  18.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0x60,0x20,0x20,0x7F,0xC0,0x00,0x00,0x00,0xFF,0xDF,0x00,0x00,0x00,0xE0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  19.     0x00,0x00,0x00,0x00,0x00,0x1E,0x73,0xC1,0x01,0x07,0x38,0xE0,0xC0,0x80,0x83,0x7E,0x71,0x89,0x09,0x09,0x09,0x08,0x08,0x0F,0x08,0x10,0xE0,0x00,0x00,0x00,0x00,0x00,
  20.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0D,0x31,0x61,0x41,0x82,0x82,0x82,0x84,0x9C,0xC6,0x81,0x81,0x81,0xC0,0x60,0x30,0x18,0x0E,0x01,0x00,0x00,0x00,0x00,0x00,
  21. };
  22. /* 图标2:'Finger3' */
  23. const unsigned char code Icon2[128] = {
  24.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x30,0x10,0x20,0x60,0xC0,0xFE,0x01,0x01,0x01,0x03,0xFC,0x70,0x18,0x08,0x18,0x10,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  25.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x9E,0xF0,0x00,0x00,0x07,0xFF,0x80,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0xE0,0x3C,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  26.     0x00,0x00,0x00,0x00,0x00,0x0C,0xF7,0x61,0x40,0x81,0x07,0x1C,0xE0,0x00,0x00,0x00,0x3C,0xE4,0xC2,0x42,0x42,0x62,0x03,0x04,0x04,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,
  27.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x18,0x60,0x41,0x81,0x81,0x81,0xC2,0x40,0x46,0xC1,0x80,0xC0,0x40,0x60,0x30,0x18,0x06,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
  28. };
  29. /* 图标3:'Finger4' */
  30. const unsigned char code Icon3[128] = {
  31.     0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0xE0,0xB0,0x08,0x08,0x08,0x38,0xFE,0x83,0x01,0x01,0x03,0xFE,0x18,0x04,0x04,0x04,0x0C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,
  32.     0x00,0x00,0x00,0x00,0x0F,0x71,0x80,0x00,0x01,0x07,0x3E,0xF8,0x80,0x00,0x01,0x7F,0xE0,0x00,0x00,0x0F,0xF0,0x00,0x00,0x00,0xF0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,
  33.     0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xE0,0x00,0x03,0x1F,0x98,0x88,0x08,0x05,0x04,0x84,0x7E,0x21,0x21,0x21,0x21,0x01,0x03,0xC6,0x3C,0x00,0x00,0x00,0x00,
  34.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x40,0x80,0x80,0x80,0xC1,0x43,0x43,0x41,0xC0,0xC0,0x40,0x60,0x30,0x18,0x06,0x01,0x00,0x00,0x00,0x00,0x00,
  35. };
  36. /* 图标4:'Finger5' */
  37. const unsigned char code Icon4[128] = {
  38.     0x00,0x00,0x00,0x00,0x00,0xF0,0x08,0x08,0x08,0x18,0x30,0xE0,0xFC,0x03,0x01,0x01,0x06,0xF8,0xF8,0x04,0x04,0x04,0x0C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  39.     0x10,0xF8,0x08,0x08,0x08,0x08,0x33,0xFC,0xE0,0x00,0x00,0x00,0x3F,0xC0,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0xC0,0xFF,0xC0,0x40,0x20,0x20,0x20,0x40,0xC0,0x00,
  40.     0x00,0x00,0x07,0x0C,0x10,0x60,0x80,0x00,0x07,0x1E,0x10,0x88,0x88,0x8B,0x0C,0x04,0x04,0x84,0xC5,0x40,0x00,0x30,0x3F,0x0F,0x00,0x80,0x40,0x60,0x30,0x10,0x0F,0x00,
  41.     0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x38,0x60,0x40,0xC0,0x80,0x80,0xC1,0x41,0x5E,0xC7,0x81,0x80,0x80,0xC0,0x40,0x30,0x1E,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  42. };
  43. /*
  44. * 指针数组:每一项存放一个图标字模数组的首地址。
  45. * 用法:
  46. *   ShowIcon(x, y0, IconsPtr[i]);   // i = 0~4,即可显示第 i 个图标
  47. * 后期要更换图标时,只需把某个位置替换成新数组名(或新数组地址)即可,
  48. * 其它调用代码无需改动,实现"随时改变图标数组"。
  49. */
  50. const unsigned char code * const IconsPtr[5] = {
  51.     Icon0,   /* 索引 0:'Finger1' */
  52.     Icon1,   /* 索引 1:'Finger2' */
  53.     Icon2,   /* 索引 2:'Finger3' */
  54.     Icon3,   /* 索引 3:'Finger4' */
  55.     Icon4    /* 索引 4:'Finger5' */
  56. };
复制代码

  1. #define IconsMaxNum 5                     /* 图标总数(编号范围 0 ~ IconsMaxNum-1,即 0~4) */
复制代码


显示图标和擦除拖尾的两个函数


  1. /**************************************************************************
  2. * 函数名:ShowIcon
  3. * 功能  :在 OLED 指定位置显示一个 32x32 像素的图标,支持图标移出屏幕
  4. *         边缘时的自动裁剪(只画屏幕内可见部分),并对起始页号做越界保护。
  5. * 参数  :
  6. *   x     —— 图标左上角在屏幕上的 X 坐标(可为负,表示图标向左移出屏幕)
  7. *   y0    —— 图标左上角所在的起始页号(一页 8 像素,图标共 4 页 = 32 像素高)
  8. *   ICON  —— 图标点阵数据首地址(存放在 code 区,每个图标固定 32*4=128 字节)
  9. * 返回  :无
  10. * 说明  :
  11. *   1. 图标固定尺寸为 32 列 x 32 像素(32 列,4 页)。
  12. *   2. 点阵数据按"页优先"排列:ICON[page*32 + 列号],即每页连续 32 字节。
  13. *   3. 本函数要求图标能在屏幕上完整放下 4 页,因此 y0 最大只能到 4
  14. *      (4+4=8 页,恰好放在 128x64 屏的底部),y0>4 直接返回不显示。
  15. *   4. 依据 x 的位置分三种情况处理,算出实际可见宽度 IconWidth
  16. *      和源数据起始偏移 ColumnStart:
  17. *        - x<0  :图标左半部分移出屏幕左侧,屏幕起点 x0 归 0,
  18. *                 源数据跳过被遮挡的左边部分(从 ColumnStart 列开始取);
  19. *        - x>96 :图标右半部分超出屏幕右侧(96+32=128),只画剩余宽度;
  20. *        - 其余 :图标完整落在屏幕内,宽度为 32。
  21. *   5. x<-32 或 x>=128 时图标完全不可见,直接返回。
  22. *   6. 逐页(共 4 页)定位光标,把该页中可见的 IconWidth 列数据写入 OLED。
  23. **************************************************************************/
  24. void ShowIcon( int x, u8 y0, const u8 code *ICON )
  25. {
  26.     u8 IconWidth, ColumnStart = 0, x0 = x; /* IconWidth:实际可见宽度; ColumnStart:源数据起始列偏移; x0:屏幕实际起始列 */
  27.     u8 page, i;
  28.     if( y0>4 ) return;                     /* 起始页越界保护:y0+4 超过 8 页会写出屏外,直接返回 */
  29.     if( x<0 )                              /* ==== 情况1:图标左侧移出屏幕 ==== */
  30.     {
  31.         if( x>-32 )                        /* 图标还有部分可见(x 在 -31~-1 之间) */
  32.         {
  33.             IconWidth = 32+x;              /* 可见宽度 = 32 - 移出宽度(|x|) */
  34.             ColumnStart = 32-IconWidth;    /* 源数据从被遮挡处开始取,跳过不可见的左边部分 */
  35.             x0=0;                          /* 从屏幕第 0 列开始显示 */
  36.         }
  37.         else return;                       /* x<=-32,图标完全移出屏幕,不显示 */
  38.     }
  39.     else if( x>96 )                        /* ==== 情况2:图标右侧超出屏幕(96=128-32) ==== */
  40.     {
  41.         if( x<128 )                        /* 图标还有部分可见 */
  42.         {
  43.             IconWidth = 128-x;             /* 可见宽度 = 屏幕右边界 128 - 起始列 x */
  44.         }
  45.         else return;                       /* x>=128,图标完全移出屏幕右侧,不显示 */
  46.     }
  47.     else                                   /* ==== 情况3:图标完整位于屏幕内(0<=x<=96) ==== */
  48.     {
  49.         IconWidth = 32;                    /* 完整宽度 32 列 */
  50.     }
  51.     for( page=0; page<4; page++ )          /* 逐页绘制,图标高 4 页(32 像素) */
  52.     {
  53.         OLED_Set_Pos( x0, y0+page );       /* 定位到当前页的实际起始列 x0 */
  54.         for( i=0; i<IconWidth; i++ )       /* 只写入可见的 IconWidth 列 */
  55.         {
  56.             OLED_WR_Byte( ICON[page*32+i+ColumnStart], OLED_DATA );  /* 取源点阵数据写 OLED */
  57.         }
  58.     }
  59. }
  60. /**************************************************************************
  61. * 函数名:OLED_ClearPages
  62. * 功能  :局部清屏。清除从起始页 pStart 到结束页 pEnd 之间的显示内容
  63. *         (将指定页范围内的所有列数据全部写 0x00,即该页区域全黑)
  64. * 参数  :
  65. *   pStart  —— 起始页地址(页号)
  66. *   pEnd    —— 结束页地址(页号),需满足 pStart <= pEnd
  67. * 返回  :无
  68. * 说明  :
  69. *   1. OLED 屏按"页-列"组织,一页高 8 像素,横向共 128 列。
  70. *   2. 每清一页:先把光标定位到该页的第 0 列,再连续写 128 个
  71. *      0x00(数据模式 OLED_DATA),把该页整行 128 列的点阵清空。
  72. *   3. 遍历 pStart 至 pEnd 的所有页即可完成指定区域的清除。
  73. *   4. 若要全屏清屏,调用时令 pStart=0、pEnd=最大页号即可。
  74. **************************************************************************/
  75. void OLED_ClearPages( u8 pStart, u8 pEnd )
  76. {
  77.     u8 pagenum, i;
  78.     for( pagenum=pStart; pagenum<=pEnd; pagenum++ )  /* 逐页遍历:从起始页到结束页 */
  79.     {
  80.         OLED_Set_Pos( 0, pagenum );                  /* 光标定位到当前页的第 0 列 */
  81.         for( i=0; i<128; i++)                        /* 连续写满整页 128 列 */
  82.         {
  83.             OLED_WR_Byte( 0x00, OLED_DATA );         /* 写入数据 0x00,该列点阵全灭 */
  84.         }
  85.     }
  86. }
  87. /**************************************************************************
  88. * 函数名:ClearIconsSide
  89. * 功能  :清除 OLED 上某一列的显示内容(把该列 4 个页全部写 0x00)。
  90. *         主要用于滑动动画中清掉图标移动后留下的残影。
  91. * 参数  :
  92. *   x     —— 要清除的列坐标(0~127)
  93. *   page  —— 起始页号(该列从 page 页开始,连续清 4 页 = 32 像素高)
  94. * 返回  :无
  95. * 说明  :
  96. *   1. 先判断列坐标 x 是否在屏幕有效范围(0~127)内:
  97. *      越界则直接返回,避免向屏外地址写数据。
  98. *   2. 在有效范围内,对该列从 page 起连续 4 页各写一个 0x00:
  99. *      - OLED_Set_Pos(x, page+i) 把光标定位到第 page+i 页、第 x 列;
  100. *      - OLED_WR_Byte(0x00, OLED_DATA) 写入数据 0x00,清空该页该列
  101. *        8 个像素点。
  102. *   3. 连续清 4 页(i=0~3),正好覆盖一个 32 像素高的图标区域,
  103. *      因此本函数常与高 4 页的图标(如 32x32 图标)配合使用。
  104. **************************************************************************/
  105. void ClearIconsSide( int x, int page )
  106. {
  107.     u8 i;
  108.     if( x>=0 && x<128 )                 /* 列坐标有效性判断:必须在 0~127 内 */
  109.     {
  110.         for( i=0; i<4; i++ )            /* 从起始页起,连续清除 4 页(共 32 像素高) */
  111.         {
  112.             OLED_Set_Pos( x, page+i );  /* 定位到第 page+i 页、第 x 列 */
  113.             OLED_WR_Byte( 0x00, OLED_DATA );  /* 写入 0x00,清除该列当前页的点阵 */
  114.         }
  115.     }
  116.     else return;                        /* x 越界(屏外),不操作直接返回 */
  117. }
复制代码

单向滑动的函数
  1. /**************************************************************************
  2. * 函数名:IconsSlideLeft
  3. * 功能  :以【整体向左滑动 43 列】的动画,把图标滚动切换,使【屏幕中间】
  4. *         最终停在编号为 IconNum 的图标上(终点 = ShowIconsCurrent(IconNum))。
  5. * 参数  :
  6. *   IconNum —— 动画结束后停在屏幕中间的图标编号(int)
  7. * 返回  :无
  8. * 说明  :
  9. *   1. 可见三位置固定坐标:左 x=5、中 x=48、右 x=91,间距 43 列。
  10. *      起点布置为"中位置 = IconNum-1",整体左移 43 列后中位置落到 IconNum。
  11. *   2. 4 个槽位(含屏外第3槽 x=134)对应编号:IconNum-2 ~ IconNum+1,
  12. *      超出 0 ~ IconsMaxNum-1 的槽位不绘制(保持空白)。
  13. *   3. 每步:先 ClearIconsSide 清原图标最右列(画图列+33),再左移一列重画。
  14. *   4. 边界处理:
  15. *        IconNum < 0              :钳位为 0,直接返回(不重画);
  16. *        IconNum > IconsMaxNum-1  :钳位为 IconsMaxNum-1,直接返回(不重画);
  17. *        IconNum == 0             :起点终点相同,直接返回(不重画)。
  18. *      正常菜单操作(每次增减1)时,上一帧画面即为本帧应显示画面,
  19. *      无需重画;首次调用请先 ShowIconsCurrent(IconNum) 初始化。
  20. *   5. 每步延时 delay_ms(10),共 43 步约 430ms。
  21. **************************************************************************/
  22. void IconsSlideLeft( int IconNum )
  23. {
  24.     int x[4] = { 5, 48, 91, 134 };    /* 4 个槽位当前画图列坐标 */
  25.     int c[4] = { 38, 81, 124, 167 };  /* 4 个槽位需清除列坐标(画图列+33) */
  26.     int n = 43;                       /* 滑动总列数 */
  27.     int k, idx;
  28.     /* --- 越界钳位 --- */
  29.     if( IconNum < 0 ) IconNum = 0;
  30.     if( IconNum > IconsMaxNum - 1 ) IconNum = IconsMaxNum - 1;
  31.     /* --- 边界值:起点终点相同,直接返回(不重画,避免空转) --- */
  32.     if( IconNum == 0 )
  33.     {
  34.         return;
  35.     }
  36.     /* --- 逐列左滑:先清后画(自擦自画,终点精确落位) --- */
  37.     while( n-- )
  38.     {
  39.         for( k=0; k<4; k++ )
  40.         {
  41.             ClearIconsSide( c[k], 0 );        /* 清本槽右侧残影列 */
  42.             idx = IconNum + k - 2;            /* 本槽图标编号 */
  43.             if( idx >= 0 && idx < IconsMaxNum )
  44.             {
  45.                 ShowIcon( x[k], 0, IconsPtr[ idx ] );
  46.             }
  47.         }
  48.         for( k=0; k<4; k++ ) { x[k]--; c[k]--; }
  49.         delay_ms( IconsSlideSpeed );
  50.     }
  51. }
  52. /**************************************************************************
  53. * 函数名:IconsSlideRight
  54. * 功能  :以【整体向右滑动 43 列】的动画,把图标滚动切换,使【屏幕中间】
  55. *         最终停在编号为 IconNum 的图标上(终点 = ShowIconsCurrent(IconNum))。
  56. * 参数  :
  57. *   IconNum —— 动画结束后停在屏幕中间的图标编号(int)
  58. * 返回  :无
  59. * 说明  :
  60. *   1. 可见三位置固定坐标:左 x=5、中 x=48、右 x=91,间距 43 列。
  61. *      起点布置为"中位置 = IconNum+1",整体右移 43 列后中位置落到 IconNum。
  62. *   2. 4 个槽位(含屏外第0槽 x=-38)对应编号:IconNum-1 ~ IconNum+2,
  63. *      超出 0 ~ IconsMaxNum-1 的槽位不绘制(保持空白)。
  64. *   3. 每步:先右移一列坐标,再 ClearIconsSide 清原图标最左列(新位置-1),
  65. *      然后在右移后的位置重画(自擦自画,终点精确落位)。
  66. *   4. 边界处理:
  67. *        IconNum < 0              :钳位为 0,直接返回(不重画);
  68. *        IconNum > IconsMaxNum-1  :钳位为 IconsMaxNum-1,直接返回(不重画);
  69. *        IconNum == IconsMaxNum-1 :起点终点相同,直接返回(不重画)。
  70. *   5. 每步延时 delay_ms(10),共 43 步约 430ms。
  71. **************************************************************************/
  72. void IconsSlideRight( int IconNum )
  73. {
  74.     int x[4] = { -38, 5, 48, 91 };    /* 4 个槽位当前画图列坐标(含屏外第0槽) */
  75.     int c[4] = { -39, 4, 47, 90 };    /* 4 个槽位需清除列坐标(画图列-1) */
  76.     int n = 43;                       /* 滑动总列数 */
  77.     int k, idx;
  78.     /* --- 越界钳位 --- */
  79.     if( IconNum < 0 ) IconNum = 0;
  80.     if( IconNum > IconsMaxNum - 1 ) IconNum = IconsMaxNum - 1;
  81.     /* --- 边界值:起点终点相同,直接返回(不重画,避免空转) --- */
  82.     if( IconNum == IconsMaxNum - 1 )
  83.     {
  84.         return;
  85.     }
  86.     /* --- 逐列右滑:先移后画(自擦自画,终点精确落位) --- */
  87.     while( n-- )
  88.     {
  89.         for( k=0; k<4; k++ ) { x[k]++; c[k]++; }   /* 先右移一列 */
  90.         for( k=0; k<4; k++ )
  91.         {
  92.             ClearIconsSide( c[k], 0 );        /* 清本槽左侧残影列 */
  93.             idx = IconNum + k - 1;            /* 本槽图标编号 */
  94.             if( idx >= 0 && idx < IconsMaxNum )
  95.             {
  96.                 ShowIcon( x[k], 0, IconsPtr[ idx ] );
  97.             }
  98.         }
  99.         delay_ms( IconsSlideSpeed );
  100.     }
  101. }
复制代码


循环滑动的函数
  1. /**************************************************************************
  2. * 函数名:IconsSLoopLeft
  3. * 功能  :以【整体向左滑动 43 列】的循环滚动动画,把图标向左切换一格,
  4. *         使【屏幕中间】最终停在编号为 IconNum 的图标上,且 4 个槽位
  5. *         始终填满 5 个图标(取模循环),不存在空白。
  6. * 参数  :
  7. *   IconNum —— 动画结束后停在屏幕中间的图标编号(0 ~ IconsMaxNum-1)。
  8. *              本函数为循环滚动,参数任意值均合法,不需要钳位。
  9. * 返回  :无
  10. * 说明  :
  11. *   1. 可见三位置固定坐标:左 x=5、中 x=48、右 x=91,间距 43 列;
  12. *      屏外第 4 槽 x=134,用于滑入。
  13. *   2. 起点布置(语义 A):4 槽编号 = IconNum-2、IconNum-1、IconNum、IconNum+1,
  14. *      全部对 IconsMaxNum 取模,保证 4 个槽始终有图标。
  15. *      整体左移 43 列后,槽0 的 IconNum-1 落到中位置,终点中位置 = IconNum。
  16. *   3. 每步:先逐一 ClearIconsSide 清各槽右侧残影列,再左移一列重画,
  17. *      自擦自画,终点精确落位,无缝循环。
  18. *   4. 循环取模公式(防负数):
  19. *        idx = ((idx % IconsMaxNum) + IconsMaxNum) % IconsMaxNum;
  20. *   5. 每步延时 delay_ms( IconsSlideSpeed ),共 43 步。
  21. **************************************************************************/
  22. void IconsLoopLeft( int IconNum )
  23. {
  24.     int x[4] = { 5, 48, 91, 134 };    /* 4 个槽位当前画图列坐标 */
  25.     int c[4] = { 38, 81, 124, 167 };  /* 4 个槽位需清除列坐标(画图列+33) */
  26.     int n = 43;                       /* 滑动总列数 */
  27.     int k, idx;
  28.     /* --- 逐列左滑:先清后画(自擦自画,终点精确落位) --- */
  29.     while( n-- )
  30.     {
  31.         for( k=0; k<4; k++ )
  32.         {
  33.             ClearIconsSide( c[k], 0 );                  /* 清本槽右侧残影列 */
  34.             idx = IconNum + k - 2;                       /* 本槽图标编号(未取模) */
  35.             idx = ((idx % IconsMaxNum) + IconsMaxNum) % IconsMaxNum;  /* 循环取模到 0~4 */
  36.             ShowIcon( x[k], 0, IconsPtr[ idx ] );        /* 恒有图标,直接画 */
  37.         }
  38.         for( k=0; k<4; k++ ) { x[k]--; c[k]--; }         /* 4 槽整体左移一列 */
  39.         delay_ms( IconsSlideSpeed );
  40.     }
  41. }
  42. /**************************************************************************
  43. * 函数名:IconsSLoopRight
  44. * 功能  :以【整体向右滑动 43 列】的循环滚动动画,把图标向右切换一格,
  45. *         使【屏幕中间】最终停在编号为 IconNum 的图标上,且 4 个槽位
  46. *         始终填满 5 个图标(取模循环),不存在空白。
  47. * 参数  :
  48. *   IconNum —— 动画结束后停在屏幕中间的图标编号(0 ~ IconsMaxNum-1)。
  49. *              本函数为循环滚动,参数任意值均合法,不需要钳位。
  50. * 返回  :无
  51. * 说明  :
  52. *   1. 可见三位置固定坐标:左 x=5、中 x=48、右 x=91,间距 43 列;
  53. *      屏外第 0 槽 x=-38,用于从左侧滑入。
  54. *   2. 起点布置(语义 A):4 槽编号 = IconNum-1、IconNum、IconNum+1、IconNum+2,
  55. *      全部对 IconsMaxNum 取模,保证 4 个槽始终有图标。
  56. *      整体右移 43 列后,槽1 的 IconNum-1 落到中位置,终点中位置 = IconNum。
  57. *   3. 每步:先把 4 槽坐标整体右移一列,再逐一 ClearIconsSide 清各槽左侧
  58. *      残影列,然后在右移后的位置重画,自擦自画,终点精确落位,无缝循环。
  59. *   4. 循环取模公式(防负数):
  60. *        idx = ((idx % IconsMaxNum) + IconsMaxNum) % IconsMaxNum;
  61. *   5. 每步延时 delay_ms( IconsSlideSpeed ),共 43 步。
  62. **************************************************************************/
  63. void IconsLoopRight( int IconNum )
  64. {
  65.     int x[4] = { -38, 5, 48, 91 };    /* 4 个槽位当前画图列坐标(含屏外第0槽) */
  66.     int c[4] = { -39, 4, 47, 90 };    /* 4 个槽位需清除列坐标(画图列-1) */
  67.     int n = 43;                       /* 滑动总列数 */
  68.     int k, idx;
  69.     /* --- 逐列右滑:先移后画(自擦自画,终点精确落位) --- */
  70.     while( n-- )
  71.     {
  72.         for( k=0; k<4; k++ ) { x[k]++; c[k]++; }        /* 先整体右移一列 */
  73.         for( k=0; k<4; k++ )
  74.         {
  75.             ClearIconsSide( c[k], 0 );                  /* 清本槽左侧残影列 */
  76.             idx = IconNum + k - 1;                       /* 本槽图标编号(未取模) */
  77.             idx = ((idx % IconsMaxNum) + IconsMaxNum) % IconsMaxNum;  /* 循环取模到 0~4 */
  78.             ShowIcon( x[k], 0, IconsPtr[ idx ] );        /* 恒有图标,直接画 */
  79.         }
  80.         delay_ms( IconsSlideSpeed );
  81.     }
  82. }
复制代码


这几个滑动函数的参数,是移动之后停留在中间位置的图标的编号,调用的时候可以用一个变量来指定
  1. int MenuIndex = 0;                        /* 当前菜单编号 */
复制代码

单向滑动测试
  1.     if( !P01 && MenuIndex < IconsMaxNum - 1 )
  2.                                 {
  3.                                                 MenuIndex++;
  4.                                                 IconsSlideLeft( MenuIndex );          /* 菜单左滑 */
  5.                                                 ShowIconInfo( MenuIndex );
  6.                                 }
  7.                                 else if( !P00 && MenuIndex > 0 )
  8.                                 {
  9.                                                 MenuIndex--;
  10.                                                 IconsSlideRight( MenuIndex );         /* 菜单右滑 */
  11.                                                 ShowIconInfo( MenuIndex );
  12.                                 }
复制代码


循环滑动测试
  1.     if( !P01 )          /* P01 按下:向左滚动,编号 +1(循环) */
  2.                                 {
  3.                                                 MenuIndex = ( MenuIndex + 1 ) % IconsMaxNum;    /* 加 1 取模,4->0 自动回绕 */
  4.                                                 IconsLoopLeft( MenuIndex );                     /* 菜单左滑 */
  5.                                                 ShowIconInfo( MenuIndex );                      /* 更新图标下方信息 */
  6.                                 }
  7.                                 else if( !P00 )     /* P00 按下:向右滚动,编号 -1(循环) */
  8.                                 {
  9.                                                 MenuIndex = ( MenuIndex + IconsMaxNum - 1 ) % IconsMaxNum;  /* 加 4 取模,0->4 自动回绕 */
  10.                                                 IconsLoopRight( MenuIndex );                    /* 菜单右滑 */
  11.                                                 ShowIconInfo( MenuIndex );                      /* 更新图标下方信息 */
  12.                                 }
复制代码

初始化时预先把图标显示在指定位置上,还有显示文字的部分,跟你的思路相同就不放了




能体会到发现一个不理解的现象然后找原因然后要么解决掉问题要么被问题解决掉的那种快乐是我的幸运
回复

使用道具 举报 送花

已绑定手机

8

主题

7

回帖

118

积分

注册会员

积分
118
 楼主| 发表于 2026-10-19 15:08:16 | 显示全部楼层
大*** 发表于 2026-10-16 15:00
这个效果没有使用缓存,可以根据这个思路,把将数据发给屏幕的部分替换成改成写进缓存的
这里用到的几条关 ...

问题解决,谢谢
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-11-8 02:08 , Processed in 0.070397 second(s), 49 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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