之前电脑上存了很多自己写的关于arduino的有趣的小demo,因为重装了系统,不小心误删了所有的文件(气的半死),所以现在准备一有空就重写一下之前写过的东东,顺带再温习一次,这次总不能再删了吧,嘿嘿。

这次主要想记录一下点阵的使用,方便以后查阅,也分享出来和伙伴们一起学习进步。这次在代码中,用的最多的就是指针的使用,就当回顾知识点了。

  用到的材料:一个16*16点阵(由4块8*8的led点阵组成的),arduino的uno。

  用到的库文件:LedControl.h ,因为点阵是使用的max7219,这个库很不错。

先看看效果,下面是视频链接:

arduino之庆祝祖国70周年

下面直接上代码,有兴趣的小伙伴可以玩玩。

 #include <LedControl.h>
const int DIN = ;
const int CLK = ;
const int CS = ;
int maxLen;//字的总个数
int row;//纵向移动数组的行数
int col;//横向移动数组的列数
//自定义函数
void showWordByArr(LedControl led, byte[][]); //通过数组显示
void showWordByPtr(LedControl led, byte(*word)[]); //通过数组指针显示
void showWords(LedControl led, byte(*words)[][]); //显示一组文字
void showTopMoveWords(LedControl led, byte(*words)[][]); //向上移动显示文字
void showLeftMoveWords(LedControl led, byte(*words)[][]); //向左移动显示文字 //初始化对象,每个对象最多可以操作8个设备(超过8个设备就再创建一个对象)。
LedControl led = LedControl(DIN, CLK, CS , );//我这里是4块8*8的led点阵,所以设备数量填4(最大为8)。
byte a[][] = //实心五角星
{
0x01, 0x00, //第一,二个设备
0x01, 0x00,
0x03, 0x80,
0x03, 0x80,
0x03, 0x80,
0x07, 0xC0,
0xFF, 0xFE,
0x7F, 0xFC,
0x3F, 0xF8, //第三,四个设备
0x0F, 0xE0,
0x0F, 0xE0,
0x1F, 0xF0,
0x1E, 0xF0,
0x18, 0x30,
0x20, 0x08,
0x00, 0x00
};
byte b[][] = //空心五角星
{
0x01, 0x00, 0x01, 0x00, 0x02, 0x80, 0x02, 0x80, 0x02, 0x80, 0x04, 0x40, 0xFC, 0x7E, 0x40, 0x04,
0x30, 0x18, 0x08, 0x20, 0x08, 0x20, 0x11, 0x90, 0x16, 0x50, 0x18, 0x30, 0x20, 0x08, 0x00, 0x00
};
byte c[][] = //空心取反
{
0xFE, 0xFF, 0xFE, 0xFF, 0xFC, 0x7F, 0xFC, 0x7F, 0xFC, 0x7F, 0xF8, 0x3F, 0x00, 0x01, 0x80, 0x03,
0xC0, 0x07, 0xF0, 0x1F, 0xF0, 0x1F, 0xE0, 0x0F, 0xE1, 0x0F, 0xE7, 0xCF, 0xDF, 0xF7, 0xFF, 0xFF
}; byte topWords[][][] = //庆祝祖国70周年
{
{0x00},
{
0x01, 0x00, 0x00, 0x80, 0x3F, 0xFE, 0x20, 0x00, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0x2F, 0xFC,
0x20, 0x80, 0x21, 0x40, 0x21, 0x40, 0x22, 0x20, 0x42, 0x20, 0x44, 0x10, 0x88, 0x08, 0x10, 0x06
},
{
0x20, 0x00, 0x13, 0xFC, 0x12, 0x04, 0xFA, 0x04, 0x0A, 0x04, 0x12, 0x04, 0x13, 0xFC, 0x38, 0x90,
0x54, 0x90, 0x94, 0x90, 0x10, 0x90, 0x11, 0x12, 0x11, 0x12, 0x12, 0x12, 0x14, 0x0E, 0x18, 0x00
},
{
0x20, 0x00, 0x11, 0xF8, 0x11, 0x08, 0xF9, 0x08, 0x09, 0x08, 0x11, 0xF8, 0x11, 0x08, 0x39, 0x08,
0x55, 0x08, 0x95, 0xF8, 0x11, 0x08, 0x11, 0x08, 0x11, 0x08, 0x11, 0x08, 0x17, 0xFE, 0x10, 0x00
},
{
0x00, 0x00, 0x7F, 0xFC, 0x40, 0x04, 0x40, 0x04, 0x5F, 0xF4, 0x41, 0x04, 0x41, 0x04, 0x4F, 0xE4,
0x41, 0x04, 0x41, 0x44, 0x41, 0x24, 0x5F, 0xF4, 0x40, 0x04, 0x40, 0x04, 0x7F, 0xFC, 0x40, 0x04
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x18, 0x44, 0x24, 0x44, 0x42, 0x08, 0x42, 0x08, 0x42,
0x10, 0x42, 0x10, 0x42, 0x10, 0x42, 0x10, 0x24, 0x10, 0x18, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x3F, 0xF8, 0x21, 0x08, 0x21, 0x08, 0x2F, 0xE8, 0x21, 0x08, 0x21, 0x08, 0x3F, 0xF8,
0x20, 0x08, 0x27, 0xC8, 0x24, 0x48, 0x24, 0x48, 0x27, 0xC8, 0x40, 0x08, 0x40, 0x28, 0x80, 0x10
},
{
0x10, 0x00, 0x10, 0x00, 0x1F, 0xFC, 0x20, 0x80, 0x20, 0x80, 0x40, 0x80, 0x1F, 0xF8, 0x10, 0x80,
0x10, 0x80, 0x10, 0x80, 0xFF, 0xFE, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80
},
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x20,0x00,0x00,0x00
} };
byte words[][][]= //愿祖国繁荣昌盛,越来越好,
{
{
0x00,0x00,0x3F,0xFE,0x20,0x80,0x27,0xF8,0x24,0x08,0x27,0xF8,0x24,0x08,0x27,0xF8,
0x22,0x50,0x24,0x48,0x29,0x44,0x20,0x80,0x20,0x44,0x4A,0x42,0x4A,0x12,0x91,0xF0
},
{
0x20,0x00,0x11,0xF8,0x11,0x08,0xF9,0x08,0x09,0x08,0x11,0xF8,0x11,0x08,0x39,0x08,
0x55,0x08,0x95,0xF8,0x11,0x08,0x11,0x08,0x11,0x08,0x11,0x08,0x17,0xFE,0x10,0x00
},
{
0x00,0x00,0x7F,0xFC,0x40,0x04,0x40,0x04,0x5F,0xF4,0x41,0x04,0x41,0x04,0x4F,0xE4,
0x41,0x04,0x41,0x44,0x41,0x24,0x5F,0xF4,0x40,0x04,0x40,0x04,0x7F,0xFC,0x40,0x04
},
{
0x20,0x20,0x3F,0x20,0x40,0x3E,0xBE,0x48,0x2A,0xA8,0xFF,0x28,0x4A,0x10,0x7F,0x28,
0x04,0x46,0x08,0x80,0x1F,0x00,0x02,0x10,0x3F,0xF8,0x01,0x08,0x15,0x20,0x22,0x10
},
{
0x08,0x20,0x08,0x20,0xFF,0xFE,0x08,0x20,0x00,0x00,0x7F,0xFE,0x40,0x02,0x81,0x04,
0x01,0x00,0x7F,0xFC,0x03,0x80,0x05,0x40,0x09,0x20,0x31,0x18,0xC1,0x06,0x01,0x00
},
{
0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,0x00,0x00,
0x3F,0xF8,0x20,0x08,0x20,0x08,0x3F,0xF8,0x20,0x08,0x20,0x08,0x3F,0xF8,0x20,0x08
},
{
0x00,0x90,0x00,0x88,0x3F,0xFC,0x20,0x80,0x20,0x88,0x3E,0x48,0x22,0x50,0x22,0x24,
0x4A,0x54,0x44,0x8C,0x81,0x04,0x3F,0xF8,0x24,0x48,0x24,0x48,0xFF,0xFE,0x00,0x00
},
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x20,0x00,0x00,0x00
},
{
0x10,0x28,0x10,0x24,0x10,0x20,0x7D,0xFC,0x11,0x20,0x11,0x24,0xFD,0x24,0x11,0x28,
0x11,0x28,0x51,0x10,0x5D,0x94,0x51,0x2C,0x70,0x44,0x50,0x00,0x4F,0xFE,0x80,0x00
},
{
0x01,0x00,0x01,0x00,0x01,0x00,0x7F,0xFC,0x01,0x00,0x11,0x10,0x09,0x10,0x09,0x20,
0xFF,0xFE,0x03,0x80,0x05,0x40,0x09,0x20,0x31,0x18,0xC1,0x06,0x01,0x00,0x01,0x00
},
{
0x10,0x28,0x10,0x24,0x10,0x20,0x7D,0xFC,0x11,0x20,0x11,0x24,0xFD,0x24,0x11,0x28,
0x11,0x28,0x51,0x10,0x5D,0x94,0x51,0x2C,0x70,0x44,0x50,0x00,0x4F,0xFE,0x80,0x00
},
{
0x10,0x00,0x10,0xFC,0x10,0x04,0x10,0x08,0xFC,0x10,0x24,0x20,0x24,0x20,0x25,0xFE,
0x24,0x20,0x48,0x20,0x28,0x20,0x10,0x20,0x28,0x20,0x44,0x20,0x84,0xA0,0x00,0x40
},
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x20,0x00,0x00,0x00
}
};
byte leftWords[][][]= //我爱你中国!
{
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x1A,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
},
{
0x04,0x24,0x24,0x24,0x7F,0xC4,0x44,0x04,0x04,0xFF,0x04,0x44,0x34,0x05,0x04,0x00,
0x00,0x10,0x12,0x21,0xFE,0x40,0x82,0x02,0x04,0xC8,0x30,0x28,0x44,0x82,0x1F,0x00
},
{
0x01,0x26,0x34,0x2C,0x24,0x24,0x37,0x4C,0x44,0x44,0x4C,0x74,0xC4,0x45,0x06,0x00,
0x00,0x82,0x84,0x89,0x91,0xE1,0xB2,0xAA,0xA4,0xA4,0xAA,0xB2,0x81,0x01,0x01,0x00
},
{
0x00,0x01,0x06,0x1F,0xE0,0x02,0x04,0x18,0xF0,0x10,0x13,0x10,0x10,0x14,0x18,0x00,
0x80,0x00,0x00,0xFF,0x00,0x08,0x30,0xC0,0x02,0x01,0xFE,0x00,0x80,0x60,0x18,0x00
},
{
0x00,0x00,0x0F,0x08,0x08,0x08,0x08,0xFF,0x08,0x08,0x08,0x08,0x0F,0x00,0x00,0x00,
0x00,0x00,0xF0,0x20,0x20,0x20,0x20,0xFF,0x20,0x20,0x20,0x20,0xF0,0x00,0x00,0x00
},
{
0x00,0x7F,0x40,0x48,0x49,0x49,0x49,0x4F,0x49,0x49,0x49,0x48,0x40,0x7F,0x00,0x00,
0x00,0xFF,0x02,0x12,0x12,0x12,0x12,0xF2,0x12,0x52,0x32,0x12,0x02,0xFF,0x00,0x00
},
{
0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
}
}; void setup() {
for (int i = ; i < ; ++i)
{
led.shutdown(i, false);//关闭省电模式,这一步必须做,否则显示不出来(因为在构造函数中,默认开启了省电模式,所以,我们要关闭该模式)。
led.clearDisplay(i);//清空数据
}
maxLen = sizeof(words)/sizeof(*words);//计算总的字数
row = * (sizeof(topWords) / sizeof(*topWords));//计算向上移动的字的总行数
col = * (sizeof(leftWords) / sizeof(*leftWords));//计算向左移动的字的总列数
} void loop() {
// put your main code here, to run repeatedly:
showWordByPtr(led, b); //显示空心五角星
delay();
for(int i =;i<;++i)
{
showWordByArr(led, a); //实心五角星
delay();
showWordByArr(led, c); //空心取反
delay();
}
showWordByArr(led, a); //实心五角星
delay();
showTopMoveWords(led, topWords); //字向左滚动
delay();
showWords(led, words); //字原地变换
delay();
showLeftMoveWords(led, leftWords); //字向右滚动
delay();
} void showWordByArr(LedControl led, byte word[][])
{
for (int i = ; i < ; ++i)
{
if (i < )
{
for (int j = ; j < ; ++j)
{
led.setRow(i, j, word[j][i]);
}
}
else
{
for (int j = ; j < ; ++j)
{
led.setRow(i, j, word[j + ][i - ]);
}
}
}
} void showWordByPtr(LedControl led, byte (*word)[])
{
for (int i = ; i < ; ++i)
{
if (i < )
{
for (int j = ; j < ; ++j)
{
led.setRow(i, j, *(*(word + j) + i));
}
}
else
{
for (int j = ; j < ; ++j)
{
led.setRow(i, j, *(*(word + j + ) + i - ));
}
}
}
} void showWords(LedControl led, byte (*words)[][])
{
for (int i = ; i < maxLen; ++i)
{
showWordByPtr(led, *(words + i));
delay();
}
} void showTopMoveWords(LedControl led, byte(*words)[][])
{
byte *temp = *(*words); //获取第一个二维数组的第一行的(第一个元素)的指针
byte* dump = temp;
for(int n =;n<=row-;++n)
{
dump = temp;
for (int i = ; i < ; ++i)//共4块8*8led点阵,每块显示完再到下一块
{
dump = temp;
if (i < ) //第一、二块的点阵
{
for (int j = ; j < ; ++j) //每块点阵共8行,所以循环8次
{
led.setRow(i, j, *(dump + i));
dump+=; //指向下一行的第一个位置
}
}
else //第三、四块点阵显示
{
dump+=; //因为是显示二维数组的后半部分,这里要加一下。
for (int j = ; j < ; ++j)
{
led.setRow(i, j, *(dump+i-));
dump+=;
}
}
}
temp += ;//每次循环完,指向下一行。
delay(); //每次显示之间间隔35ms,这是我自己测试的,如果想要更快或更慢可以相应调整这个参数。
}
} void showLeftMoveWords(LedControl led, byte(*words)[][])
{
byte* first = *(*words);
byte* firstChangeFlag = first + ;//开始遍历的指针需要变换的标志(也就是当first和firstChangeFlag相等时,说明first需要再偏移17).
byte* temp = first; //负责显示第一、二个led点阵的指针
byte* temp1 = first + ; //负责显示第三、四个点阵的指针
for (int n = ; n < col - ; ++n)
{
temp = first;
temp1 = first + ;
for (int i=;i<;++i)
{
if (i < ) //第一、二个点阵
{
for (int j = ; j < ; ++j)
{
led.setColumn(i, j, *temp);
if (temp == firstChangeFlag)
{
temp += ;
}
else
{
temp++;
}
}
}
else //第三、四个点阵
{
for (int k=; k<; ++k)
{
led.setColumn(i, k, *temp1);
if (temp1 == firstChangeFlag+)
{
temp1 += ;
}
else
{
temp1++;
}
}
}
}
if (first == firstChangeFlag)
{
first += ;
firstChangeFlag = first + ;
}
else
{
first++;
}
//delay(1000);
}
}

最后总结一下:

  1. 汉字的点阵数组是使用16*16字模软件提取出来的,我用的是字模提取 v2.2版本,网上搜一下就有。

  2. 原来写过的,只是单纯的显示汉字,这次把文字移动显示加上去了。

  3. 向左移动文字的那个函数想了好久才写出来的,主要是太浮躁了,后来静下心来仔细推敲,是发现指针遍历数组的顺序有问题,这才解决了。

  4. 通过视频可以看到,向左移动显示的效果还是有点问题的,上面一半的显示和下面一半的显示有一点不同步,难道是处理器跟不上?(自我安慰)。希望有路过大神指点一下。

  5. 最后要感谢下面的文章,是当初玩点阵入门的时候的参考资料。

LedControl库的使用

Arduino Uno 使用MAX7219驱动单个8*8点阵LED模块 - 凌顺实验室

2019-10-15更新:

  今天上班钻孔的时候(我是做模具的),突然来了灵感,想到了解决横向滚动,上下屏不同步的解决办法。

回来一试,效果很好(几乎看不出来,不同步了)。原来我是按照先显示第1和第2块led点阵,再显示第3块和第4块点阵的方式的(这是向上滚动字幕的显示方式),

既然向左滚动,那应该是先显示最左边的点阵,即先显示第1和第3块点阵,再显示右边的第2和第4块led点阵,这样就解决了,代码稍加改动如下:

 void showLeftMoveWords(LedControl led, byte(*words)[][])
{
byte* first = *(*words);
byte* firstChangeFlag = first + ;//开始遍历的指针需要变换的标志(也就是当first和firstChangeFlag相等时,说明first需要再偏移17).
byte* temp = first; //负责显示第一、二个led点阵的指针
byte* temp1 = first + ; //负责显示第三、四个点阵的指针
for (int n = ; n < col - ; ++n)
{
temp = first;
temp1 = first + ;
//原来是先显示第1块和第2块,再显示第3,4块的,所以导致上下屏不同步。
for (int i = ; i < ; ++i) //这里循环2次,分2次显示,先显示第1块和第3块led,再显示第2块和第4块led。
{
for (int j = ; j < ; ++j)
{
led.setColumn(i, j, *temp);
if (temp == firstChangeFlag)
{
temp += ;
}
else
{
temp++;
}
}
for (int k = ; k < ; ++k)
{
led.setColumn(i+, k, *temp1);
if (temp1 == firstChangeFlag + )
{
temp1 += ;
}
else
{
temp1++;
}
}
}
if (first == firstChangeFlag)
{
first += ;
firstChangeFlag = first + ;
}
else
{
first++;
}
}
}

再次总结:

  1. 这个点阵模块在某宝上花了三十几块大洋买的,玩到这样也算对的起我的大洋了。。。

  2. 突然发现,点阵可以拿来玩一些数据结构的演练,有空得好好试下玩玩(比如,拿这点阵玩贪吃蛇。。。)。

  3. 遇到问题,一定要冷静思考,切勿焦躁,烦躁是大忌,这也是成为一名职业程序员的基本修养(虽然,目前还不是)。

arduino之16*16点阵庆祝祖国70周年的更多相关文章

  1. 矢量图标转成16*16大小的SVG格式

    著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:一一链接:http://www.zhihu.com/question/32233782/answer/68629385来源:知 ...

  2. UCOSii任务就绪表之OSUnMapTbl[16*16]的数组是如何得到的

    我比较喜欢图,如下图: 图1: INT8U const OSUnMapTbl[]数组内的数据. 1.UCOSii的优先级相关内容 首先先介绍一个概念:优先级.UCOSii的优先级按倒叙排列,即优先级数 ...

  3. 不使用局部变量和for循环或其它循环打印出如m=19,n=2結果为2 4 8 16 16 8 4 2形式的串

    需求:不使用局部变量和for循环或其它循环打印形如:2 4 8 16 16 8 4 2 这样的串 代码MainTest.java package com.szp.study.javase.specia ...

  4. 2017.9.16~17,热烈庆祝共创力罗老师《敏捷MINI体验式实战培训》在某大型企业成功举办!

    2017.9.16~17日,深圳市共创力企业管理咨询有限公司为某上市企业提供了为期两天的内训服务.该次内训的主题为<敏捷MINI体验式实践培训>,为期两天.此次培训由共创力资深讲师Geor ...

  5. 2017年1月4日 16:16:24开始学习Linux——好像回到上次发随笔的时间。

    auto为C语言局部变量的默认属性 static指明变量的静态属性,也具有作用域限定符的意义 static修饰的全局变量作用域只是生命的文件中,修饰的函数作用域只是声明的文件中 register指明将 ...

  6. Hbase常见异常 分类: B7_HBASE 2015-02-02 16:16 412人阅读 评论(0) 收藏

    1. HBase is able to connect to ZooKeeper but the connection closes immediately hbase(main):001:0> ...

  7. Linux mint 启动文本模式(不启动图形界面)

    Linux Mint 系统用了很久,很顺手,赞一个! 有一天想同时运行多个虚拟机linux系统做实验,想着只启动文本模式可以省点内存资源,结果试了多种方法都不成功,网上现有针对Ubuntu原版和Cen ...

  8. Python中print()函数不换行的方法以及分隔符替换

    一.让print()函数不换行 在Python中,print()函数默认是换行的.但是,在很多情况下,我们需要不换行的输出(比如在算法竞赛中).那么,在Python中如何做到这一点呢? 其实很简单.只 ...

  9. Python使用print打印时,展示内容不换行

    原理 Python的print()函数中参数end='' 默认为\n,所以会自动换行; 默认的print()函数: print(end='\n') 方案 Python 2: 在print语句的末尾加上 ...

随机推荐

  1. 【Leetcode_easy】876. Middle of the Linked List

    problem 876. Middle of the Linked List 参考 1. Leetcode_easy_876. Middle of the Linked List; 完

  2. Configuration system failed to initialize

    引用:https://cloud.tencent.com/developer/article/1336954 重装.net Framework

  3. FutureTask源码阅读

    FutureTask功能用法 类结构 源码中详细说明了FutureTask生命周期状态及变化 /** * The run state of this task, initially NEW. The ...

  4. GSVA的使用

    GSVA的简介 Gene Set Variation Analysis,被称为基因集变异分析,是一种非参数的无监督分析方法,主要用来评估芯片核转录组的基因集富集结果.主要是通过将基因在不同样品间的表达 ...

  5. 使用redis调用lua脚本的方式对接口进行限流

    java端实现: //初始化一个redis可执行的lua DefaultRedisScript<List> defaultRedisScript = new DefaultRedisScr ...

  6. LeetCode 590. N叉树的后序遍历(N-ary Tree Postorder Traversal)

    590. N叉树的后序遍历 590. N-ary Tree Postorder Traversal 题目描述 给定一个 N 叉树,返回其节点值的后序遍历. LeetCode590. N-ary Tre ...

  7. 【HTML5校企公益课】第二天

    1.上午讲昨天的作业. <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> & ...

  8. quartz定时任务存储

    今天不聊quartz的概念,像任务bean,触发器,调度器这些随随便便都可以百度到,其中任务bean要实现job接口.对于这些创建生成的定时任务,它可以保存在内存中,重启失效,也可以保存在数据库里重启 ...

  9. 汉字转拼音js工具:

    / JavaScript Document var PinYin = { "a": "\u554a\u963f\u9515", "ai": ...

  10. Nio学习笔记(大部分网上摘抄)

    Nio与IO的区别 原有的 IO 是面向流的.阻塞的,NIO 则是面向块的.非阻塞的. 1.IO流每次从流中读一个或多个字节,直至读完所有字节,他们没有被缓存在其他地方,并且,IO流不能移动流中的数据 ...