##简述
在前几篇博客中介绍了智能家居系统的整体结构以及各个部分实现原理,感谢好多的朋友前来问候,给与了好多建议与支持,让我有了动力来写这篇博客,这篇博客作为本系统的终结篇,将会介绍剩下的问题。


##实现原理
以下会分别介绍下位机中关键部分的实现技术,包括μC/OS-II多任务实现、串口数据的读取、对数据的解析等。首先看一张下位机整体结构图,这样心里就有了比较清晰的框架了:

###下位机硬件资源介绍

  1. zigbee核心板
  2. DS18B20模块(温度传感器)
  3. MQ_2(烟雾传感器)
  4. 客厅LED流水灯(模拟真实环境)
  5. 蜂鸣器
  6. DHT11(温湿度传感器)
  7. 卧室LED灯
  8. 光敏传感器
  9. HCSR501(人体热释电)
  10. 系统检测灯
  11. MCU(STM32F103C8T6)

###μC/OS-II多任务的实现
μC/OS-II是一个可裁剪的、可固话的、可移植的、抢占式实时多任务系统内核,适用于多种微处理器和微控制器,能够移植到超过100多种微处理器应用开发中。本次下位机中就移植了这样一个小型的嵌入式操作系统,使得整个系统显示十分的流畅,而且也很好管理。

μC/OS-II的移植这里就不说了,网上有好多的介绍,其中正点原子和野火的讲的都比较详细,可以去看看,首先说明,我的这个工程也是参考他们的。一下是我的整个工程的结构,整体上还算比较详细的:

通过代码可以很清晰的看出来各个传感器的 驱动、数据的读取等细节,这里主要说说系统多的任务的实现。

主函数开始后进行了一些列的初始化操作,随后初始化了μC/OS-II系统,并且创建了一个开始任务:
各个模块初始化操作:

 delay_init();                   //延时初始化   uart_init(115200);              //串口1初始化uart3_init(115200);             //串口3初始化(连接ZigBee接口)JTAG_Set(JTAG_SWD_DISABLE);     //关闭JTAG接口NVIC_Configuration();           //设置NVIC中断分组2:2位抢占优先级,2位响应优先级BEEP_Init();                    //初始化蜂鸣器接口LED_Init();                           //初始化与LED连接的硬件接口Scan_Key_Configuration();       //初始化按键接口STEP_MOTOR_Start();             //初始化步进电机接口Lsens_Init();                           //初始化光敏传感器接口MQ_2_Configuration();           //初始化烟雾传感器接口HC_SR501_GPIO_Configuration();  //初始化红外热释点接口STEP_MOTOR_Configuration();     //初始化步进电机接口while(DHT11_Init())              //DHT11初始化,检测不到会卡死在这里   {
#if FLAG_SHOW_VALUEprintf("\r\nDHT11 Init Error");
#endifdelay_ms(600);}
#if FLAG_SHOW_VALUEprintf("DHT11 OK\r\n");
#endifwhile(DS18B20_Init())           //初始化DS18B20,检测不到会卡死在这里不断检测{printf("\r\nDS18B20 Init Error");delay_ms(600);}printf("DS18B20 Init OK\r\n");

创建开始任务:

 OSInit();   OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务OSStart();

开始任务创建成功后便会在开始任务里边进行其他任务的初始化操作:

//开始任务
void start_task(void *pdata)
{OS_CPU_SR cpu_sr = 0;pdata = pdata;                            OSStatInit();                         //初始化统计任务.这里会延时1秒钟左右    OS_ENTER_CRITICAL();            //进入临界区(无法被中断打断) //红外热释任务OSTaskCreate(hc_sr501_task,(void *)0,(OS_STK*)&HC_SR501_TASK_STK[HC_SR501_STK_SIZE-1],HC_SR501_TASK_PRIO);//创建温湿度任务OSTaskCreate(dht11_task,(void *)0,(OS_STK*)&DHT11_TASK_STK[DHT11_STK_SIZE - 1],DHT11_TASK_PRIO);                                   //创建温度任务OSTaskCreate(ds18b20_task,(void *)0,(OS_STK*)&DS18B20_TASK_STK[DS18B20_STK_SIZE-1],DS18B20_TASK_PRIO); //创建光敏检测任务OSTaskCreate(telesky_task,(void *)0,(OS_STK*)&TELESKY_TASK_STK[TELESKY_STK_SIZE-1],TELESKY_TASK_PRIO); //创建烟雾检测任务OSTaskCreate(mq_2_task,(void *)0,(OS_STK*)&MQ_2_TASK_STK[MQ_2_STK_SIZE-1],MQ_2_TASK_PRIO); //创建串口3任务,用来进行和上位机通讯OSTaskCreate(uart3_task,(void *)0,(OS_STK*)&UART3_TASK_STK[UART3_STK_SIZE-1],UART3_TASK_PRIO); //创建蜂鸣器任务OSTaskCreate(beep_task,(void *)0,(OS_STK*)&BEEP_TASK_STK[BEEP_STK_SIZE-1],BEEP_TASK_PRIO);//按键扫描任务OSTaskCreate(key_task,(void *)0,(OS_STK*)&KEY_TASK_STK[KEY_STK_SIZE-1],KEY_TASK_PRIO);//创建步进电机任务OSTaskCreate(step_motor_task,(void *)0,(OS_STK*)&STEP_MOTOR_TASK_STK[STEP_MOTOR_STK_SIZE-1],STEP_MOTOR_TASK_PRIO);OSTaskSuspend(START_TASK_PRIO);  //挂起起始任务.OS_EXIT_CRITICAL();                //退出临界区(可以被中断打断)
}

可以很清楚的看到,开始任务里边创建了多个任务,接着,各个任务创建成功后边会挂起任务,退出临界区,开始各个任务的轮训操作。

上面各个任务创建时,都指定了任务优先级,堆栈大小等信息。在app.h文件中可以看到:

//开始任务
#define START_TASK_PRIO                                         10     //开始任务的优先级设置为最低
#define START_STK_SIZE                                              64     //设置任务堆栈大小
OS_STK START_TASK_STK[START_STK_SIZE];                      //创建任务堆栈空间
void start_task(void *pdata);                               //任务函数接口//创建步进电机任务
#define STEP_MOTOR_TASK_PRIO                        11
#define STEP_MOTOR_STK_SIZE                         64
OS_STK STEP_MOTOR_TASK_STK[STEP_MOTOR_STK_SIZE];
void step_motor_task(void *pdata);// //按键扫描任务
// #define KEY_TASK_PRIO  10     设置任务优先级#define KEY_STK_SIZE  90      //设置任务堆栈大小
OS_STK KEY_TASK_STK[KEY_STK_SIZE];                          //创建任务堆栈空间
void key_task(void *pdata);                                 //任务函数接口//蜂鸣器任务--根据各个传感器数据,进行报警
#define BEEP_TASK_PRIO                                                          9
#define BEEP_STK_SIZE                                                               64
OS_STK BEEP_TASK_STK[BEEP_STK_SIZE];
void beep_task(void *pdata);// //人体感应模块 任务
#define HC_SR501_TASK_PRIO                                      8
#define HC_SR501_STK_SIZE                                       64
OS_STK HC_SR501_TASK_STK[HC_SR501_STK_SIZE];
void hc_sr501_task(void *pdata);//光敏传感器采集任务
#define TELESKY_TASK_PRIO                                        7       //设置任务优先级
#define TELESKY_STK_SIZE                                             64      //设置任务堆栈大小
OS_STK TELESKY_TASK_STK[TELESKY_STK_SIZE];                  //创建任务堆栈空间
void telesky_task(void *pdata);                             //任务函数接口//DHT11任务(温湿度传感器)
#define DHT11_TASK_PRIO                                  6       //设置任务优先级
#define DHT11_STK_SIZE                                       64      //设置任务堆栈大小
OS_STK DHT11_TASK_STK[DHT11_STK_SIZE];                      //创建任务堆栈空间
void dht11_task(void *pdata);                               //任务函数接口//MQ-2任务(烟雾传感器)
#define MQ_2_TASK_PRIO                                      5       //设置任务优先级
#define MQ_2_STK_SIZE                                   90      //设置任务堆栈大小
OS_STK MQ_2_TASK_STK[MQ_2_STK_SIZE];                        //创建任务堆栈空间
void mq_2_task(void *pdata);                                //任务函数接口//DS18B20任务
#define DS18B20_TASK_PRIO                            4
#define DS18B20_STK_SIZE                             64
OS_STK DS18B20_TASK_STK[DS18B20_STK_SIZE];
void ds18b20_task(void *pdata);//串口发送数据任务(用来想上位机 实时 传输输出)
#define UART3_TASK_PRIO                             3
#define UART3_STK_SIZE                              90
OS_STK UART3_TASK_STK[UART3_STK_SIZE];
void uart3_task(void *pdata);

任务的优先级决定了任务在被打断时执行的顺序,优先级越高,越有优先权。


###串口数据的读取
在单片机开发过程中串口的操作可以算是最普通也是最基础的操作了,好多东西都是需要通过串口进行输出,这样可以对程序执行过程中的一些中间数据进行输出。这里主要说说串口数据的读取。

数据的读取使用中断的方式进行交互,这样效率很高。这里执行看核心代码即可:

void recv_zigbee_msg(u8 Res)
{if(Res == END_RESD_MSG){FLAG_ZIGBEE_RECV_BEGIN = 0;USART3_RX_BUF[USART3_RX_STA++&0X3FFF] = Res;cpynbyte2buffer(USART3_RX_BUF, USART3_RX_STA);USART3_RX_STA = 0;memset(USART3_RX_BUF, 0, sizeof(USART3_RX_BUF));}else if(Res == BGN_RESD_MSG || FLAG_ZIGBEE_RECV_BEGIN){ FLAG_ZIGBEE_RECV_BEGIN = 1;USART3_RX_BUF[USART3_RX_STA++&0X3FFF] = Res;}else{FLAG_ZIGBEE_RECV_BEGIN = 0;USART3_RX_STA = 0;memset(USART3_RX_BUF, 0, sizeof(USART3_RX_BUF));}
}

这里接收数据时对帧头进行了一个简单的判断,正确后接着接收,碰到帧尾后将数据拷贝到了一个缓冲区中,然后清空接收缓冲。整个过程就这么简单。


###数据的打包和解析操作
####数据解析
前一部分介绍了数据的接收,这里再说说对数据的解析。从上面的代码中可以看出来有个函数:**cpynbyte2buffer(),**该函数是吸纳对数据的解析操作,如下所示:

void cpynbyte2buffer(u8 *data, u8 len)
{int i = 0;u8 data_postion = 0;protocol recvMsg;if (BGN_RESD_MSG == data[data_postion++]){printf("begin\r\n");recvMsg.potocol_len = data[data_postion++];recvMsg.device = data[data_postion++];recvMsg.device_cmd = data[data_postion++];recvMsg.data_len = data[data_postion++];if (recvMsg.data_len > 0){recvMsg.data = (u8 *)malloc(sizeof(u8)*recvMsg.data_len);for (i = 0;i < recvMsg.data_len ;i++){recvMsg.data[i] = data[data_postion++];}}if (data[data_postion] == END_RESD_MSG){printf("end\r\n");recv_data(&recvMsg);}}
}

在上面对数据结构体进行了赋值后便开始了整整的数据或者命令的执行,如 **recv_data(protocol *protocol)**所示:

void recv_data(protocol *protocol)
{switch(protocol->device){case MODULE_BEEP:                  exec_module_beep(protocol);                         break;case MODULE_BED_ROOM_LED_LEFT:     exec_module_led(protocol);                         break; case MODULE_BED_ROOM_LED_RIGHT:    exec_module_led(protocol);                            break; case MODULE_PARLOUR_LED_MAIN:      exec_module_led(protocol);                            break;case MODULE_PARLOUR_LED_TOP:       exec_module_led(protocol);                         break;case MODULE_PARLOUR_LED_HELP:      exec_module_led(protocol);                         break;case MODULE_KITCHIN_LED:           exec_module_led(protocol);                         break;//case MODULE_CURTAIN:               exec_module_curtain(protocol);                       break;case MODULE_ALL_LED:                              exec_module_all_led(protocol);                      break;//case MODULE_LEAVE_HOME:                     exec_module_leave_home(protocol);               break;case MODULE_GO_HOME:                              exec_module_go_home(protocol);                      break;case MODULE_SMOKE:                                    exec_module_change_smoke_value(protocol);   break;case MODULE_DS18B20:                              exec_module_change_parlour_temp(protocol);break;case MODULE_DHT11_HUM:                          exec_module_change_parlour_hum(protocol);   break;default:                                                                              break;}
}

####数据打包发送

数据发送任务函数:

    pack_send_data(MODULE_DS18B20, PROTOCOL_FULL_DATA, DATA_SIZE,parlour_temp_data);    //客厅温度delay_ms(400);pack_send_data(MODULE_DHT11_TEMP, PROTOCOL_FULL_DATA, DATA_SIZE, bed_tempture_data);//卧室温度delay_ms(400);pack_send_data(MODULE_DHT11_HUM,PROTOCOL_FULL_DATA,DATA_SIZE,humidity_data);        //客厅湿度delay_ms(400);pack_send_data(MODULE_SMOKE,PROTOCOL_FULL_DATA,DATA_SIZE,kitchen_smoke_data);       //厨房浓度值delay_ms(400);

上面是数据发送任务里调用的发送函数,该函数中对各个传感器采集到的数据进行了打包并发送操作。可以看打包发送函数:

*void pack_send_data(u8 drive, u8 drive_cmd, u8 data_len, u8 data)

/** @function   pack_send_data* @input* @output* @brief   通讯协议功能的实现.*          本文件实现了数据包的发送和接受,以及根据数据类型执行对应的函数*/
void pack_send_data(u8 drive, u8 drive_cmd, u8 data_len, u8 *data)
{protocol Msg;Msg.send_begin        = BGN_RESD_MSG;         //帧头 #//若数据长度 > 0,即有数据if(data_len > 0){   Msg.potocol_len = PROTOCOL_BASIC_SIZE + data_len - 1;}else{Msg.potocol_len = PROTOCOL_BASIC_SIZE;}//填充数据结构体Msg.device       = drive;Msg.device_cmd     = drive_cmd;Msg.data_len   = data_len;Msg.data        = data;Msg.send_end    = END_RESD_MSG;         //帧尾*//发送数据send_data(&Msg);
}

这里列出来核心代码,具体实现代码请看工程。打包发送函数中主要做了2件事情:一:对数据成员初始化,二:判断一帧数据的大小!数据大小值很重要的,这在数据解析过程可需要用到。

至此,整个毕设的东西差不多都介绍完了。zigbee部分 这里不讲解。

忙碌的几个月的生活还是挺美好的!ok
加油吧,未来是美好的!


技术在于交流、分享……
Email:kevinlq0912@163.com
QQ:2313828706
公众号:devstone


备注:麻烦大家看下文章中说明,要源码要资料的,文章已经说了到哪里可以免费下载所有资料。如果还不知道,可以关注微信公众号:devstone,后台回复关键词下载。

基于ZigBee和STM32的智能家居控制系统的设计与实现(四)相关推荐

  1. 基于ZigBee和STM32的智能家居控制系统的设计与实现(五)--终结篇

    基于ZigBee和STM32的智能家居控制系统的设计与实现(五)–终结篇 说明 首先祝贺自己顺利的完成了毕业答辩工作,想起整个过程还是挺让自己感动的.最后还被评为优秀毕业设计,虽然并没有什么luan用 ...

  2. 基于ZigBee和STM32的智能家居控制系统的设计与实现(二)

    基于ZigBee和STM32的智能家居控制系统的设计与实现(二)   上一篇博客中总体介绍智能家居系统的基本实现原理,这篇博客和以后的几篇博客会详细进行相应的介绍.这里首先进行硬件电路的设计. 硬件电 ...

  3. 基于ZigBee和STM32的智能家居控制系统的设计与实现

    基于ZigBee和STM32的智能家居控制系统的设计与实现(一) 时间过的好快,已经到了做毕业设计的时候了,本次毕业设计题目是自己选的,为什么做这个?原因很简单,想把自己所学的大部分知识都应用上,虽然 ...

  4. 基于ZigBee和STM32的智能家居控制系统的设计与实现(三)

    基于ZigBee和STM32的智能家居控制系统的设计与实现(三) 自从前两篇博客介绍了智能家居系统的基本实现机理后,收到了好多朋友的来信,和我讨论了好多的这方面的知识,在此很高兴,虽然自己做的这个所谓 ...

  5. 关于开源项目「基于ZigBee和STM32的智能家居控制系统」的使用说明

    阅读本文大概需要 6.6 分钟 大家好,我是 devstone,很感谢大家对这个项目的喜爱和关心,自从该项目公开以来断断续续有很多人加我好友询问一些基础问题,我也回复过很多,当然了以后也可能会有人问到 ...

  6. 《ZigBee开发笔记》第六部分 项目篇 基于ZigBee和Openwrt的智能家居控制系统(五)

    声明:本项目的所有源码均公开,但未经同意不得转载或用于其他用途,有任何问题请联系博主,感谢大家的支持. 上一节介绍了上位机,本节将介绍智能网关部分,智能网关是用的开源系统OpenWrt.处理器使用的是 ...

  7. 基于 STM32 的语音识别智能家居控制系统的设计(LD3320语音识别芯片+ESP8266 WIFI模块+DHT11温湿度采集+MQ系列 烟雾及可燃气体+蜂鸣器+步进电机模拟窗帘+OLED液晶显示+

    ## **基于 STM32 的语音识别智能家居控制系统的设计(LD3320语音识别芯片+ESP8266 WIFI模块(阿里云 或ONENET或局域网)+DHT11温湿度采集+MQ系列 烟雾及可燃气体+ ...

  8. 基于微信的智能家居控制系统的设计与实现

    基于微信的智能家居控制系统的设计与实现 目 录 1 绪论 6 1.1 课题研究的背景 6 1.2 智能家居系统的研究现状和发展前景 6 1.3 课题研究的意义 7 1.4 设计的研究内容 8 2 相关 ...

  9. 基于Zigbee和MQTT的智能家居应用

    基于Zigbee和MQTT的智能家居应用 摘要:本文提出了基于Zigbee和MQTT的一种智能家居设计方案,与小米华为等做成品的方案不同,本文方案主要设计的是不同的设备控制器,对于用户定制的自由度大, ...

最新文章

  1. 如何利用隐写术配合四个重定向连接到C2服务器
  2. Docker网络相关
  3. 20155313 预备作业二
  4. android点击加号,Android仿微信朋友圈点击加号添加图片功能
  5. 好快!京东推出全新快递服务: 最快30分钟送达
  6. Android运行时权限,设置帮助类BaseActivity;电话权限,短信权限,
  7. 【资料整理】squid安装和配置代理上网
  8. HDU - 1520 Anniversary party (有向入门树形DP)
  9. UML建模与软件工程
  10. 【3dmax千千问】初学3dmax插件神器第17课|VRAY渲染教程|哪三种表现方式最能影响3dmax疯狂模渲大师设计效果图的写实程度?食住玩3dmax入门到精通进阶教程
  11. 1寸,2的照片多大啊
  12. 数学建模-多元线性回归
  13. keras LSTM实现imdb电影评论文本二分类
  14. erp软件的优点和用途
  15. 基础快读(新手入门)(C++实现)
  16. 2019年暑假第八周总结
  17. VB.net 移动文件夹去另一个地址,删除文件夹里某种类型的文件
  18. 使用Python将图片变成铅笔素描
  19. 【量化笔记】Markowitz均值-方差模型
  20. 梯度下降算法与随机梯度下降算法:实现波士顿房价问题

热门文章

  1. HMC5883L地磁传感器驱动
  2. JVM之一:GC垃圾回收原理及算法分析
  3. POI插入附件到Excle
  4. autojs之多线程-Threads
  5. Python中的pandas库简介及其使用
  6. 英伟达发布全新GPU:采用图灵架构 支持光线追踪
  7. 09-word不显示段落标记(去掉回车符号)取消拼写错误
  8. android java 调试工具_调试应用  |  Android 开发者  |  Android Developers
  9. 8B10B编解码的Verilog实现
  10. 《一篇文章全吃透》—YYModel的使用技巧