在SSD1306控制器内部有滚动显示的控制命令,
以向右滚动显示为例,命令如下
  OLED_SD1306_WriteCmd(0x26);//r
  OLED_SD1306_WriteCmd(0x00);//duty
  OLED_SD1306_WriteCmd(0x04);//start page
  OLED_SD1306_WriteCmd(0x07); //speed 
  OLED_SD1306_WriteCmd(0x05);//end page
  OLED_SD1306_WriteCmd(0x01);//scroll timers
  OLED_SD1306_WriteCmd(0x00); //duty 
  OLED_SD1306_WriteCmd(0xff);//duty
  OLED_SD1306_WriteCmd(0x2f);//active
使用内部控制命令的局限性有,步伐不好控制,还有就是对于滚动显示的内容不能很好实时的更新,比如
图片A滚动显示之后接着图片B接着滚动显示,而是用内部控制命令的话,对于在A图片显示完毕之后衔接B的图片的时机非常不好把握,
所以针对多个图片的衔接滚动显示,我的解决方法如下:
首先为要滚动显示的图片建立文件ID,如下
#define       c_idx_16x10_ascii_v               4   
#define       c_idx_16x10_ascii_w               5   
#define       c_idx_16x10_digit_0               6   
#define       c_idx_16x10_digit_1               7   
#define       c_idx_16x10_digit_2               8   
#define       c_idx_16x10_digit_3               9   
#define       c_idx_16x10_digit_4               10   
#define       c_idx_16x10_digit_5               11   
#define       c_idx_16x10_digit_6               12   
#define       c_idx_16x10_digit_7               13   
#define       c_idx_16x10_digit_8               14   
#define       c_idx_16x10_digit_9               15   
#define       c_idx_16x10_dir_p               16
对要显示的图片建立所以值,在建立索引值之后,可以根据各图片的ID,建立成滚动列表
const u16 T_MuneMainBmpIdxInfo2[][2]= //此处为主菜单需要显示警告信息的时候列表
{
{c_idx_null},
{c_idx_16x24_MenuMain_0,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_1,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_2,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_3,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_4,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_5,c_idx_16x12_Menu_Drop},
{c_idx_10x20_menu_warrning,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_0,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_1,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_2,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_3,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_4,c_idx_16x12_Menu_Drop},
{c_idx_16x24_MenuMain_5,c_idx_16x12_Menu_Drop},
{c_idx_10x20_menu_warrning},
{c_idx_null},
};
在建立好图片ID表格之后,还需要建立另外一个表格,该表格用于存储,在显示该图片的时候,存储该图片的大小,
该大小为X或者Y的尺寸,,至于是X还是Y,主要是取决于取模方式,
该表格如下,
const u8 T_MuneMainBmpIdxInfo2_Size[]=
{
64,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
c_16x12_menu_drop_x_size,
c_16x24_menumain_x_size,
32,
c_ListEnd,
};
好了,在建立完这两张表格之后,那么就可以根据这两张表格来滚动显示该组合的图片了,
定义:g_scroll_add_inc 该变量用于滚动的累加器,
具体方法如下:
首先根据g_scroll_add_inc 根据此变量,算出,第一个要显示的图片的尺寸和第一个图片的ID
u8 gui_menu_waits_scroll_get_files(void)
{
  u16 px_add;
  u16 *p_list = (u16*)&T_MenuScrollWaitsList[0][0];//指向表格
  u16 p_data;//真实数据
  u8 p_bmp_size;//算出的图片大小
  u16 list_idx,list_offset;//临时变量
  px_add = c_OLED_X_POS_Max;//当调用该函数的时候,说明表格0这个位置的数据已经显示完毕
  list_idx = 1;
  list_offset = 0;
  p_bmp_size = 0;
  while(1)
  {
  p_data = *(p_list+list_idx*c_list_waits_size+list_offset);//得出链表中的数据
  if(p_data == c_null_info)//判断元素是否为空数据
  {
     list_idx++;
     list_offset = 0;
     continue; 
  }
  p_bmp_size = gui_get_files_x_size(p_data);//根据获得的索引值,算出图片大小
  px_add+=p_bmp_size;
  if(g_scroll_add_inc == px_add)//如果偏移量相等,说明p_data 这个数据里面的索引值的图片已经不用显示,所以要指到下个图片
  {
    
    list_offset++;
    if(list_offset >(c_list_waits_size-1))
    {
      list_offset = 0;
      list_idx++;
    }
    g_scroll_waits_idx = list_idx;
    g_scroll_waits_offset = list_offset;
    return 0;
  }
  else if(g_scroll_add_inc < px_add)//偏移量不相同,并且小的话,说明,说明p_data这个里面的图片是需要显示的
  {
    g_scroll_waits_idx = list_idx;
    g_scroll_waits_offset = list_offset;   
    return (p_bmp_size-(px_add-g_scroll_add_inc));
  }
  list_offset++;//这里面操作隐含的条件是 g_scroll_add_inc 大于 px_add,所以继续偏移
  if(list_offset > (c_list_waits_size-1))
  {
    list_offset = 0;
    list_idx++;
  }
  }
 
}
此函数的作用有这几点,第一根据g_scroll_add_inc 算出第一个要显示的图片ID编号,
第二同时结合g_scroll_add_inc和该ID所对应的图片尺寸算出,第一张图片的显示范围
比如算出的ID是 16x24_xxx,那么该图片的X尺寸是24个点,那么范围就是要显示的
x_start ~24,该x_start 范围在0-24之间,
在算出和装载第一个图片的内容到内存之后,那么接下来就要计算接下来的图片,
接下来的图片,根据OLED的尺寸,以32X64的OLED为例,那么第二个图片肯定是一个完整的图片,,,
然后一直到最后一个图片,最后一个图片同样的有可能是显示一部分,有可能是全部显示出来,
而这个显示的一部分,则是显示该图片的后部分,,
具体参考代码如下
void gui_menu_waits_scroll(void)
{
  u16 *p_List;
  u8 x_pos;
  u16 pdata;
  u8 bmpsize;
  u8 load_x_pos_start;
  u8 load_x_pos_size;
  x_pos = 0;
   gui_buffer_ClearRam();
  p_List = (u16*)&T_MenuScrollWaitsList[0][0];  
   if(g_scroll_add_inc < c_OLED_X_POS_Max)
   {
       x_pos = gui_loadpic_to_ram(x_pos,0,c_idx_null,0,c_OLED_X_POS_Max-g_scroll_add_inc);
  g_scroll_waits_idx = 1;
  g_scroll_waits_offset = 0;       
   }
   else
   {   
       load_x_pos_start = gui_menu_waits_scroll_get_files();
  pdata = *(p_List+g_scroll_waits_idx*c_list_waits_size+g_scroll_waits_offset);
  load_x_pos_size = gui_get_files_x_size(pdata);
  x_pos = gui_loadpic_to_ram(x_pos,0,pdata,load_x_pos_start,load_x_pos_size);
  g_scroll_waits_offset++;
  if(g_scroll_waits_offset > (c_list_waits_size-1))
  {
     g_scroll_waits_offset = 0;
     g_scroll_waits_idx++;
  }
  pdata = *(p_List+g_scroll_waits_idx*c_list_waits_size+g_scroll_waits_offset);
  if(pdata == c_null_info)
  {
    g_scroll_waits_idx++;
    g_scroll_waits_offset = 0;
  }       
   }
  while(1)
  {
    if(x_pos >= c_OLED_X_POS_Max)
    {
     break;
    }
    pdata = *(p_List+g_scroll_waits_idx*c_list_waits_size+g_scroll_waits_offset);
    if(pdata == c_null_info)
    {
     g_scroll_waits_idx++;
     g_scroll_waits_offset = 0;
     pdata = *(p_List+g_scroll_waits_idx*c_list_waits_size+g_scroll_waits_offset);
    }
    else
    {
     bmpsize = gui_get_files_x_size(pdata);
     if((c_OLED_X_POS_Max-x_pos)>= bmpsize)
     {
      load_x_pos_start = 0;
      load_x_pos_size = bmpsize;
     }
     else
     {
      load_x_pos_start = 0;
      load_x_pos_size = c_OLED_X_POS_Max-x_pos;
     }
    }
    x_pos = gui_loadpic_to_ram(x_pos,0,pdata,load_x_pos_start,load_x_pos_size);
    g_scroll_waits_offset++;
    if(g_scroll_waits_offset > (c_list_waits_size-1))
    {
      g_scroll_waits_offset = 0;
      g_scroll_waits_idx++;
    }
  }          
//  if(g_scroll_running_status)
  {
  g_scroll_add_inc+=2;
  }
  gui_updata_to_oled();
 
}
具体思路如下:
第一根据,g_scroll_add_inc算出在屏幕滚动的开始位置算出要显示的第一个图片的ID,并且要算出第一个图片要截取多少去显示
第二,根据要显示的OLED的尺寸,去计算接下来的图片和最后一个图片,至于具体是某个图片则要根据你自己所建立的图片ID所决定,比如这里的图片ID表格T_MuneMainBmpIdxInfo2
要指出的时候,这些图片ID表格和图片长度表格,可以是单数组存放方式,也可以是多维数据的方式,但是在使用的时候,切记要注意越界的问题,所以在建立文件长度表格T_MuneMainBmpIdxInfo2_Size的时候,在最后一个位置我放的数据是c_ListEnd,以防止在访问的时候,越界,至于c_ListEnd 这个标志的值具体是多少,可以根据具体的工程来定,最好不要和图片ID混合,
在此所要说明的是,对于多变和多信息的处理的时候,最好以建立表格的方式去访问,,,,用表格的方式去访问的因素有,工程可维护性强,第二数据结构组织方式易懂,方便,,