北方

  • 2019-09-11
  • 回复了主题帖: 有奖话题#三人行必有我师#,说一说,那些在论坛生活中给予你指导,给予你帮助的网...

    @dcexpert,@okhxyyo,@soso 以及各位版主,祝大家节日快乐。 谢谢这些网友的帮助。

  • 2019-09-06
  • 回复了主题帖: 获奖名单:直播|贝能国际新型玻璃破碎检测方案

    确认个人信息无误。 如果可以,换E金币吧,谢谢。

  • 2019-08-15
  • 回复了主题帖: 《Python编程:从入门到实践》

    zan

  • 2019-08-14
  • 回复了主题帖: 获奖名单|TTI 和 Molex 直播【更小型、高速、可靠的连接器推动物联网应用的新发展】

    确认个人信息无误,谢谢!

  • 2019-08-12
  • 发表了主题帖: 【DFRobot无线通信模块】+ DFRobot Gravity: UART A6 GSM & GPRS 无线通信模块评测

    1 DFRobot Gravity: UART A6 GSM & GPRS 无线通信模块是一个非常精巧的扩展板,主要是基于GSM无线通信模块的快速开发. 2. 这个模块是安可信A9,和A9G兼容管脚的开发板,对于开发板的连接和控制是用UART串行接口实现的.    具体的参数参照WIKI,这里展示了具体的使用方法. 3. 按照手册上的使用方法连接arduino开发板的11和10引脚,使用9600的波特率连接,下载如下测试程序.   #include <SoftwareSerial.h> SoftwareSerial mySerial(11, 10); // TX-Pin11, RX-Pin10 void updateSerial() { delay(2000); while (Serial.available()) { mySerial.write(Serial.read());//如果Serial收到数据则通过mySerial输出 } while(mySerial.available()) { Serial.write(mySerial.read());//如果mySerial收到数据则通过Serial输出 } } void setup() { Serial.begin(9600); mySerial.begin(9600); } void loop() { mySerial.println("AT"); //握手测试,成功则返回OK updateSerial(); mySerial.println("AT+CSQ"); //信号质量测试,值为0-31,31表示最好 updateSerial(); mySerial.println("AT+CCID"); //读取SIM,可以检测是否有SIM卡或者是否接触良好 updateSerial(); mySerial.println("AT+CREG?"); //检测是否注册网络 updateSerial(); mySerial.println("AT+SNFS=0"); //调整为耳机模式(AT+SNFS=1 表示扬声器模式) updateSerial(); mySerial.println("AT+CRSL=2"); //调整音量,值为0-15,15表示音量最大 updateSerial(); while(1) { if(mySerial.available()) { Serial.write(mySerial.read());//如果mySerial收到数据则通过Serial输出 } if(Serial.available()) { mySerial.write(Serial.read());//如果Serial收到数据则通过mySerial输出 } } } 连接图片 4. 上电后,GSM模块启动,间断蓝灯闪烁,应该是模块正常工作的状态,不过在串口没有反馈信号. 经过测试,应该是波特率配置不成功. 需要进一步调试. 需要注意的是这个模块只能用5V电压驱动,在3.3V的时候,模块供电不足,不能正常启动.蓝色LED灯也不闪烁. 按照A9的手册,这个波特率是采用自协调和同步的方式,出现这样子,还是需要重新分析. 出厂的标准波特率其实是115200,不过配合arduino的正常读取,用9600也应该是可以的. 此内容由EEWORLD论坛网友北方原创,如需转载或用于商业用途需征得作者同意并注明出处

  • 回复了主题帖: 不小心把lis25ba的一个焊盘弄掉了,飞了一根线

    qwqwqw2088 发表于 2019-8-12 10:14 烙铁不能停留时间太长,温度要适当的高些
    焊接OK,但是实在要很使用要很温柔才行  

  • 回复了主题帖: 不小心把lis25ba的一个焊盘弄掉了,飞了一根线

    littleshrimp 发表于 2019-8-10 07:30 你准备使用什么单片机?可以把单片机电压降下来试试,或者使用IKS01A3板子上的电压转换芯片,在DIL24 Sock ...
    我也把这个板子的Vcc给弄掉了。没法再弄下去了。 因为焊接的过程很正常,但是使用的过程中不知什么时候就掉了。 研究后发现,焊盘接触时间过长,然后引脚稍微受力大一些就game over了。 没有找到好的解决办法前不敢再测试了。焊盘其实只有一层铜箔。

  • 2019-07-24
  • 发表了主题帖: 【沁恒试用】 使用触摸按键和GPIO完成拨号和挂断的功能 #3

    本帖最后由 北方 于 2019-7-24 16:47 编辑 1、经过对基本功能的测试,进入了触摸手机的软件开发工作 2、首先选择CH549L的使用的引脚 参照下图, 对照扩展引脚的接口, CH549 16通道触摸按键对用通道和引用,目前把CH4~CH7预留,直接跳到CH12~CH15,板载 *                      CH0~CH15 分别对应引脚 P1.0~P1.7  P0.0~P0.7         其中 硬件SPI接口预留          CH549          P1.4        =       SCS          P1.5        =       MOSI          P1.6        =       MISO          P1.7        =       SCK 引用GPIO点亮LED灯,板载LED为P22~P25 *                         LED 输出接口                          LED 0~12 分别对应引脚 P2.0~P2.7 P4.2~P4.5    *                         UART0 接口预留                         P3.0 = RXD                           P3.1 = TXD   3. 代码说明如下 3.1 程序初始化后,扫描ADC口,读取touch的按键,对照用LED显示按键的位置 其中使用chneo变量来确定1-12个按键和对应的LED灯。 3.2 然后读取最后按下的按键,以离开为准,用switch~case来给uart0输出AT命令,按键11用ATD+号码拨出电话号码,用12号按键挂掉电话,用ATH命令。 3.3 在确定了按键读取后,就可以使用更丰富的按键组合来实现按键和电话拨打功能。   3.4 代码如下: #include ".\Public\CH549.H" #include ".\Public\DEBUG.H" #include ".\TouchKey\TouchKey.H" #include ".\SPI\SPI.H" #pragma NOAREGS #define COLORED 0 #define UNCOLORED 1 UINT16 PowerValue[16]; UINT8 PressedKey; //保存触摸按键上电未触摸值 volatile UINT16 Press_Flag = 0; //按下标志位 UINT8C CPW_Table[16] = { 30,30,30,30, 30,30,30,30, //与板间电容有关的参数,分别对应每个按键 30,30,30,30, 30,30,30,30, }; /******************************************************************************* * Function Name : ABS * Description : 求两个数差值的绝对值 * Input : a,b * Output : None * Return : 差值绝对值 *******************************************************************************/ UINT16 ABS(UINT16 a,UINT16 b) { if(a>b) { return (a-b); } else { return (b-a); } } /******************************************************************************* * Function Name : LED_Port_Init * Description : LED引脚初始化,推挽输出 * P22~P25 * Input : None * Output : None * Return : None *******************************************************************************/ void LED_Port_Init(void) { P2 |= (0xFF); //默认熄灭 P2_MOD_OC &= ~(0xFF); P2_DIR_PU |= (0xFF); P4 |= (0xF<<2); //默认熄灭 P4_MOD_OC &= ~(0xF<<2); P4_DIR_PU |= (0xF<<2); } /******************************************************************************* * Function Name : LED_Control * Description : 点灯控制 * Input : LEDx: 0~3 分别对应P22~P25四个LED灯(低驱) // Revised. * status: 0:灭 1:亮 * Output : None * Return : None *******************************************************************************/ void LED_Control(UINT8 LEDx,UINT8 status) { if(LEDx>=8) { LEDx = LEDx - 8; if(status) //点亮 { P4 &= ~(1<<(2+LEDx)); } else //熄灭 { P4 |= (1<<(2+LEDx)); } return; } if(LEDx>=0) // (LEDx<8) { if(status) //点亮 { P2 &= ~(1<<(LEDx)); } else //熄灭 { P2 |= (1<<(LEDx)); } return; } } //主函数 void main() { UINT8 ch; UINT8 chneo; UINT16 value; UINT16 err; UINT16 i=0; //触摸模拟变化差值 CfgFsys( ); //CH549时钟选择配置 mDelaymS(20); mInitSTDIO( ); //串口0初始化 //printf("BitPhone start ...\n"); LED_Port_Init(); TouchKey_Init(); Press_Flag = 0; //无按键按下 /* 获取按键初值 */ for(chneo = 1; chneo!=12; chneo++) { if(chneo>4) { ch = chneo + 4; } if(chneo<=4) { ch = chneo; } PowerValue[ch] = TouchKeySelect( ch,CPW_Table[ch] ); //printf("%d ",PowerValue[ch] ); } printf("\n"); //SPI setting //SPIMasterModeSet(3); //SPI_CK_SET(12); //SCS = 0; //SPI主机发送数据 //CH549SPIMasterWrite(i); //mDelaymS(5); while(1) { //CH549SPIMasterWrite(i); mDelaymS(5); /* 按键检测 */ for(chneo = 1; chneo!=12; chneo++) { if(chneo>4) { ch = chneo + 4; } if(chneo<=4) { ch = chneo; } value = TouchKeySelect( ch,CPW_Table[ch] ); err = ABS(PowerValue[ch],value); if( err > DOWM_THRESHOLD_VALUE ) //差值大于阈值,认为按下 { if((Press_Flag & (1<<ch)) == 0) //说明是第一次按下 { //printf("ch %d pressed,value:%d\n",(UINT16)ch, value); /* 点灯处理 */ LED_Control(chneo,1); //LED_Control(chneo-6,1); } Press_Flag |= (1<<ch); } else if( err < UP_THRESHOLD_VALUE ) //说明抬起或者未按下 { if(Press_Flag & (1<<ch)) //刚抬起 { Press_Flag &= ~(1<<ch); //printf("ch %d up,value:%d\n",(UINT16)ch, value); /* 灭灯处理 */ LED_Control(chneo,0); //LED_Control(chneo-6,0); PressedKey= chneo; } } } switch (PressedKey) { case 1: PressedKey=0; printf("0"); break; case 2: PressedKey=0; printf("1"); break; case 3: PressedKey=0; printf("2"); break; case 4: PressedKey=0; printf("3"); break; case 5: PressedKey=0; printf("4"); break; case 6: PressedKey=0; printf("5"); break; case 7: PressedKey=0; printf("6"); break; case 8: PressedKey=0; printf("7"); break; case 9: PressedKey=0; printf("8"); break; case 10: PressedKey=0; printf("9"); break; case 11: //Call PressedKey=0; printf("ATD"); break; case 12: PressedKey=0; printf("\n"); break; case 0: // Hand Off PressedKey=0; printf("ATH"); break; } } } 4. 最后编译的结果有20个警告,是定义了变量空间没有访问,需要后续优化。 总共24+2个引脚被定义和使用,占了44个引脚的60%,仍然有扩展功能的空间,所有CH549L具有足够丰富的功能。 编译的二进制文档如下: 此内容由EEWORLD论坛网友北方原创,如需转载或用于商业用途需征得作者同意并注明出处

  • 2019-07-22
  • 发表了主题帖: 【沁恒试用】增加SPI的引用 #2

    1、在完成基本框架构成设计之后,逐步增加系统增加系统资源的调用,这次增加SPI。 2、SPI需要4个引脚,这里使用的是SPI0,占用了          CH549          P1.4        =       SCS          P1.5        =       MOSI          P1.6        =       MISO          P1.7        =       SCK 3、软件调用前需要引用spi.h头文件,并加载spi.c这样就可以调用spi,使用起来就很简单。 程序启动设定spi,     SPIMasterModeSet(3);      SPI_CK_SET(12); 然后直接加载 SCS = 0;                                                               //SPI主机发送数据     CH549SPIMasterWrite(i);  就可以写入SPI数据了。 4、代码扩展如下。 #include ".\Public\CH549.H" #include ".\Public\DEBUG.H" #include ".\TouchKey\TouchKey.H" #include ".\SPI\SPI.H" /****************************************************************************** 使用CH549 硬件SPI接口 CH549 P1.4 = SCS P1.5 = MOSI P1.6 = MISO P1.7 = SCK *******************************************************************************/ #pragma NOAREGS UINT16 PowerValue[16]; //保存触摸按键上电未触摸值 volatile UINT16 Press_Flag = 0; //按下标志位 UINT8C CPW_Table[16] = { 30,30,30,30, 30,30,30,30, //与板间电容有关的参数,分别对应每个按键 30,30,30,30, 30,30,30,30, }; UINT16 ABS(UINT16 a,UINT16 b) { if(a>b) { return (a-b); } else { return (b-a); } } void LED_Port_Init(void) { P2 |= (0xF<<2); //默认熄灭 P2_MOD_OC &= ~(0xF<<2); P2_DIR_PU |= (0xF<<2); } void LED_Control(UINT8 LEDx,UINT8 status) { if(LEDx>3) { return; } if(status) //点亮 { P2 &= ~(1<<(2+LEDx)); } else //熄灭 { P2 |= (1<<(2+LEDx)); } } //主函数 void main() { UINT8 ch; UINT16 value; UINT16 err; UINT16 i=0; //触摸模拟变化差值 CfgFsys( ); //CH549时钟选择配置 mDelaymS(20); mInitSTDIO( ); //串口0初始化 printf("TouchKey demo start ...\n"); LED_Port_Init(); TouchKey_Init(); Press_Flag = 0; //无按键按下 /* 获取按键初值 */ for(ch = 8; ch!=12; ch++) { PowerValue[ch] = TouchKeySelect( ch,CPW_Table[ch] ); printf("%d ",PowerValue[ch] ); } printf("\n"); //SPI setting SPIMasterModeSet(3); SPI_CK_SET(12); SCS = 0; //SPI主机发送数据 CH549SPIMasterWrite(i); mDelaymS(5); while(1) { CH549SPIMasterWrite(i); mDelaymS(5); } } 此内容由EEWORLD论坛网友北方原创,如需转载或用于商业用途需征得作者同意并注明出处

  • 2019-07-17
  • 发表了主题帖: 3、基于Nucleo-L476L的健康运动助手项目开发

    本帖最后由 北方 于 2019-7-17 16:57 编辑 1、简述-基于Nucleo-L476L的健康运动助手    基于Nucleo-L476L的健康运动助手是一个基于STM32L476L的便携运动健康电子助手的原型设计。实现以下功能:    启动后不读取传感器数据,降低功耗。当检测到运动数据后,启动计步器,开始计算运动步数,同时读取运动环境的温度和湿度,同时读取大气压,折算运动位置的海拔。在中止运动一段时间后,停止计数,并输出运动量。   2、采用的硬件     采用Nucleo-STM32L476和X-NUCLEO-IKS01A3。其中应用到的四种传感器有: LSM6DSO 用于计步器计数, LIS2DW12 用于从休眠中唤醒,进入传感器读取和计步器计数 LPS22HH   用于读取大气压数据 STTS751   用于读取环境温度   3、开发环境和工具 3.1 开发环境使用Arduino1.8.9 3.2 开发需要先安装以上4种传感器的arduino驱动程序,然后直接在程序中引用库就可以了。   4、实现代码 这个代码使用了2个标志位mems_event = 0 和 ped_event=0,分别启动中断,上升沿启动内部置位的变化。 同时设定了一个IDLEPERIOD,演示设置位10000ms,即10秒,之后就退出计数。   /** ****************************************************************************** * @brief Arduino test application for the STMicrolectronics X-NUCLEO-IKS01A3 ****************************************************************************** */ // Includes #include <LSM6DSOSensor.h> #include <LIS2DW12Sensor.h> #include <LPS22HHSensor.h> #include <STTS751Sensor.h> #ifdef ARDUINO_SAM_DUE #define DEV_I2C Wire1 #elif defined(ARDUINO_ARCH_STM32) #define DEV_I2C Wire #elif defined(ARDUINO_ARCH_AVR) #define DEV_I2C Wire #else #define DEV_I2C Wire #endif #define SerialPort Serial #define INT_1 4 #define IDLEPERIOD 10000 // Components LSM6DSOSensor *AccGyr; LIS2DW12Sensor *Acc2; LPS22HHSensor *Press; STTS751Sensor *Temp; //Interrupts. volatile int mems_event = 0; volatile int ped_event = 0; uint16_t step_count = 0; char report[256]; uint32_t previous_tick; void INT0Event_cb(); void INT1Event_cb(); void runningmode(); void setup() { // Led. pinMode(LED_BUILTIN, OUTPUT); // Initialize serial for output. SerialPort.begin(115200); // Initialize I2C bus. DEV_I2C.begin(); //Interrupts. attachInterrupt(A3, INT0Event_cb, RISING); attachInterrupt(INT_1, INT1Event_cb, RISING); //1. Using LSM6DSOSensor for Pedometer AccGyr = new LSM6DSOSensor (&DEV_I2C); AccGyr->Enable_X(); AccGyr->Enable_G(); AccGyr->Enable_Pedometer(); previous_tick = millis(); //2. Using LIS2DW12Sensor for wakeup detection Acc2 = new LIS2DW12Sensor (&DEV_I2C); Acc2->Enable_X(); Acc2->Enable_Wake_Up_Detection(); //3. Using LPS22HHSensor Press = new LPS22HHSensor(&DEV_I2C); Press->Enable(); //4. Using STTS751Sensor Temp = new STTS751Sensor (&DEV_I2C); Temp->Enable(); } void loop() { if (mems_event) { mems_event=0; LIS2DW12_Event_Status_t status; Acc2->Get_Event_Status(&status); if (status.WakeUpStatus) { // Output data. SerialPort.println("Wake up Detected!"); runningmode(); } } } void runningmode() { bool idel=1; while (idel){ if (ped_event) { ped_event=0; LSM6DSO_Event_Status_t status; AccGyr->Get_X_Event_Status(&status); if (status.StepStatus) { // New step detected, so print the step counter AccGyr->Get_Step_Count(&step_count); //snprintf(report, sizeof(report), "Step counter: %d", step_count); //SerialPort.println(report); } } // Print the step counter in any case every 3000 ms uint32_t current_tick = millis(); if((current_tick - previous_tick) >= IDLEPERIOD) { AccGyr->Get_Step_Count(&step_count); snprintf(report, sizeof(report), "Step counter: %d", step_count); SerialPort.println(report); previous_tick = millis(); // Read pressure and temperature. float pressure = 0, temperature2 = 0; Press->GetPressure(&pressure); //Read temperature float temperature = 0; Temp->GetTemperature(&temperature); SerialPort.print("| Pres[hPa]: "); SerialPort.print(pressure, 2); SerialPort.print(" | Temp[C]: "); SerialPort.print(temperature, 2); SerialPort.print("\n "); // Quit the while loop, idel=0; } } } void INT1Event_cb() { ped_event = 1; } void INT0Event_cb() { mems_event = 1; } 5、结果演示 5.1 初步显示计步器功能 5.2 综合计步器和环境温度和气压显示功能 显示唤醒后,开始计算运动步数,这里用手的摇动来显示结果,同时显示出环境温度和大气压。   6. 基于Nucleo-L476L的传感器数据读取的几点说明和建议 演示视频: 此内容由EEWORLD论坛网友北方原创,如需转载或用于商业用途需征得作者同意并注明出处

  • 2019-07-16
  • 发表了主题帖: 2、基于Nucleo-L476L的全部传感器数据读取和演示

    本帖最后由 北方 于 2019-7-16 15:52 编辑 1、基于Nucleo-L476L的全部传感器数据读取和演示主要是演示评测计划中全部传感器数据的读取和输出。 根据分析传感器的数据表,可以看出,这些传感器全部是 通过I2C总线读取和访问的。每个传感器具有一个唯一的地址码,再I2C读取的时候,指定地址码就可以唯一的访问这个传感器。传感器的地址码再开发板的反面完整地列出,详见上一帖的照片。 再这样的情况下,对于传感器数据的读取就变为对I2C的访问和读取,这样简化了设计,而且具有快速移植的特点。 2、开发环境和IDE 2.1 原计划中采用的arduino平台是一个快速开发和评测的工具,但是代码编译同样具有高效特点,因为,调用的编译器是GCC。对于代码的效率,重要的是代码逻辑的优化,那么同样具有复杂程序开发的能力。编译的hex可执行文件,可以直接写入flash,即使是工业化开发也没有问题。 2.2 再完成了arduino平台的开发后,其实同样的开发板移植到mbed平台也是非常迅速的,可以发现,很多代码都可以直接使用,适当调整一下格式就可以了。但是因为本次活动的先发先评的积分规则,如果同时进行评测mbed的平台会影响其他评测的计分,毕竟还有没有收到快递的。 2.3 使用Arduino-uno和使用Nucleo-Arduino开发的最大区别是标准arduino使用原生I2C库wire.h,使用更简单。而Nucleo-arduino重写了I2C的驱动,使用的是TwoWire类,用一个指针传递DEVICE_I2C,这样和STM的HAL等开发库的代码保持一致。所以,如果使用arduino-uno等均需要再wire部分进行调整。 3. 综合全部传感器数据读取的程序helloworld代码如下。因为是arduino代码,所以非常直观。 // Includes #include <LSM6DSOSensor.h> #include <LIS2DW12Sensor.h> #include <LIS2MDLSensor.h> #include <LPS22HHSensor.h> #include <STTS751Sensor.h> #include <HTS221Sensor.h> #ifdef ARDUINO_SAM_DUE #define DEV_I2C Wire1 #elif defined(ARDUINO_ARCH_STM32) #define DEV_I2C Wire #elif defined(ARDUINO_ARCH_AVR) #define DEV_I2C Wire #else #define DEV_I2C Wire #endif #define SerialPort Serial // Components LSM6DSOSensor *AccGyr; LIS2DW12Sensor *Acc2; LIS2MDLSensor *Mag; LPS22HHSensor *PressTemp; HTS221Sensor *HumTemp; STTS751Sensor *Temp3; void setup() { // Led. pinMode(LED_BUILTIN, OUTPUT); // Initialize serial for output. SerialPort.begin(115200); // Initialize I2C bus. DEV_I2C.begin(); AccGyr = new LSM6DSOSensor (&DEV_I2C); AccGyr->Enable_X(); AccGyr->Enable_G(); Acc2 = new LIS2DW12Sensor (&DEV_I2C); Acc2->Enable_X(); Mag = new LIS2MDLSensor (&DEV_I2C); Mag->Enable(); PressTemp = new LPS22HHSensor(&DEV_I2C); PressTemp->Enable(); HumTemp = new HTS221Sensor (&DEV_I2C); HumTemp->Enable(); Temp3 = new STTS751Sensor (&DEV_I2C); Temp3->Enable(); } void loop() { // Led blinking. digitalWrite(LED_BUILTIN, HIGH); delay(250); digitalWrite(LED_BUILTIN, LOW); delay(250); // Read humidity and temperature. float humidity = 0, temperature = 0; HumTemp->GetHumidity(&humidity); HumTemp->GetTemperature(&temperature); // Read pressure and temperature. float pressure = 0, temperature2 = 0; PressTemp->GetPressure(&pressure); PressTemp->GetTemperature(&temperature2); //Read temperature float temperature3 = 0; Temp3->GetTemperature(&temperature3); // Read accelerometer and gyroscope. int32_t accelerometer[3]; int32_t gyroscope[3]; memset(accelerometer, 0, 3); memset(gyroscope, 0, 3); AccGyr->Get_X_Axes(accelerometer); AccGyr->Get_G_Axes(gyroscope); //Read accelerometer int32_t accelerometer2[3]; memset(accelerometer2, 0, 3); Acc2->Get_X_Axes(accelerometer2); //Read magnetometer int32_t magnetometer[3]; memset(magnetometer, 0, 3); Mag->GetAxes(magnetometer); // Output data. SerialPort.print("| Hum[%]: "); SerialPort.print(humidity, 2); SerialPort.print(" | Temp[C]: "); SerialPort.print(temperature, 2); SerialPort.print(" | Pres[hPa]: "); SerialPort.print(pressure, 2); SerialPort.print(" | Temp2[C]: "); SerialPort.print(temperature2, 2); SerialPort.print(" | Temp3[C]: "); SerialPort.print(temperature3, 2); SerialPort.print(" | Acc[mg]: "); SerialPort.print(accelerometer[0]); SerialPort.print(" "); SerialPort.print(accelerometer[1]); SerialPort.print(" "); SerialPort.print(accelerometer[2]); SerialPort.print(" | Gyr[mdps]: "); SerialPort.print(gyroscope[0]); SerialPort.print(" "); SerialPort.print(gyroscope[1]); SerialPort.print(" "); SerialPort.print(gyroscope[2]); SerialPort.print(" | Acc2[mg]: "); SerialPort.print(accelerometer2[0]); SerialPort.print(" "); SerialPort.print(accelerometer2[1]); SerialPort.print(" "); SerialPort.print(accelerometer2[2]); SerialPort.print(" | Mag[mGauss]: "); SerialPort.print(magnetometer[0]); SerialPort.print(" "); SerialPort.print(magnetometer[1]); SerialPort.print(" "); SerialPort.print(magnetometer[2]); SerialPort.println(" |"); } 程序编译并上传到开发板,占用了38.180k内存(3%代码空间) 同时串口输出了全部的传感器数据,如下 4、演示视频 这个视频中,显示了变化的传感器数据读数,其中在转动和冲击时,x-y-z传感器和加速度传感器的数据都在实时地变化。 5、第一步基本数据读取和显示的评测任务完成。包括了以下的全部传感器。后续在一个演示程序中使用。 LSM6DSOSensor ; LIS2DW12Sensor ; LIS2MDLSensor ; LPS22HHSensor ; HTS221Sensor ; STTS751Sensor ; 参考的流程包括以下步骤, 导入传感器驱动, #include <LSM6DSOSensor.h> #include <LIS2DW12Sensor.h> #include <LIS2MDLSensor.h> #include <LPS22HHSensor.h> #include <STTS751Sensor.h> #include <HTS221Sensor.h>   创建传感器实例 LSM6DSOSensor *AccGyr; LIS2DW12Sensor *Acc2; LIS2MDLSensor *Mag; LPS22HHSensor *PressTemp; HTS221Sensor *HumTemp; STTS751Sensor *Temp3; // new instance   AccGyr = new LSM6DSOSensor (&DEV_I2C);   AccGyr->Enable_X();   AccGyr->Enable_G();   Acc2 = new LIS2DW12Sensor (&DEV_I2C);   Acc2->Enable_X();   Mag = new LIS2MDLSensor (&DEV_I2C);   Mag->Enable();   PressTemp = new LPS22HHSensor(&DEV_I2C);   PressTemp->Enable();   HumTemp = new HTS221Sensor (&DEV_I2C);   HumTemp->Enable();   Temp3 = new STTS751Sensor (&DEV_I2C);   Temp3->Enable(); 初始化I2C端口 #define DEV_I2C Wire   DEV_I2C.begin(); 逐个读取传感器数据并用串口以115200的波特率输出 float humidity = 0, temperature = 0;   HumTemp->GetHumidity(&humidity);   HumTemp->GetTemperature(&temperature);   // Read pressure and temperature.   float pressure = 0, temperature2 = 0;   PressTemp->GetPressure(&pressure);   PressTemp->GetTemperature(&temperature2);   //Read temperature   float temperature3 = 0;   Temp3->GetTemperature(&temperature3);   // Read accelerometer and gyroscope.   int32_t accelerometer[3];   int32_t gyroscope[3];   memset(accelerometer, 0, 3);   memset(gyroscope, 0, 3);   AccGyr->Get_X_Axes(accelerometer);   AccGyr->Get_G_Axes(gyroscope);   //Read accelerometer   int32_t accelerometer2[3];   memset(accelerometer2, 0, 3);   Acc2->Get_X_Axes(accelerometer2);   //Read magnetometer   int32_t magnetometer[3];   memset(magnetometer, 0, 3);   Mag->GetAxes(magnetometer);   此内容由EEWORLD论坛网友北方原创,如需转载或用于商业用途需征得作者同意并注明出处

  • 2019-07-15
  • 发表了主题帖: 1、基于Nucleo-L476L的HTS221等全部传感器的驱动

    本帖最后由 北方 于 2019-7-16 14:51 编辑 1、基于Nucleo-STM32L476L的Arduino实现NUCLEO-IKS01A3的全部传感器驱动实现。     初始计划是采用MKR1000,但是在使用和下载的过程中,这个开发板给变砖了。 所以只好先拿出吃灰的Nucleo-STM32L476L先实现以下基本的arduino驱动。在完成这个基本评测后再移植到其他arduino开发板上使用。 针对不同的传感器,参照以下具体代码逐个说明和实现。       这个过程中首先需要使用开发板管理器安装arduino开发板, 这样就可以设置开发板了, 然后安装NUCLEO-IKS01A3的传感器驱动, 这样就可以再程序中直接使用驱动库了。 驱动和安装说明可以从如下链接获得,https://github.com/stm32duino/Arduino_Core_STM32 这个是官方的arduino驱动。 2、传感器驱动代码和说明 2.1 首先导入HTS221Sensor.h,这个是HTS221的驱动,设定I2C的引脚后就可以直接访问HTS221传感器,程序读取传感器的数据,转换后通过串口输出。 代码如下: #include <HTS221Sensor.h> #define I2C2_SCL PB10 #define I2C2_SDA PB11 // Components. HTS221Sensor *HumTemp; TwoWire *dev_i2c; void setup() { // Led. pinMode(LED_BUILTIN, OUTPUT); // Initialize serial for output. Serial.begin(9600); // Initialize I2C bus. dev_i2c = new TwoWire(I2C2_SDA, I2C2_SCL); dev_i2c->begin(); // Initlialize components. HumTemp = new HTS221Sensor (dev_i2c); HumTemp->Enable(); } void loop() { // Led blinking. digitalWrite(LED_BUILTIN, HIGH); delay(250); digitalWrite(LED_BUILTIN, LOW); delay(250); // Read humidity and temperature. float humidity, temperature; HumTemp->GetHumidity(&humidity); HumTemp->GetTemperature(&temperature); // Output data. Serial.print("Hum[%]: "); Serial.print(humidity, 2); Serial.print(" | Temp[C]: "); Serial.println(temperature, 2); } 输出结果如下, 因为本传感器只检查温度和湿度,所以使用照片显示结果,   2.2  3D加速度+3D陀螺仪    LSM6DS +Nucleo-STM32L476L读取传感器数据 首先导入驱动程序 #include <LSM6DSOSensor.h> 同上,先设定I2C的接口,然后把变化传感器数据输出到串口 代码如下: #include <LSM6DSOSensor.h> #ifdef ARDUINO_SAM_DUE #define DEV_I2C Wire1 #elif defined(ARDUINO_ARCH_STM32) #define DEV_I2C Wire #elif defined(ARDUINO_ARCH_AVR) #define DEV_I2C Wire #else #define DEV_I2C Wire #endif #define SerialPort Serial #define INT_1 4 LSM6DSOSensor *accGyr; //Interrupts. volatile int mems_event = 0; char report[256]; void INT1Event_cb(); void sendOrientation(); void setup() { // Led. pinMode(LED_BUILTIN, OUTPUT); // Initialize serial for output. SerialPort.begin(115200); // Initialize I2C bus. DEV_I2C.begin(); //Interrupts. attachInterrupt(INT_1, INT1Event_cb, RISING); accGyr = new LSM6DSOSensor (&DEV_I2C); accGyr->Enable_X(); accGyr->Enable_6D_Orientation(LSM6DSO_INT1_PIN); } void loop() { if (mems_event) { mems_event=0; LSM6DSO_Event_Status_t status; accGyr->Get_X_Event_Status(&status); if (status.D6DOrientationStatus) { sendOrientation(); // Led blinking. digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); } } } void INT1Event_cb() { mems_event = 1; } void sendOrientation() { uint8_t xl = 0; uint8_t xh = 0; uint8_t yl = 0; uint8_t yh = 0; uint8_t zl = 0; uint8_t zh = 0; accGyr->Get_6D_Orientation_XL(&xl); accGyr->Get_6D_Orientation_XH(&xh); accGyr->Get_6D_Orientation_YL(&yl); accGyr->Get_6D_Orientation_YH(&yh); accGyr->Get_6D_Orientation_ZL(&zl); accGyr->Get_6D_Orientation_ZH(&zh); if ( xl == 0 && yl == 0 && zl == 0 && xh == 0 && yh == 1 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n | | " \ "\r\n | * | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n |________________| \r\n" ); } else if ( xl == 1 && yl == 0 && zl == 0 && xh == 0 && yh == 0 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n | | " \ "\r\n | * | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n |________________| \r\n" ); } else if ( xl == 0 && yl == 0 && zl == 0 && xh == 1 && yh == 0 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | * | " \ "\r\n |________________| \r\n" ); } else if ( xl == 0 && yl == 1 && zl == 0 && xh == 0 && yh == 0 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | * | " \ "\r\n |________________| \r\n" ); } else if ( xl == 0 && yl == 0 && zl == 0 && xh == 0 && yh == 0 && zh == 1 ) { sprintf( report, "\r\n __*_____________ " \ "\r\n |________________| \r\n" ); } else if ( xl == 0 && yl == 0 && zl == 1 && xh == 0 && yh == 0 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n |________________| " \ "\r\n * \r\n" ); } else { sprintf( report, "None of the 6D orientation axes is set in LSM6DSO - accelerometer.\r\n" ); } SerialPort.print(report); } 通过串口演示读取加速度计的变化位置, 主要代码 sprintf( report, "\r\n ________________ " \ "\r\n |________________| " \ "\r\n * \r\n" ); 2.3 3D磁力计    LIS2MD + Nucleo-STM32L476L 读取传感器数据 首先导入驱动程序 #include <LIS2DW12Sensor.h> 同上,先设定I2C的接口,然后把变化传感器数据输出到串口 代码类似上面,具体读取再后面的综合数据输出中展示。 2.4 3D加速度    LIS2DW12+Nucleo-STM32L476L 读取传感器数据 首先导入驱动程序 同上,先设定I2C的接口,然后把变化传感器数据输出到串口 代码如下: #include <LIS2DW12Sensor.h> #ifdef ARDUINO_SAM_DUE #define DEV_I2C Wire1 #elif defined(ARDUINO_ARCH_STM32) #define DEV_I2C Wire #elif defined(ARDUINO_ARCH_AVR) #define DEV_I2C Wire #else #define DEV_I2C Wire #endif #define SerialPort Serial // Components. LIS2DW12Sensor *accelero; //Interrupts. volatile int mems_event = 0; char report[256]; void INT1Event_cb(); void sendOrientation(); void setup() { // Led. pinMode(LED_BUILTIN, OUTPUT); // Initialize serial for output. SerialPort.begin(115200); // Initialize I2C bus. DEV_I2C.begin(); //Interrupts. attachInterrupt(A3, INT1Event_cb, RISING); // Initlialize components. accelero = new LIS2DW12Sensor(&DEV_I2C); accelero->Enable_X(); // Enable 6D Orientation. accelero->Enable_6D_Orientation(); } void loop() { if (mems_event) { mems_event = 0; LIS2DW12_Event_Status_t status; accelero->Get_Event_Status(&status); if (status.D6DOrientationStatus) { // Send 6D Orientation sendOrientation(); // Led blinking. digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); } } } void INT1Event_cb() { mems_event = 1; } void sendOrientation() { uint8_t xl = 0; uint8_t xh = 0; uint8_t yl = 0; uint8_t yh = 0; uint8_t zl = 0; uint8_t zh = 0; accelero->Get_6D_Orientation_XL(&xl); accelero->Get_6D_Orientation_XH(&xh); accelero->Get_6D_Orientation_YL(&yl); accelero->Get_6D_Orientation_YH(&yh); accelero->Get_6D_Orientation_ZL(&zl); accelero->Get_6D_Orientation_ZH(&zh); if ( xl == 1 && yl == 0 && zl == 0 && xh == 0 && yh == 0 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n | | " \ "\r\n | * | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n |________________| \r\n" ); } else if ( xl == 0 && yl == 1 && zl == 0 && xh == 0 && yh == 0 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n | | " \ "\r\n | * | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n |________________| \r\n" ); } else if ( xl == 0 && yl == 0 && zl == 0 && xh == 0 && yh == 1 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | * | " \ "\r\n |________________| \r\n" ); } else if ( xl == 0 && yl == 0 && zl == 0 && xh == 1 && yh == 0 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | * | " \ "\r\n |________________| \r\n" ); } else if ( xl == 0 && yl == 0 && zl == 0 && xh == 0 && yh == 0 && zh == 1 ) { sprintf( report, "\r\n __*_____________ " \ "\r\n |________________| \r\n" ); } else if ( xl == 0 && yl == 0 && zl == 1 && xh == 0 && yh == 0 && zh == 0 ) { sprintf( report, "\r\n ________________ " \ "\r\n |________________| " \ "\r\n * \r\n" ); } else { sprintf( report, "None of the 6D orientation axes is set in LIS2DW12 - accelerometer.\r\n" ); } SerialPort.print(report); } 用图形的符号表示地磁的方向, 参见代码 sprintf( report, "\r\n ________________ " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | | " \ "\r\n | * | " \ "\r\n |________________| \r\n" );   2.5 气压传感器    LPS22HH   + Nucleo-STM32L476L读取传感器数据 首先导入驱动程序 同上,先设定I2C的接口,然后把变化传感器数据输出到串口 代码类似,具体参见下一贴。 2.6 温度传感器    STTS751+  Nucleo-STM32L476L读取传感器数据 首先导入驱动程序#include <STTS751Sensor.h> 在程序中,首先定义i2c的引脚和接线,然后读取传感器数据,并输出到串口。   实现代码如下, #include <STTS751Sensor.h> #ifdef ARDUINO_SAM_DUE #define DEV_I2C Wire1 #elif defined(ARDUINO_ARCH_STM32) #define DEV_I2C Wire #elif defined(ARDUINO_ARCH_AVR) #define DEV_I2C Wire #else #define DEV_I2C Wire #endif #define SerialPort Serial #define INT_1 A4 //Interrupts. volatile int mems_event = 0; uint8_t high = 0, low = 0; uint32_t previous_tick; float temperature = 0; STTS751Sensor *Temp; void INT1Event_cb() { mems_event = 1; } void setup() { // Led. pinMode(LED_BUILTIN, OUTPUT); // Initialize serial for output. SerialPort.begin(115200); // Initialize I2C bus. DEV_I2C.begin(); //Interrupts. attachInterrupt(INT_1, INT1Event_cb, FALLING); Temp = new STTS751Sensor(&DEV_I2C); Temp->Enable(); Temp->SetOutputDataRate(4.0f); Temp->SetLowTemperatureThreshold(22.0f); Temp->SetHighTemperatureThreshold(28.0f); Temp->SetEventPin(1); Temp->GetTemperatureLimitStatus(NULL, NULL, NULL); previous_tick=millis(); } void loop() { if (mems_event) { mems_event=0; uint8_t highTemp = 0, lowTemp = 0; Temp->GetTemperatureLimitStatus(&highTemp, &lowTemp, NULL); if (highTemp){ high = 1; low = 0; } if (lowTemp){ low = 1; high = 0; } Temp->GetTemperature(&temperature); // Led blinking. digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); } uint32_t current_tick = millis(); if ((current_tick - previous_tick) >= 2000){ if (!high && !low){ Temp->GetTemperature(&temperature); } SerialPort.print("Temp[C]: "); SerialPort.print(temperature, 2); if (high){ SerialPort.println(" High temperature detected!(>28C) "); high = 0; } else if (low) { SerialPort.println(" Low temperature detected!(<22C) "); low = 0; } else { SerialPort.println(); } previous_tick = millis(); } } 程序下载和串口输出如下, 3、实现视频不单独演示,详见下一帖综合展示。       此内容由EEWORLD论坛网友北方原创,如需转载或用于商业用途需征得作者同意并注明出处

  • 2019-07-11
  • 回复了主题帖: 【奖品发送完毕】:从终端到架构,TE Connectivity(TE)助你连接5G高速未来

    确认个人信息无误 ,兑换成E金币,谢谢

  • 2019-07-10
  • 发表了主题帖: 【沁恒试用】精简手机系统设计 #1

    本帖最后由 北方 于 2019-7-10 13:55 编辑 精简手机系统设计 1、概述 精简手机系统设计是基于8051单片机沁恒CH549L和安可信A9G数据通讯模块开放的精简手机。 2、实现的功能 能够实现精简通讯和实时位置追踪功能。   3、实现的逻辑和原理 3.1 采用CH549和安可信A9G数据通讯模块通过UART口进行数据通讯和连接,连接采用的是标准的AT命令。 在CH549的开发中,使用了touchKey,ADC, GPIO,UART等多个资源,经过选择和调试,项目能够完整运行。其中CH549提供了UART0,UART1,UART2和UART3均测试,其中UART2和ouchkey的ADC有冲突,UART1在touchkey init中也有冲突,需要调整。 开发板连接如下图   本项目选择了UART0,可以在一个端口同时被板载USB-ttl转换,从desktop上也可以获取at通讯的信号,如下图   3.2 项目初步调试的代码如下,大部分是touchkey范例的参照。 #include ".\Public\CH549.H" #include ".\Public\DEBUG.H" #include ".\TouchKey\TouchKey.H" #pragma NOAREGS UINT16 PowerValue[16]; volatile UINT16 Press_Flag = 0; UINT8C CPW_Table[16] = { 30,30,30,30, 30,30,30,30, 30,30,30,30, 30,30,30,30, }; UINT16 ABS(UINT16 a,UINT16 b) { if(a>b) { return (a-b); } else { return (b-a); } } void LED_Port_Init(void) { P2 |= (0xF<<2); //默认熄灭 P2_MOD_OC &= ~(0xF<<2); P2_DIR_PU |= (0xF<<2); } void LED_Control(UINT8 LEDx,UINT8 status) { if(LEDx>3) { return; } if(status) //点亮 { P2 &= ~(1<<(2+LEDx)); } else //熄灭 { P2 |= (1<<(2+LEDx)); } } //主函数 void main() { UINT8 ch; UINT16 value; UINT16 err; //触摸模拟变化差值 CfgFsys( ); //CH549时钟选择配置 mDelaymS(20); mInitSTDIO( ); //串口0初始化 printf("TouchKey demo start ...\n"); LED_Port_Init(); TouchKey_Init(); Press_Flag = 0; for(ch = 8; ch!=12; ch++) { PowerValue[ch] = TouchKeySelect( ch,CPW_Table[ch] ); printf("%d ",PowerValue[ch] ); } printf("\n"); while(1) { /* 按键检测 */ for(ch = 8; ch!=12; ch++) { value = TouchKeySelect( ch,CPW_Table[ch] ); err = ABS(PowerValue[ch],value); if( err > DOWM_THRESHOLD_VALUE ) { if((Press_Flag & (1<<ch)) == 0) { printf("ch %d pressed,value:%d\n",(UINT16)ch, value); /* 点灯处理 */ LED_Control(ch-8,1); } Press_Flag |= (1<<ch); } else if( err < UP_THRESHOLD_VALUE ) { if(Press_Flag & (1<<ch)) { Press_Flag &= ~(1<<ch); printf("ch %d up,value:%d\n",(UINT16)ch, value); LED_Control(ch-8,0); } } } } }   其中,这里对于GPIO的访问是直接调用ch549.h中对于sbit P2的定义访问寄存器的方法,效率很高。   3.3 预留三维运动传感器的连接接口继续开发。 4. 补充说明 4.1 开发工具,推荐的开发需要keil C51,这样可以按照手册的方法添加芯片库。用开源SDCC也可以,不过只能使用标准MCS51的外设,不推荐。 4.2 程序下载比上一次的CH554评测增加了一个板载开关ON/OFF,非常方便,避免了反复插拔USB线的可能,同时USB下载速度有了明显提高,这样从keil直接下载也没有很大区别了。这个WCHISPtools可以开放接口,作为第三方程序在keil中直接调用,进一步提高效率。   4.3 实时操作系统,采用FREERTOS需要8k左右的内存,更重要的是data数据区只有256字节,在运行中受限更明显,不宜采用。RTX tiny小于1k可以使用,不过调试使用需要更熟悉时钟,不如用轮询的polling方式更简单直接。自己直接算时钟周期,其实也效果不错。 4.4 引用范例的head文件要仔细对代码,尤其是复用的引脚和中断的配置,需要列表后使用,避免冲突。 4.5 安可信的A9G资料在参见https://wiki.ai-thinker.com/gprs/a9g/boards,CH549L的芯片原理连接如下图。 引脚配置使用时需要对照使用。   5、小结 本设计可以实现一个便携手机的功能。这个设计过程中, - 完整测试了多个适合8051的实时操作系统如RTX tiny, FreeRTOS,经测试均不适合本项目,也就没有采用。 - 在多个端口的同时使用中,多次发生重复定义和接口重复的过程,加深了对CH549L的了解。   此内容由EEWORLD论坛网友北方原创,如需转载或用于商业用途需征得作者同意并注明出处

  • 2019-07-09
  • 回复了主题帖: 入围名单揭晓:ST传感器驱动移植大赛+骨传感器评测活动

    论坛中个人资料正确,能够在8月25日之前完成评测计划。

  • 2019-06-24
  • 回复了主题帖: 分高者胜:ST传感器闯天下之驱动移植大赛+骨振动传感器评测

    本帖最后由 北方 于 2019-6-24 13:28 编辑 (1)想要申请的板子: 运动和环境传感器开发板X-NUCLEO-IKS01A3 LIS25BA骨振动传感器的适配板相关资料 (2)预计移植的驱动:           3D加速度+3D陀螺仪    LSM6DS +MKR-1000 读取传感器数据           3D磁力计    LIS2MD + MKR-1000 读取传感器数据           3D加速度    LIS2DW12。+MKR-1000 读取传感器数据           气压传感器    LPS22HH   + MKR-1000 读取传感器数据           温度传感器    STTS751+  MKR-1000 读取传感器数据 骨导 传感器 LIS25BA + MKR-1000 读取传感器数据 并输出到串口。   再移植LSM6DS+ 沁源CH549 读取数据 (3)自拟评测项目: 因为CH549的资源有限,所以只能读取有限的外设,拟读取LSM6DS数据,并用http API上传到云端并在云端显示数据结果。 全部完成预计能达到85分。  

  • 回复了主题帖: “沁恒评估板诚芯送”活动答疑帖

    正在移植RTOS,没有历程自己搞。RTX和FreeRTOS选择测试中。 没有rtos,多外设访问就一团糟了。 申请助力。

  • 2019-06-11
  • 回复了主题帖: 【奖品已全部寄出,请注意查收】TouchGFX活动颁奖

    确认接受邮箱 yaof@chec.com.cn 谢谢  

  • 2019-06-10
  • 发表了主题帖: 精简手机系统设计

    精简手机系统设计 1、概述 精简手机系统设计是基于8051单片机和安可信A9G数据通讯模块开放的精简手机。 2、实现的功能 能够实现精简通讯和实时位置追踪功能。   3、实现的逻辑和原理 3.1 采用CH549和安可信A9G数据通讯模块 3.2 同时提供三维运动传感器的连接接口   4、小结 通过实现本设计,可以实现一个便携手机的功能。 此内容由EEWORLD论坛网友北方原创,如需转载或用于商业用途需征得作者同意并注明出处

  • 回复了主题帖: 【物品已全部寄出,请注意查收】沁恒送福利,评估板诚芯送

    个人信息正确!

最近访客

< 1/6 >

统计信息

已有125人来访过

  • 芯币:441
  • 好友:1
  • 主题:77
  • 回复:84
  • 课时:--
  • 资源:--

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言