历史上的今天
返回首页

历史上的今天

今天是:2025年04月02日(星期三)

正在发生

2019年04月02日 | STM32的I2C主从机通信

2019-04-02 来源:eefocus

最近一段时间在做I2C通信协议,需要在两块STM32之间做I2C通信,定的是主机用IO口模拟,从机用的是STM32的硬件I2C,我的项目要求是需要主从机之间能够进行一串数据收发而不出错,实验时在主机方面,利用IO口模拟主机,只需要理解时序就够了,同时将速度能够控制在100K(标准)左右,基本的时序理解网上大把的资料,所以主机这一块几个小时就搞定了,而在做从机时,遇到了困难,本来从机也想用IO口模拟的,但是速度达不到那么快,因此只能选择硬件做从机,现就从机用中断方式开说,总结过程中遇到的几点问题:

1、由于STM32的硬件问题,建议在使用I2C时,将其优先级设为最高。

2、针对程序中除了I2C数据收发,还有别的中断程序或者指令要执行而导致I2C数据传输堵塞时,可以在执行完该段程序后重新初始化I2C。


主机程序如下:


  1 #include "Hal_IIC/I2C.h"
  2 #include "Hal_delay/delay.h"
  3 #include "common.h"
  4 #include "gizwits_product.h"
  5 
  6 extern void delayUs(uint32_t nus);
  7 uint8_t b[5];
  8 extern uint8_t Cookr[5];
  9 extern uint8_t WR_flag;
 10 uint8_t Wifi_SET;  //WIFI状态脚
 11 extern uint8_t Power_flag;         //电磁炉开启关闭标志位
 12 uint8_t Give_Up;
 13 /*--------------------------------------------------------------------------------
 14 调用方式:void IIC_Init(void) 
 15 函数说明:私有函数,I2C专用,函数初始化
 16 ---------------------------------------------------------------------------------*/ 
 17 void IIC_Init(void)
 18 {                         
 19     GPIO_InitTypeDef GPIO_InitStructure;
 20     RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOA, ENABLE );    //使能GPIOA时钟
 21        
 22     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;
 23     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
 24     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 25     GPIO_Init(GPIOA, &GPIO_InitStructure);
 26     GPIO_SetBits(GPIOA,GPIO_Pin_11|GPIO_Pin_12);     //PA11,PA12 输出高
 27 }
 28 /*--------------------------------------------------------------------------------
 29 调用方式:void I2CStart(void) 
 30 函数说明:私有函数,I2C专用,开始信号
 31 ---------------------------------------------------------------------------------*/
 32 void IIC_Start(void)
 33 {
 34     SDA_OUT();     //sda线输出
 35     IIC_SDA=1;            
 36     IIC_SCL=1;
 37     delayUs(4);
 38      IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
 39     delayUs(4);
 40     IIC_SCL=0;  //钳住I2C总线,准备发送或接收数据 
 41 }      
 42 /*--------------------------------------------------------------------------------
 43 调用方式:void I2CStop(void) 
 44 函数说明:私有函数,I2C专用,停止信号
 45 ---------------------------------------------------------------------------------*/
 46 void IIC_Stop(void)
 47 {
 48     SDA_OUT();//sda线输出
 49     IIC_SCL=0;
 50     IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 51      delayUs(4);
 52     IIC_SCL=1; 
 53     IIC_SDA=1;//发送I2C总线结束信号
 54     delayUs(4);                                   
 55 }
 56 /*--------------------------------------------------------------------------------
 57 调用方式:I2CAck(void) 
 58 函数说明:私有函数,I2C专用,等待从器件接收方的应答,0表示接受成功,1表示失败
 59 ---------------------------------------------------------------------------------*/
 60 uint8_t IIC_Wait_Ack(void)
 61 {
 62     uint8_t ucErrTime=0;
 63     SDA_IN();      //SDA设置为输入  
 64     IIC_SDA=1;delayUs(1);       
 65     IIC_SCL=1;delayUs(1);     
 66     while(READ_SDA)
 67     {
 68         ucErrTime++;
 69         if(ucErrTime>250)
 70         {
 71             IIC_Stop();
 72             return 1;
 73         }
 74     }
 75     IIC_SCL=0;//时钟输出0        
 76     return 0;  
 77 } 
 78 /*--------------------------------------------------------------------------------
 79 调用方式:void SendAck(void) 
 80 函数说明:私有函数,I2C专用,主器件为接收方,从器件为发送方时,应答信号。
 81 ---------------------------------------------------------------------------------*/
 82 void IIC_Ack(void)
 83 {
 84     IIC_SCL=0;
 85     SDA_OUT();
 86     IIC_SDA=0;
 87     delayUs(2);
 88     IIC_SCL=1;
 89     delayUs(2);
 90     IIC_SCL=0;
 91 }
 92 /*--------------------------------------------------------------------------------
 93 调用方式:void SendAck(void) 
 94 函数说明:私有函数,I2C专用,主器件为接收方,从器件为发送方时,非应答信号。
 95 ---------------------------------------------------------------------------------*/        
 96 void IIC_NAck(void)
 97 {
 98     IIC_SCL=0;
 99     SDA_OUT();
100     IIC_SDA=1;
101     delayUs(2);
102     IIC_SCL=1;
103     delayUs(2);
104     IIC_SCL=0;
105 }                                          
106 /*--------------------------------------------------------------------------------
107 调用方式:void IIC_Send_Byte(unsigned char ch) 
108 函数说明:私有函数,I2C专用
109 ---------------------------------------------------------------------------------*/      
110 void IIC_Send_Byte(uint8_t txd)
111 {                        
112     uint8_t t;   
113     SDA_OUT();         
114     IIC_SCL=0;//拉低时钟开始数据传输
115     for(t=0;t>7;
118         if((txd&0x80)>>7)
119             IIC_SDA=1;
120         else
121             IIC_SDA=0;
122         txd<<=1;       
123         delayUs(2);   //对TEA5767这三个延时都是必须的
124         IIC_SCL=1;
125         delayUs(2); 
126         IIC_SCL=0;    
127         delayUs(2);
128     }     
129 }         
130 /*--------------------------------------------------------------------------------
131 调用方式:unsigned char IIC_Read_Byte(void) 
132 函数说明:私有函数,I2C专用
133 ---------------------------------------------------------------------------------*/
134 //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
135 uint8_t IIC_Read_Byte(unsigned char ack)
136 {
137     unsigned char i,receive=0;
138     SDA_IN();//SDA设置为输入
139     for(i=0;i<8;i++ )
140     {
141                 receive<<=1;
142         IIC_SCL=0; 
143         delayUs(5);
144             IIC_SCL=1;
145                 delayUs(5);
146         
147         if(READ_SDA)receive++;   
148          
149   }                     
150     if (!ack)
151         IIC_NAck();//发送nACK
152     else
153         IIC_Ack(); //发送ACK   
154     return receive;
155 }
156 
157 
158 //读温度传感器,温度值是由h的高字节和低字节的高四位组成,总共12位,其中负温度值是由补码形式
159 void T_Read(void)
160 {
161             
162     /***************read start*******************/
163     if(WR_flag==0x02)
164     {
165 
166     IIC_Start();
167         IIC_Send_Byte( 0x30|0x01);          //读操作
168          while(IIC_Wait_Ack());        
169    //     delayMs(500);                         //等待从机处理一个字节地址位
170     Give_Up = IIC_Read_Byte(1);        
171         for(uint8_t i=0;i<4;i++)
172         {
173             b[i] = IIC_Read_Byte(1);
174             printf("%c",b[i]);
175         }
176         b[4] = IIC_Read_Byte(0);
177         printf("%c",b[4]);
178         
179         if((b[0]==0xFA)&&(b[4]==0xFB))
180         {
181           for(uint8_t i=1;i<6;i++)
182           {
183               Cookr[i] = b[i];
184           }    
185 
186         }
187     }    
188    
189     /****************read end********************/
190   /****************write start*****************/
191         if(WR_flag==0x01)
192         {
193             IIC_Start();
194             IIC_Send_Byte(0x30);     //写操作
195             while(IIC_Wait_Ack());
196             IIC_Send_Byte(0xFA);
197             while(IIC_Wait_Ack());
198             delayMs(3);              //延时太低传输数据会出错,因为从机还没处理完数据
199             IIC_Send_Byte(Cookr[1]);
200             while(IIC_Wait_Ack());
201             delayMs(3);
202             IIC_Send_Byte(0x03);
203             while(IIC_Wait_Ack());
204             delayMs(3);
205             IIC_Send_Byte(Power_flag);
206             while(IIC_Wait_Ack());
207             delayMs(3);
208             IIC_Send_Byte(0xFB);
209             while(IIC_Wait_Ack());
210             delayMs(3);
211             IIC_Stop();
212           WR_flag=0x02;    
213         }
214         /***************write end*****************/
215      
216 }

从机使用中断方式


  1 #include "myiic.h"
  2 #include "delay.h"
  3 #include "led.h"
  4 #include "key.h"
  5 #include "usart.h"
  6 
  7 
  8 #define MY_I2C_ADDRESS    0x30                         //模拟从机地址
  9 unsigned char b[5]={0x00,0x00,0x00,0x00,0x00};         //从机接收操作
 10 uint8_t Wifi_Set=0x00;
 11 extern u8 flag;                                        //电磁炉开关中断位
 12 unsigned char a[5]={0xFA,0x00,0x00,0x00,0xFB};         
 13 //初始化IIC
 14 void I2C1_Init(void)
 15 {
 16     GPIO_InitTypeDef GPIO_InitStructure;
 17     I2C_InitTypeDef I2C_InitStructure;
 18     NVIC_InitTypeDef NVIC_InitStructure;
 19     
 20     RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);   // enable APB1 peripheral clock for I2C1
 21     
 22     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  // enable clock for SCL and SDA pins
 23     
 24     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
 25     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 26     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;        //I2C必须开漏输出,实现线与逻辑
 27     GPIO_Init(GPIOB, &GPIO_InitStructure);
 28     
 29     
 30     I2C_InitStructure.I2C_ClockSpeed = 100000;             // configure I2C1 
 31     I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
 32     I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
 33     I2C_InitStructure.I2C_OwnAddress1 = MY_I2C_ADDRESS;
 34     I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
 35     I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
 36     I2C_Init(I2C1, &I2C_InitStructure);
 37 
 38     //setup interrupts
 39     I2C_ITConfig(I2C1, I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF, ENABLE);   
 40 
 41     
 42     // Configure the I2C event priority
 43     NVIC_InitStructure.NVIC_IRQChannel                   = I2C1_EV_IRQn;
 44     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;       //抢占优先级1
 45     NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;       //响应优先级0
 46     NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
 47     NVIC_Init(&NVIC_InitStructure);
 48 
 49     // enable I2C1
 50     I2C_Cmd(I2C1, ENABLE);
 51 }
 52 
 53 
 54 //Clear ADDR by reading SR1, then SR2
 55 
 56 void I2C_clear_ADDR(I2C_TypeDef* I2Cx) {
 57     I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR);
 58     ((void)(I2Cx->SR2));
 59 }
 60 
 61 //Clear STOPF by reading SR1, then writing CR1
 62 
 63 void I2C_clear_STOPF(I2C_TypeDef* I2Cx) {
 64     I2C_GetFlagStatus(I2Cx, I2C_FLAG_STOPF);
 65     I2C_Cmd(I2Cx, ENABLE);
 66 }
 67 
 68 /*--------------------------------------------------------------------------------
 69 调用方式:void I2C1_EV_IRQHandler(void) 
 70 函数说明:私有函数,I2C专用,中断按键处理函数,从机中断都在这里面执行
 71 ---------------------------------------------------------------------------------*/
 72 
 73 uint8_t data = 0;
 74 uint8_t S_data=0;
 75 void I2C1_EV_IRQHandler(void) 
 76 {
 77 //        KV1=0;                                 //只是一个测试灯
 78         //Clear AF from slave-transmission end
 79         if(I2C_GetITStatus(I2C1, I2C_IT_AF)) 
 80         {
 81             I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
 82         }
 83         //Big state machine response, since doesn't actually keep state
 84         switch(I2C_GetLastEvent(I2C1)) 
 85             {
 86             //SLAVE
 87             //Receive
 88             case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: //EV1
 89                 I2C_clear_ADDR(I2C1);
 90                 break;
 91             case I2C_EVENT_SLAVE_BYTE_RECEIVED: //EV2
 92                 //Read it, so no one is waiting, clears BTF if necessary
 93                 b[data] = I2C_ReceiveData(I2C1);
 94         //      printf("%c",b[data]);
 95                 data++;
 96                 if(data>=5)
 97                 {
 98                                 data=0;
 99                                 if((b[0]==0xFA)&&(b[4]==0xFB))
100                                 {
101                                     a[1]=b[1];
102                                     Wifi_Set=b[2];
103                                     flag=b[3];
104                 //                    printf("%c",a[1]);
105                                 }
106 
107                 }
108                 if(I2C_GetFlagStatus(I2C1, I2C_FLAG_DUALF)) 
109                 {//Secondary Receive
110                 } 
111                 else if(I2C_GetFlagStatus(I2C1, I2C_FLAG_GENCALL)) 
112                 {//General Receive
113                 } 
114                 else 
115                 {//Normal
116                 }
117                 break;
118             case I2C_EVENT_SLAVE_STOP_DETECTED: //End of receive, EV4
119                 I2C_clear_STOPF(I2C1);
120                 break;
121 
122             //Transmit
123             case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: //EV1
124                 I2C_clear_ADDR(I2C1);
125                 //Send first byte
126                I2C_SendData(I2C1, 0x00);
127             
128                 break;
129             case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: //EV3
130                 //Determine what you want to send
131                 //data = 5;
132                 if(I2C_GetFlagStatus(I2C1, I2C_FLAG_DUALF)) 
133                 {//Secondary Transmit
134                 } 
135                 else if(I2C_GetFlagStatus(I2C1, I2C_FLAG_GENCALL)) 
136                 {//General Transmit
137                 } 
138                 else 
139                 {//Normal
140                 }
141                 //Read flag and write next byte to clear BTF if present
142                 I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF);
143                 I2C_SendData(I2C1, a[S_data]);
144                 S_data++;
145                 if(S_data>=5)
146                 S_data=0;
147                 break;
148             case I2C_EVENT_SLAVE_ACK_FAILURE://End of transmission EV3_2
149                 //TODO: Doesn't seem to be getting reached, so just
150                 //check at top-level
151                 I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
152                 break;
153             //Alternative Cases for address match
154             case I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED:    //EV1
155                 break;
156             case I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED: //EV1
157                 break;
158             case I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED:        //EV1
159                 break;
160 
161 
162             //MASTER
163             case I2C_EVENT_MASTER_MODE_SELECT: //EV5, just sent start bit
164                 break;
165             //Receive
166             case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: //EV6, just sent addr    
167                 break;
168             case I2C_EVENT_MASTER_BYTE_RECEIVED: //EV7
169                 break;
170             //Transmit
171             case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: //EV6, just sent addr     
172                 break;
173             case I2C_EVENT_MASTER_BYTE_TRANSMITTING: //EV8, about to send data
174                 break;
175             case I2C_EVENT_MASTER_BYTE_TRANSMITTED: //EV8_2, just sent data
176                 break;
177 
178             //Alternative addressing stuff, not going to worry about
179             case I2C_EVENT_MASTER_MODE_ADDRESS10: //EV9
180                 break;
181             default:
182                 //How the FUCK did you get here?
183                 //I should probably raise some error, but fuck it,
184                 //it's late
185                 break;
186 
187         }
188 
189 
190 }
191 
192 void I2C1_ER_IRQHandler(void) {
193  //       GPIO_SetBits(GPIOD, RED);
194 //    LED3=0;
195         //Can't use nice switch statement, because no fxn available
196         if(I2C_GetITStatus(I2C1,        I2C_IT_SMBALERT)) {
197         } else if(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT)) {
198         } else if(I2C_GetITStatus(I2C1, I2C_IT_PECERR)) {
199         } else if(I2C_GetITStatus(I2C1, I2C_IT_OVR)) {
200             //Overrun
201             //CLK stretch disabled and receiving
202             //DR has not been read, b4 next byte comes in
203             //effect: lose byte
204             //should:clear RxNE and transmitter should retransmit
205 
206             //Underrun
207             //CLK stretch disabled and I2C transmitting
208             //haven't updated DR since new clock
209             //effect: same byte resent
210             //should: make sure discarded, and write next
211         } else if(I2C_GetITStatus(I2C1, I2C_IT_AF)) {
212             //Detected NACK
213             //Transmitter must reset com
214                 //Slave: lines released
215                 //Master: Stop or repeated Start must must be generated
216                 //Master = MSL bit
217             //Fixup
218             I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
219         } else if(I2C_GetITStatus(I2C1, I2C_IT_ARLO)) {
220             //Arbitration Lost
221             //Goes to slave mode, but can't ack slave address in same transfer
222             //Can after repeat Start though
223         } else if(I2C_GetITStatus(I2C1, I2C_IT_BERR)) {
224             //Bus Error
225             //In slave mode: data discarded, lines released, acts like restart
226             //In master mode: current transmission continues
227         }
228 }


推荐阅读

史海拾趣

飞虹(FeiHong)公司的发展小趣事

2013年8月26日,苏州锋驰微电子有限公司在江苏省苏州市张家港市正式成立,法定代表人为Fang Gang Feng。公司初期便明确了以集成电路IP、物联网、计算机软硬件、电子产品、集成电路及应用电路方案技术的设计、研发为核心业务的发展方向。在成立之初,面对激烈的市场竞争,苏州锋驰凭借对技术的执着追求和敏锐的市场洞察力,逐步在行业内站稳脚跟。

艾迪沃德公司的发展小趣事
尽量使用稳定的交流电源供电,避免电压波动过大对电源电路造成冲击。
BAE Systems公司的发展小趣事

随着全球化的加速,BAE Systems公司积极寻求跨国合作与拓展机会。公司与多家国际知名企业建立了紧密的合作关系,共同开展研发项目和市场拓展。这些合作不仅帮助公司获取了更多的技术和市场资源,也提升了公司在全球电子行业的地位和影响力。通过跨国合作,BAE Systems公司的产品和服务逐渐进入全球市场,为公司的持续发展注入了新的活力。

Antenova公司的发展小趣事

Antenova公司在行业内率先推出了第二代GPS射频天线模块,这一创新产品为嵌入式GPS应用提供了高性能的解决方案。该产品的推出不仅树立了行业标杆,还为公司带来了可观的收入增长。同时,Antenova还不断推出其他领先产品,进一步巩固了公司在天线设计领域的领先地位。

Alpha-Micro Electronics公司的发展小趣事

Antenova公司在行业内率先推出了第二代GPS射频天线模块,这一创新产品为嵌入式GPS应用提供了高性能的解决方案。该产品的推出不仅树立了行业标杆,还为公司带来了可观的收入增长。同时,Antenova还不断推出其他领先产品,进一步巩固了公司在天线设计领域的领先地位。

European Crystal Org公司的发展小趣事

European Crystal Org(ECO)公司诞生于欧洲一个小城市的一个旧仓库里。创始人约翰·史密斯是一位对晶体技术充满热情的电子工程师。他意识到晶体在电子领域的重要性,并决定专注于研发和生产高质量的晶体振荡器。初创时期,ECO面临着资金短缺、技术挑战和市场认可度低的困境。然而,约翰凭借对技术的执着和对市场的敏锐洞察,成功研发出了一款性能卓越的晶体振荡器,赢得了几家小型电子制造商的青睐。这些早期客户的信任为ECO奠定了坚实的市场基础。

问答坊 | AI 解惑

关于09年射频的一道征题

本帖最后由 paulhyde 于 2014-9-15 09:00 编辑 题目不错,应该也有不少人看过,分享之哈。呵呵  …

查看全部问答>

汽车电子硬件工程师的成长

了解美国的硬件工程师的成长是一件有趣的事情,不过残酷的是,在中国是不可复制的。 一般美国的工程师的技术上分级一般,有5级 Entry Level 1 Hardware Engineer 最初级硬件工程师 一般是刚进公司的毕业生,主要的工作是打杂和学习公司开发流程 ...…

查看全部问答>

哪位高手先帮我仿真一下这个程序啊!作业要交,来不及啦!

我还没学会仿真啊。就是一个序列检测器!谢谢大家啦!要WORD版的,截图放在WORD里! library ieee; use ieee.std_logic_1164.all; entity  test_code is port ( clk,reset :  in  std_logic;    & ...…

查看全部问答>

嵌入式 进入linux 键盘不能用.

我把串口线接好,建立一个超级终端,进入linux 就不能用键盘了,在windows下还可以用,什么问题了?谢谢各位了。…

查看全部问答>

FPGA培训--FPGA高级逻辑设计研修班

一、 主管单位:中国高科技产业化研究会 主办单位:中国高科技产业化研究会信号处理专家委员会 二、 研修时间:2009年9月17-19日(16日报到) 三、 研修地点:北  京(具体地点及路线图详见报到通知) 四、 课程简介 本课程为期三天, ...…

查看全部问答>

STR910常见问题解答

2006年10月6日,我们在ST的英文网站上举行了一个有关STR91x系列芯片的网上研讨会,在这个研讨会中世界各地的工程师提出了很多问题,我们把大家最关心的一些问题集中起来,汇编成一个《STR910常见问题解答》,现将全文翻译转载如下,供国内同行 ...…

查看全部问答>

STM32TIM1_BDTR_的位11,位10两位OSSR.OSS有点不理解请高手指点下I

STM32TIM1_BDTR_的位11,位10两位OSSR.OSS有点不理解请高手指点下. 首先OSSR位:数据手册解释如下:  OSSR: 运行模式关闭状态选择位.TIM1_BDTR_MOD=1  0:当定时器不工作时,禁止OC/OCN输出(OC/OCN使能输出信号=0); 1:当定时器不工作 ...…

查看全部问答>

xilinx spartan-3e prom 配置问题

配置RAM成功,程序能运行(LCD显示程序),但是在配置 xcf04s serial platform flash prom时,也提示programe succeed,但lcd上却没有显示,这个是哪里出现了问题呢?求解啊!…

查看全部问答>

频谱仪选购请教

想买一台频谱仪,主要用于430MHz,860Mhz,2.4GHz的rf收发单元的测试,有哪位可以推荐你们使用过觉着不错的品牌型号吗? 若采用了你的建议,可以请吃一顿。…

查看全部问答>