微雪RS485 CAN HAT

产品概述

RS485 CAN HAT 是微雪电子为树莓派开发的一款的带 RS485 和 CAN 通信功能的扩展板,具备 RS485、CAN 通信功能。

特点

  • 基于Raspberry Pi 40pin GPIO接口,适用于Raspberry Pi系列主板
  • 具备CAN功能,使用SPI接口CAN控制器MCP2515,搭配收发器SN65HVD230
  • 具备RS485功能,使用UART控制,半双工通讯,收发器为SP3485
  • 板载TVS(瞬态电压抑制管),RS485通讯可有效抑制电路中的浪涌电压和瞬态尖峰电压,防雷防静电
  • 预留控制接口,方便其他控制器控制
  • 提供完善的配套资料手册(提供wiringPi与python例程)

产品参数

  • 工作电压: 3.3V
  • CAN控制芯片: MCP2515
  • CAN收发器: SN65HVD230
  • 485收发器: SP3485
  • 产品尺寸: 65mmx30mm
  • 固定孔通经: 3.0mm

接口说明

  • CAN总线

| 功能引脚 | 树莓派接口(BCM) | 描述 |
| 3V3 | 3V3 | 3.3V电源正 |
| GND | GND | 电源地 |
| SCK | SCK | SPI时钟输入 |
| MOSI | MOSI | SPI数据输入 |
| MISO | MISO | SPI数据输出 |
| CS | CE0 | 数据/命令选择 |
| INT | 25 | 中断输出 |

  • RS485总线

| 功能引脚 | 树莓派接口(BCM) | 描述 |
| 3V3 | 3V3 | 3.3V电源正 |
| GND | GND | 电源地 |
| RXD | RXD | 串口接收 |
| TXD | TXD | 串口发送 |
| RSE | 4 | 设置收发 |

对于RSE引脚,可以选择不使用,模块出厂默认使用的是硬件自动接收与发送。

硬件说明

CAN总线

CAN 模块的功能是处理所有 CAN 总线上的报文接收和发送。报文发送时,首先将报文装载到正确的报文缓冲器和控制寄存器中。通过 SPI 接口设置控制寄存器中的相应位或使用发送使能引脚均可启动发送操作。通过读取相应的寄存器可以检查通讯状态和错误。 会对在 CAN总线上检测到的任何报文进行错误检查,然后与用户定义的滤波器进行匹配,以确定是否将报文移到两个接收缓冲器中的一个。
由于树莓派本身并不支持CAN总线,因此使用SPI接口的CAN控制器,搭配一个收发器完成CAN功能。 Microchip 的 MCP2515 是一款CAN协议控制器,完全支持 CAN V2.0B 技术规范。该器件能发送和接收标准和扩展数据帧以及远程帧。 MCP2515 自带的两个验收屏蔽寄存器和六个验收滤波寄存器可以过滤掉不想要的报文,因此减少了主单片机(MCU)的开销。MCU通过SPI接口与该器件连接,即树莓派通过SPI接口连接芯片,对于树莓派使用该芯片不需要编写驱动,只需要打开设备树中的内核驱动即可使用。


更多详细请参考数据手册;
SN65HVD230 是德州仪器公司生产的 3.3V CAN 收发器,该器件适用于较高通信速率、良好抗干扰 能力和高可靠性 CAN 总线的串行通信。SN65HVD230 具有高速、斜率和等待 3 种不同的工作模式。 其工作模式控制可通过 Rs 控制引脚来实现。CAN 控制器的输出引脚 Tx 接到 SN65HVD230 的数据 输入端 D,可将此 CAN 节点发送的数据传送到 CAN 网络中;而 CAN 控制器的接收引脚 Rx 和 SN65HVD230 的数据输出端 R 相连,用于接收数据。
RS485 CAN HAT SN65HVD230.png

RS485总线

SP3485接口芯片是一种RS-485驱动芯片。用于RS-485通信的低功耗收发器。 采用单一电源+3.3V工作,采用半双工通讯方式。RO和DI端分别为接收器的输出和驱动器的输入端;(RE) ̅和DE端分别为接收和发送的使能端,当(RE) ̅为逻辑0时,器件处于接收状态;当DE为逻辑1时,器件处于发送状态;A端和B端分别为接收和发送的差分信号端,当A-B>+0.2V时,RO输出逻辑1;当A-B<-0.2V时,RO输出逻辑0。A和B端之间加匹配电阻,一般可选100Ω的电阻。


其中:SP3485芯片的RE与DE管脚是设置接收与发送;
本模块默认的出厂设置是采用硬件自动的收发,也可以选择软件上控制管脚来选择发送与接收,可以通过焊接板上的0欧姆电阻来选择控制方式。
硬件自动控制:
RS485 CAN HAT 485SR.png

数据接收:P_TX此时为高电平, 为休闲状态。这时候三级管导通,SP3485芯片的RE引脚为低电平,数据接收使能,RO开始接收数据,将485AB口接受到的数据传到MCU。
数据发送:P_TX会有一个下拉的电平,表示开始发送数据,此时三极管截止,DE引脚为高电平,数据发送使能。此时,如果发送的数据为‘1’的时候,三极管会处于导通,虽然接收会变为有效状态但由于芯片在发送阶段时是高阻状态,所以还是保持发送状态,正常传输‘1’。
注意:使用自动收发由于三级管的通断的速度问题,会导致自动收发的波特率无法做到太高,如果需要很高的波特率建议使用收动收发。

树莓派使用

安装库

  • 安装BCM2835, 打开树莓派终端,并运行一下指令
  1. wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.60.tar.gz
  1. tar zxvf bcm2835-1.60.tar.gz
  2. cd bcm2835-1.60/
  3. sudo ./configure
  4. sudo make
  5. sudo make check
  6. sudo make install
  7. 更多的可以参考官网:http://www.airspayce.com/mikem/bcm2835/
  • 安装wiringPi
  1. sudo apt-get install wiringpi
  1. 对于树莓派4B可能需要进行升级:

  2. wget https://project-downloads.drogon.net/wiringpi-latest.deb
  3. sudo dpkg -i wiringpi-latest.deb
  4. gpio -v
  5. 运行gpio -v会出现2.52版本,如果没有出现说明安装出错
  • python
  1. sudo apt-get update
  1. sudo apt-get install python-serial
  2. sudo pip install python-can

下载例程

在树莓派终端运行:

  1. sudo apt-get install p7zip-full
  1. wget http://www.waveshare.net/w/upload/d/de/RS485_CAN_HAT_Code.7z
  2. 7z x RS485_CAN_HAT_Code.7z -r -o./RS485_CAN_HAT_Code
  3. sudo chmod 777 -R RS485_CAN_HAT_Code/

CAN使用

本演示程序使用了两个树莓派以及两个RS485 CAN HAT模块
提供python与c语言程序

前置工作

将模块插在树莓派上,然后修改开机脚本config.txt

  1. sudo nano /boot/config.txt

在最后一行加入如下:

  1. dtparam=spi=on
  1. dtoverlay=mcp2515-can0,oscillator=12000000,interrupt=25,spimaxfrequency=2000000

其中oscillator=12000000,是板载的晶振大小12M,如下图

  • 如果购买日期早于2019年8月份,请使用下面的:

如图,红色框内为8M的晶振

  1. dtparam=spi=on
  1. dtoverlay=mcp2515-can0,oscillator=8000000,interrupt=25,spimaxfrequency=1000000

保存退出后,重启树莓派:

  1. sudo reboot

重启后,运行命令查看是否初始化成功:

  1. dmesg | grep -i '(can|spi)'


如果不接上模块可能提示如下:
RS485 CAN HAT CAN2.png

请检查是否连接上模块。是否开启SPI并开启MCP2515内核驱动。是否进行重启。
确定好两边树莓派都这样处理了,把两个模块的H与L对应连接
如果使用的是其他的CAN设备,确定连线H-H,L-L即可

C

  • 阻塞接收,树莓派打开终端,运行:
  1. cd RS485_CAN_HAT_Code/RS485_CAN_HAT_Code/CAN/wiringPi/receive/
  1. make clean
  2. make
  3. sudo ./can_receive

接收程序是阻塞的,直到读取到数据就结束。

  • 发送,树莓派打开终端,运行:
  1. cd RS485_CAN_HAT_Code/RS485_CAN_HAT_Code/CAN/wiringPi/receive/
  1. make clean
  2. make
  3. sudo ./can_send

此时接收接收到对应的id的报文:

python

树莓派打开终端,运行:

  1. cd RS485_CAN_HAT_Code/RS485_CAN_HAT_Code/CAN/python/
  1. 先运行接收:

  2. sudo python can_reveive.py
  3. 发送端:

  4. sudo python can_send.py

RS485使用

本演示程序使用了两个树莓派以及两个RS485 CAN HAT模块
提供python与wiringPi语言程序

前置工作

开启Uart接口

打开树莓派终端,输入以下指令进入配置界面

  1. sudo raspi-config
  1. 选择Interfacing Options -> Serial,关闭shell访问,打开硬件串口

</pre>

然后重启树莓派:

  1. sudo reboot

打开/boot/config.txt文件,找到如下配置语句使能串口,如果没有,可添加在文件最后面。

  1. enable_uart=1

对于树莓派3B用户,串口用于蓝牙,需要注释掉:

  1. dtoverlay=pi3-miniuart-bt

然后重启树莓派:

  1. sudo reboot

确定好两边树莓派都这样处理了,把两个模块的A与B对应连接
如果使用的是其他的485设备,确定连线A-A,B-B即可

C

  • 阻塞接收,树莓派打开终端,运行:
  1. cd RS485_CAN_HAT_Code/RS485_CAN_HAT_Code/485/WiringPi/send
  1. make clean
  2. make
  3. sudo ./485_receive

接收程序是阻塞的,直到读取到数据就结束。

  • 发送,树莓派打开终端,运行:
  1. cd RS485_CAN_HAT_Code/RS485_CAN_HAT_Code/485/WiringPi/send
  1. make clean
  2. make
  3. sudo ./485_send

此时接收端接收到程序

python例程

  1. cd RS485_CAN_HAT_Code/RS485_CAN_HAT_Code/485/python/
  1. 先运行接收:

  2. sudo python reveive.py
  3. 发送端:

  4. sudo python send.py

故障排查

如果485通信不正常,请分步调试:

  1. 确定树莓派的硬件版本,如果是树莓派ZERO/3B,则程序中的串口需要修改成/dev/ttyAMA0;
  2. 确定485的A,B是否与控制的485设备A,B一一对应;
  3. 可以先使用USB to 485设备与RS485 CAN HAT通信,保证树莓派的设置没有问题;

原理图

Can485原理图.JPG

485Demo

receive.py

# -*- coding:utf-8 -*-
import RPi.GPIO as GPIO
import serial
import time

#if use half-auto, EN_485 = LOW is Receiver, EN_485 = HIGH is Send
MODE = 0 #mode = 0 is full-guto, mode = 1 is half-auto
if MODE == 1:
    EN_485 =  4
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(EN_485,GPIO.OUT)
    GPIO.output(EN_485,GPIO.HIGH)

ser = serial.Serial("/dev/ttyS0",115200,timeout=0.01) #receive data once every 0.01S 
print ser.portstr

ser.flushInput()

data = ""
print("You can always receive data, press Ctrl + C to exit")
while 1: 
    while ser.inWaiting() > 0:
        data = ser.readline()
    if data != "":
        print(data)
        data = ""

send.py

# -*- coding:utf-8 -*-
import RPi.GPIO as GPIO
import serial

#if use half-auto, EN_485 = LOW is Receiver, EN_485 = HIGH is Send
MODE = 0 #mode = 0 is full-guto, mode = 1 is half-auto
if MODE == 1:
    EN_485 =  4
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(EN_485,GPIO.OUT)
    GPIO.output(EN_485,GPIO.HIGH)

ser = serial.Serial("/dev/ttyS0",115200,timeout=1) 
print ser.portstr

command = "hello world"
print("send:"),command  
len = ser.write(command)    
print("len = "),len

print("You can always send data, press Ctrl + C to exit")
while 1:
    strInput = raw_input('enter some words:')  
    ser.write(strInput)

ser.flush()

485_receive.c

#include <wiringSerial.h>
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>     //exit()
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <sys/time.h>

// if use half-auto, EN_485 = LOW is Receiver, EN_485 = HIGH is Send
#define MODE 0 //mode = 0 is full-guto, mode = 1 is half-auto
#define EN_485 4
#define UART_DEV "/dev/ttyS0"

int fd;

void  Handler(int signo)
{
    //System Exit
    printf("\r\nHandler:serialClose \r\n");
    serialClose(fd);

    exit(0);
}

int main(void)
{
    // Exception handling:ctrl + c
    signal(SIGINT, Handler);

    if(MODE == 1){
        if(wiringPiSetupGpio() < 0) { //use BCM2835 Pin number table
            printf("set wiringPi lib failed !!! \r\n");
            return 1;
        } else {
            printf("set wiringPi lib success  !!! \r\n");
        }
        pinMode(EN_485, OUTPUT);
        digitalWrite(EN_485,LOW);
    }

    if((fd = serialOpen(UART_DEV, 115200)) < 0) {
        printf("serial err\n");
        return -1;
    }
    printf("use device %s\r\n", UART_DEV);

    printf("You can always receive data, press Ctrl + C to exit\r\n");
    char str;
    for (;;) {
        str = serialGetchar(fd);
        if(str < 128) // ascii
            printf("%c", str);
        fflush(stdout); // Empty the output buffer and output the contents of the buffer
    }
    return 0;
}

485_send.c

#include <wiringSerial.h>
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>     //exit()
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <sys/time.h>

// if use half-auto, EN_485 = LOW is Receiver, EN_485 = HIGH is Send
#define MODE 0 //mode = 0 is full-guto, mode = 1 is half-auto
#define EN_485 4
#define UART_DEV "/dev/ttyS0"

int fd;

void  Handler(int signo)
{
    //System Exit
    printf("\r\nHandler:serialClose \r\n");
    serialClose(fd);

    exit(0);
}

int main(void)
{
    if(MODE == 1){
        if(wiringPiSetupGpio() < 0) { //use BCM2835 Pin number table
            printf("set wiringPi lib failed !!! \r\n");
            return 1;
        } else {
            printf("set wiringPi lib success  !!! \r\n");
        }
        pinMode(EN_485, OUTPUT);
        digitalWrite(EN_485,HIGH);
    }

    printf("use device %s\r\n", UART_DEV);
    if((fd = serialOpen(UART_DEV, 115200)) < 0) {
        printf("serial err\n");
        return -1;
    }

    serialFlush(fd);
    serialPrintf(fd,"\r");
    char str[] = "hello world\n";
    printf("send data:%s\r\n", str);
    serialPuts(fd, str);

    char str_buf[100];
    printf("You can always receive data, press Ctrl + C to exit\r\n");
    printf("You can enter up to %d characters\r\n", sizeof(str_buf));
    for(;;){        
        scanf("%s", str_buf); 
        strcat(str_buf,"\n"); //Add newline
        serialPuts(fd, str_buf);
    }

    serialClose(fd);
    return 0;
}

can_receive.py

import os
import can

os.system('sudo ip link set can0 type can bitrate 100000')
os.system('sudo ifconfig can0 up')

can0 = can.interface.Bus(channel = 'can0', bustype = 'socketcan_ctypes')# socketcan_native

#msg = can.Message(arbitration_id=0x123, data=[0, 1, 2, 3, 4, 5, 6, 7], extended_id=False)
msg = can0.recv(10.0)
print msg
if msg is None:
    print('Timeout occurred, no message.')

os.system('sudo ifconfig can0 down')

can_send.py

import os
import can

os.system('sudo ip link set can0 type can bitrate 100000')
os.system('sudo ifconfig can0 up')

can0 = can.interface.Bus(channel = 'can0', bustype = 'socketcan_ctypes')# socketcan_native

msg = can.Message(arbitration_id=0x123, data=[0, 1, 2, 3, 4, 5, 6, 7], extended_id=False)
can0.send(msg)

os.system('sudo ifconfig can0 down')

can_receive.c


```cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>

int main()
{
    int ret;
    int s, nbytes;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;
    
    memset(&frame, 0, sizeof(struct can_frame));
    
    system("sudo ip link set can0 type can bitrate 100000");
    system("sudo ifconfig can0 up");
    printf("this is a can receive demo\r\n");
    
    //1.Create socket
    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (s < 0) {
        perror("socket PF_CAN failed");
        return 1;
    }
    
    //2.Specify can0 device
    strcpy(ifr.ifr_name, "can0");
    ret = ioctl(s, SIOCGIFINDEX, &ifr);
    if (ret < 0) {
        perror("ioctl failed");
        return 1;
    }

    //3.Bind the socket to can0
    addr.can_family = PF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0) {
        perror("bind failed");
        return 1;
    }
    
    //4.Define receive rules
    struct can_filter rfilter[1];
    rfilter[0].can_id = 0x123;
    rfilter[0].can_mask = CAN_SFF_MASK;
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

    //5.Receive data and exit
    while(1) {
        nbytes = read(s, &frame, sizeof(frame));
        if(nbytes > 0) {
            printf("can_id = 0x%X\r\ncan_dlc = %d \r\n", frame.can_id, frame.can_dlc);
            int i = 0;
            for(i = 0; i < 8; i++)
                printf("data[%d] = %d\r\n", i, frame.data[i]);
            break;
        }
    }
    
    //6.Close the socket and can0
    close(s);
    system("sudo ifconfig can0 down");
    
    return 0;
}

can_send.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>

int main()
{
    int ret;
    int s, nbytes;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;
    memset(&frame, 0, sizeof(struct can_frame));

    system("sudo ip link set can0 type can bitrate 100000");
    system("sudo ifconfig can0 up");
    printf("this is a can send demo\r\n");
        
    //1.Create socket
    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (s < 0) {
        perror("socket PF_CAN failed");
        return 1;
    }
    
    //2.Specify can0 device
    strcpy(ifr.ifr_name, "can0");
    ret = ioctl(s, SIOCGIFINDEX, &ifr);
    if (ret < 0) {
        perror("ioctl failed");
        return 1;
    }
    
    //3.Bind the socket to can0
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0) {
        perror("bind failed");
        return 1;
    }
    
    //4.Disable filtering rules, do not receive packets, only send
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);

    //5.Set send data
    frame.can_id = 0x123;
    frame.can_dlc = 8;
    frame.data[0] = 1;
    frame.data[1] = 2;
    frame.data[2] = 3;
    frame.data[3] = 4;
    frame.data[4] = 5;
    frame.data[5] = 6;
    frame.data[6] = 7;
    frame.data[7] = 8;
    
    printf("can_id  = 0x%X\r\n", frame.can_id);
    printf("can_dlc = %d\r\n", frame.can_dlc);
    int i = 0;
    for(i = 0; i < 8; i++)
        printf("data[%d] = %d\r\n", i, frame.data[i]);
    
    //6.Send message
    nbytes = write(s, &frame, sizeof(frame)); 
    if(nbytes != sizeof(frame)) {
        printf("Send Error frame[0]!\r\n");
        system("sudo ifconfig can0 down");
    }
    
    //7.Close the socket and can0
    close(s);
    system("sudo ifconfig can0 down");
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容

  • 穿越巅峰阅读 118评论 0 0
  • 有时候一个不经意的动作会让人生气,有时候一个不经意的动作会让两个相爱的人分离;候一个不经意的动作会让两个相...
    林月花溪阅读 343评论 0 0
  • 这串佛珠或是朋友对生活的感悟 或是对上苍的感恩 是对生命的苦行 又或是对蓝天白云青山碧水的赞叹 让我欣赏到了一种独...
    云翼_d2e8阅读 332评论 5 12
  • 文/凡人仆 第三章:措手不及而来的“穷病” “明天准备好应战了吗?” 阿笑在电话那边问我,对于应届毕业生找实习单位...
    凡人仆阅读 420评论 8 6
  • 事实是既成的,所以有其客观性,它独立于我们的观念而存在。事实需要我们主动去认识从而获得一手资料。如果没有条件获得...
    blueberry_mran阅读 621评论 0 0