爱板网论坛

查看: 223|回复: 0

[教程] 16..STM32F469I--- 温湿度检测+障碍物检测报警系统

[复制链接]

主题

好友

6514

积分

状元

  • TA的每日心情
    郁闷
    8 小时前
  • 签到天数: 592 天

    连续签到: 13 天

    [LV.9]以坛为家II

    发表于 2018-1-12 14:37:07 |显示全部楼层
    【STM32F469I试用】 温湿度检测+障碍物检测报警系统【转】

    主要内容有两个,如题,分别是温度湿度检测和障碍物检测报警
    实现功能:
    [1]        实时检测室内的温度和湿度,并通过串口发送,PC串口助手显示(LCD还没调好,所以先用串口输出温湿度数据)
    [2]        当有障碍物进入开发板(光电管)一定范围时,开发板发出震动警报,并且亮红灯

    硬件使用STM32F469IDISCO开发板+Gokit的扩展板,主要用到上面的DHT11温湿度传感器,检测温湿度;反射型光电传感器,检测有物体进入可检测区域;直流无刷电机,当光电传感器检测到无提示,电机启动,发出震动警报(电机上有齿轮,会震动,换成偏心轮震动更强烈)。涉及到的内容有GPIO,USART,SysTick,EXTI,TIM,PWM等。
    1.          硬件分析:
    STM32F469 DISCO开发板设计了一个兼容Arduino的接口,而GoKit扩展板也是兼容该接口的,刚好可以即插即用(可见兼容很重要啊)。
    先查看看扩展板的原理图(由于这是别人家的图,就不发原理图了,有兴趣的自己去他们论坛下载):
    温湿度传感器:

    1.jpg


    (数据手册)
    使用的是DHT11,使用单总线数据传输,只有一根数据线,命令和数据都通过该线传输,当主机发送开始信号后,从机响应,然后开始输出数据,DOUT引脚连接的是Arduino接口的D3脚。
    光电传感器:

    2.jpg


    原理,左边的光电管导通,发出红外光,当观点管前面没有障碍物或距离较远,就不会有光反射回来,右边光电管截止,比较器正输入端电压高于负输入端,OUT输出高电平,当障碍物到光电管可检测距离之内时,右边光电接收管接收到红外光而导通,正输入端电压低于负输入端,OUT输出低电平,输出端OUT接的是Arduino D2。
    直流无刷电机:

    3.jpg


    Aruidno的 D4,D5脚经电机驱动芯片后分别接入电机两端,一端输入PWM波形,另一端低电平,电机正传,反之,电机反转。
    再看STM32F469DISCO开发板的Arduino接口部分:

    4.jpg


    D2,D3,D4,D5分别接到 PG13,PA1,PG12,PA2,由于stm32f469ni芯片的PG12引脚不具有PWM功能,所以D4无法驱动电机,只能实现一个方向的转动,不过也够了,这个帖子里电机是用来实现震动的,转向不重要。
    所以,引脚设置如下:
    D2——光管比较器的输出端——PG13——外部中断
    D3——温湿度传感器DOUT——PA1——输出/输入
    D5——电机PWM驱动引脚——PA2——TIM9_CH1
    另外,板载虚拟串口,连接的是USART3,使用它输出调试信息和温度湿度数据:
    USART3_TX——PB10——复用
    USART3_RX——PB11——复用
    2.          使用STM32CUBEMX生成工程
    本帖使用STM32CUBEMX4.12.0,STM32F4CUBE 4.10.0,可以在官网或社区下载。
    新建工程的帖子论坛已经很多了,我就不详细写了,主要说一下主要的配置:

    5.jpg


    没有按板子型号选,是因为如果选择开发板型号,cube会默认把该型号开发板上使用引脚全都初始化,这会带来很大的方便(特别是像这块板,引脚特别多),但我现在不想要这样,所以自己选芯片型号。

    6.jpg


    按照上面的分析,配置好相应的引脚,打开TIM9,PWM模式,打开USART3异步模式,另外如果使用外部晶振HSE,还需要打开RCC。加多一个PD3设置为输出模式,用于点亮板子上的绿色LED LD7,显示程序运行状态,截图中漏掉了。

    7.jpg


    时钟配置,随便设置一下就好,这里设置到最高180M只是为了测试玩玩,其实这几个应用完全没必要这么高。

    8.jpg


    PG13设置为上升沿下降沿双触发,因为要同时检测有东西进入和离开检测区域。
    USART3的设置,默认即可。

    9.jpg


    定时器设置,向上计数,不分频,period=9000-1,pules=900,即设置PWM频率20K,占空比10%.

    10.jpg


    最后保存设置,生成MDK工程,打开工程,开始添加自己的代码。

    11.jpg


    3.          代码添加与测试。
    首先,在主函数while循环中加入点灯的代码,测试看程序是否正常:

    12.jpg


    编译下载运行一气呵成,没任何问题。
    然后完善串口部分的代码,使得我们可以使用printf函数来方便的输出想要的信息(温湿度)。

    13.jpg


    加入上面的代码的代码就行了,主函数中继续加入测试代码,

    14.jpg


    然后运行看效果:

    15.jpg


    到这里,准备工作做好了,下面才是真正的主要阶段,如何读取温湿度传感器的数据,以及根据红外传感器来控制电机。
    l  读取温湿度传感器DHT11的数据
    在写读取数据部分之前,先有些准备工作要做:
    1.          实现微秒延时(delay_us)
    以前用标准库的时候,基本都是用SysTick来做,ms和us延时只需要调用一个函数就行了,但是在cube库里面就不能这样做,为什么呢?看一下标准库ms和us延时的实现方法,每次根据时间计算出一个tick值,写入SysTick->LOAD寄存器,等待计数器到达0就行了,但是Cube库中,Systick已经用来实现固定的1ms的延时即 HAL_Delay(),每1ms都会产生一次中断,并且重装载并重新开始计数,如果我们还按之前的做法,就会破坏这个函数的准确性,造成很多cube库函数出现不可预知的问题,所以此法行不通。当然,ms延时已经有了,直接用HAL_Delay(),我们需要自己实现us延时。
    方法肯定不止一种,首先想到的是使用一个定时器,比如基本定时器TIM6或者其他定时器,这样做当然是可以的。不过能不能还是用SysTick实现呢?答案当然也是可以的。
    Cube库中,设置SysTick的时钟等于系统时钟,

    16.jpg


    设置Tick次数为SYSCLK/1000,即tick SYSCLK/1000次就是1ms,此时产生中断,那tick SYSCLK/1000000不就是1us吗,只是没有产生中断而已,所以实现方法就很简单了。

    17.jpg


    如图,直接用宏定义#defineDelay_ms  HAL_Delay是为了移植方便,就不用去代码中一个一个把Delay_ms()改为HAL_Delay()了。
    Delay_us可以写成一个函数,但是为了提高效率,我使用了宏定义(亲测在延时很小的时候效率相差很大),然后宏定义一个常量是当前系统时钟,当修改了系统时钟时,只需要修改这个宏就可以了。思路就是,先计算出延时时间所需要的Tick数,SYSCLK/1000000对应1 us,记录下当前SysTick->VAL的值,然后counter一直在递减,直到达到计算好的次数,延时时间到,退出,if语句成立时,表明定时器产生下溢,重装载了VAL。
    测试一下,看是否正确:

    18.jpg


    19.jpg


    20.jpg


    延时1us、10us、100us误差都是0.125us,说明这是IO口翻转本身需要的时间,我们的延时函数精度还是非常高的。
    2.          配置DHT11的Dout引脚
    前面说了,DHT11使用单总线,意味着与之相连的引脚既要输出也要输入,分别用于发送命令和接受数据,由于程序中需要频繁的切换输入输出状态,同样处于效率考虑,我们用直接操作定时器的方式,并且依旧使用宏定义来实现,而不是使用库函数,当然,也就是把库函数自己写一遍而已,去掉了各种判断和循环。

    21.jpg


    这段代码完全考虑了移植性的问题,非常方便,只需要修改前三行就行了,不过STM32F1系列例外,该系列GPIO寄存器不一样,需要修改。
    3.          准备工作做好了,可以开始读数据了
    根据手册,读取数据前需要先发送开始命令,然后DHT11传感器产生回应,然后开始发送数据。对于主机来说就是
    设置gpio为输出——发送开始命令——设置为输入——检测回应——接收数据
    通信时序如下(数据手册):

    22.jpg


    23.jpg


    24.jpg


    第三幅图是从机回应信号,然后从机就开始发送数据,连续发5字节,前4字节是数据,第5字节是检验码,数据格式:

    25.jpg


    分析好了时序,就可以写代码测试了:
    发送开始命令的函数如下:

    26.jpg


    然后然后主函数中测试:

    27.jpg


    每隔0.5秒发送一次开始命令,但是没做任何事情,只是把DATA引脚设置为输入状态,然后等待,看开始命令是否成功,传感器是否有数据发出来:

    28.jpg


    每0.5s发送一次开始信号

    29.jpg


    20ms低电平(手册写至少18ms)作为开始信号,然后拉高,并设置为输入状态,等待从机响应

    30.jpg


    从机相应信号,低/高电平分别80多微秒,

    31.jpg


    后面就是一连串的数据,一共5字节,可见我们只发送了开始信号,并不需要做其他”读”操作,数据即可自动发送出来,使用非常方便,接下来只需要按照协议解析数据就可以,并让数据显示出来就可以了,这部分就不详介绍了,直接看结果:

    32-1.jpg


    32-2.jpg


    这是用串口打印出来,PC上用串口助手接收的结果,手册说该传感器25度是精度+-2度,现在我这里手机显示温度21度,还是比较接近的。不过这个温度传感器不适用于需要高精度测量的应用。
    温湿度测量部分就写完了,好像有点啰嗦,有耐心看到这里的我表示非常感谢。
    l  障碍物检测与报警
    这一个就比较简单了,因为GPIO引脚和定时器参数在前面生成工程的时候已经配置好了,不过之前忘了打开EXTI中断,这里补上,然后重新生成工程,再编译:

    33.jpg


    要做的工作很简单,根据前面的分析,当没有障碍物在光电管前面时,比较器输出高,当障碍物进入可检测范围,挡住光电管,则比较器输出低,相应引脚上会产生下降沿中断,此时应打开点击,产生震动发出警报;当障碍物远离,比较器又变回输出高,此时产生上升沿中断,应关闭点击,解除警报。
    得益于Cube库的方便,上面所述功能代码做起来都很简单:

    34.jpg


    中断回调函数,发生EXTI中断时会调用,在里面实现自己需要的功能即可。

    35.jpg


    打开和关闭电机,都只需要调用一个函数就能完成,非常方便。
    编译上诉程序,下载到开发板中,就能顺利运行了,当有物体在光电管上面一定距离内,电机就会转动,发出震动,同时有个红色LED亮(这是硬件上设计的),当物体远离或离开正上方之后,震动停止,电机被关闭,LED熄灭,运行效果见视频。
    从视频里可以看到,黑色物体检测最大距离只有大约15mm,而白色物体有40~50mm之多,因为白色物体反光能力强,黑色物体反光能力弱,所以要更近的距离,反射的光才足以使光电三极管导通,从而检测到物体。当然检测距离可以通过板子上的一个可调电阻在一定范围内调节。

    STM32F469_DISCO.rar (3.34 MB, 下载次数: 0, 售价: 2 铜板)



    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    关闭

    站长推荐上一条 /4 下一条

    手机版|爱板网

    GMT+8, 2018-5-24 08:18 , Processed in 0.094800 second(s), 14 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-5   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001056号

    Powered by Discuz!

    返回顶部