比派科技banana pi专区
直播中

brantsun

10年用户 128经验值
擅长:MEMS/传感技术 控制/MCU RF/无线
私信 关注
[经验]

【Banana Pi M1+试用体验】【结项】智能家庭中央控制系统

本帖最后由 brantsun 于 2016-8-21 17:52 编辑

一,项目概述
       智能产品未来的发展,首先就需要致力于改变消费者“不必要”的消费习惯,通过技术的进步从而让产品的价格也开始有竞争力,良好的市场推广和简单易上手的APP支持,才能让产品更好地与市场融入。而智能家居的发展在未来也是非常火的,未来家装智能家居是不可缺少的产品,我们的作品,智能家庭中央控制系统,意在用一块小的嵌入式板子就能作为整个家庭控制网络的核心,当然是可以实现的。
材料:香蕉派,路由器,温湿度传感器,一氧化碳传感器,STM32f103,24L01无线通讯模块,八通路继电器,风扇,有刷电机。
二 ,项目实现过程

1.首先我们需要给香蕉派刷好Debian系统。(具体点击链接查看)
2我们需要配置好我们的香蕉派上的服务器环境以及设置好静态IP。
3.将自己写好的网站部署到自己的香蕉派服务器上。
4.建立起与部署好的网站所需要的数据---数据库的搭建。
5.配置好所有需要的gpio口,写好相关模块的驱动程序,并且加入到开机自启动
6.配置好开机权限的自动给予,并且先用php座位后台进行测试。
7.后台全新升级,使用jsp。
好了,我们来说说我们最终的作品吧!我们最终的作品采用了jsp作为后台。
首先,登录页面,没有账号的话可以注册,用户名相同无法注册,当输入完用户名后会触发数去焦点事件,然后,通过AJAX和后台通讯,查询数据库。
打开的英国威廉希尔公司网站 :
1.png
用户登录平台:
QQ截图20160806230129.png
用户注册界面:
捕获.PNG
登陆成功后会到我们的传感器信息显示页面:
(这里显示的都是我们的所有传感器的测量的信息)
QQ截图20160806230148.png
然后大家可以点击添加设备,会有下面这些设备:
QQ截图20160806230220.png
添加完设备后点击我的设备:
(这就是我们刚才添加的设备)
QQ截图20160806230206.png QQ截图20160806230212.png
QQ截图20160806230227.png
QQ截图20160806230232.png
同时我们还可以添加和修改自己的信息:
QQ截图20160806230247.png
那么一以上就是我们整个电脑端的介绍
8.客户端的实现
这是我们最初做的一款app,只实现了开关量的控制:
图片1.png
网页的附件:用压缩软件解压zip后得到war格式的文件再用解压软件解压就好了:
MIS_QIMO.zip (3.31 MB)
(下载次数: 2, 2016-8-21 16:52 上传)

后来我们加上了生活信息的显示,连接上香蕉派服务器后就能显示了,如果有燃气泄漏则客户单会报警,发出声音:
Screenshot_2016-08-21-16-41-08.png
apk附件:
智能家居控制.zip (737.52 KB)
(下载次数: 7, 2016-8-21 16:53 上传)

9.这是stm32和温湿度传感器,一氧化碳传感器2.4g无线通讯模块,二通路驱动模块,风扇和窗帘。

香蕉派部分:
为了极大的利用香蕉派,风扇和窗帘我们使用了香蕉派控制的。
窗帘:使用了一个有刷减速电机和三个红外距离传感器,减速电机主要控制窗帘的卷起和放下,红外距离传感器主要是用来检测窗帘当前所在的位置。
风扇:我们是使用了香蕉派产生的一路pwm来控制的。(link:用香蕉派产生硬件pwm。
24L01无线模块:和stm32单片机通讯。
stm32部分:
24L01无线模块:和香蕉派通讯。
温湿度传感器:测量当前室内的温湿度。
一氧化碳传感器:检测是否有燃气泄漏。
led:检测是否和香蕉派连接成功,如果成功会规律的闪烁。

efef.jpg
我们的香蕉派会每3秒去读取数据库,将读取的数据发送给单片机;
  1. #include
  2. #include
  3. #include "/usr/include/mysql/mysql.h"
  4. extern int d1,d2,d3,d4;
  5. void mysqlupdate(void) {
  6.     MYSQL my_connection;
  7.     int res;
  8.         char txt[70];
  9.         sprintf(txt,"update ths set tem=%d,hum=%d,smok=%d,watertemp=%d",d1,d2,d3,d4);
  10.         printf("%s",txt);
  11.     mysql_init(&my_connection);
  12.     if (mysql_real_connect(&my_connection, "localhost","root", "root","users", 0, NULL, CLIENT_FOUND_ROWS))
  13.      {
  14.           printf("Connection successn");
  15.           res = mysql_query(&my_connection, txt);
  16.           if(!res)
  17.            {
  18.             printf("inserted %lu rowsn",(unsigned long)mysql_affected_rows(&my_connection));
  19.             }
  20.           else
  21.             {
  22.              fprintf(stderr, "Insert error %d: %sn",mysql_errno(&my_connection),mysql_error(&my_connection));
  23.              }
  24.         mysql_close(&my_connection);
  25.      }

  26.     else
  27.         {
  28.                 fprintf(stderr, "Connection failedn");
  29.                 if (mysql_errno(&my_connection))
  30.                   {
  31.                    fprintf(stderr, "Connection error %d: %sn",mysql_errno(&my_connection),mysql_error(&my_connection));
  32.                    }
  33.         }

  34. }
  35. int readmysql(char *a){
  36.   MYSQL mysql;//mysql connection
  37.   MYSQL_RES *res;
  38.   MYSQL_ROW row;
  39.   char *query;
  40.   char *string;
  41.   int t,r,b;
  42.   char text[70];
  43. sprintf(text,"select * from equstate where equname='%s'",a);
  44. //printf("%s",text);
  45. mysql_init(&mysql);
  46. if(mysql_real_connect(&mysql, "localhost","root", "root","users", 0, NULL, CLIENT_FOUND_ROWS)){
  47. //        query="select * from equstate where equname='' ";
  48.         t=mysql_query(&mysql,text);
  49.         if(t)
  50.         {
  51.         printf("err:%s",mysql_error(&mysql));
  52.         }
  53.         res=mysql_store_result(&mysql);
  54.         while(row=mysql_fetch_row(res))
  55.         {
  56. //        for(t=0;t
  57. //        {
  58. //        printf("%st",row[2]);
  59. //        }
  60. //        printf("n");
  61.         b=atoi(row[2]);
  62.   //      printf("%dn",b);
  63.         }
  64.         mysql_free_result(res);
  65.         mysql_close(&mysql);
  66. }
  67. else{
  68.        fprintf(stderr, "Connection failedn");
  69.        if (mysql_errno(&mysql))
  70.         {
  71.       fprintf(stderr, "Connection error %d: %sn",mysql_errno(&mysql),mysql_error(&mysql));
  72.         }

  73. }
  74. return b;
  75. }
这里大家可能会遇到一个问题,就是装完mysql后,在编译程序时并不能找到mysql的c库;
例如:#include "/usr/include/mysql/mysql.h"会出错。
怎样解决?
这样:
  1. apt-get install libmysqlclient-dev
安装完库后就可以使用了。
24L01的驱动,通过C语言gpio库写的:
24l01send.zip (22.82 KB)
(下载次数: 2, 2016-8-21 17:39 上传)

QQ截图20160821172045.png
  1. #include "pyinclude.h"
  2. #include "NRF24L01.h"

  3. /***************************************************************
  4. //模块名称:NRF24L01无线模块
  5. //功    能:数据收发
  6. //            -----------------
  7. //           |                 |
  8. //           |             PD6|--->CE
  9. //           |             PD7|--->CSN
  10. //           |             PD8|--->SCK
  11. //           |             PD9|-->MOSI
  12. //           |             PD10|<--MISO
  13. //           |             PD11|<--IRQ
  14. //           |                 |
  15. //            -----------------
  16. ****************************************************************/

  17. uchar  TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x11,0x11,0x11};        //本地地址
  18. uchar  RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01};        //接收地址


  19. /*******************************************************************
  20. //函数名称:void NRF24L01_IO_set(void)
  21. //函数功能:NRF24L01引脚初始化
  22. //参    数:无
  23. //返 回 值:无
  24. ********************************************************************/
  25. void NRF24L01_IO_set(void)
  26. {
  27.         RF24L01_CE;
  28.         RF24L01_CSN;
  29.         RF24L01_SCK;
  30.         RF24L01_MOSI;
  31.         RF24L01_MISO;
  32.         RF24L01_IRQ;

  33. }

  34. /*******************************************************************
  35. //函数名称:SPI_RW()
  36. //函数功能:完成GPIO模拟SPI的功能,将输出字节(MOSI)从MSB循环输出
  37. //          同时将输入字节(MISO)从LSB循环移入,上升沿读入,下降沿
  38. //          输出。(从SCK被初始化为低电平可以判出)
  39. //参    数:byte(字节)
  40. //返 回 值:byte
  41. ********************************************************************/
  42. uchar SPI_RW(uchar data)
  43. {
  44.         uchar i,temp=0;
  45.         for(i=0;i<8;i++) // output 8-bit
  46.         {
  47.                 if((data & 0x80)==0x80)
  48.                 {
  49.                             RF24L01_MOSI_1;   // output 'uchar', MSB to MOSI
  50.                 }
  51.                 else
  52.                 {
  53.                             RF24L01_MOSI_0;
  54.                 }        
  55.                 data = (data << 1);           // shift next bit into MSB..
  56.                 temp<<=1;
  57.                 RF24L01_SCK_1;                // Set SCK high..
  58.                 if((RF24L01_MISO_PIN)==1)temp++;  // capture current MISO bit
  59.                 RF24L01_SCK_0;                // ..then set SCK low again
  60.         }
  61.         return(temp);           // return read uchar
  62. }

  63. /*******************************************************************
  64. //函数名称:void inerDelay_us(uchar n)
  65. //函数功能:n 延时数
  66. //参    数:无
  67. //返 回 值:无
  68. ********************************************************************/
  69. void inerDelay_us(uchar n)
  70. {
  71.         for(;n>0;n--);
  72. }

  73. /****************************
  74. //函数名称:SPI_Read()
  75. //函数功能:读取寄存器的值
  76. //参    数:reg(寄存器)
  77. //返 回 值:reg_val(寄存器值)
  78. *****************************/
  79. uchar SPI_Read(uchar reg)
  80. {
  81.         uchar reg_val;
  82.         RF24L01_CSN_0;          // CSN low, initialize SPI communication...
  83.         SPI_RW(reg);            // Select register to read from..
  84.         reg_val = SPI_RW(0);    // ..then read registervalue
  85.         RF24L01_CSN_1;          // CSN high, terminate SPI communication
  86.         return(reg_val);        // return register value
  87. }

  88. /******************************************************************
  89. //函数名称:SPI_RW_Reg()
  90. //函数功能:寄存器访问函数,把设定的值写进相应的寄存器,并读取返回值
  91. //参    数:reg(寄存器选择),value(设定值)
  92. //返 回 值:status
  93. ********************************************************************/
  94. uchar SPI_RW_Reg(uchar reg, uchar value)
  95. {
  96.         uchar status1;
  97.         RF24L01_CSN_0;             // CSN low, init SPI transaction
  98.         status1 = SPI_RW(reg);     // select register
  99.         SPI_RW(value);             // ..and write value to it..
  100.         RF24L01_CSN_1;             // CSN high again
  101.         return(status1);           // return nRF24L01 status uchar
  102. }

  103. /********************************************************
  104. //函数名称:uchar SPI_Read_Buf()
  105. //函数功能:接收时读取FIFO缓冲区的值
  106. //参    数:reg(寄存器),*pBuf(数据存储),bytes(字节数)
  107. //返 回 值:status
  108. *********************************************************/
  109. uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar chars)
  110. {
  111.         uchar status2,uchar_ctr;
  112.         RF24L01_CSN_0;                   // Set CSN low, init SPI tranaction
  113.         status2 = SPI_RW(reg);           // Select register to write to and read status uchar
  114.         for(uchar_ctr=0;uchar_ctr
  115.         {
  116.                 pBuf[uchar_ctr] = SPI_RW(0);  
  117.         }
  118.         RF24L01_CSN_1;                           
  119.         return(status2);                 // return nRF24L01 status uchar
  120. }

  121. /***********************************************************
  122. //函数名称:SPI_Write_Buf()
  123. //函数功能:发射缓冲区访问,把数组里的数放到FIFO缓冲区中
  124. //参    数:reg(寄存器选择),*pBuf(待写数据,bytes(字节数))
  125. //返 回 值:status NRF24L01状态位
  126. ************************************************************/
  127. uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar chars)
  128. {
  129.         uchar status1,uchar_ctr;
  130.         RF24L01_CSN_0;             //SPI使能      
  131.         status1 = SPI_RW(reg);   
  132.         for(uchar_ctr=0; uchar_ctr
  133.         {
  134.                 SPI_RW(*pBuf++);
  135.         }
  136.         RF24L01_CSN_1;            //关闭SPI
  137.         return(status1);          //
  138. }

  139. /**************************
  140. //函数名称:RX_Mode()
  141. //函数功能:设定为接收模式
  142. //参    数:无
  143. //返 回 值:无
  144. ***************************/
  145. void RX_Mode(void)
  146. {
  147.         RF24L01_CE_0;
  148.         SPI_Write_Buf(WRITE_REG + RX_ADDR_P0,TX_ADDRESS,TX_ADR_WIDTH);
  149.         
  150.         SPI_RW_Reg(WRITE_REG + EN_AA,0X01);     //Enable Auto.ACK:Pipe0
  151.         SPI_RW_Reg(WRITE_REG + EN_RXADDR,0X01); //Enable Pipe0
  152.         SPI_RW_Reg(WRITE_REG + RF_CH,40);       //Selsct RF channl 40
  153.         SPI_RW_Reg(WRITE_REG + RX_PW_P0,TX_PLOAD_WIDTH);
  154.         SPI_RW_Reg(WRITE_REG + RF_SETUP,0X0f);
  155.         SPI_RW_Reg(WRITE_REG + CONFIG,0X0f);   //Set PWR_UP bit ,enable CRC(2bytes)&Prim:RX.RX_DR enabled
  156.         RF24L01_CE_1;                                  //Set CE pin high to enable RX device  
  157. }

  158. /*****************************
  159. //函数名称:TX_Mode()
  160. //函数功能:设定24L01发送方式
  161. //参    数:无
  162. //返 回 值:无
  163. ******************************/
  164. void TX_Mode(void)
  165. {
  166.         RF24L01_CE_0;
  167.         SPI_Write_Buf(WRITE_REG + TX_ADDR,TX_ADDRESS,TX_ADR_WIDTH);
  168.         SPI_Write_Buf(WRITE_REG + RX_ADDR_P0,TX_ADDRESS,TX_ADR_WIDTH);
  169.         
  170.         SPI_RW_Reg(WRITE_REG + EN_AA,0X01);         //Enable Auto.Ack:Pipe0
  171.         SPI_RW_Reg(WRITE_REG + EN_RXADDR,0X01);     //Enable Pipe0
  172.         SPI_RW_Reg(WRITE_REG + SETUP_RETR,0X1a);    //500us + 80us,10 retrans
  173.         SPI_RW_Reg(WRITE_REG + RF_CH,40);           //Select RF channal 40
  174.         SPI_RW_Reg(WRITE_REG + RF_SETUP,0X0f);      //TX_PWR:0dBm,Datarate:2Mbps,LNA:HCURR
  175.         SPI_RW_Reg(WRITE_REG +CONFIG,0X0e);         //Set PWR_UP bit,enable CRC(2bytes)&Prim:TX.MAX_RT&TX_DS enabled
  176.         RF24L01_CE_1;
  177.         inerDelay_us(130);    //注意不能太小
  178. }

  179. //****************************************************************************************************/
  180. //函数:void SetRX_Mode(void)
  181. //功能:数据接收配置
  182. //****************************************************************************************************/
  183. void SetRX_Mode(void)
  184. {
  185.         RF24L01_CE_0 ;
  186.         SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);  // IRQ收发完成中断响应,16位CRC        ,主接收
  187.         RF24L01_CE_1;
  188.         inerDelay_us(130);    //注意不能太小
  189. }

  190. /*******************************************************************
  191. //函数名称:unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)
  192. //函数功能:数据读取后放入rx_buf接收缓冲区中
  193. //参    数:*rx_buf(待收数据)
  194. //返 回 值:revale (完成标志)
  195. ********************************************************************/
  196. uchar nRF24L01_RxPacket(uchar* rx_buf)
  197. {
  198.         uchar revale=0;
  199.         uchar  sta;
  200.         sta=SPI_Read(STATUS);         // 读取状态寄存其来判断数据接收状况               
  201.         if(sta&0x40)                 // 判断是否接收到数据
  202.         {
  203.                 RF24L01_CE_0 ;                                          //SPI使能
  204.                 SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH); // read receive payload from RX_FIFO buffer
  205.                 SPI_RW_Reg(FLUSH_RX,0xff);
  206.                 revale =1;                         //读取数据完成标志
  207.         }
  208.         SPI_RW_Reg(WRITE_REG+STATUS,sta);    //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志
  209.         return revale;
  210. }

  211. /*************************************************
  212. //函数名称:void nRF24L01_TxPacket(char * tx_buf)
  213. //函数功能:发送 tx_buf中数据
  214. //参    数:*tx_buf(待发数据)
  215. //返 回 值:无
  216. ***************************************************/
  217. uchar nRF24L01_TxPacket(uchar * tx_buf)
  218. {
  219.         uchar revale=0;
  220.         uchar  sta;
  221.         RF24L01_CE_0 ;                        //StandBy I模式        
  222. //        SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);   // 装载接收端地址
  223.         SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);                      // 装载数据        
  224.         //SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);                    // IRQ收发完成中断响应,16位CRC,主发送
  225.         RF24L01_CE_1;                 //置高CE,激发数据发送
  226.         while ((RF24L01_IRQ_PIN)!=0);
  227.         sta=SPI_Read(STATUS);         // 读取状态寄存其来判断数据接收状况
  228.         SPI_RW_Reg(WRITE_REG+STATUS,sta);//通过写1来清楚中断标志
  229.         SPI_RW_Reg(FLUSH_TX,0xff);
  230.         if(sta&MAX_RT)
  231.         return MAX_RT;                                                //达到最大重发次数
  232.         else if(sta&TX_DS)                  //发送完成
  233.         return TX_DS;
  234.         else
  235.         return revale;                 //其他原因发送失败
  236.         //inerDelay_us(10);
  237. }
  238. /********************************
  239. //函数名称:init_NRF24L01()
  240. //函数功能:NRF24L01初始化
  241. //参    数:无
  242. //返 回 值:无
  243. *********************************/
  244. void init_NRF24L01(void)
  245. {
  246.         //inerDelay_us(100);
  247.         NRF24L01_IO_set();
  248.         RF24L01_CE_0 ;           // chip enable
  249.         RF24L01_CSN_1;           // Spi disable
  250.         RF24L01_SCK_0;           // Spi clock line init high
  251.         SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);    // 写本地地址        
  252.         SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); // 写接收端地址
  253.         SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      //  频道0自动        ACK应答允许        
  254.         SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //  允许接收地址只有频道0,如果需要多频道可以参考Page21  
  255.         SPI_RW_Reg(WRITE_REG + RF_CH, 40);         //   设置信道工作为2.4GHZ,收发必须一致
  256.         SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为32字节
  257.         SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0f);   //设置发射速率为1MHZ,发射功率为最大值0dB
  258.         SPI_RW_Reg(WRITE_REG + CONFIG, 0x0E);     // IRQ收发完成中断响应,16位CRC        ,主接收
  259. }
  260. /********************************
  261. //函数名称:uchar NRF24L01_Check(void)
  262. //函数功能:检查NRF24L01是否连接
  263. //参    数:无
  264. //返 回 值:0连接成功;1连接失败
  265. *********************************/
  266. uchar NRF24L01_Check(void)
  267. {
  268.         uchar buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
  269.         uchar i;            
  270.         SPI_Write_Buf(WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址.        
  271.         SPI_Read_Buf(TX_ADDR,buf,5); //读出写入的地址  
  272.         for(i=0;i<5;i++)if(buf[i]!=0XA5)break;                                                                    
  273.         if(i!=5)return 1;  //检测24L01错误        
  274.         return 0;                  //检测到24L01
  275. }

在linux下编译的时候要这样:
  1. objects = test24L01.o pyinclude.o NRF24L01.o gpio_lib.o testmysql.o
  2.          start : $(objects)
  3.         gcc -lmysqlclient -o start $(objects)
  4. test24L01.o : NRF24L01.h pyinclude.h gpio_lib.h testmysql.h
  5. NRF24L01.o : NRF24L01.h pyinclude.h gpio_lib.h
  6. pyinclude.o : pyinclude.h gpio_lib.h
  7. gpio_lib.o : gpio_lib.h
  8. testmysql.o: /usr/include/mysql/mysql.h
  9. .PHONY : clean
  10. clean :
  11.         -rm start $(objects)
同时需要注意有些地方的缩进,不然会报错。makefile是非常严格的。
两个部分的威廉希尔官方网站
QQ截图20160821173113.png
QQ截图20160821173129.png
单片机的代码:
stm32.zip (356.81 KB)
(下载次数: 0, 2016-8-21 17:38 上传)

很遗憾我们现在没有能将香蕉派连接到外网,我们做好了单片机端的微信控制,我们后续有更新我们会及时发帖分享的。
整个系统的控制就涉及到了HTTP协议,喜欢的朋友们可以去了解了解GET 和POST请求,我们就是通过get和post请求来控制的,只需自己定制一套通讯协议就可实现。由于快到结贴时间了,现在也比较忙,我先结贴,之后的帖子我会给大家详细介绍如何去实现控制,当然后台是最重要的,一定要掌握一门后台语言!同时也非常感谢电子发烧友william hill官网 的活动,从这次活动中我学到了很多东西,收获很大,后续我会陆续将我的收获分享给大家。

回帖(6)

猎国倾城

2016-8-30 17:37:24
顶顶顶!
举报

曲终人散

2016-8-30 22:43:41
o(≧v≦)o~~好棒
举报

Gavin Wang

2016-8-31 08:10:23
大神能不能共享一下你的相关的代码啊文件啊 比如网页的代码
举报

电子工程师2014

2016-9-3 21:55:34
香蕉派不错啊
举报

更多回帖

发帖
×
20
完善资料,
赚取积分