打印
[STM32H7]

【STM32H7S78-DK测评】基于STM32H7S7智慧工农业控制台

[复制链接]
49|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
    今年的中央一号文件提出,“持续实施数字乡村发展行动,发展智慧农业”。近年来,物联网、大数据、人工智能等技术在农业领域深入应用,促进农业生产更便捷、管理更高效,智能农业监控系统。基于STM32H7S7智慧工农业控制台通过STM32H7S7嵌入式系统结合各种传感器、执行器和通信模块,实现对农田环境的实时监测、自动控制和数据传输。所需要的器件:
   4G模块:移远EC800    WiFi:EWM3080


土壤传感器可以同时测量土壤温度、土壤体积含水量和土壤电导率三项参数,通过RS485 modbus 与STM32H7S7进行通信。



   首先基于STM32H7S78-DK强大的GUI显示能力,  作为看板和控制台,实时监测农业各种参数,控规按键进行远程遥控。基于Freertos和touchGFX搭建物联网边缘控制台,通过4G或者WiFi读取传感器参数,实时显示。TouchGFX生态链工具支持全系列STM32 MCU,能够最大化发挥STM32H7RS内置的硬件图形优化器性能,并且通过“所见即所得”的开发界面,自动生成代码,让用户使用起来非常的简单且高效。TouchGFX Core提供了性能测量信号,通过与STM32CubeMX配置的GPIO同步,可以实现对渲染时间等指标的可视化。在生成器中,GPIO类的函数被用于响应这些信号。
  STM32H7S78的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2ms一张,实现了更多的动画效果以及性能优化,把CPU从图形任务中释放出来,低功耗,少存储,具有更高的GUI性能,可实现平滑而丰富的图形效果。





  物接入(IoT Hub)是面向物联网领域开发者的全托管云服务,通过主流的物联网协议(如 MQTT)通讯,可以在智能设备与云端之间建立安全的双向连接,快速实现物联网项目。物接入分为设备型(原物管理)和数据型两种项目类型。设备型适用于基于设备的物联网场景;数据型适用于基于数据流的物联网场景。利用物接入来作为搭建物联网应用的第一步,支持亿级并发连接和消息数,支持海量设备与云端安全可靠的双向连接,无缝对接阿里云,华为云,或者百度天工平台和百度智能云。

框架:


物模型:物模型由一个或多个属性构成,可以用他来表示一类(或同一型号的一批)设备。基于物模型可以创建物影子。
    MQTT(Message Queuing Telemetry Transport)是一个基于二进制消息的客户端服务端架构的发布/订阅(Publish/Subscribe)模式的消息传输协议,最早由
IBM 提出的,如今已经业界通行规范,更符合机器与机器的通信(M2M)以及物联网环境(IoT)。

   MQTT 关键代码:
#include "mqtt.h"
#include "stdlib.h"
#include "string.h"

_MQTT_INFO mqtt_info;

/*******************************************************************************
* Function Name  : Mqtt_Init
* Description    : MQTT³õʼ»¯
* Input          : keep_time   ±£»îʱ¼ä
                                   Data_Send   ·¢Ëͻص÷
                                   Data_Recv   ½ÓÊջص÷
* Output         : None
* Return         : None
* Note                         : None
*******************************************************************************/
void Mqtt_Init(uint16_t keep_time,void (*Data_Send)(u8 *databuff, u16 len),void (*Data_Recv)(u8 *databuff, u16 len))
{
        mqtt_info.keep_live_time = keep_time;
        mqtt_info.mqtt_Data_Send = Data_Send;
        mqtt_info.mqtt_Data_Recv = Data_Recv;
}

/*******************************************************************************
* Function Name  : Mqtt_Connect
* Description    : MQTTÁ¬½Ó±¨ÎÄ
* Input          : client_id   ¿Í»§¶ËID
                                   usr_name   Óû§Ãû
                                   passward   ÃÜÂë
* Output         : None
* Return         : None
* Note                         : None
*******************************************************************************/
void Mqtt_Connect(char *client_id, char *usr_name, char *passward)
{
        int temp,Remaining_len;
        u16 Fixed_len,Variable_len,Payload_len;
        u16 client_id_len,usr_name_len,passward_len;
        uint8_t *buff;
       
        //Êý¾Ý»º³åÇøÖ¸Õë
        buff = mqtt_info.TX_Buff;
       
        client_id_len = strlen(client_id);
        usr_name_len = strlen(usr_name);
        passward_len = strlen(passward);
       
        Fixed_len = 1;                                                        //Á¬½Ó±¨ÎÄÖУ¬¹Ì¶¨±¨Í·³¤¶ÈÔÝʱÏÈ=1
        Variable_len = 10;                                                    //Á¬½Ó±¨ÎÄÖУ¬¿É±ä±¨Í·³¤¶È=10
        Payload_len = 2 + client_id_len + 2 + usr_name_len + 2 + passward_len; //Á¬½Ó±¨ÎÄÖУ¬¸ºÔس¤¶È      
        Remaining_len = Variable_len + Payload_len;                           //Ê£Ó೤¶È=¿É±ä±¨Í·³¤¶È+¸ºÔس¤¶È
       
        *buff++ = MSG_MQTT_CONN;                       //¹Ì¶¨±¨Í·µÚ1¸ö×Ö½Ú £º¹Ì¶¨0x10       
       
        do{                                      //Ñ­»·´¦Àí¹Ì¶¨±¨Í·ÖеÄÊ£Ó೤¶È×Ö½Ú£¬×Ö½ÚÁ¿¸ù¾ÝÊ£Óà×Ö½ÚµÄÕæʵ³¤¶È±ä»¯
                temp = Remaining_len%128;            //Ê£Ó೤¶ÈÈ¡Óà128
                Remaining_len = Remaining_len/128;   //Ê£Ó೤¶ÈÈ¡Õû128
                if(Remaining_len>0)                      
                        temp |= 0x80;                    //°´Ð­ÒéÒªÇóλ7ÖÃλ         
                *buff++ = temp;         //Ê£Ó೤¶È×ֽڼǼһ¸öÊý¾Ý
                Fixed_len++;                             //¹Ì¶¨±¨Í·×ܳ¤¶È+1   
        }while(Remaining_len>0);                 //Èç¹ûRemaining_len>0µÄ»°£¬ÔٴνøÈëÑ­»·
       
        *buff++ = 0x00;    //¿É±ä±¨Í·µÚ1¸ö×Ö½Ú £º¹Ì¶¨0x00                   
        *buff++ = 0x04;    //¿É±ä±¨Í·µÚ2¸ö×Ö½Ú £º¹Ì¶¨0x04
        *buff++ = 0x4D;           //¿É±ä±¨Í·µÚ3¸ö×Ö½Ú £º¹Ì¶¨0x4D--M
        *buff++ = 0x51;           //¿É±ä±¨Í·µÚ4¸ö×Ö½Ú £º¹Ì¶¨0x51--Q
        *buff++ = 0x54;           //¿É±ä±¨Í·µÚ5¸ö×Ö½Ú £º¹Ì¶¨0x54--T
        *buff++ = 0x54;           //¿É±ä±¨Í·µÚ6¸ö×Ö½Ú £º¹Ì¶¨0x54--T
        *buff++ = 0x04;           //¿É±ä±¨Í·µÚ7¸ö×Ö½Ú £º¹Ì¶¨0x04,ЭÒ鼶±ð
        *buff++ = 0xC2;           //¿É±ä±¨Í·µÚ8¸ö×Ö½Ú £ºÊ¹ÄÜÓû§ÃûºÍÃÜÂëУÑ飬²»Ê¹ÓÃÒÅÖö£¬²»±£Áô»á»°
        *buff++ = mqtt_info.keep_live_time/256;    //¿É±ä±¨Í·µÚ9¸ö×Ö½Ú £º±£»îʱ¼ä¸ß×Ö½Ú
        *buff++ = mqtt_info.keep_live_time%256;    //¿É±ä±¨Í·µÚ10¸ö×Ö½Ú£º±£»îʱ¼ä¸ß×Ö½Ú
       
        //¿Í»§¶ËID
        *buff++ = client_id_len/256;             //¿Í»§¶ËID³¤¶È¸ß×Ö½Ú
        *buff++ = client_id_len%256;             //¿Í»§¶ËID³¤¶ÈµÍ×Ö½Ú
        memcpy(buff,client_id,client_id_len);    //¸´ÖÆ¿Í»§¶ËID
        buff += client_id_len;
       
        //Óû§Ãû     
        *buff++ = usr_name_len/256;                      //Óû§Ãû³¤¶È¸ß×Ö½Ú
        *buff++ = usr_name_len%256;                          //Óû§Ãû³¤¶ÈµÍ×Ö½Ú
        memcpy(buff,usr_name,usr_name_len);      //¸´ÖÆÓû§Ãû       
        buff += usr_name_len;
       
        //ÃÜÂë
        *buff++ = passward_len/256;                            //ÃÜÂ볤¶È¸ß×Ö½Ú
        *buff++ = passward_len%256;                            //ÃÜÂ볤¶ÈµÍ×Ö½Ú
        memcpy(buff,passward,passward_len);     //¸´ÖƹýÀ´ÃÜÂë×Ö´®
        buff += passward_len;

        //·¢ËÍÊý¾Ý
        if(mqtt_info.mqtt_Data_Send != NULL)
                mqtt_info.mqtt_Data_Send(mqtt_info.TX_Buff,Fixed_len + Variable_len + Payload_len);
}

/*******************************************************************************
* Function Name  : Mqtt_DisConnect
* Description    : MQTT¶Ï¿ªÁ¬½Ó
* Input          : None
* Output         : None
* Return         : None
* Note                         : None
*******************************************************************************/
void Mqtt_DisConnect(void)
{
        uint8_t *buff;
       
        //Êý¾Ý»º³åÇøÖ¸Õë
        buff = mqtt_info.TX_Buff;
       
        *buff++ = MSG_MQTT_DISCONN;                            //¹¦ÄÜÂë
        *buff++ = 0x00;                            

        //·¢ËÍÊý¾Ý
        if(mqtt_info.mqtt_Data_Send != NULL)
                mqtt_info.mqtt_Data_Send(mqtt_info.TX_Buff,2);
}

/*******************************************************************************
* Function Name  : Mqtt_Ping
* Description    : MQTTÐÄÌø
* Input          : None
* Output         : None
* Return         : None
* Note                         : None
*******************************************************************************/
void Mqtt_Ping(void)
{
        uint8_t *buff;
       
        //Êý¾Ý»º³åÇøÖ¸Õë
        buff = mqtt_info.TX_Buff;
       
        *buff++ = MSG_MQTT_PING;                            //¹¦ÄÜÂë
        *buff++ = 0x00;                            

        //·¢ËÍÊý¾Ý
        if(mqtt_info.mqtt_Data_Send != NULL)
                mqtt_info.mqtt_Data_Send(mqtt_info.TX_Buff,2);
}

/*******************************************************************************
* Function Name  : Mqtt_PingAck
* Description    : MQTTÐÄÌøÓ¦´ð,·þÎñ¶Ëµ÷ÓÃ
* Input          : None
* Output         : None
* Return         : None
* Note                         : None
*******************************************************************************/
void Mqtt_PingAck(void)
{
        uint8_t *buff;
       
        //Êý¾Ý»º³åÇøÖ¸Õë
        buff = mqtt_info.TX_Buff;
       
        *buff++ = MSG_MQTT_PING_ACK;                            //¹¦ÄÜÂë
        *buff++ = 0x00;                          

        //·¢ËÍÊý¾Ý
        if(mqtt_info.mqtt_Data_Send != NULL)
                mqtt_info.mqtt_Data_Send(mqtt_info.TX_Buff,2);
}

/*******************************************************************************
* Function Name  : Mqtt_Subscribe
* Description    : SUBSCRIBE¶©ÔÄtopic±¨ÎÄ
* Input          : topic_name£º¶©ÔÄtopic±¨ÎÄÃû³Æ  PackID  ±¨Îıêʶ·û(°üºÅ)  
                   QoS£º¶©Ôĵȼ¶        
* Output         : None
* Return         : None
* Note                         : None
*******************************************************************************/
void Mqtt_Subscribe(char *topic_name, uint16_t PackID, uint8_t QoS)
{       
        int temp,Remaining_len;
        u16 topic_len,pack_len,Variable_len,Payload_len;
        uint8_t *buff;
       
        //Êý¾Ý»º³åÇøÖ¸Õë
        buff = mqtt_info.TX_Buff;
        //Ö÷Ìⳤ¶È
        topic_len = strlen(topic_name);
        Variable_len = 2;                           //SUBSCRIBE±¨ÎÄÖÐ,±¨Îıêʶ·û³¤¶È,¹Ì¶¨Îª2
        Payload_len = 2 + strlen(topic_name) + 1;   //¼ÆËãÓÐЧ¸ººÉ³¤¶È = 2×Ö½Ú(topic_name³¤¶È)+ topic_name×Ö·û´®µÄ³¤¶È + 1×Ö½Ú·þÎñµÈ¼¶
        Remaining_len = Variable_len + Payload_len; //Ê£Ó೤¶È
       
        *buff++ = MSG_MQTT_SUBSCRIBE;                               //µÚ1¸ö×Ö½Ú £º¹Ì¶¨0x82        

        do{                                      //Ñ­»·´¦Àí¹Ì¶¨±¨Í·ÖеÄÊ£Ó೤¶È×Ö½Ú£¬×Ö½ÚÁ¿¸ù¾ÝÊ£Óà×Ö½ÚµÄÕæʵ³¤¶È±ä»¯
                temp = Remaining_len%128;            //Ê£Ó೤¶ÈÈ¡Óà128
                Remaining_len = Remaining_len/128;   //Ê£Ó೤¶ÈÈ¡Õû128
                if(Remaining_len>0)                      
                        temp |= 0x80;                    //°´Ð­ÒéÒªÇóλ7ÖÃλ         
                *buff++ = temp;         //Ê£Ó೤¶È×ֽڼǼһ¸öÊý¾Ý  
        }while(Remaining_len>0);                 //Èç¹ûRemaining_len>0µÄ»°£¬ÔٴνøÈëÑ­»·
       
        *buff++ = PackID/256;                    //±¨Îıêʶ·û¸ß×Ö½Ú,°üºÅ
        *buff++ = PackID%256;                             //±¨Îıêʶ·ûµÍ×Ö½Ú,°üºÅ
        *buff++ = topic_len/256;                 //topic_name³¤¶È¸ß×Ö½Ú
        *buff++ = topic_len%256;                         //topic_name³¤¶ÈµÍ×Ö½Ú
        memcpy(buff,topic_name,topic_len);       //¸´ÖÆtopic_name       
        buff += topic_len;
       
        *buff++ = QoS;                           //×îºó1¸ö×Ö½Ú£º¶©Ôĵȼ¶
       
        pack_len = buff - mqtt_info.TX_Buff;
       
        //·¢ËÍÊý¾Ý
        if(mqtt_info.mqtt_Data_Send != NULL)
                mqtt_info.mqtt_Data_Send(mqtt_info.TX_Buff,pack_len);
}

/*******************************************************************************
* Function Name  : Mqtt_UnSubscribe
* Description    : È¡Ïû¶©ÔÄtopic±¨ÎÄ
* Input          : topic_name£º¶©ÔÄtopic±¨ÎÄÃû³Æ  PackID  ±¨Îıêʶ·û(°üºÅ)      
* Output         : None
* Return         : None
* Note                         : None
*******************************************************************************/
void Mqtt_UnSubscribe(char *topic_name, uint16_t PackID)
{       
        int temp,Remaining_len;
        u16 topic_len,pack_len,Variable_len,Payload_len;
        uint8_t *buff;
       
        //Êý¾Ý»º³åÇøÖ¸Õë
        buff = mqtt_info.TX_Buff;
        //Ö÷Ìⳤ¶È
        topic_len = strlen(topic_name);
        Variable_len = 2;                           //SUBSCRIBE±¨ÎÄÖÐ,±¨Îıêʶ·û³¤¶È,¹Ì¶¨Îª2
        Payload_len = 2 + strlen(topic_name);   //¼ÆËãÓÐЧ¸ººÉ³¤¶È = 2×Ö½Ú(topic_name³¤¶È)+ topic_name×Ö·û´®µÄ³¤¶È
        Remaining_len = Variable_len + Payload_len; //Ê£Ó೤¶È
       
        *buff++ = MSG_MQTT_UNSUBSCRIBE;                               //µÚ1¸ö×Ö½Ú £º¹Ì¶¨0xA2        

        do{                                      //Ñ­»·´¦Àí¹Ì¶¨±¨Í·ÖеÄÊ£Ó೤¶È×Ö½Ú£¬×Ö½ÚÁ¿¸ù¾ÝÊ£Óà×Ö½ÚµÄÕæʵ³¤¶È±ä»¯
                temp = Remaining_len%128;            //Ê£Ó೤¶ÈÈ¡Óà128
                Remaining_len = Remaining_len/128;   //Ê£Ó೤¶ÈÈ¡Õû128
                if(Remaining_len>0)                      
                        temp |= 0x80;                    //°´Ð­ÒéÒªÇóλ7ÖÃλ         
                *buff++ = temp;         //Ê£Ó೤¶È×ֽڼǼһ¸öÊý¾Ý  
        }while(Remaining_len>0);                 //Èç¹ûRemaining_len>0µÄ»°£¬ÔٴνøÈëÑ­»·
       
        *buff++ = PackID/256;                    //±¨Îıêʶ·û¸ß×Ö½Ú,°üºÅ
        *buff++ = PackID%256;                             //±¨Îıêʶ·ûµÍ×Ö½Ú,°üºÅ
        *buff++ = topic_len/256;                 //topic_name³¤¶È¸ß×Ö½Ú
        *buff++ = topic_len%256;                         //topic_name³¤¶ÈµÍ×Ö½Ú
        memcpy(buff,topic_name,topic_len);       //¸´ÖÆtopic_name       
        buff += topic_len;
       
        pack_len = buff - mqtt_info.TX_Buff;
       
        //·¢ËÍÊý¾Ý
        if(mqtt_info.mqtt_Data_Send != NULL)
                mqtt_info.mqtt_Data_Send(mqtt_info.TX_Buff,pack_len);
}

/*******************************************************************************
* Function Name  : Mqtt_Publish
* Description    : Ïòtopic·¢²¼±¨ÎÄ
* Input          : topic_name£º¶©ÔÄtopic±¨ÎÄÃû³Æ  PackID  ±¨Îıêʶ·û(°üºÅ)  
                   QoS£ºµÈ¼¶    data ÓÐЧÊý¾Ý   data_len  ÓÐЧÊý¾Ý³¤¶È
* Output         : None
* Return         : None
* Note                         : PackIDÖ»Óе±QoSΪ1»ò2ʱÓÐЧ
*******************************************************************************/
void Mqtt_Publish(char *topic_name, uint16_t PackID, uint8_t QoS, uint8_t *data, uint16_t data_len)
{       
        int temp,Remaining_len;
        u16 topic_len,pack_len,Payload_len;
        uint8_t *buff;
       
        //Êý¾Ý»º³åÇøÖ¸Õë
        buff = mqtt_info.TX_Buff;
        //Ö÷Ìⳤ¶È
        topic_len = strlen(topic_name);
        Payload_len = 2 + strlen(topic_name) + data_len;   //¼ÆËãÓÐЧ¸ººÉ³¤¶È = 2×Ö½Ú(topic_name³¤¶È)+ topic_name×Ö·û´®µÄ³¤¶È + Êý¾Ý³¤¶È
        Remaining_len = Payload_len; //Ê£Ó೤¶È
       
        if(QoS == 0)
        {
                *buff++ = MSG_MQTT_PUBLISH_QS0;                               //µÚ1¸ö×Ö½Ú £º¹Ì¶¨0x30
        }
        else if(QoS == 1)
        {
                Remaining_len += 2;                      //Ê£Ó೤¶È,2Ϊ±¨Îıêʶ·û³¤¶È
                *buff++ = MSG_MQTT_PUBLISH_QS1;                               //µÚ1¸ö×Ö½Ú £º¹Ì¶¨0x32
        }
        else if(QoS == 2)
        {
                Remaining_len += 2;                      //Ê£Ó೤¶È,2Ϊ±¨Îıêʶ·û³¤¶È
                *buff++ = MSG_MQTT_PUBLISH_QS2;                               //µÚ1¸ö×Ö½Ú £º¹Ì¶¨0x34
        }

        do{                                      //Ñ­»·´¦Àí¹Ì¶¨±¨Í·ÖеÄÊ£Ó೤¶È×Ö½Ú£¬×Ö½ÚÁ¿¸ù¾ÝÊ£Óà×Ö½ÚµÄÕæʵ³¤¶È±ä»¯
                temp = Remaining_len%128;            //Ê£Ó೤¶ÈÈ¡Óà128
                Remaining_len = Remaining_len/128;   //Ê£Ó೤¶ÈÈ¡Õû128
                if(Remaining_len>0)                      
                        temp |= 0x80;                    //°´Ð­ÒéÒªÇóλ7ÖÃλ         
                *buff++ = temp;         //Ê£Ó೤¶È×ֽڼǼһ¸öÊý¾Ý  
        }while(Remaining_len>0);                 //Èç¹ûRemaining_len>0µÄ»°£¬ÔٴνøÈëÑ­»·
       
        *buff++ = topic_len/256;                 //topic_name³¤¶È¸ß×Ö½Ú
        *buff++ = topic_len%256;                         //topic_name³¤¶ÈµÍ×Ö½Ú
        memcpy(buff,topic_name,topic_len);       //¸´ÖÆtopic_name       
        buff += topic_len;
       
        if(QoS != 0)  
        {
                *buff++ = PackID/256;                    //±¨Îıêʶ·û¸ß×Ö½Ú,°üºÅ
                *buff++ = PackID%256;                             //±¨Îıêʶ·ûµÍ×Ö½Ú,°üºÅ
        }
       
        //¸´ÖÆÓû§Êý¾Ý
        memcpy(buff,data,data_len);
        buff += data_len;
       
        pack_len = buff - mqtt_info.TX_Buff;
       
        //·¢ËÍÊý¾Ý
        if(mqtt_info.mqtt_Data_Send != NULL)
                mqtt_info.mqtt_Data_Send(mqtt_info.TX_Buff,pack_len);
}

/*******************************************************************************
* Function Name  : Mqtt_RecvHandle
* Description    : MQTT½ÓÊÕÊý¾Ý½âÎö
* Input          : buff   Êý¾Ý»º³åÇø
* Output         : None
* Return         : None
* Note                         : 0  ³É¹¦,ÆäËü ʧ°Ü
*******************************************************************************/
uint8_t Mqtt_RecvHandle(uint8_t *buff)
{
        uint8_t *p;
        uint8_t encodeByte = 0;
        uint32_t multiplier = 1, Remaining_len = 0;
        uint8_t QS_level = 0;
       
        p = buff;
       
        //½âÎö½ÓÊÕÊý¾Ý
        if((*p != 0x30)&&(*p != 0x32)&&(*p != 0x34))   //²»ÊÇ·¢²¼±¨ÎÄÍ·
                return 1;
       
        if(*p != 0x30) QS_level = 1;    //±ê¼ÇqsµÈ¼¶²»Îª0
       
        p++;
        //ÌáÈ¡Ê£ÓàÊý¾Ý³¤¶È
        do{
                encodeByte = *p++;
                Remaining_len += (encodeByte & 0x7F) * multiplier;
                multiplier *= 128;
               
                if(multiplier > 128*128*128) //³¬³öÊ£Ó೤¶È×î´ó4¸ö×Ö½ÚµÄÒªÇó,´íÎó
                        return 2;
        }while((encodeByte & 0x80) != 0);
       
        //ÌáÈ¡Ö÷ÌâÊý¾Ý³¤¶È
        mqtt_info.rx_topic_len = *p++;
        mqtt_info.rx_topic_len = mqtt_info.rx_topic_len * 256 + *p++;
        //ÌáÈ¡Ö÷Ìâ
        memcpy(mqtt_info.RX_Topic,p,mqtt_info.rx_topic_len);
        p += mqtt_info.rx_topic_len;
       
        if(QS_level != 0)  //Ìø¹ý±¨Îıêʶ·û
                p += 2;   
       
        //ÌáÈ¡Óû§ÄêÊý¾Ý
        if(mqtt_info.mqtt_Data_Recv != NULL)
                mqtt_info.mqtt_Data_Recv(p,Remaining_len - mqtt_info.rx_topic_len - 2);
       
        return 0;
}


后台对接阿里云








W3.png (114.17 KB )

W3.png

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:项目经理
简介:资深嵌入式开发工程师

80

主题

148

帖子

3

粉丝