Arduino--常用函数(三)

一、随机数

  1. randomSeed()
randomSeed(seed)

描述
使用randomSeed()初始化伪随机数生成器,使生成器在随机序列中的任意点开始。这个序列,虽然很长,并且是随机的,但始终是同一序列。
如需要在一个random()序列上生成真正意义的随机数,在执行其子序列时使用randomSeed()函数预设一个绝对的随机输入,例如在一个断开引脚上的analogRead()函数的返回值。
反之,有些时候伪随机数的精确重复也是有用的。这可以在一个随机系列开始前,通过调用一个使用固定数值的randomSeed()函数来完成。
参数
long,int - 通过数字生成种子。
返回
没有返回值
例子

long randNumber;
void setup(){
Serial.begin(9600);
randomSeed(analogRead(0));
}
void loop(){
randNumber = random(300);
Serial.println(randNumber);
delay(50);
}

6.2 random()

random()

描述
使用random()函数将生成伪随机数。
语法

random(max)
random(min, max)

参数

min - 随机数的最小值,随机数将包含此值。 (此参数可选)
max - 随机数的最大值,随机数不包含此值。

返回

min和max-1之间的随机数( 数据类型为long )

注意
如需要在一个random()序列上生成真正意义的随机数,在执行其子序列时使用randomSeed()函数预设一个绝对的随机输入,例如在一个断开引脚上的analogRead()函数的返回值。
反之,有些时候伪随机数的精确重复也是有用的。这可以在一个随机系列开始前,通过调用一个使用固定数值的randomSeed()函数来完成。
例子

long randNumber;
void setup(){
Serial.begin(9600);
//如果模拟输入引脚0为断开,随机的模拟噪声
//将会调用randomSeed()函数在每次代码运行时生成
//不同的种子数值。
//randomSeed()将随机打乱random函数。
randomSeed(analogRead(0));
}
void loop() {
//打印一个0到299之间的随机数
randNumber = random(300);
Serial.println(randNumber);
//打印一个10到19之间的随机数
randNumber = random(10, 20);
Serial.println(randNumber);
delay(50);
}

二、位操作

  1. lowByte()
    描述
    提取一个变量(例如一个字)的低位(最右边)字节。
    语法
    lowByte(x)
    参数
    x:任何类型的值
    返回
    字节

  2. highByte()
    描述
    提取一个字节的高位(最左边的),或一个更长的字节的第二低位。
    语法
    highByte(x)
    参数
    x:任何类型的值
    返回
    byte

  3. bitRead()
    描述
    读取一个数的位。
    语法
    bitRead(x, n)
    参数
    X:想要被读取的数 N:被读取的位,0是最低有效位(最右边)
    返回
    该位的值(0或1)。

  4. bitWrite()
    描述
    在位上写入数字变量。
    语法
    bitWrite(x, n, b)
    参数
    X:要写入的数值变量
    N:要写入的数值变量的位,从0开始是最低(最右边)的位
    B:写入位的数值(0或1)
    返回

  5. bitSet()
    描述
    为一个数字变量设置一个位。
    语句
    bitSet(x, n)
    语法
    X:想要设置的数字变量
    N:想要设置的位,0是最重要(最右边)的位
    返回

  6. bitClear()
    描述
    清除一个数值型数值的指定位(将此位设置成 0)
    语法
    bitClear(x, n)
    参数
    X:指定要清除位的数值 N:指定要清除位的位置,从0开始,0 表示最右端位
    返回值

  7. bit()
    描述
    计算指定位的值(0位是1,1位是2,2位4,以此类推)。
    语法
    bit(n)
    参数
    n:需要计算的位
    返回值
    位值

三、设置中断函数

  1. attachInterrupt()
attachInterrupt(interrupt, function, mode)

描述
当发生外部中断时,调用一个指定函数。当中断发生时,该函数会取代正在执行的程序。大多数的Arduino板有两个外部中断:0(数字引脚2)和1(数字引脚3)。
arduino Mege有四个外部中断:数字2(引脚21),3(20针),4(引脚19),5(引脚18)。
语法
interrupt:中断引脚数
function:中断发生时调用的函数,此函数必须不带参数和不返回任何值。该函数有时被称为中断服务程序。
mode:定义何时发生中断以下四个contstants预定有效值:
LOW 当引脚为低电平时,触发中断
CHANGE 当引脚电平发生改变时,触发中断
RISING 当引脚由低电平变为高电平时,触发中断
FALLING 当引脚由高电平变为低电平时,触发中断.
返回

注意事项
当中断函数发生时,delay()和millis()的数值将不会继续变化。当中断发生时,串口收到的数据可能会丢失。你应该声明一个变量来在未发生中断时储存变量。
使用中断
在单片机自动化程序中当突发事件发生时,中断是非常有用的,它可以帮助解决时序问题。一个使用中断的任务可能会读一个旋转编码器,监视用户的输入。
如果你想以确保程序始终抓住一个旋转编码器的脉冲,从来不缺少一个脉冲,它将使写一个程序做任何事情都要非常棘手,因为该计划将需要不断轮询的传感器线编码器,为了赶上脉冲发生时。其他传感器也是如此,如试图读取一个声音传感器正试图赶上一按,或红外线槽传感器(照片灭弧室),试图抓住一个硬币下降。在所有这些情况下,使用一个中断可以释放的微控制器来完成其他一些工作。
程序示例

int pin = 13;
volatile int state = LOW;
void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, CHANGE);
}
void loop()
{
digitalWrite(pin, state);
}
void blink()
{
state = !state;
}
  1. detachInterrupt()
detachInterrupt(interrupt)

描述
关闭给定的中断。
参数
interrupt: 中断禁用的数(0或者1).

四、开关中断

  1. interrupts()(中断)
    描述
    重新启用中断(使用noInterrupts()命令后将被禁用)。中断允许一些重要任务在后台运行,默认状态是启用的。禁用中断后一些函数可能无法工作,并传入信息可能会被忽略。中断会稍微打乱代码的时间,但是在关键部分可以禁用中断。
    参数

    返回

    例子
void setup() {

}
void loop()
{
noInterrupts();
//重要、时间敏感的代码
interrupts();
//其他代码写在这里
}
  1. noInterrupts()(禁止中断)
    描述
    禁止中断(重新使能中断interrupts())。中断允许在后台运行一些重要任务,默认使能中断。禁止中断时部分函数会无法工作,通信中接收到的信息也可能会丢失。
    中断会稍影响计时代码,在某些特定的代码中也会失效。
    参数

    返回

    例子
void setup()
void loop()
{
noInterrupts();
//关键的、时间敏感的代码放在这
interrupts();
//其他代码放在这
}

五、通讯

Serial

用于Arduino控制板和一台计算机或其他设备之间的通信。所有的Arduino控制板有至少一个串口(又称作为UART或USART)。它通过0(RX)和1(TX)数字引脚经过串口转换芯片连接计算机USB端口与计算机进行通信。因此,如果你使用这些功能的同时你不能使用引脚0和1作为输入或输出。
您可以使用Arduino IDE内置的串口监视器与Arduino板通信。点击工具栏上的串口监视器按钮,调用begin()函数(选择相同的波特率)。
Arduino Mega 有三个额外的串口:Serial 1使用19(RX)和18(TX),Serial 2使用17(RX)和16(TX),Serial3使用15(RX)和14(TX)。 若要使用这三个引脚与您的个人电脑通信,你需要一个额外的USB转串口适配器,因为这三个引脚没有连接到Mega上的USB转串口适配器。若要用它们来与外部的TTL串口设备进行通信,将TX引脚连接到您的设备的RX引脚,将RX引脚连接到您的设备的TX引脚,将GND连接到您的设备的GND。(不要直接将这些引脚直接连接到RS232串口;他们的工作电压在+/- 12V,可能会损坏您的Arduino控制板。)
Arduino Leonardo板使用Serial 1通过0(RX)和1(TX)与viaRS-232通信,Serial预留给使用Mouse and Keyboard libarariies的USB CDC通信 。

  1. if (Serial)
    说明
    表示指定的串口是否准备好。
    在Leonardo上,if(Serial)表示不论有无USB CDC,串行连接都是开放的。对于所有其他的情况,包括Leonardo上的if(Serial1),将一直返回true。 这来自于 Arduino 1.0.1 版本的介绍.
    语法
    对于所有的arduino板:
if (Serial)
Arduino Leonardo 特有:
if (Serial1)
Arduino Mega 特有:
if (Serial1)
if (Serial2)
if (Serial3)

参数

返回
布尔值:如果指定的串行端口是可用的,则返回true。如果查询Leonardo的USB CDC串行连接之前,它是准备好的,将只返回false。
例子

void setup() {
//初始化串口和等待端口打开:
Serial.begin(9600);
while (!Serial) {
//等待串口连接。只有 Leonardo 需要。
}
}
void loop() {
//正常进行
}
  1. Serial.available()
    说明
    获取从串口读取有效的字节数(字符)。这是已经传输到,并存储在串行接收缓冲区(能够存储64个字节)的数据。 available()继承了 Stream类。
    语法
Serial.available()

仅适用于Arduino Mega :

Serial1.available()
Serial2.available()
Serial3.available()

参数

返回
可读取的字节数
例子

incomingByte = 0; //传入的串行数据
void setup() {
Serial.begin(9600); // 打开串行端口,设置传输波特率为9600 bps
}
void loop() {
//只有当你接收到数据时才会发送数据,:
if (Serial.available() > 0) {
//读取传入的字节:
incomingByte = Serial.read();
//显示你得到的数据:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}

Arduino Mega 的例子:

void setup() {
Serial.begin(9600);
Serial1.begin(9600);
}
void loop() {
//读取端口0,发送到端口1:
if (Serial.available()) {
int inByte = Serial.read();
Serial1.print(inByte, BYTE);

}
//读端口1,发送到端口0:
if (Serial1.available()) {
int inByte = Serial1.read();
Serial.print(inByte, BYTE);
}
}
  1. Serial.begin() 初始化串口波特率
    说明
    将串行数据传输速率设置为位/秒(波特)。与计算机进行通信时,可以使用这些波特率:300,1200,2400,4800,9600,14400,19200,28800,38400,57600或115200。当然,您也可以指定其他波特率 - 例如,引脚0和1和一个元件进行通信,它需要一个特定的波特率。
    语法
Serial.begin(speed) 仅适用于Arduino Mega : Serial1.begin(speed) Serial2.begin(speed) Serial3.begin(speed)

参数

speed: 位/秒 (波特) - long

返回

例子

void setup() {
Serial.begin(9600); // 打开串口,设置数据传输速率为9600bps
}
void loop() {
Arduino Mega 的例子:
// Arduino Mega 可以使用四个串口
// (Serial, Serial1, Serial2, Serial3),
// 从而设置四个不同的波特率:
void setup(){
Serial.begin(9600);
Serial1.begin(38400);
Serial2.begin(19200);
Serial3.begin(4800);
Serial.println(“Hello Computer”);
Serial1.println(“Hello Serial 1”);
Serial2.println(“Hello Serial 2”);
Serial3.println(“Hello Serial 3”);
}
void loop() {}
  1. Serial.end()
    说明
    停用串行通信,使RX和TX引脚用于一般输入和输出。要重新使用串行通信, 需要 Serial.begin()语句。
    语法
Serial.end()

仅适用于Arduino Mega: Serial1.end() Serial2.end() Serial3.end()
参数

返回

  1. Serial.find()
    说明
    Serial.find() 从串行缓冲器中读取数据,直到发现给定长度的目标字符串。如果找到目标字符串,该函数返回true,如果超时则返回false。
    Serial.flush() 继承了 Stream 类.
    语法
Serial.find(target)

参数
target : 要搜索的字符串(字符)
返回
布尔型

  1. Serial.findUntil()
    说明
    Serial.findUntil()从串行缓冲区读取数据,直到找到一个给定的长度或字符串终止位。
    如果目标字符串被发现,该函数返回true,如果超时则返回false。
    Serial.findUntil()继承了Stream类。
    语法
Serial.findUntil(target, terminal)

参数
target : 要搜索的字符串(char) terminal : 在搜索中的字符串终止位 (char)
返回
布尔型

  1. Serial.flush()
    说明
    等待超出的串行数据完成传输。(在1.0及以上的版本中,flush()语句的功能不再是丢弃所有进入缓存器的串行数据。)
    flush()继承了Stream类.
    语法
Serial.flush()

仅 Arduino Mega 可以使用的语法:

Serial1.flush()
Serial2.flush()
Serial3.flush()

参数

返回

  1. Serial.parseFloat()
    描述
    Serial.parseFloat()命令从串口缓冲区返回第一个有效的浮点数.不属于数字(或减号)的字符将被跳过。parseFloat()以不是浮点数的第一个字符结尾。
    Serial.parseFloat()继承了Stream类。
    语法
Serial.parseFloat()

参数

返回
float

  1. Serial.parseInt()
    说明
    查找传入的串行数据流中的下一个有效的整数。 parseInt()继承了Stream类。
    语法
Serial.parseInt()

下面三个命令仅适用于Arduino Mega:

Serial1.parseInt()
Serial2.parseInt()
Serial3.parseInt()

参数

返回
int : 下一个有效的整数

  1. Serial.peek()
    说明
    返回传入的串行数据的下一个字节(字符),而不是进入内部串行缓冲器调取。也就是说,连续调用 peek()将返回相同的字符,与调用read()方法相同。peek()继承自 Stream类。
    语法
Serial.peek()

仅适用于Arduino Mega :

Serial1.peek()
Serial2.peek()
Serial3.peek()

参数

返回
传入的串行数据的第一个字节(或-1,如果没有可用的数据的话)- int

  1. Serial.print() 从串口打印输出数据
    说明
    以人们可读的ASCII文本形式打印数据到串口输出。此命令可以采取多种形式。每个数字的打印输出使用的是ASCII字符。浮点型同样打印输出的是ASCII字符,保留到小数点后两位。Bytes型则打印输出单个字符。字符和字符串原样打印输出。Serial.print()打印输出数据不换行,Serial.println()打印输出数据自动换行处理。
    例如
Serial.print(78)输出为“78”
Serial.print(1.23456)输出为“1.23”
Serial.print(“N”)输出为“N”
Serial.print(“Hello world.”)输出为“Hello world.”
也可以自己定义输出为几进制(格式);可以是BIN(二进制,或以2为基数),OCT(八进制,或以8为基数),DEC(十进制,或以10为基数),HEX(十六进制,或以16为基数)。对于浮点型数字,可以指定输出的小数数位。例如
Serial.print(78,BIN)输出为“1001110”
Serial.print(78,OCT)输出为“116”
Serial.print(78,DEC)输出为“78”
Serial.print(78,HEX)输出为“4E”
Serial.println(1.23456,0)输出为“1”
Serial.println(1.23456,2)输出为“1.23”
Serial.println(1.23456,4)输出为“1.2346”

你可以通过基于闪存的字符串来进行打印输出,将数据放入F()中,再放入Serial.print()。例如 Serial.print(F(“Hello world”)) 若要发送一个字节,则使用 Serial.write()。

语法

Serial.print(val)
Serial.print(val,格式)

参数
val:打印输出的值 - 任何数据类型
格式:指定进制(整数数据类型)或小数位数(浮点类型)
返回
字节 print()将返回写入的字节数,但是否使用(或读出)这个数字是可设定的
例子

/ *
使用for循环打印一个数字的各种格式。
/
int x = 0; // 定义一个变量并赋值
void setup() {
Serial.begin(9600); // 打开串口传输,并设置波特率为9600
}
void loop() {
/ /打印标签
Serial.print(“NO FORMAT”); // 打印一个标签
Serial.print("\t"); // 打印一个转义字符
Serial.print(“DEC”);
Serial.print("\t");
Serial.print(“HEX”);
Serial.print("\t");
Serial.print(“OCT”);
Serial.print("\t");
Serial.print(“BIN”);
Serial.print("\t");
for(x=0; x< 64; x++){ // 打印ASCII码表的一部分, 修改它的格式得到需要的内容
 / /打印多种格式:
  Serial.print(x);       // 以十进制格式将x打印输出 - 与 "DEC"相同
Serial.print("\t");    // 横向跳格
 Serial.print(x, DEC);  // 以十进制格式将x打印输出
Serial.print("\t");    // 横向跳格
 Srial.print(x, HEX);  // 以十六进制格式打印输出
Serial.print("\t");    // 横向跳格
 Serial.print(x, OCT);  // 以八进制格式打印输出
Serial.print("\t");    // 横向跳格
 Serial.println(x, BIN);  // 以二进制格式打印输出
                    //然后用 "println"打印一个回车
delay(200);            // 延时200ms
}

Seril.println(""); // 打印一个空字符,并自动换行
}

编程技巧 作为1.0版本,串行传输是异步的; Serial.print()将返回之前接收到的任何字符。

  1. Serial.println()
    说明
    打印数据到串行端口,输出人们可识别的ASCII码文本并回车 (ASCII 13, 或 ‘\r’) 及换行(ASCII 10, 或 ‘\n’)。此命令采用的形式与Serial.print ()相同 。
    语法
Serial.println(val)
Serial.println(val, format)

参数
val: 打印的内容 - 任何数据类型都可以
format: 指定基数(整数数据类型)或小数位数(浮点类型)
返回
字节(byte)
println()将返回写入的字节数,但可以选择是否使用它。
例子

/*
模拟输入信号
读取模拟口0的模拟输入,打印输出读取的值。
由 Tom Igoe创建于2006年3月24日
*/
int analogValue = 0; // 定义一个变量来保存模拟值
void setup() {
//设置串口波特率为9600 bps:
Serial.begin(9600);
}
void loop() {
analogValue = analogRead(0); //读取引脚0的模拟输入:
//打印g各种格式:
Serial.println(analogValue); //打印ASCII编码的十进制
Serial.println(analogValue, DEC); //打印ASCII编码的十进制
Serial.println(analogValue, HEX); //打印ASCII编码的十六进制
Serial.println(analogValue, OCT); //打印ASCII编码的八进制
Serial.println(analogValue, BIN); //打印一个ASCII编码的二进制
delay(10); // 延时10毫秒:
}
  1. Serial.read()
    说明
    读取传入的串口的数据。read() 继承自 Stream 类。
    语法
serial.read()
Arduino Mega独有:
serial1.read()
serial2.read()
serial3.read()

参数

返回
传入的串口数据的第一个字节(或-1,如果没有可用的数据)- int

例子

int incomingByte = 0; // 传入的串行数据
void setup() {
Serial.begin(9600); // 打开串口,设置数据传输速率9600
}
void loop() {
// 当你接收数据时发送数据
if (Serial.available() > 0) {
// 读取传入的数据:
incomingByte = Serial.read();
//打印你得到的:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
  1. Serial.readBytes()
    说明
    Serial.readBytes()从串口读字符到一个缓冲区。如果预设的长度读取完毕或者时间到了 (参见 Serial.setTimeout()),函数将终止.
    Serial.readBytes()返回放置在缓冲区的字符数。返回0意味着没有发现有效的数据。
    Serial.readBytes()继承自 Stream 类.
    语法
Serial.readBytes(buffer, length)

参数
buffer:用来存储字节(char[]或byte[])的缓冲区
length:读取的字节数(int)
返回
byte

  1. Serial.readBytesUntil()
    说明
    Serial.readBytesUntil()将字符从串行缓冲区读取到一个数组。如果检测到终止字符,或预设的读取长度读取完毕,或者时间到了 (参见 Serial.setTimeout())函数将终止。
    Serial.readBytesUntil()返回读入数组的字符数。返回0意味着没有发现有效的数据。
    Serial.readBytesUntil()继承自 Stream类。
    语法
Serial.readBytesUntil(character, buffer, length)

参数
character :要搜索的字符(char)
buffer :缓冲区来存储字节(char[]或byte[])
length:读的字节数(int)
返回
byte

  1. Serial.setTimeout()
    说明
    Serial.setTimeout()设置使用Serial.readBytesUntil() 或Serial.readBytes()时等待串口数据的最大毫秒值. 默认为1000毫秒。
    Serial.setTimeout()继承自Stream 类。
    语法
    Serial.setTimeout(time)
    参数
    time :以毫秒为单位的超时时间(long)。
    返回
  2. Serial.write()
    说明
    写入二级制数据到串口。发送的数据以一个字节或者一系列的字节为单位。如果写入的数字为字符,需使用print()命令进行代替。
    语法
Serial.write(val)
Serial.write(str)
Serial.write(buf, len)
Arduino Mega还支持:Serial1,Serial2,Serial3 (替代Serial)

参数
val: 以单个字节形式发的值
str: 以一串字节的形式发送的字符串
buf: 以一串字节的形式发送的数组
len: 数组的长度
返回
byte
write() 将返回写入的字节数,但是否使用这个数字是可选的
例子

void setup(){
Serial.begin(9600);
}
void loop(){
Serial.write(45); // 发送一个值为45的字节
int bytesSent = Serial.write(“hello”); //发送字符串“hello”,返回该字符串的长度.
}
  1. Serial.SerialEvent()
    暂无说明。
  2. Stream
    暂无说明。

十一、USB(仅适用于 Leonardo 和 Due)

  1. Mouse(键盘)
Mouse.begin()
Mouse.click()
Mouse.end()
Mouse.move()
Mouse.press()
Mouse.release()
Mouse.isPressed()
  1. Keyboard(鼠标)
Keyboard.begin()
Keyboard.end()
Keyboard.press()
Keyboard.print()
Keyboard.println()
Keyboard.release()
Keyboard.releaseAll()
Keyboard.write()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,049评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,478评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,109评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,097评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,115评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,280评论 1 279
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,748评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,398评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,553评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,440评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,487评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,176评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,750评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,821评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,049评论 1 257
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,559评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,150评论 2 341

推荐阅读更多精彩内容