CSK05T 自电容触控芯片的使用
这一个多月接触了这款芯片,这个芯片应该是一款老芯片,网上找到的资料很少,仅有一个数据手册,所以用起来比较头疼,前前后后调试了一个月,其中还因为去搞其他东西而中断了一段时间,现在已经解决了,所以来写一下如何去使用它。
这一个多月接触了这款芯片,这个芯片应该是一款老芯片,网上找到的资料很少,仅有一个数据手册,所以用起来比较头疼,前前后后调试了一个月,其中还因为去搞其他东西而中断了一段时间,现在已经解决了,所以来写一下如何去使用它
一、认识CSK0XT芯片
二、使用CSK05T
这里仅仅展示CSK05T芯片,对于其他同类型的芯片也是一样的操作
首页,我们可以看到它的引脚分布有六根引脚供我们使用,按照顺序来分别是VCC,RESET,SCL,SDA,INT,GND。我这边用的是软件IIC,主控是STM32F103RCT6,SCL引脚定义为PC5,SDA是PB0,RESET是PC4,这个中断脚有问题,死活检测不到中断,不知道是代码问题还是硬件问题,所以这里我们舍弃这个引脚改用定时器中断
我们把六个引脚接好线就可以开始测试了,首先写IIC通信,这个IIC通信官方已经给出了,不过一开始测试的时候怎么都没法通信,搞得我重新写了一个IIC,写完了测试没问题,突然发现又可以用了,真的奇怪,下面给出IIC代码
ctp_hynitron_iic.c代码
#include "stdio.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_usart.h"
#include "ctp_hynitron_iic.h"
#include "touch.h"
#define IIC_DELAY (1)//1:320k
void iic_io_init(void)//iic 设置为 OD模式
{
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD ; //开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD ; //开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOC, GPIO_Pin_5);
GPIO_SetBits(GPIOB, GPIO_Pin_0);
}
void RST_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC, GPIO_Pin_4);
}
void rest_hyn_ic(void)
{
RST_init();
SET_RESET_PIN_LOW;//控制触摸IC复位引脚
delay_ms(10);
SET_RESET_PIN_HIGH;
}
//延时nus
void delay_us(uint32 nus)
{
while(nus){
nus--;
};
}
//产生IIC起始信号
static void IIC_Start(void)
{//START:when CLK is high,DATA change form high to low
WRITE_SDA(1);
WRITE_SCL(1);
delay_us(IIC_DELAY);
WRITE_SDA(0);
delay_us(IIC_DELAY*2);
WRITE_SCL(0);
delay_us(IIC_DELAY);
}
//产生IIC停止信号
static void IIC_Stop(void)
{//STOP:when CLK is high DATA change form low to high
uint16 j=0;
WRITE_SCL(0);
WRITE_SDA(0);
delay_us(IIC_DELAY);
WRITE_SCL(1);
for(j=0;;j++){
if (READ_SCL)break;
if(j>60000){
break;
}
}
delay_us(IIC_DELAY*2);
WRITE_SDA(1);
delay_us(IIC_DELAY);
}
static void rest_IIC(void)
{
uint8 time = 0;
for(time = 0; time < 10; time++)
{
IIC_Stop();
delay_us(IIC_DELAY*5);
IIC_Start();
}
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
static uint8 IIC_Wait_Ack(uint8 Wait_Ack)
{
uint32 i = 0;
uint8 ret = 0;
delay_us(IIC_DELAY);
WRITE_SDA(1);//WRITE_SCL to OD
WRITE_SCL(1);//WRITE_SCL to OD
if(Wait_Ack){
for(i = 0; ;i++){
delay_us(IIC_DELAY);
if (READ_SCL)break;
if(i > 10000){
ret = 1;
break;
}
}
}
delay_us(IIC_DELAY);
if(READ_SDA)ret = 1;
else ret = 0;
WRITE_SCL(0);
return ret;
}
//产生ACK应答
static void IIC_Ack(void)
{
WRITE_SCL(0);
WRITE_SDA(0);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
WRITE_SCL(1);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
WRITE_SCL(0);
}
//不产生ACK应答
static void IIC_NAck(void)
{
WRITE_SCL(0);
WRITE_SDA(1);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
WRITE_SCL(1);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
WRITE_SCL(0);
}
//IIC发送一个字节
//返回从机有无应答
static uint8 IIC_Send_Byte(uint8 txd ,uint8 Wait_Ack )
{
uint8 t;
delay_us(IIC_DELAY);
for(t=0;t<8;t++){
if(txd&0x80){WRITE_SDA(1);}
else {WRITE_SDA(0);}
txd<<=1;
delay_us(IIC_DELAY);
WRITE_SCL(1);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
WRITE_SCL(0);
delay_us(IIC_DELAY);
}
if(IIC_Wait_Ack(Wait_Ack)) {
rest_IIC();
return HYN_FAULT;//wait ack fail
}
else {
return HYN_TRUE;
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
static uint8 IIC_Read_Byte(uint8 ack)
{
uint16 i,j,receive=0;
WRITE_SDA(1);//set SDA to OD
for(i=0;i<8;i++ ){
WRITE_SCL(0);
delay_us(IIC_DELAY);//+4
delay_us(IIC_DELAY);
delay_us(IIC_DELAY);
WRITE_SCL(1);
for(j=0;i==0;j++){
if (READ_SCL)break;
if(j>60000){
break;
}
}
delay_us(IIC_DELAY);
receive<<=1;
if(READ_SDA){receive++;}
delay_us(IIC_DELAY);
}
if (ack == 0){
IIC_NAck();//发送nACK
}
else {
IIC_Ack(); //发送ACK
}
return receive;
}
void test(void)
{
IIC_Start();
uint8_t ack =IIC_Send_Byte(TOUCH_IIC_ADDR<<1,1);
IIC_Stop();
}
//---------------------------------------------------------------------//
uint8 TP_HRS_WriteBytes(uint8 iic_addr,uint16 reg_addr,uint8* buff,uint16 buff_len,uint8 reg_num)//写数据
{
uint8 iic_wait = 0;
if((iic_addr == TOUCH_IIC_ADDR)||(iic_addr == TOUCH_BOOT_IIC_ADDR)){
iic_wait = 1;
}
IIC_Start();
if(IIC_Send_Byte(iic_addr<<1 , 1) == HYN_FAULT){//发送器件地址
return HYN_FAULT;
}
if(reg_num==2){
if(IIC_Send_Byte(reg_addr>>8 , iic_wait) == HYN_FAULT){
return HYN_FAULT;
}
}
if(IIC_Send_Byte(reg_addr, iic_wait) == HYN_FAULT){//发送寄存器地址低8位
return HYN_FAULT;
}
for(;buff_len>0;buff_len--){
if(IIC_Send_Byte(*buff, iic_wait) == HYN_FAULT){
return HYN_FAULT;
}
buff++;
}
IIC_Stop();
return 0;
}
uint8 TP_HRS_ReadBytes(uint8 iic_addr,uint16 reg_addr,uint8* buff,uint16 buff_len,uint8 reg_num)//读数据
{
uint8 iic_wait = 0;
if((iic_addr == TOUCH_IIC_ADDR)||(iic_addr == TOUCH_BOOT_IIC_ADDR)){
iic_wait = 1;
}
IIC_Start();
if(IIC_Send_Byte(iic_addr<<1, 1) == HYN_FAULT){ //发送器件地址
return HYN_FAULT;
}
if(reg_num==2){
if(IIC_Send_Byte(reg_addr>>8,iic_wait) == HYN_FAULT){
return HYN_FAULT;
}
}
if(IIC_Send_Byte(reg_addr,iic_wait) == HYN_FAULT){//发送寄存器地址低8位
return HYN_FAULT;
}
IIC_Stop();
//-------------------------------------------//
delay_us(30);//30us以上
IIC_Start();
if(IIC_Send_Byte((iic_addr<<1)|0x01,1) == HYN_FAULT){
return HYN_FAULT;
}
for(;buff_len>0;buff_len--){
if(buff_len==1){
*buff=IIC_Read_Byte(0); //sned NCK
}
else{
*buff=IIC_Read_Byte(1); //send ACK
}
buff++;
//delay_us(120);//30us以上
}
IIC_Stop();
return HYN_TRUE;
}
uint8 TP_HRS_Write_and_check(uint8 iic_addr,uint16 reg_addr,uint8* buff,uint16 buff_len,uint8 reg_num)//写数据 并回读判断是否写入ok,最长32字节
{
uint8 read_buff[32] = {0};
uint8* buff_temp = buff;
uint8 i = 0;
if(TP_HRS_WriteBytes( iic_addr, reg_addr,buff,buff_len,reg_num) == HYN_FAULT)return HYN_FAULT; //写数据
if(buff_len >32)return HYN_FAULT;
delay_us(100);
if(TP_HRS_ReadBytes( iic_addr, reg_addr,read_buff, buff_len, reg_num) == HYN_FAULT)return HYN_FAULT; //读数据
for(i = 0; i < buff_len; i++){
if(read_buff[i] != buff_temp[i])return HYN_FAULT;
}
return HYN_TRUE;
}
ctp_hynitron_iic.h代码
#ifndef CTP_HYNITRON_IIC_H__
#define CTP_HYNITRON_IIC_H__
#include "stm32f10x.h"
void iic_io_init(void);
#define WRITE_SCL(x) GPIO_WriteBit(GPIOC, GPIO_Pin_5, (BitAction)(x))
#define WRITE_SDA(x) GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)(x))
#define READ_SDA GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)
#define READ_SCL GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_5)
#define CSK_REST(x) GPIO_WriteBit(GPIOC, GPIO_Pin_4, (BitAction)(x))
#define SET_RESET_PIN_HIGH GPIO_WriteBit(GPIOC, GPIO_Pin_4, Bit_SET)
#define SET_RESET_PIN_LOW GPIO_WriteBit(GPIOC, GPIO_Pin_4, Bit_RESET)
uint8_t TP_HRS_WriteBytes(uint8_t iic_addr,uint16_t reg_addr,uint8_t* buff,uint16_t buff_len,uint8_t reg_num);//写数据
uint8_t TP_HRS_ReadBytes(uint8_t iic_addr,uint16_t reg_addr,uint8_t* buff,uint16_t buff_len,uint8_t reg_num);//读数据
uint8_t TP_HRS_Write_and_check(uint8_t iic_addr,uint16_t reg_addr,uint8_t* buff,uint16_t buff_len,uint8_t reg_num);//写数据 并回读判断是否写入ok,最长32字节
void rest_hyn_ic(void);
//void delay_us(uint32_t nus);
#endif
可以先测试一下这个IIC代码能不能用,如果能用是最好的,如果不能用可以去网上找一下别人的IIC代码,反正都是通用的,地址是0x15,0xFF是版本号,下面是测试结果


结果是正确的,IIC可以正常使用,然后我们需要配置一下这个芯片的信息,连同按键功能一块写在一个总的文件里。
首先我们建一个新的文件叫touch.h,放一些基本配置信息,例如芯片地址,按键功能函数等
touch.h
#ifndef _TP_H_
#define _TP_H_
#include "stm32f10x.h"
typedef unsigned char uint8;
typedef unsigned short int uint16;
typedef unsigned int uint32;
#define F_W (V1.7)
#define DBG_UART
#ifdef DBG_UART
#define HYN_DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define HYN_DBG(...)
#endif
#define TOUCH_IIC_ADDR (0x15)//7位地址
#define TOUCH_BOOT_IIC_ADDR (0x6A)//7位地址
#define BIT(x) (1UL << (x))
#define HYN_TRUE (0)
#define HYN_FAULT (1)
typedef struct {
uint8 state;
uint8 gesture_id;
uint16 x;
uint16 y;
}Touch;
extern uint8 touch_int_flig;
void iic_io_init(void);
uint8 TP_HRS_ReadBytes(uint8 iic_addr,uint16 reg_addr,uint8* buff,uint16 buff_len,uint8 reg_num);//读数据
void rest_hyn_ic(void);
void touch_event_init(void);
uint8 get_touch_inform(Touch* tpes);
uint32 get_touch_event(void);
uint8 get_slide_event(void);//滑条触摸事件
void get_touch_ic_signal(void);
#endif
有了头文件,还需要一个写按键功能的文件
Task.c
#include "stm32f10x_usart.h"
#include "ctp_hynitron_iic.h"
#include "touch.h"
#include "stm32f10x.h"
#include "delay.h"
#define KEY_NUM (5)//总的按键数量 <=8
uint8 touch_int_flig=0;
uint32 key_state=0;
uint32 key_state_last=0;
void init_CSK_para(void)//初始化标准品参数
{
uint8 data_buff[8] = {0x00};
uint8 retry = 0;
for(retry = 0; retry < 10; retry++)
{
HYN_DBG("CSKXXT init start = %d time\r\n",retry);
rest_hyn_ic(); //RST脚拉低delay 10ms,再拉高。
delay_ms(50 + (retry*2));//unit=ms
data_buff[0] = 0x00;
if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, 0x1F, data_buff, 1, 1) == HYN_FAULT)continue;//禁止扫描
delay_ms(20);//unit=ms
data_buff[0] = 0x1F;//5个通道
if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, 0x14, data_buff, 1, 1) == HYN_FAULT)continue;//写数据
data_buff[0] = 6; //扫描分频
data_buff[1] = 0xff; //固定0xff
data_buff[2] = 25; //扫描电流
data_buff[3] = 100; //噪声阈值
data_buff[4] = 200; //阈值L
data_buff[5] = (200>>8);//阈值H
data_buff[6] = 100; //全局灵敏度
if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, 0x18, data_buff, 7, 1) == HYN_FAULT)continue;//写数据
// data_buff[0] = 0x20;
// if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, 0x61, data_buff, 1, 1) == HYN_FAULT)continue;//写int模式
// data_buff[0] = 10;
// if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, 0x74, 1, data_buff, 1) == HYN_FAULT)continue;//写系统周期
// data_buff[0] = 20;
// if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, (0x80 + (0) * 4 + 1),data_buff,1,1) == HYN_FAULT)continue;//设置CS01通道的灵敏度
// data_buff[0] = 20;
// if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, (0x80 + (1) * 4 + 1),data_buff,1,1) == HYN_FAULT)continue;//设置CS02通道的灵敏度
// data_buff[0] = 20;
// if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, (0x80 + (2) * 4 + 1),data_buff,1,1) == HYN_FAULT)continue;//设置CS03通道的灵敏度
// data_buff[0] = 20;
// if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, (0x80 + (3) * 4 + 1),data_buff,1,1) == HYN_FAULT)continue;//设置CS04通道的灵敏度
// data_buff[0] = 20;
// if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, (0x80 + (4) * 4 + 1),data_buff,1,1) == HYN_FAULT)continue;//设置CS05通道的灵敏度
data_buff[0] = 0x01;
if(TP_HRS_Write_and_check(TOUCH_IIC_ADDR, 0x1F, data_buff, 1, 1) == HYN_FAULT)continue;//使能扫描
HYN_DBG("CSKxxT init OK\r\n");
break;
}
if(retry >= 10){
HYN_DBG("CSKxxT init fail\r\n");
}
}
void touch_event_init(void)
{
key_state=0;
key_state_last=0;
init_CSK_para();
}
uint32 get_touch_event(void)
{
uint8 read_buff[2] = {0x00,0x00};
uint32 keycode = 0;
uint8 result = HYN_TRUE;
// if(touch_int_flig){//接收到中断后开始读按键状态
// touch_int_flig = 0;
result = TP_HRS_ReadBytes( TOUCH_IIC_ADDR, 0x1F,read_buff, 1,1);
if(result == HYN_FAULT){//iic err
init_CSK_para();//重新设置标准品参数
return 0;
}
else{
if((read_buff[0]&0x01)!=0x01){
init_CSK_para();//重新设置标准品参数
return 0;
}
}
result = TP_HRS_ReadBytes( TOUCH_IIC_ADDR, 0x22,read_buff,2, 1);
if(result == HYN_TRUE){//读键值
key_state=(uint32)(read_buff[1]<<8) + read_buff[0];
if((key_state != key_state_last) && (key_state_last)){//抬起时上报按键事件
keycode = key_state_last;
}
// if((key_state != key_state_last) && (key_state)){//按下时上报按键事件
// keycode=key_state;
// }
key_state_last = key_state;
if(keycode)HYN_DBG("key_code=0x%04x\r\n",keycode);
if(keycode == 2)
{
choose++;
Tick=keycode;
}
if(keycode == 8)
{
choose--;
Tick=keycode;
}
}
// }
return keycode;
}
uint8 sig_buff[KEY_NUM*2+2]={0x00};
void get_touch_ic_signal(void)
{
uint8 i=0;
uint16 signal=0;
// HYN_DBG("\r\n----diff----\r\n");//读信号量
if(TP_HRS_ReadBytes( TOUCH_IIC_ADDR, 0x44, sig_buff , KEY_NUM*2, 1) == HYN_TRUE){//CSK标准品(CSK05T CSK08T)
for(i = 0;i < KEY_NUM*2;i += 2){
signal=(uint16)(sig_buff[i]<<8) + sig_buff[i+1];
HYN_DBG("%05d ",signal);
}
HYN_DBG("\r\n");
}
// HYN_DBG("\r\n----rawdata----\r\n");//读原始信号
// if(TP_HRS_ReadBytes( TOUCH_IIC_ADDR, 0x28, sig_buff, KEY_NUM*2, 1) == HYN_TRUE){// CSK标准品(CSK05T CSK08T)
// for(i = 0;i < KEY_NUM*2;i += 2){
// signal=(uint16)(sig_buff[i]<<8) + sig_buff[i+1];
// HYN_DBG("%05d ",signal);
// }
// HYN_DBG("\r\n");
// }
}
由于我们需要定时器中断,所以就不需要在这里配置中断了,获取按键函数里面的中断要去掉,接下来配置定时器中断。
tim.c
#include "stm32f10x.h" // Device header
/**
* 函 数:定时中断初始化
* 参 数:无
* 返 回 值:无
*/
void Timer_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
/*配置时钟源*/
TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
/*中断输出配置*/
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定时器更新标志位
//TIM_TimeBaseInit函数末尾,手动产生了更新事件
//若不清除此标志位,则开启中断后,会立刻进入一次中断
//如果不介意此问题,则不清除此标志位也可
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
//即抢占优先级范围:0~3,响应优先级范围:0~3
//此分组配置在整个工程中仅需调用一次
//若有多个中断,可以把此代码放在main函数内,while循环之前
//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //选择配置NVIC的TIM2线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //指定NVIC线路的抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
}
/* 定时器中断函数,可以复制到使用它的地方
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
*/
tim.h
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
#endif
这样我们需要的代码都OK了,就可以测试了,我们把定时器里面的中断函数注释去掉,里面写上
这样就可以读出来按键的值了,把返回值找一个变量存储进行判断就OK了
当然也不一定这么顺利,如果用不了这个函数,还有另一种方法可以使用,可以看下一个帖子
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)