###物联网管家机器人零入门设计

  • 设计思路:
    在科技迅速发展的今天,生活压力的增加,人们渴望追求更优越的生活条件,所以加班的现象越来越普遍。那么当你不在家并且家里没人的时候,如果家里失火、煤气忘关,或者说管道漏水等。如何能够实时的了解家中的情况,并且能够在最短速度内报警,把损失降低到最小,显得尤为重要。因此,萌发了做一款可移动侦测采集室内数据的智能小车。

  • 功能介绍:
    室内环境复杂,为了保证小车不撞到障碍。使用单片机控制超声波测距,对环境障碍进行180度探测,寻找最优路径实现避障功能。假如需要小车实现多点定点检测,那么只需规划出特殊的路线,利用红外检测路线,实现自动巡航功能。传感器采集回来的数据,由MCU简单处理后,通过网络设备无线上传到“云”服务器,用户可以在电脑端,手机端查看小车移动采集的数据。当采集回来的数据,超出正常值时,可以触发“报警”功能。搭载害气体传感器接口,烟雾粉尘传感器,可实现有害气体(煤气)泄露报警,室内粉尘检测。小车采用wifi联网,为了解决大多数非专业用户在不懂编程的情况下依然能正常使用,小车采用Airkiss技术,用户可以在手机端通过微信或者特定APP就可以实现正常配网。第三方API接入展示

  • 功能设计:
    鉴于智能小车行动灵活的特点,在车上搭载功能外设(如温湿度计,烟雾粉尘检测模块,有害气体传感器等设备),就可以实现灵活多点数据采集,实现多点测温,火灾预警,PM2.5空气质量分析,有害气体泄露报警等功能。 本指南以嵌入式常用传感器为例,目的为初学者提供一个较为全面开发例程。

  • 硬件介绍:

    1. 智能小车主控以stm32f103系列MCU为例(其他芯片参考移植),这里使用中国移动麒麟座开发板进行设计(感谢中移硬件赞助)。
      Alt text
  • 麒麟座采用stm32f103ret6芯片为主控芯片,搭载了GSM模块 WiFi模块和温湿度传感器,角度传感器等部件,是一款功能较为齐全的硬件开发平台,出于尽可能丰富外设,做一款较完善的教程的考虑,使用麒麟开发板可以节约空间,方便添加跟多外设。

  • 2.使用E18-D80NK 红外接近开关,用于对障碍物进行检测,触发中断执行避障机制。
    Alt text

  • 3.使用PM2.5传感器 GP2Y1014AU粉尘传感器,用于对空气中大于0.8um的颗粒物浓度进行检测。
    Alt text

  • 4.夏普光学灰尘传感器(GP2Y1014AU0F)在检测非常细的颗粒,如香烟烟雾,是特别有效的,并且是常用的空气净化器系统。该装置中,一个红外发光二极管和光电晶体管,对角布置成允许其检测到在空气中的灰尘反射光。传感器中心有个洞可以让空气自由流过,定向发射LED光,通过检测经过空气中灰尘折射过后的光线来判断灰尘的含量。这里通过读取输出脚的模拟电压来判读颗粒浓度,用到stm32 内部ADC转换。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    /*************************************************************************************
    ADC1初始化程序 PB1口用于LED信号触发
    *************************************************************************************/
    void Adc_Init(void)
    {
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB , ENABLE );
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//
    GPIO_Init(GPIOA, &GPIO_InitStructure); //
    ADC_DeInit(ADC1); //
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //
    ADC_InitStructure.ADC_ScanConvMode = ENABLE; //
    ADC_InitStructure.ADC_ContinuousConvMode =DISABLE; //
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//

    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC
    ADC_InitStructure.ADC_NbrOfChannel = 1; //
    ADC_Init(ADC1, &ADC_InitStructure); //
    ADC_Cmd(ADC1, ENABLE); //
    ADC_ResetCalibration(ADC1); //
    while(ADC_GetResetCalibrationStatus(ADC1)); //
    ADC_StartCalibration(ADC1); //
    while(ADC_GetCalibrationStatus(ADC1)); //

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB, GPIO_Pin_1 );
    }

    /*******************************************************************
    得到 ADC单通道多次平均值
    ch=通道 S为规则序列 time=n次读取求平均值
    *******************************************************************/
    u16 Get_Adc_Average(u8 ch,u8 s,u8 times)
    {
    float temp_val=0;
    float pm;
    u8 t;
    u8 z=0;
    for(t=0;t<times+z;t++)
    {
    GPIO_SetBits(GPIOB, GPIO_Pin_1 );
    GPIO_ResetBits(GPIOB, GPIO_Pin_1);

    delay_us(40);
    if(Get_Adc(ch,s)>300)
    {
    temp_val+=Get_Adc(ch,s);
    }
    else
    {
    z++;
    if(z>100)
    return 0;
    }
    delay_us(280);
    GPIO_SetBits(GPIOB, GPIO_Pin_1 );
    delay_us(9680);
    }
    temp_val=temp_val/times;
    return temp_val;
    }
  • 5.模块 MQ-5液化气天然气 城市煤气传感器模块:检测燃气是否泄露
    MQ-5有两个输出信号脚,一个是数字输(0,1)另一个是模拟输出,数字输出可以通过调节灵敏度来设置物理阀值,相对模拟输出来说 数字输出简单,可直接通过MCU端口检测,但数字输出不精确不直观,本次仍然以模拟信号进行ADC转化,通过程序判断具体燃气浓度,具体ADC配置思路同上。通过串口调试得到的数据如下:
    Alt text

  • 6.火焰传感器模块 火源探测模块 :用于检测室内是否有明火.该模块也有数字信号输出脚和模拟信号输出脚,但由于stm32f103只有3个ADC,火焰检测采集模拟量意义不大,所以直接用的是数字信号输出脚,将其配置成外部中断。也可以不用中断直接检测引脚电压来判断是否有明火。
    Alt text

  • 7.SPI接口的 oled液晶显示屏:Oled显示屏直接使用厂家提供的官方驱动源码就行,没必要去研究它具体寄存器操作方式。我们只需学会使用IIC协议 或SPI协议能给屏幕发送指令就可以了。具有协议不在赘述,网上有很多,而且协议是固定通用的。
    Alt text

  • 8.RCWL-0516 微波雷达感应开关模块:用来进行人体感应,在设备开启离家模式时,如果感应到人,则会触发报警。
    Alt text
    Alt text

  • 9.串口控制插卡SD卡语音模块:用于语音播报
    Alt text
    Alt text
    Alt text

    1
    2
    3
    4
    5
    6
    void Usart1_Init(unsigned int baud)
    {
    GPIO_InitTypeDef gpioInitStruct;
    USART_InitTypeDef usartInitStruct;
    NVIC_InitTypeDef nvicInitStruct;
    }

    定义: uint8_t stop[]={0x7e,0x03,0x1e,0x1d,0xef,0x00}; //停止命令
    串口输出: printf(stop);

注:前提是串口重定义过,才能使用printf函数。(网上搜索串口重定义的相关知识,) 否则 直接使用stm32f10x标准库里面的USART_SendData();函数进行逐个字节输出.

  • 10 .舵机:一种角度电机,可以精确控制转动角度:舵机通过控制器发送不同占空比的PWM来改变它转动的角度,每个角度对于一个特定的频率的PWM,关于stm32 pwm的配置如下.
    Alt text
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    void TIM4_PWM_Init(u16 arr,u16 psc)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef
    TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    TIM_TimeBaseStructure.TIM_Period = arr;
    TIM_TimeBaseStructure.TIM_Prescaler =psc;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC3Init(TIM4, &TIM_OCInitStructure);

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC4Init(TIM4, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);
    TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);
    }
    通过库标准函数改变舵机转动角度:TIM_SetCompare3(TIM4,1870); TIM_SetCompare4(TIM4,1880);
    1. 直流电机驱动模块:模块用于驱动TT马达,输入信号同样是PWM 配置方式与舵机相同,操作方式如上图所示。选用这块模块优点 是芯片模块比晶体管模块发热小,缺点是占用控制芯片管脚多(4路PWM)
      Alt text
      Alt text
  • 12.超声波测距模块
  • 采用IO触发测距,给至少10us的高电平信号;
  • 模块自动发送8个40khz的方波,自动检测是否有信号返回;
  • 有信号返回,通过IO输出一高电平,高电平持续的时间就是
    超声波从发射到返回的时间.测试距离=(高电平时间*声速(340M/S))/2;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    //超声波测距用到stm32定时器输入捕获功能配置过程如下:
    /*********************************************************
    初始化定时器2为捕获模式
    ********************************************************/
    void TIM2_Cap_Init(u16 arr,u16 psc)
    {
    TIM_ICInitTypeDef TIM2_ICInitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 ÊäÈë
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_ResetBits(GPIOA,GPIO_Pin_0);
    TIM_TimeBaseStructure.TIM_Period = arr;
    TIM_TimeBaseStructure.TIM_Prescaler =psc;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1;
    TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM2_ICInitStructure.TIM_ICFilter =0x00;
    TIM_ICInit(TIM2, &TIM2_ICInitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE);//ÔÊÐí¸üÐ
    TIM_Cmd(TIM2,ENABLE );
    }
    /*************************************************************
    定时器2中断服务程序

    *************************************************************/
    void TIM2_IRQHandler(void)
    {
    if((TIM2CH1_CAPTURE_STA&0X80)==0)
    {
    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
    if(TIM2CH1_CAPTURE_STA&0X40)
    {
    if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)
    {
    TIM2CH1_CAPTURE_STA|=0X80;
    TIM2CH1_CAPTURE_VAL=0XFFFF;
    }else TIM2CH1_CAPTURE_STA++;
    }
    }
    if(TIM_GetITStatus(TIM2, TIM_IT_CC1) !=
    {
    if(TIM2CH1_CAPTURE_STA&0X40)
    {
    TIM2CH1_CAPTURE_STA|=0X80;
    TIM2CH1_CAPTURE_VAL=TIM_GetCapture1(TIM2);
    TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising);
    }else
    {
    TIM2CH1_CAPTURE_STA=0;
    TIM2CH1_CAPTURE_VAL=0;
    TIM2CH1_CAPTURE_STA|=0X40;
    TIM_SetCounter(TIM2,0);
    TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling);
    }
    }
    }


    TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update);
    TIM2_1CAP();
    }


    /***********************************************************
    距离转化函数
    ***********************************************************/
    void TIM2_1CAP()
    {
    if(TIM2CH1_CAPTURE_STA&0X80)
    {
    temp=TIM2CH1_CAPTURE_STA&0X3F;
    temp*=65536;
    temp+=TIM2CH1_CAPTURE_VAL;
    temp=temp*17;
    z=temp/1000;
    TIM2CH1_CAPTURE_STA=0;
    }
    }

  • 13.硬件材料
    Alt text
    Alt text
    Alt text
    Alt text
  • 14.硬件部分介绍完毕,程序部分也穿插在其中一并说了。现在,来看下onenet web应用部分,具体onenet web应用部分如何设计,我就不在多说,论坛里都能找到,我只说论坛里没用的
    Alt text
    本次设计用stm32f103接入onenet EDP服务器 和第三方服务器,这是结构简图:
    Alt text
    这是室内可燃气体泄露触发的报警:
    Alt text
    这是获取第三方网站本地气象数据效果:
    Alt text