BF7006学习笔记7 - CAN

BF7006学习笔记7 - CAN目录 1 初始化 1 1 选择时钟源 1 2 复位 CAN 模块 1 3 CAN 跨时域计数时间配置 1 4 使能 CAN 模块 1 5 设置 CAN 为置位模式 1 6 设置 CAN 模式 1 7 设置波特率 1 7 1 CAN BTR0 的位 0 5 设置时钟预设值 1 7 2 CAN BTR1 的 0 6 设置波特率 1 8

大家好,我是讯享网,很高兴认识大家。

目录

1. 初始化

1.1 选择时钟源

1.2 复位CAN模块

1.3 CAN跨时域计数时间配置

1.4 使能CAN模块

1.5 设置CAN为置位模式

1.6 设置CAN模式

1.7 设置波特率

1.7.1 CAN_BTR0的位0:5设置时钟预设值

1.7.2 CAN_BTR1的0:6设置波特率

1.8 设置同步跳转宽度

1.9 设置采样次数

1.10 设置错误报警限制值

1.11 设置验收滤波

1.11.1 单滤波标准帧

1.11.2 单滤波扩展帧

1.11.3 双滤波标准帧

1.12 退出置位模式

1.13 初始化中断

2. 发送数据

2.1 判断总线是否忙

2.2 设置帧参数

2.3 设置ID

2.4 设置数据

2.5 使能发送

3. 接收数据

3.1 中断接收函数

3.2 获取帧数据数量

3.3 读入帧数据

4. 验证

4.1 单滤波标准帧

 4.2 单滤波扩展帧

4.3 双滤波标准帧


BF7006只有一组CAN总线,最高支持500Kbit/s,支持CAN总线协议2.0A 和2.0B(支持扩展格式)。

1. 初始化

1.1 选择时钟源

支持2个时钟源:系统时钟和外部晶振时钟。通过SYS_CAN_CLKSEL寄存器设置


讯享网

由于推荐使用外部晶振时钟,所以这个寄存器一般设置为0即可。这里判断一下是否是使用内部RC振荡器,如果是内部RC则选择系统时钟。

  if(SYS_PLL_SOURCE_SEL == 0xACB3) //Using SYS_PLL_SEL_RC1M { SYS_CAN_CLKSEL = 0x01; fSRC = 32; } else { SYS_CAN_CLKSEL = 0; //Default select extra crystal. if(SYS_PLL_SOURCE_SEL == 0xCCD2) //XTAL = 16M fSRC = 16; else if(SYS_PLL_SOURCE_SEL == 0x8D9C) //XTAL = 8M fSRC = 8; }

讯享网

1.2 复位CAN模块

通过SYS_CAN_RST寄存器设置。

讯享网SYS_CAN_RST = 0x00; //Reset can SYS_CAN_RST = 0x01;

1.3 CAN跨时域计数时间配置

通过SYS_CAN_DOMAIN寄存器设置。

 这个寄存器配置的含义不太清晰,也没有详细的说明。板子本身是16M晶振,32M的系统时钟,按道理应该设置为0x02,但是例程设置为0x04。另外,外部晶振可以是12MHz的选项,但是这里没有设置,不知道是不是12M不支持CAN?

SYS_CAN_DOMAIN = 0x04; if(SystemCoreClock == 32*1000*1000) { if(SYS_PLL_SOURCE_SEL == 0x8D9C) //XTAL = 8M SYS_CAN_DOMAIN = 0x04; else if(SYS_PLL_SOURCE_SEL == 0xCCD2) //XTAL = 16M SYS_CAN_DOMAIN = 0x02; } else if(SystemCoreClock == 16*1000*1000) { if(SYS_PLL_SOURCE_SEL == 0x8D9C) //XTAL = 8M SYS_CAN_DOMAIN = 0x02; else if(SYS_PLL_SOURCE_SEL == 0xCCD2) //XTAL = 16M SYS_CAN_DOMAIN = 0x01; } else if(SystemCoreClock == 8*1000*1000) { SYS_CAN_DOMAIN = 0x01; }

1.4 使能CAN模块

通过CAN_ENABLE寄存器使能CAN模块,虽然使能了CAN模块,但是CAN并没有开始工作,还需要退出置位模式。

讯享网CAN_ENABLE = 0x01;

1.5 设置CAN为置位模式

通过CAN_MOD寄存器的位0设置为置位模式,复位是1,即默认是置位模式。

CAN_MOD |= 0x01;

1.6 设置CAN模式

通过CAN_MOD寄存器的位1:2设置和CAN_CMR寄存器的位4设置4种模式:普通模式、只听模式、自测试模式和自接收模式。

讯享网CAN_MOD &= 0xF9; switch(mode) { case CAN_MODE_LISTEN_ONLY: CAN_MOD |= (1 << 1); break; case CAN_MODE_SELF_TEST: CAN_MOD |= (1 << 2); break; case CAN_MODE_SELF_RECEIVE: CAN_CMR |= (1 << 4); break; default: break; }

1.7 设置波特率

通过CAN_BTR0和CAN_BTR1寄存器设置波特率。

1.7.1 CAN_BTR0的位0:5设置时钟预设值

CAN通信时钟周期 = 2 * CAN模块时钟周期 *( CAN_BTR0_BRP+1) 即

CAN模块时钟频率 = 2 * CAN通信时钟频率  * ( CAN_BTR0_BRP+1)

CAN_BTR0_BRP = CAN模块时钟频率 / (2 * CAN通信时钟频率)- 1,设CAN模块时钟频率为fSRC, CAN通信时钟频率为fCAN,CAN通信时钟频率这个没有说明,只能通过例程推导。当波特率=1M时,CAN_BTR0_BRP一定为0,fCAN为fSRC的一半,fCAN最大16M,最小8M;当波特率=500K时,fSRC为32M,CAN_BTR0_BRP为1,fCAN = fSRC / 4 = 8,fSRC为16M/8M,CAN_BTR0_BRP为0,fCAN = fSRC / 2 = 8M/4M;当波特率=250K时,fSRC为32M,CAN_BTR0_BRP为3,fCAN = fSRC / 8 = 4,fSRC为16M,CAN_BTR0_BRP为1,fCAN = fSRC / 4 = 4,fSRC为8M,CAN_BTR0_BRP为0,fCAN = fSRC / 2 = 4M。

推导出公式:fCAN = baud * 16。baud = 1M时,fCAN最大16M,符合例程要求;baud = 500K时,fCAN最大8M;baud = 250K时,fCAN最大4M;baud = 400K时,fCAN最大6.4M(例程32M频率是最大8MHz)。

if(fSRC * 1000 * 1000 / 2 > (baud * 16)) CAN_BTR0 = ((fSRC * 1000 * 1000 / 2) / (baud * 16) - 1); else CAN_BTR0 = 0;

1.7.2 CAN_BTR1的0:6设置波特率

由于fCAN = 1 / (2 * CAN模块时钟周期 * (1 + BRP)),所以baud = fCAN / (3 + TSEG1 + TSEG2),即

TSEG1 + TSEG2= fCAN / baud - 3

TSEG1和TSEG2的关系是如何计算的没有说明,不知道内在联系是什么。

baud = 1M:fSRC = 32M时,TSEG = 16 / 1 - 3 = 13, 例程设置SEG1 = 10, SEG2 =3;fSRC = 16M时,TSEG = 8 / 1 - 3 = 5,SEG1 =  4, SEG2 = 1。

baud = 500K:fSRC = 32M时,TSEG = 8 / 0.5 - 3 = 13;fSRC = 16M时,TSEG = 8 / 0.5 - 3 = 13;fSRC = 8M时,TSEG = 4 / 0.5 - 3 = 5。

baud = 400K:fSRC = 32M时,TSEG = 8 / 0.4 - 3 = 17, SEG1 = 13, SEG2 = 7;fSRC = 8M时,TSEG = 4 / 0.4 - 3 = 7,SEG1 = 5,SEG2 = 2。

从结果推导,SEG1 = SEG * 4 / 5,SEG2 = SEG * 1 / 5。

讯享网fCAN = (fSRC * 1000 * 1000) / (2 * (CAN_BTR0 + 1)); tmp = fCAN / baud - 3; //TSEG1 + TSEG2 CAN_BTR1 = ((tmp * 4 / 5) | ((tmp / 4) << 4)) & 0x7f;

1.8 设置同步跳转宽度

通过CAN_BTR0寄存器的位6:7位设置

SJW 加大后允许误差加大,但通信速度下降。SJW 为补偿此误差的最大值(即每一次误差补偿都不能超过这个值,1~4Tq)。

例程设置为0,即同步跳转宽度 = 时钟预设值。

1.9 设置采样次数

通过CAN_BTR1寄存器的位7位设置。

例程设置为1,即采样3次。

CAN_BTR1 |= 0x80; //3 sample times

1.10 设置错误报警限制值

通过CAN_EMLR寄存器设置

讯享网CAN_EMLR = 100;

1.11 设置验收滤波

数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有 11 个位的 ID,扩展格式有 29 个位的 ID。ID的设置就对应验收滤波,BF7006的验收滤波由4个8位的验收码寄存器(CAN_IDAR0 / CAN_IDAR1 / CAN_IDAR2 / CAN_IDAR3)和屏蔽码寄存器(CAN_IDMR0 / CAN_IDMR1 / CAN_IDMR2 / CAN_IDMR3)组成。长滤波对应29个位的ID,短滤波对应11个位的ID,而且BF7006可以设置为单滤波或双滤波器,当设置为双滤波器时,只能设置2个短滤波。

屏蔽码寄存器的位设置为1时,对应ID的位无关。例如屏蔽码的第三位为0,则验收码的第三位必须与接收到的报文的第三位一致才能把报文接收,如果屏蔽器的第三位为1,则说明不关心这个位。

1.11.1 单滤波标准帧

ID为11位,即标准帧的ID位数, 一个标准帧的结构如下图所示:

例如ID为0x7E1, 即0b 0[111 1110 0001],只有中括号内的11位才有效,IDAR0等于0b 0[111 1110 0001]的红色部分,即IDAR0 = 0b1111 1100,IDAR1等于0b 0[1111 1100 001]的红色部分,即IDAR1 = 0b001x xxxx。IDAR1的位4表示是否过滤数据帧(0)还是远程帧(1)。对于IDAR2和IDAR3,可以用于设置数据的前2个字节过滤。同理设置IDMR寄存器。

case CAN_TYPE_SINGLE_STANDARD: CAN_IDAR0 = (uint8_t)(accept >> 3); CAN_IDAR1 = (uint8_t)(accept << 5); CAN_IDAR2 = (uint8_t)(accept >> 16); CAN_IDAR3 = (uint8_t)(accept >> 24); CAN_IDMR0 = (uint8_t)(mask >> 3); CAN_IDMR1 = (uint8_t)(mask << 5); CAN_IDMR2 = (uint8_t)(mask >> 16); CAN_IDMR3 = (uint8_t)(mask >> 24); mod |= (1 << 3); //Single filter break;

是否过滤数据帧还是远程帧,可以通过accept和mask的位11决定

讯享网if((accept & ((uint32_t)1 << 11)) > 0) CAN_IDAR1 |= ((uint8_t)0x01 << 4); if((mask & ((uint32_t)1 << 11)) > 0) CAN_IDMR1 |= ((uint8_t)0x01 << 4);

IDAR1和IDMR1的低4位没有使用,所以最好设置为1。

CAN_IDAR1 |= 0x0F; CAN_IDMR1 |= 0x0F;

1.11.2 单滤波扩展帧

ID为29位,即扩展帧的ID位数,一个扩展帧的结构如下图所示:

 例如扩展ID为0x1835f107,即0b 000[1 1000 0011 10][01 1111 0001 0000 0111],左边的中括号和标准帧一样,右边的中括号为18位的扩展ID。IDAR0等于0b 000[1 1000 0011 10][01 1111 0001 0000 0111]的红色部分,即IDAR0 = 0b1100 0001,IDAR1等于0b 000[1 1000 0011 10][01 1111 0001 0000 0111]的红色部分,即IDAR1 = 0b1100 1111,IDAR2等于0b 000[1 1000 0011 10][01 1111 0001 0000 0111]的红色部分,即IDAR2 = 0b1000 1000,IDAR3等于0b 000[1 1000 0011 10][01 1111 0001 0000 0111]的红色部分,即IDAR3 = 0b0011 1xxx。

讯享网case CAN_TYPE_SINGLE_EXTEND: CAN_IDAR0 = (uint8_t)(accept >> 21); CAN_IDAR1 = (uint8_t)(accept >> 13); CAN_IDAR2 = (uint8_t)(accept >> 5); CAN_IDAR3 = (uint8_t)(accept << 3); CAN_IDMR0 = (uint8_t)(mask >> 21); CAN_IDMR1 = (uint8_t)(mask >> 13); CAN_IDMR2 = (uint8_t)(mask >> 5); CAN_IDMR3 = (uint8_t)(mask << 3); mod |= (1 << 3); //Single filter break;

从上面2种情况可以看出,低位寄存器保存的是高位的ID或MASK。

IDAR3的位2表示是否过滤数据帧还是远程帧。

if((accept & ((uint32_t)1 << 29)) > 0) CAN_IDAR3 |= ((uint8_t)0x01 << 2); //CAN_FRAME_REMOTE if((mask & ((uint32_t)1 << 29)) > 0) CAN_IDMR3 |= ((uint8_t)0x01 << 2);

同样,IDAR3和IDMR3的低2位没有使用,设置为1。

讯享网CAN_IDAR3 |= 0x03; CAN_IDMR3 |= 0x03;

1.11.3 双滤波标准帧

双滤波是通过2个16位的标准帧设置的,所以每2个寄存器组成一个单滤波即可。

case CAN_TYPE_DOUBLE_STANDARD: CAN_IDAR0 = (uint8_t)(accept >> 3); CAN_IDAR1 = (uint8_t)(accept << 5); CAN_IDAR2 = (uint8_t)((accept >> 16) >> 3); CAN_IDAR3 = (uint8_t)((accept >> 16) << 5); CAN_IDMR0 = (uint8_t)(mask >> 3); CAN_IDMR1 = (uint8_t)(mask << 5); CAN_IDMR2 = (uint8_t)((mask >> 16) >> 3); CAN_IDMR3 = (uint8_t)((mask >> 16) << 5); if((accept & ((uint16_t)1 << 11)) > 0) CAN_IDAR1 |= ((uint8_t)0x01 << 4); if((mask & ((uint16_t)1 << 11)) > 0) CAN_IDMR1 |= ((uint8_t)0x01 << 4); if((accept & (((uint32_t)1 << 16) << 11)) > 0) CAN_IDAR3 |= ((uint8_t)0x01 << 4); if((mask & (((uint32_t)1 << 16) << 11)) > 0) CAN_IDMR3 |= ((uint8_t)0x01 << 4); CAN_IDAR1 |= (uint8_t)((accept >> 12) & 0x0F); CAN_IDMR1 |= (uint8_t)((mask >> 12) & 0x0F); CAN_IDAR3 |= 0x0F; CAN_IDMR3 |= 0x0F; mod &= ~(1 << 3); break;

这里有个特殊的地方,IDAR1和IDMR1对应的低4位是可以设置过滤条件的,对应DATA0的高4位。

1.12 退出置位模式

讯享网CAN_MOD &= ~0x01; //Exit setting mode

1.13 初始化中断

通过CAN_IE寄存器使能接收中断。

CAN_IE = 0x01; NVIC_EnableIRQ(CAN_RX_IRQn);

2. 发送数据

接口函数:

讯享网bool_t canWriteBytes(uint8_t port, canFrame_st stFrame)

帧结构:

typedef struct { uint32_t id; uint8_t format:1; //1:extend frame; 0:standard frame uint8_t type:1; //1:remote frame; 0:data frame uint8_t resv:6; uint8_t len; uint8_t dat[8]; }canFrame_st;

2.1 判断总线是否忙

通过CAN_SR寄存器的位2和位3判断是否可以发送数据。

讯享网while(((CAN_SR & (1 << 2)) == 0) || ((CAN_SR & (1 << 3)) == 0));

2.2 设置帧参数

通过CAN_FRCTL寄存器设置。

temp = stFrame.len & 0x0f; if(stFrame.format == 1) temp |= 0x80; if(stFrame.type == 1) temp |= 0x40; CAN_FRCTL = temp;

2.3 设置ID

根据帧类型通过CAN_ID0~3设置

讯享网if(stFrame.format == 1) //extend frame { CAN_ID0 = (uint8_t)(stFrame.id >> 21); CAN_ID1 = (uint8_t)(stFrame.id >> 13); CAN_ID2 = (uint8_t)(stFrame.id >> 5); CAN_ID3 = (uint8_t)(stFrame.id << 3); } else //standard frame { CAN_ID0 = (uint8_t)(stFrame.id >> 3); CAN_ID1 = (uint8_t)(stFrame.id << 5); CAN_ID2 = 0; CAN_ID3 = 0; }

2.4 设置数据

CAN_DATA0 = stFrame.dat[0]; CAN_DATA1 = stFrame.dat[1]; CAN_DATA2 = stFrame.dat[2]; CAN_DATA3 = stFrame.dat[3]; CAN_DATA4 = stFrame.dat[4]; CAN_DATA5 = stFrame.dat[5]; CAN_DATA6 = stFrame.dat[6]; CAN_DATA7 = stFrame.dat[7];

2.5 使能发送

讯享网CAN_CMR |= 0x01;

3. 接收数据

接收数据通过中断读入到缓冲中。

3.1 中断接收函数

对应的中断函数是void CAN_RX_IRQHandler(void)。

清除中断标志位:

//CAN_CLRISR = 0x01; SYS_CAN_SPWKFLAG = 0x01;

例程还会设置CAN_CLRISR,但是文档里面CAN_CLRISR的位0是保留位,无实际意义。

判断是否是RX中断:

讯享网if((CAN_IF & 0x01) == 0) //rx interrupt flag return;

把帧数据拷贝到全局缓冲中:

canFrame_st *pFrame; pFrame = (canFrame_st *)&gCanRecvFrame[gCanRecvIn[0]]; gCanRecvIn[0] += sizeof(canFrame_st);

读入ID和帧格式:

讯享网 tmp[0] = CAN_ID0; tmp[1] = CAN_ID1; tmp[2] = CAN_ID2; tmp[3] = CAN_ID3; /* save recive frame format and id */ if((CAN_FRCTL & 0x80) != 0) { pFrame->format = 1; //Extended frame pFrame->id = (uint32_t)((tmp[0] << 21U) | (tmp[1] << 13U) | (tmp[2] << 5U) | (tmp[3] >> 3U)); } else { pFrame->format = 0; //Standard frame pFrame->id = (uint32_t)((tmp[0] << 3U) | (tmp[1] >> 5U)); }

读入帧类型:

 /* save receive frame type */ if((CAN_FRCTL & 0x40) != 0) { pFrame->type = 1; } else { pFrame->type = 0; }

读入数据:

讯享网 /* save receive data lenth */ tmp[0] = CAN_FRCTL; pFrame->len = (uint8_t)(tmp[0] & 0x0f); if(pFrame->len > 0x08) { pFrame->len = 0x08U; } /* save receive data */ for(tmp[0] = 0; tmp[0] < pFrame->len; tmp[0]++) { pFrame->dat[tmp[0]] = CAN_DATA(tmp[0]); }

清除数据缓冲器状态和接收中断: 

CAN_CMR |= (1 << 2);

3.2 获取帧数据数量

讯享网///<summary> /// Get can frame number. ///</summary> ///<param name="port">can port</param> ///<returns>the number of received frame</returns> uint16_t canGetQueueStatus(uint8_t port) { uint16_t datLen = 0; uint16_t bufSize; bufSize = sizeof(gCanRecvFrame); datLen = (bufSize + gCanRecvIn[port] - gCanRecvRd[port]) % bufSize; datLen /= sizeof(canFrame_st); return datLen; }

3.3 读入帧数据

///<summary> /// Read can data. ///</summary> ///<param name="port">can port</param> ///<param name="*frame">the frame buffer</param> ///<param name="num">the number of the frame </param> ///<returns>fail or ok</returns> bool_t canReadBytes(uint8_t port, canFrame_st *frame, uint16_t num) { uint16_t bufSize; if(port >= HW_CAN_MAX) return FALSE; bufSize = sizeof(gCanRecvFrame); if(num > canGetQueueStatus(port)) { num = canGetQueueStatus(port); } while(num) { memcpy((uint8_t *)frame, (uint8_t *)gCanRecvFrame + gCanRecvRd[port], sizeof(canFrame_st)); num--; frame++; gCanRecvRd[port] += sizeof(canFrame_st); gCanRecvRd[port] %= bufSize; } return TRUE; }

4. 验证

4.1 单滤波标准帧

将CAN初始化为自检测模式,发送三帧数据,而过滤条件是ID为7Dx(x = 0...F),数据0必须为0x11。

讯享网canInit(HW_CAN0, 500*1000, CAN_MODE_SELFTEST); canSetFilter(HW_CAN0, CAN_TYPE_SINGLE_STANDARD, ((uint32_t)0xFF << 24) | ((uint32_t)0x11 << 16) | 0x07DF | ((uint32_t)1 << 11), ((uint32_t)0xFF << 24) | ((uint32_t)0x00 << 16) | 0x000F | ((uint32_t)1 << 11)); canFrame_st frame; frame.id = 0x7d1; frame.format = 0; frame.type = 0; frame.len = 8; frame.dat[0] = 0x11; frame.dat[1] = 0x22; frame.dat[2] = 0x33; frame.dat[3] = 0x44; frame.dat[4] = 0x55; frame.dat[5] = 0x66; frame.dat[6] = 0x77; frame.dat[7] = 0x88; canWriteBytes(HW_CAN0, frame); frame.dat[0] = 0xaa; canWriteBytes(HW_CAN0, frame); frame.id = 0x7ff; canWriteBytes(HW_CAN0, frame);

发送一帧数据,然后在循环中查询是否有数据,并打印到串口:

if(canGetQueueStatus(HW_CAN0) > 0) { canFrame_st frame; canReadBytes(HW_CAN0, &frame, 1); Printf("Can Frame:\n"); Printf("ID:%x\n", frame.id); Printf("format:%x\n", frame.format); Printf("type:%x\n", frame.type); Printf("len:%d\n", frame.len); Printf("Data:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", frame.dat[0], frame.dat[1], frame.dat[2], frame.dat[3], frame.dat[4], frame.dat[5], frame.dat[6], frame.dat[7]); }

打印结果:

讯享网Can Frame: ID:7d1 format:0 type:0 len:8 Data:0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88

可以看到第一帧的数据是符合过滤条件的,所以CAN有读到这帧数据;第二笔数据的第一个数据为0xaa,不是0x11,被过滤掉了;第三笔数据ID是0x7FF,不符合0x7Dx,也被过滤掉了。

过滤条件可以增加过滤是否数据帧或远程帧:

canSetFilter(HW_CAN0, CAN_TYPE_SINGLE_STANDARD, ((uint32_t)0xFF << 24) | ((uint32_t)0x11 << 16) | 0x07DF | ((uint32_t)1 << 11), ((uint32_t)0xFF << 24) | ((uint32_t)0x00 << 16) | 0x000F | ((uint32_t)0 << 11));

即将mask参数的位11设置为0,而accept参数的位11设置为0(数据帧通过)或1(远程帧通过),发送2帧测试:

讯享网canFrame_st frame; frame.id = 0x7d1; frame.format = 0; frame.type = 0; frame.len = 8; frame.dat[0] = 0x11; frame.dat[1] = 0x22; frame.dat[2] = 0x33; frame.dat[3] = 0x44; frame.dat[4] = 0x55; frame.dat[5] = 0x66; frame.dat[6] = 0x77; frame.dat[7] = 0x88; canWriteBytes(HW_CAN0, frame); frame.type = 1; frame.len = 0; canWriteBytes(HW_CAN0, frame);

打印结果:

Can Frame: ID:7d1 format:0 type:1 len:0 Data:0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0

注意,远程帧并没有数据,从结果看,第一帧数据被过滤了,接收到了第二帧远程帧数据。

 4.2 单滤波扩展帧

设置过滤条件为ID符合0x1835xxxx通过过滤。

讯享网canSetFilter(HW_CAN0, CAN_TYPE_SINGLE_EXTEND, 0x1835FFFF | ((uint32_t)1 << 29), 0x0000FFFF | ((uint32_t)1 << 29));
小讯
上一篇 2025-04-09 13:19
下一篇 2025-02-18 16:36

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/69395.html