ABOV 程序 – 移动监测运动平台控制

文章目录

提示:ABOV 实现多机通信控制,来实现移动监测运动平台的控制



前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、ABOV是什么?

在这里插入图片描述
在这里插入图片描述
ABOV半导体在2006年自韩国HYNIX分离出来,有超过20年单片机领域耕耘经验。ABOV半导体有单片机和标准IC另类产品

二、应用设定

1.应用场景设定

产品用于自动测试人体感应PIR对不同距离角度下感应效果

2.所使用的方法

1.Inventor 3维建模
2.ABOV单片机作为机械控制IC

IO输出 AD检测 串口通信

3.STM32单片机 作为系统终端控制IC
4.C# 作为电脑终端控制软件

3.最终实现的设定

实现对两台运动机构的控制,并完成机构上待测产品的测试 并将数据回传到多路终端

二、使用步骤

1.完成实验结构三维建模

主机构建模如下:

在这里插入图片描述
从机构建模如下:
在这里插入图片描述
两台构安装过后如下:
在这里插入图片描述

2.完成通信模式的构想

代码如下(示例):
在这里插入图片描述

3.完成从机调试

从机调试如下:

在这里插入图片描述

3.完成主机调试

三、从机制作

1.效果图

ABOV移动小车从机

ABOV从机移动效果

2.原理图

在这里插入图片描述
在这里插入图片描述

3.程序

代码源码下载---->
在这里插入图片描述

代码生成器配置:
在这里插入图片描述Keil完成代码后续:
在这里插入图片描述
OCD2完成仿真:
在这里插入图片描述

1.主程序

main.c:

//======================================================
// Main program routine
// - Device name  : MC95FG308
// - Package type : 28SOP
//======================================================
// For XDATA variable : V1.041.00 ~
#define		MAIN	1

// Generated    : Fri, Nov 12, 2021 (21:10:31)
#include	"MC95FG308.h"
#include	"func_def.h"

#include	"IO_code.h"
#include	"usart_code.h"
#include	"function_code.h"



void main()
{
	cli();          	// disable INT. during peripheral setting
	port_init();    	// initialize ports
	clock_init();   	// initialize operation clock
	ADC_init();     	// initialize A/D convertor
	Timer0_init();  	// initialize Timer0
	UART_init();    	// initialize UART interface
	sei();          	// enable INT.
	
	// TODO: add your main code here
	placeX_now = 0;	    //上电默认为0 坐标吧
	while(1){
   	   fn_function_check();  //在这里进行处理函数
	   // TODO: add other code here
	}
}

//======================================================
// interrupt routines
//======================================================

void INT_USART0_Rx() interrupt 6
{
	// USART0 Rx interrupt
	// TODO: add your code here
	dataR0  = UART_read(0);
	fn_check_usart(0,&dataR0);
	
	//UART_write(0,dataR0);
}

void INT_USART1_Rx() interrupt 10
{
	// USART1 Rx interrupt
	// TODO: add your code here
}

void INT_Timer0() interrupt 12
{
	// Timer0 interrupt
	// TODO: add your code here
	Led_Time_Change(100);
}

void INT_ADC() interrupt 18
{
	// ADC interrupt
	// TODO: add your code here
}

void INT_BIT() interrupt 22
{
	// BIT interrupt
	// TODO: add your code here
}

//======================================================
// peripheral setting routines
//======================================================

unsigned char UART_read(unsigned char ch)
{
	unsigned char dat;
	
	if (ch == (unsigned char)0) {	// UART0
		while(!(USTAT & 0x20));	// wait
		dat = UDATA;   	// read
	}
	if (ch == (unsigned char)1) {	// UART1
		while(!(USTAT1 & 0x20));	// wait
		dat = UDATA1;  	// read
	}
	return	dat;
}

unsigned int ADC_read()
{
	// read A/D convertor
	unsigned int adcVal;
	
	while(!(ADCM & 0x10));	// wait ADC busy
	adcVal = (ADCRH << 8) | ADCRL;	// read ADC
	ADCM &= ~0x40;  	// stop ADC
	return	adcVal;
}

void ADC_init()
{
	// initialize A/D convertor
	ADCM = 0x00;    	// setting
	ADCM2 = 0x04;   	// trigger source, alignment, frequency
	IEN3 |= 0x01;   	// enable ADC interrupt
}

void ADC_start(unsigned char ch)
{
	// start A/D convertor
	ADCM = (ADCM & 0xf0) | (ch & 0xf);	// select channel
	ADCM |= 0x40;   	// start ADC
}

void Timer0_init()
{
	// initialize Timer0
	// 8bit timer, period = 9.984000mS
	T0CR = 0x96;    	// timer setting
	T0DR = 0xE9;    	// period count
	IEN2 |= 0x01;   	// Enable Timer0 interrupt
	T0CR |= 0x01;   	// clear counter
}

void UART_init()
{
	// initialize UART interface
	// UART0 : ASync. 9615bps N 8 1
	UCTRL2 = 0x02;  	// activate UART0
	UCTRL1 = 0x06;  	// Async/Sync, bit count, parity
	UCTRL2 |= 0xAC; 	// interrupt, speed
	//UCTRL2 |= 0x10;	// enable line when you want to use wake up in STOP mode
	UCTRL3 = 0x00;  	// stop bit
	UBAUD = 0x4D;   	// baud rate

	// UART1 : ASync. 9615bps N 8 1
	UCTRL12 = 0x02; 	// activate UART1
	UCTRL11 = 0x06; 	// Async/Sync, bit count, parity
	UCTRL12 |= 0xAC;	// interrupt, speed
	//UCTRL12 |= 0x10;	// enable line when you want to use wake up in STOP mode
	UCTRL13 = 0x00; 	// stop bit
	UBAUD1 = 0x4D;  	// baud rate

	IEN1 |= 0x11;   	// enable UART interrupt
}

void UART_write(unsigned char ch, unsigned char dat)
{
	if (ch == (unsigned char)0) {	// UART0
		while(!(USTAT & 0x80));	// wait
		UDATA = dat;   	// write
	}
	if (ch == (unsigned char)1) {	// UART1
		while(!(USTAT1 & 0x80));	// wait
		UDATA1 = dat;  	// write
	}
}

void clock_init()
{
	// external clock
	cli();
	IEN3 |= 0x10;   	// Enable BIT interrupt
	sei();

	BCCR = 0x05;    	// 16msec BIT
	SCCR = 0x81;    	// External clock
	PCON = 0x03;    	// STOP1 mode entry
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	SCCR &= ~0x80;  	// clock changed
	IEN3 &= ~0x10;  	// Disable BIT interrupt
}

void port_init()
{
	// initialize ports
	//   3 : AN4      in  
	//   8 : P10      out 
	//   9 : P11      out 
	//  16 : TxD1     out 
	//  17 : RxD1     in  
	//  19 : XIN      in  
	//  20 : XOUT     out 
	//  25 : TxD0     out 
	//  26 : RxD0     in  
	//  28 : P31      out 
	P0IO = 0xE7;    	// direction
	P0PU = 0x08;    	// pullup
	P0OD = 0x00;    	// open drain
	P0DB = 0x00;    	// debounce
	P0   = 0x00;    	// port initial value

	P1IO = 0xFB;    	// direction
	P1PU = 0x00;    	// pullup
	P1OD = 0x00;    	// open drain
	P1DB = 0x00;    	// debounce
	P1   = 0x00;    	// port initial value

	P2IO = 0xFE;    	// direction
	P2PU = 0x00;    	// pullup
	P2OD = 0x00;    	// open drain
	P2DB = 0x00;    	// debounce
	P2   = 0x00;    	// port initial value

	P3IO = 0x7F;    	// direction
	P3PU = 0x80;    	// pullup
	P3OD = 0x00;    	// open drain
	P3DB = 0x00;    	// debounce
	P3   = 0x00;    	// port initial value

	// Set port function
	PSR0 = 0x10;    	// AN7 ~ AN0
	PSR1 = 0x00;    	// I2C, AN14 ~ AN8
}

1.IO程序

IO_code.h :


#ifndef		_IO_CODE_
#define		_IO_CODE_
#include	"MC95FG308.h"
#include	"func_def.h"

#define 	TIME_Goforward  	6	 //时间为前进控制时间
#define 	TIME_GoBACK_Long    18	 //时间为回退长控制时间
#define 	TIME_GoBACK_short   6	 //时间为回退短控制时间

#define 	IO_Goforward  P11  //IO口为前进控制口
#define 	IO_GoBACK	  P10  //IO口为后退控制口

unsigned int fn_IO_run(unsigned char distance);	      //前进控制程序
unsigned int fn_IO_goback(unsigned char back_time);   //后退控制程序

void delay_ms(unsigned int count);
void delay_us(unsigned int count);
void delay_s(unsigned int count);
void Led_Time_Change(unsigned int count);
void Led_flash(void);

#endif	 
 

IO_code.c :

#include	"IO_code.h"
#include	"usart_code.h" 
#include	"function_code.h"



/************************************************************
* @brief  
* unsigned int fn_IO_run(unsigned char distance)
* @param  
* @retval 
*************************************************************/ 
unsigned int fn_IO_run(unsigned char distance){	  // 前进控制程序
    unsigned  char xdistance;
	if(distance<=placeX_MIN){return 0;}	      // 前进不能小于最小位移坐标
	for(xdistance=0 ;xdistance<distance ;xdistance++ ){
		IO_Goforward = 1 ;
		delay_s(1);
		IO_Goforward = 0 ;			   //循环前进
	 	delay_s(TIME_Goforward);
		if(bdata_effect==1){		    //中通接收到新的指令就出去了
		   return xdistance; 
		}
	}
	return xdistance;
}

/************************************************************
* @brief  
* unsigned int fn_IO_goback(unsigned char back_time)
* @param  
* @retval 
*************************************************************/ 
unsigned int fn_IO_goback(unsigned char back_time){	  	  // 后退控制程序
	IO_GoBACK = 1 ;
	delay_s(1);
	IO_GoBACK = 0 ;
	delay_s(back_time);
	if(bdata_effect==1){
	  return 2; 
	}
	return 0;
}
 
/************************************************************
* @brief  
* void Led_Time_Change(unsigned int count)
* @param  
* @retval 
*************************************************************/ 
unsigned char count_Ledtime;
void Led_Time_Change(unsigned int count){  //中断定时器里IO闪烁
	if(count_Ledtime++>count){
		count_Ledtime=0;
		P31 = ~P31;	
	}	
}

/************************************************************
* @brief  
* void Led_flash(void)
* @param  
* @retval 
*************************************************************/ 
void Led_flash(void){
    P31 = ~P31;
	delay_ms(100);
	P31 = ~P31;
	delay_ms(100);
	P31 = ~P31;
}

/************************************************************
* @brief  
* Delay  函数
* @param  
* @retval 
*************************************************************/ 
void delay_us(unsigned int count){
  unsigned int a=0 ; 
  for(a=0;a<count;a++){	
	;		
  }	
}

//-----------------------------------------------------
void delay_ms(unsigned int count){
  unsigned int a=0,b=0; 
  for(a=0;a<count;a++){
	delay_us(400);			
  }
 
}

void delay_s(unsigned int count){
  unsigned int a=0,b=0; 
  for(a=0;a<count;a++){
	delay_ms(1100);	
	if(bdata_effect==1){
		return; 
	}		
  }	
}

2.USAR串口程序

usart_code.c:

#ifndef		_USART_CODE_
#define		_USART_CODE_
#include	"MC95FG308.h"
#include	"func_def.h"


extern volatile unsigned char bdata_begin  ;
extern volatile unsigned char  bdata_judge ;
extern volatile unsigned char  bdata_effect ;
extern volatile unsigned char  bdata_error ;  

#define _DATA_GET  0xAB 
#define _DATA_GET_CODE  4
#define _DATA_GET_MODE  7 
#define   U_Scom_car    0xBA
#define   U_Scom_code1   0x01	  //开始
#define   U_Scom_code2   0x02	  //暂停
#define   U_Scom_code3   0x03	  //位移到目标坐标附件 
#define   U_Scom_code4   0x04	  //开始测试目标坐标
#define   U_Scom_code5   0x05	  //返回起点
#define   U_Scom_code6   0x06	 //复位
#define   U_Scom_code7   0x07	 //故障
extern unsigned char UART_SENDCODE[_DATA_GET_CODE];
extern unsigned char dataR0 ;
extern unsigned char UART_GETcommand_car;  //串口最终的设备地址
extern unsigned char UART_GETcommand_code;  //串口最终的命令
extern unsigned char UART_GETcommand_X;  //串口最终的X命令
extern unsigned char UART_GETcommand_Y;  //串口最终的Y命令
 
  
void fn_usart_senddata(unsigned char ch, unsigned char *dat ,unsigned int num );
   
void fn_check_usart(unsigned char ch,unsigned char *dataget);
void fn_usart_sendcommande(unsigned char com_car, unsigned char com_code ,unsigned char com_X , unsigned char com_Y );

 

#endif	 


 

usart_code.c :

#include	"usart_code.h"
#include	"IO_code.h"

volatile unsigned char bdata_begin  ;
volatile unsigned char  bdata_judge ;
volatile unsigned char  bdata_effect ;
 
//---------------------- 接收对应 码值 ---------------------------------
const  unsigned char UART_GETCODE[_DATA_GET_MODE][_DATA_GET_CODE]=
							{{0xAB,0x01,0x00,0x00},//开始
							{0xAB,0x02,0x00,0x00},//暂停
							{0xAB,0x03,0x00,0x00},//位移到目标坐标附件  
                            {0xAB,0x04,0x00,0x00},//开始测试目标坐标 
 							{0xAB,0x05,0x00,0x00},//返回起点
							{0xAB,0x06,0x00,0x00},//复位
							{0xAB,0x07,0x00,0x00}};//故障
volatile  unsigned  char uart_get_buffer[4]={0x00,0x00,0x00,0x00}; //串口接收端字节缓存器

//---------------------- 发送对应 码值存储器 ---------------------------------							 
volatile unsigned char UART_SENDCODE [_DATA_GET_CODE]={0xBA,0x01,0x00,0x00};

volatile  unsigned char dataR0 = 0;	  //串口单字节缓存器													 
volatile  unsigned char UART_GETcommand_car;  //串口最终的设备地址
volatile  unsigned char UART_GETcommand_code;  //串口最终的命令
volatile  unsigned char UART_GETcommand_X;  //串口最终的X命令
volatile  unsigned char UART_GETcommand_Y;  //串口最终的Y命令


 
/************************************************************
* @brief  
* void fn_usart_senddata(   // 串口多数据发送函数 将单子节函数的发送程序进行封装
	unsigned char ch, 	    //串口编号
	unsigned char *dat,	    //串口发送数据地址
	unsigned int num )	    //串口发送数据个数
* @param  
* @retval 
*************************************************************/
void fn_usart_senddata(unsigned char ch, unsigned char *dat ,unsigned int num ){
	unsigned int i;	
	for(i=0 ; i<num ; i++){	 
		UART_write(ch,dat[i]);  //多字节写入操作		
	}
}
 
/************************************************************
* @brief  
* static void fn_get_usart(
		unsigned char ch,  	    //串口编号
		unsigned char *dataget)	//串口单字节接收到的数据变量地址
* @param  
* @retval 
*************************************************************/
static void fn_get_usart(unsigned char ch,unsigned char *dataget){ //串口接收定制化函数
	static unsigned char num_dataget;	//静态记录个数变量
	unsigned char data_dataget;
	data_dataget = *dataget	;
	if(ch == 0){ //USAR 0 串口		 
		if(bdata_begin == 0){
			uart_get_buffer[0]=0x00; 	  // 清理指令缓存集变量空间
			uart_get_buffer[1]=0x00;
			uart_get_buffer[2]=0x00;
			uart_get_buffer[3]=0x00;
			if(data_dataget ==_DATA_GET){	//判断指令开始是否对应到了起始变量
				bdata_begin =1;
				bdata_judge = 0;
				num_dataget = 0;  //当识别到了特定指令 开始记录数据			 		 
			}else{
				num_dataget = 0;  //识别到是否为 指令中开头关键字 _DATA_GET
				bdata_judge = 0;
				return;
			}				
		}					
	 	uart_get_buffer[num_dataget++]=data_dataget;	 //对指令缓存器进行数据存储
		if(num_dataget==_DATA_GET_CODE){ //记录制定长度的信号
			bdata_begin =0;
			num_dataget = 0;
			bdata_judge = 1;	// 信号被成功截取标志位		
		}	
	}
	
}


/************************************************************
* @brief  
* static void fn_effect_usart(
		unsigned char ch,  	    //串口编号
		unsigned char *dataget)	//串口单字节接收到的数据变量地址
* @param  
* @retval 
*************************************************************/
static void fn_effect_usart(unsigned char ch,unsigned char *dataget){
	unsigned char ndec=0;	 // 二维行坐标
	unsigned char ndem=0;	 // 二维纵坐标
	unsigned char effect_data=0;   // 指令判断缓存器
	unsigned char effect_data2=0;  // 指令判断缓存器
	if(ch==0){
		if(bdata_judge==0){return;}	// 信号被成功截取标志位
		bdata_judge = 0;
		for(ndem=0 ;ndem<_DATA_GET_MODE ;ndem++ ){	//遍历指令集对
			for(ndec = 0;ndec<_DATA_GET_CODE-2 ;ndec++){ //减去2 因为 X Y指令不做判断
			    effect_data =  dataget[ndec];
				effect_data2 = UART_GETCODE[ndem][ndec];
				if(UART_GETCODE[ndem][ndec] != dataget[ndec] ){	// 如果遍历到对应的指令位置			    		 
					break;
				}
				if(ndec==_DATA_GET_CODE-1-2){  //如果判断4指令长度中两个指令对应上即 UART_GETcommand_car	 UART_GETcommand_code 对应上就可以存储指令了
					UART_GETcommand_car = dataget[0]; //串口最终的设备地址
					UART_GETcommand_code = dataget[1]; //串口最终的命令
					UART_GETcommand_X = dataget[2];  //串口最终的X命令
					UART_GETcommand_Y = dataget[3]; //串口最终的Y

					fn_usart_senddata(0,dataget,_DATA_GET_CODE); //将截取到的正确指令返回主机
					 
					dataget[0]=0x00; 	 // 存储过后清理缓存器
					dataget[1]=0x00;
					dataget[2]=0x00;
					dataget[3]=0x00;				 
					bdata_effect = 1;	// 指令正式生效
			 		
					return;
				}				
			}	
		}
		dataget[0]=0x00; 		 //便利了半天没有找到对应的指令
		dataget[1]=0x00;
		dataget[2]=0x00;
		dataget[3]=0x00;		
	}		 
}

/************************************************************
* @brief  
* void fn_check_usart(
		unsigned char ch,  	    //串口编号
		unsigned char *dataget)	//串口单字节接收到的数据变量地址
* @param  
* @retval 
*************************************************************/
void fn_check_usart(unsigned char ch,unsigned char *dataget){	  //对外判断接口函数对以上的程序进行封装
  if(bdata_effect==1){return;}
  fn_get_usart(ch , dataget);
  fn_effect_usart(ch , uart_get_buffer);
  
}

/************************************************************
* @brief  
* void fn_usart_sendcommande(
	unsigned char com_car, 
	unsigned char com_code,
	unsigned char com_X, 
	unsigned char com_Y )
* @param  	 指令发送函数
* @retval 
*************************************************************/
void fn_usart_sendcommande(unsigned char com_car, unsigned char com_code ,unsigned char com_X , unsigned char com_Y ){
	UART_SENDCODE[0] = 	com_car;
	UART_SENDCODE[1] = 	com_code;
	UART_SENDCODE[2] = 	com_X;
	UART_SENDCODE[3] = 	com_Y;
	fn_usart_senddata(0,UART_SENDCODE,_DATA_GET_CODE);
} 
 

3.功能function

function_code.h:

#ifndef		_FUNCTION_CODE_
#define		_FUNCTION_CODE_
#include	"MC95FG308.h"
#include	"func_def.h"
#include	"IO_code.h"
#include	"usart_code.h"


#define  placeX_MAX   6	     //设备运行 的最远距离 单位米
#define  placeX_MIN   0		 //设备运行 的最进距离 单位米
extern volatile  unsigned int placeX_now  ;  // 记录当前的位置  单位米
extern volatile  unsigned int placeX_aim ;	 // 记录串口发来的数据位置  单位米

void fn_function_check(void);    //行为动作函数 
												 
#endif

function_code.c:

#include	"function_code.h"
#include	"usart_code.h"
#include	"IO_code.h"
volatile  unsigned int placeX_now = 0;
volatile  unsigned int placeX_aim = 0;
 
void fn_function_check(void){
  	if(bdata_effect==0){return;}  // 串口识别到有效的数据标志位
	bdata_effect = 0;		      // 清除串口识别到有效的数据标志位开始执行
    IO_Goforward = 0;		      // 将前进的IO口关闭
    IO_GoBACK = 0;			      // 将后退的IO口关闭
	   		
	switch(UART_GETcommand_code){ //识别到的指令
		case 0x01:	//开始	     	    	
		    placeX_now = 0;	 //初步设定当前位置为x=0	
			fn_usart_sendcommande(U_Scom_car, U_Scom_code1,placeX_now,0x00); //将发送车号,发送指令 当前坐标 返回给主机
			break;

		case 0x02:	//暂停 		 	
			fn_usart_sendcommande(U_Scom_car, U_Scom_code2,placeX_now,0x00);//将发送车号,发送指令 当前坐标 返回给主机
			break;
				
		case 0x03:	//位移到目标坐标附件
			if((UART_GETcommand_X<placeX_now)||(UART_GETcommand_X<placeX_MIN)||(UART_GETcommand_X>placeX_MAX)){
				fn_usart_sendcommande(U_Scom_car, U_Scom_code3,0xFF,0xFF);break; //发送异常信号0xFF 
			}	   // 运动目标坐标不能小于当前坐标,不能低于最小坐标,不能高于最大坐标

			placeX_aim = UART_GETcommand_X;	 //取得目标坐标		
			placeX_now += fn_IO_run(placeX_aim-placeX_now); // 设备开始运行并更新当前坐标			 
			fn_usart_sendcommande(U_Scom_car, U_Scom_code3,placeX_now,0x00);  //将发送车号,发送指令 当前坐标 返回给主机			
			break;

		case 0x04:	//开始测试目标坐标 						 
			if((UART_GETcommand_X<placeX_now)||(UART_GETcommand_X>placeX_MAX)||(UART_GETcommand_X<placeX_MIN+1)){
				fn_usart_sendcommande(U_Scom_car, U_Scom_code4,0xFF,0xFF);break;  //发送异常信号0xFF 
			}	   // 运动目标坐标不能小于当前坐标,不能低于最小坐标,不能高于最大坐标

			placeX_aim = UART_GETcommand_X;	//取得目标坐标	
			//---------------------------- 专注最后一步的测试 -------------------------		
			placeX_now += fn_IO_run(placeX_aim-placeX_now-1); //快速移动到待测试点前一个坐标
			delay_s(2);									      //等待2秒进入目标一步的测试
			placeX_now += fn_IO_run(placeX_aim-placeX_now);	  // 进入目标一步的测试

			fn_usart_sendcommande(U_Scom_car, U_Scom_code4,placeX_now,0x00);  //将发送车号,发送指令 当前坐标 返回给主机
			break;

		case 0x05:	//返回起点
			placeX_aim=0;		    
			placeX_now = fn_IO_goback(TIME_GoBACK_Long);  //执行返回复位行为		 	
			fn_usart_sendcommande(U_Scom_car, U_Scom_code5,placeX_now,0x00);  //将发送车号,发送指令 当前坐标 返回给主机
			break;

		case 0x06:	//复位
		    Led_flash();
		    placeX_aim=0;
			if(placeX_now==0){
				 fn_IO_run(0x01); //向前一步走先要不就退后到墙上了
				 placeX_now = fn_IO_goback(TIME_GoBACK_short);  //执行返回复位行为
			}else{
				placeX_now = fn_IO_goback(TIME_GoBACK_Long);  //执行返回复位行为	
			}	    						 	
			fn_usart_sendcommande(U_Scom_car, U_Scom_code6,placeX_now,0x00);  //将发送车号,发送指令 当前坐标 返回给主机	
			break;

		case 0x07:	//故障
		    bdata_effect = 0;		 	
			fn_usart_sendcommande(U_Scom_car, U_Scom_code7,placeX_now,0x00);  //将发送车号,发送指令 当前坐标 返回给主机
			break;
	}
 
}

总结

未完待续。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>