
STM32智能台灯系统
1、系统介绍
本次我们教程中的项目为STM32智能台灯系统。希望通过对本项目的学习,大家可以成功的搭建出来智能台灯系统。并且可以在此基础上开发一些新的功能或者能够搭建其他各种各样类似的物联网系统。
关于系统的名称可以是以下不同的名称:基于机智云平台的智能台灯系统、STM32物联网智能台灯、STM32多功能台灯系统等等。
目前教程还处于开发阶段,视频和文档都在持续更新中,预计11月上旬更新完毕。
适用对象
该系统需要一定的C语言知识和STM32单片机开发经验,最起码了解过STM32单片机并简单的使用过,比如说使用单片机下载过程序。如果没有下载过程序,或对STM32单片机没有一点了解的同学,可以先简单了解一下。在我们的这个教程中,我主要会讲解系统所需要的每一个模块的用法,手把手的带大家实现相应的逻辑功能,主要讲解的是如何完成一个物联网系统。
1、适用于对物联网感兴趣的同学,想自己亲手做一个物联网系统。
2、该系统的开发也有一定的工作量,可适用于课程设计等。
3、想做其它物联网系统,可以学习该教程的开发方法,同样适用于开发一些其它相似的物联网系统。
实物展示
实物主要由单片机硬件电路和手机APP组成,通过APP可以远程控制硬件电路功能,并且硬件电路的一些状态也可以上发给APP。教程上使用的是通过PCB板焊接的硬件电路。有需要的同学也可以通过面包板简单搭建电路,代码和功能都是一样的,只需要注意传感器和单片机之间的连接即可。
硬件电路
单片机硬件系统可以通过多种方式搭建,主要有两种方式
1、PCB板:通过画系统的电路图,然后交给PCB生产厂家进行打板。我们只需要在做好的PCB电路板上面将相关的模块和元器件进行焊接即可。这种方式需要有系统的原理图,做出来的系统比较美观(视频教程使用的方式就为PCB板,外观美观,并且集成CH340芯片,可以一键下载程序)。
2、面包板:面包板则搭建相对简单,不过需要许多的杜邦线对单片机和传感器模块进行连接。硬件实物比较杂乱,并且稳定性较低,容易损坏。简单实现功能可使用该方式。
两种方式各有好坏,具体使用哪种方式根据自己的需求去选择。不管用那种方式,都可以实现本系统的所有功能。相关原理图和面包板搭建方式等内容,可以后续关注公众号进行获取。
系统功能
1、灯光调节:
手动模式,通过按键对灯光亮度进行调节。
自动模式,通过光敏电阻和人体检测传感器自动对灯光进行调控。
2、坐姿检测:
超声波检测距离,当距离小于设定的阈值时,触发声光报警电路。
3、番茄时钟:
OLED显示设置的番茄时钟的倒计时。
4、语音控制
可以语音切换自动模式和手动模式
可以语音设置番茄钟时间。
可以语音控制灯光亮度。
5、OLED显示
显示自动/手动模式
显示灯光亮度
显示超声波距离
显示番茄钟时间
6、APP远程功能
可以选择自动模式和手动模式。
在手动模式下可以远程调节灯光亮度。
可以设置超声波检测距离阈值。
可以下发番茄钟时间。
系统框架
整个系统主要分为硬件部分和云平台部分,硬件部分主要是通过STM32单片机对各种传感器模块数据进行处理,然后通过wifi模块与云平台进行数据的交互。云平台我们采取的是机智云平台,使用该平台的好处是单片机端程序写好之后,可以一键式生成APP界面,不用单独的再写一个APP界面,实现快捷开发。
2、代码工程
开发模式
STM32单片机目前主要开发方式有库函数开发和寄存器开发,比较流行的就是使用库函数模式进行开发。寄存器开发类似于51单片机开发,只不过STM32的寄存器要比51单片机多很多,因此再使用寄存器方式开发效率就很低。
库函数是由ST公司针对SMT32提供的函数接口,我们可以通过调用这些函数接口来实现对STM32的控制。就比如当年我们学C语言时使用的printf函数,我们不必关心其内部是怎么实现的,学会向这个函数传入相应的参数即可。每个函数里面就是各种对寄存器的调用,厂商已经帮我们实现了。
那寄存器是什么呢?寄存器说白了就是具有特定功能的内存单元的一个别名。比如说我们想控制单片机的管脚来输出高低电平,其实就是往一个地址里面进行读写数据。那我们就把这个能够控制管脚输出高低电平的地址起一个别名,这个别名就是所谓的寄存器。
代码框架
基本代码框架:主要是系统基本功能的实现,比如按键、串口、定时器、延迟函数和各种传感器模块驱动代码等内容的实现,但是并没有机智云平台和功能实现相关的代码,主要是为了方便大家跟着视频一步一步进行操作。视频教程也是在基本代码框架工程的基础上,不断加入机智云平台相关代码,并开发相应的逻辑功能。从而实现完整的系统功能。
基本代码框的目录为下图所示:
1、 APP:主要是一些传感器模块的驱动代码(代码框架里没有实现,需要根据需求移植)。
2、 BSP:基本功能代码,比如LED灯、串口、定时器灯模块的实现。
3、 Libraries:厂商封装的库函数,我们需要调用这些库函数去实现相应功能。
4、 Main:主函数main.c实现的地方
5、 Output:编译生成的中间文件和下载到单片机的Hex文件。
STM32单片机的开发工具为keil,我们通过keil软件打开基本代码,可以看到左侧的各种文件,其中BSP文件夹下为一些基本的功能实现,红圈里则为厂商提供的一些文件。
startup_stm32f10x_md.s:单片机启动文件,该文件是由汇编语言编写,是上电之后执行的第一个程序。主要是初始化堆栈指针等内容,然后调用C语言main函数。
Core_cm3.c、Core_cm3.h:主要是实现了操作内核外设寄存器的一些函数,我们其实很少用到
stm32f10x.h:这个头文件实现了外设的所有的寄存器的映射,其实就是完成了给地址起别名的操作。
system_stm32f10x.c、system_stm32f10x.h:实现了 STM32 的时钟配置,操作的是片上的 RCC 这个外设.调用完之后。系统在上电之后,会首先执行由汇编编写的启动文件,启动文件中的复位函数中调用的 SystemInit 函数就在这个文件里面定义。调用完之后,系统的时钟就被初始化成 72M。
FWLB文件夹:ST 公司针对每个 STM32 外设而编写的库函数文件。我们调用的库函数的实现就是在这些文件中编写的。
功能驱动
bsp_led.c:板子上LED灯功能实现
我们设计的电路板上面设计的声光报警电路驱动就在该文件中实现,主要就是驱动蜂鸣器和LED灯。让单片机输出高低电平就可以使声光报警电路关闭或打开。
bsp_delay.c:延时函数实现
延时函数的实现我们是通过SysTic系统定时器来实现的。SysTick—系统定时器是属于内核中的一个外设。系统定时器是一个 24bit的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK。因此我们就可以通过使用SysTick的计数功能来实现延时函数的实现。
再使用DelayMs函数之前,需要在主函数里面调用Delay_Init函数。(其实不管什么模块,代码上几乎都有Init函数,都需要在main主函数中调用从而对模块进行初始化)
void Delay_Init(void);
void DelayUs(unsigned short us);
void DelayXms(unsigned short ms);
void DelayMs(unsigned short ms);
bsp_usart.c:串口功能实现
Stm32单片机提供了多个串口,USART串口是STM32与外部设备交互信息的模块。其中Bsp_usart1.c功能为单片机与电脑串口打印工具通信。Bsp_usart2.c:单片机与Wifi模块通信。Bsp_usart3.c:单片机与语音识别模块进行通信。
bsp_Key.c:按键功能实现
我们设计的电路板预留了三个按键,按键的实现其实和LED灯的实现相差无异。当按键按下的时候,单片机管脚会输入低电平。因此只要我们调用函数去检测管脚的输入状态,如果输入状态为低电平的时候,就说明有按键按下了。
bsp_timer.c:定时器功能
STM32F1 系列中,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。
基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部IO。
通用定时器 TIM2/3/4/5 可以定时可以输出比较,可以输入捕捉。
高级定时器 TIM1/8 可以定时,可以输出比较,可以输入捕捉,还可以有互补输出信号。
这个timer.c文件中使用的是TIM4。我们把定时器设置自动重装载寄存器 的值为 1000,设置时钟预分频器为 71,则驱动计数器的时钟:CK_CNT = CK_INT / (71+1)=1M,则计数器计数一次的时间等于: 1/CK_CNT=1us,当计数器计数到自动重装载寄存器的值 1000 时,产生一次中断,则中断一次的时间为1/CK_CNT*ARR=1ms
3、机智云平台
机智云平台是面向开发者的一站式智能硬件开发平台。机智云平台提供了一些API接口供我们使用,能够降低对物联网设备的开发的门槛,我们可以通过调用提供的API将硬件设备快速的连接到云端。
Gagent是一个固件,主要的作用是数据转发,是设备数据、机智云、应用端(APP)的数据交互桥梁。我们只需要将该固件烧录到WIFI模块,就可以实现硬件设备与云端和APP的通信。因此使用该固件,可以节省我们自己编写与云平台通信信息。降低开发难度和节省时间。
机智云平台开发流程:
Step1:注册账号
登录机智云官网https://www.gizwits.com/5,创建一个机智云平台的账号。
注册完成之后,我们可以看到网站首页有一个开发者中心,我们后续的开发都是在开发者中心进行的。
Step2:创建设备
在机智云平台上创建产品,后续我们单片机通过wifi模块将数据上传到机智云平台,就是上传到这个产品中。单片机与机智云平台通信,其实就是单片机与机智云平台上的的某个产品进行通信。
在开发者中心,我们可以点击创建按钮,会让你选择创建的产品。我们选择自定义方案创建产品。
产品名称:可以随意填写。
类型:我们使用的是wifi接入,所以选择wifi模块
数据传输方式:
定长:指在功能数据点上报下发时一并传输。
变长:指在功能数据点上报下发时只传输改变的功能数据点。比如一个灯有开关、亮度两个功能时,触发改变亮度这个功能时,定长是两个功能数据点的状态数据都传输,变长则只会传输亮度这个功能数据点。两者各有优势,定长对于开发更方便,变长则更节省传输资源。
功耗方式:选择正常
产品创建好之后,我们就可以创建数据点,数据点即设备产品的功能的抽象,用于描述产品功能及其参数。创建数据点后,设备与云端通讯的数据格式即可确定,设备、机智云可以相互识别设备与机智云互联互通的数据。
数据点的创建需要根据我们系统的需求来进行创建,比如我们智能台灯系统中需要远程控制单片机的灯光模式(切换手动模式或者自动模式),因此我们可以创建一个灯光模式的数据点。
标识名:用于应用层传输,客户端或业务云开发时需要使用。命名规则遵循标准的开发语言变量名命名规范,支持英文字母、数字和下划线,以英文字母开头。
显示名称:自定义功能点名称。
读写类型:
① 只读:表示该数据点非控制,数据只支持从设备上报。
② 可写:表示该数据点可控制。设备端可上报该数据点数据;云端/客户端可对该数据点数据做出下发控制。
③ 报警:表示该数据点非控制,数据只支持从设备上报,数据类型需为布尔值。
④ 故障:表示该数据点非控制,数据只支持从设备上报,数据类型需为布尔值。云端会对设备上报的该数据点做统计,可在“运行状态”查看。
数据类型:
① 布尔值:表示两个状态:0,或1。如开关状态等,建议使用布尔数据类型。
② 枚举类型:可定义一个有限的取值集合。当定义的某个功能(元器件)有固定的若干个值。
③ 数值:填写数值范围,数值可为负数/小数,机智云自动将数值转换为正数。
④ 扩展:填写数据长度,数据内容由用户自定义。对于上述功能点无法满足的复杂功能可采用。机智云不建议使用此类型数据,设备上报该数据点的数据,机智云无法识别。
比如我们智能台灯系统需要定义的数据点及相应的格式就有以下几种:
Step3:烧写GAgent固件
GAgent是运行在各种通讯模组上的一款应用程序(固件),可以提供上层应用(手机APP等控制端、云端)到产品设备的双向数据通讯,产品开发者使用GAgent后,只需要关心产品的业务逻辑开发,不用关心数据的通讯功能开发,大大降低了开发的难度。
单片机通过串口发送命令给WIFI模块,从而与云平台进行连接和数据的交换。实现接入机智云,我们只需要给WIFI模块烧录一个Gagent固件,在该固件里实现了一些网络的传输协议,因此我们不必再关注具体的网络是怎么实现的。Gagent实现了设备、机智云、应用端(APP)的数据的交互。
我们将下载的压缩包进行解压,里面会有如下几个文件,首先我们需要根据WIFI模块的Flash大小去选择应该烧录那个文件,并且我们需要选择带有combine字段的bin文件。
首先我们需要从安信可官网下载ESP8266系列模组的固件烧录软件,我们使用下载的烧录器将GAgent固件烧录到我们的ESP8266上面。 选择我们对应flash大小的combine文件,我手头的ESP8266M模块是ESP-01,flash只有8Mbit,因此我选择了8Mbit的combint文件。SPI SPEED选择40MHz,SPI MODE选择DOUT,波特率选择115200。
固件下载方式
1、PCB板下载。
开发板已经集成好了一颗CH340芯片,可以直接通过板子的串口给ESP-01模块下载固件,只需要将下图三个跳线帽全部都置到右边。然后点击START即可下载,如果没有反应,可以重新拔插一下wifi模块。待软件最下面的进度条加载完成,即完成下载。
2、USB转TTL下载器下载
如果没有智能台灯系统的PCB板,Wifi固件也可以通过USB转TTL线对ESP-01S模块进行连接,直接将固件下载到模块中去。将wifi模块的串口与USB转TTL下载器的串口进行连接如下图所示。需要注意的是,用下载器下载,需要Wifi模块的IO0引脚一个低电平,即可完成下载。
Step4:代码移植
创建完产品和数据点之后,我们就可以通过云平台直接生成一份代码。该代码实现了机智云通信协议的解析与封包、传感器数据与通信数据的转换逻辑,并封装成了简单的 API。当设备收到云端或 APP 端的数据后,开发者只需要在对应的事件处理逻辑中添加传感器的控制函数,便可完成产品的开发。在选择硬件平台的时候,我们需要选择其它平台。
Product Key:产品标识码,开发者通过机智云后台创建新产品后,自动生成的一个32位字符串。在机智云的数据库中是一个唯一的号码,开发者将Product Key写入设备主控MCU后,机智云通过此标识码对设备进行识别并自动完成注册。设备接入机智云的前提是,需要机智云认同这个设备。Product Key是设备接入机智云的一个重要参数
Product Secret:产品密钥,在生成Product Key的时候云端会对应生成一个Product Secret,该参数为关键性机密参数。
代码包下载完成之后我们就可以将有用的程序移植到我们的基本代码框架里面,Gizwits工程主要实现了机智云通信协议的解析与封包,并封装成了简单的API。当设备收到云端或APP端的数据后,程序会将数据转换成对应的事件并通知到应用层,开发者只需要在对应的事件处理逻辑API中添加传感器的控制函数,就可以完成产品的开发。
User文件里面的main.c文件,这个我们一般不需要管,也不用移植,Utile文件里面有6个文件,主要包括工具函数、数据点的相关压缩,解压函数,环形缓冲区等接口。我们对这些文件不需要进行修改,只需要直接移植到我们自己的程序中去即可。
在Gizwits 文件夹下有2个.C文件和2个.H文件,这四个文件需要移植到我们自己的工程里面,也是我们需要添加自己一些修改的地方。
gizwits_product.c:该文件为功能相关处理函数,用户需要对该文件里面部分的函数进行完善和修改,以实现相应的功能。
gizwits_product.h存放产品相关宏定义,一般无需修改。
gizwits_protocol.c协议相关处理的文件,完成和wifi模块通信协议的解析,主要提供一些API接口函数供用户调用。
gizwits_protocol.h协议处理相关文件,定义产品密钥、结构体等,一般无需修改
将文件复制到我们框架工程
将Gizwite工程里面的Gizwits文件夹和Utils文件夹下面的文件都添加到我们工程里面里面的WIFI文件夹下面。
2、将文件添加到工程编译中
3、将wifi串口接收的数据写入缓冲区
单片机与WIFI模块是通过串口2连接的,wifi模块从云平台获取到数据,然后通过串口2发送给单片机。由于数据是一直可以从机智云平台下发,因此需要将数据写入循环缓冲区里面,当我们处理数据时,就从这个循环buffer里面取出来相应的数据。
因此在串口2的中断接收函数里面,我们直接调用gizPutData,将获取到的数据先写入循环buffer,以待后续的处理。
void USART2_IRQHandler(void)
{
uint8_t u8res = 0;
if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)
{
u8res = USART_ReceiveData(USART2);
gizPutData(&u8res,1);
}
}
4、实现串口向wifi模块发送数据
for(i=0; i<len; i++)
{
USART_SendData(USART2, buf[i]);//STM32 test demo
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET);
if(i >=2 && buf[i] == 0xFF)
{
USART_SendData(USART2, 0X55);//STM32 test demo
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET);
}
}
5、实现毫秒的定时
网络协议层的运行需要一个系统时间,事件单位为毫秒,所以我们需要实现毫秒定时器(必须是 1ms 的精确定时,若不准确,会影响到超时重发、定时上报等处理), gizTimerMs()函数具体位置在 gizwits_product.c 文件下。在定时器中断函数里面添加完gizTimerMs()函数之后,需要在gizwits_product.h进行声明一下,gizTimerMs()函数才能够被其它.c文件引用,并且在bsp_timer.c文件引用时需要包含gizwits_product.h头文件。
gizTimerMs();
6、 实现mcuRestart复位函数
WIFI 在通信过程中会对 MCU 进行请求复位,而复位调用函数为mcuRestart(),该函数是空的,我们需在函数中实现软复位,函数位置在gizwits_product.c 中。我们只需要在该接口中增加__set_FAULTMASK(1);NVIC_SystemReset();
void mcuRestart(void)
{
__set_FAULTMASK(1);
NVIC_SystemReset();
}
4、功能实现
配网模式
WIFI 设备与云端通信前需要配置配网模式,而设置配网模式是调用了gizwitsSetMode()函数,其函数可实现模组配网功能或复位、产测和绑定功能,gizwitsSetMode()函数具体位置在 gizwits_protocol.c 文件下,它共有五种配置模式,复位、 SoftAP、 AirLink 模式、产测模式和允许用户绑定设备模式。在本次项目中,我们使用的配网方式为SoftAP模式。我们通过按键的方式对设备进行入网模式的配置,当按下按键时,完成配网的设置
关于配网模式,我们只需要关注SoftAP、 AirLink 模式,这两种模式我们可以根据自己的需求进行配置。
AirLink模式:当设备处于该模式下,会不断的接收待特定编码的wifi广播包,手机连接可用的wifi网络后,通过指定的APP发送编码后的WIFI网络的SSID和密码广播,设备接收到之后自动尝试连接此WiFi网络,连接成功即配置完成。
SoftAP模式:设备在SoftAP模式下相当于一个热点,手机可以连接到该热点中,并将可用的wifi网络SSID和密码发送给设备,设备接收到配置信息后自动尝试连接该路由器,连接成功则自动切换到正常使用的模式。
数据的上传和下发
gizwitsHandle((dataPoint_t*)¤tDataPoint);
单片机将采集到的数据通过wifi模块上传到机智云平台,或者机智云平台下发数据控制单片机实现相应的功能,都是在gizwitsHandle接口中实现的。