基于CC2530设计的智能风扇

1. 项目介绍

随着空调降温设备的频繁使用,全球气候不断变暖空调降温设备排放出的物质对环境的影响越来越大。二是人们在熟睡之后经常因为温度太低而感冒或者温度升高而不适,风扇相比空调更加适用于老人儿童和体质较弱的人使用。
通过物联网技术的智能风扇设计可以解决因为睡熟导致降温设备依旧运行工作,实现更加节能更加智能的控制。

通过温度传感器对环境温度进行数据采集和语音控制模块来调节风速实现对风扇的智能控制,使风扇随温度变化来自动调节风力大小。

具体实现功能如下:

  1. 实现语音控制,可以识别到语音命令并自动做出相应的工作;
  2. 实现温度实时监测;
  3. 实现通过实时温度来自动控制风扇转速;
  4. 实现通电后可以进行风扇的开光和转数调节:

实现思路:

采用DHT11温湿度传感器,采集环境温度,根据设置的温度阀值与采集的环境温度做对比,控制风扇的开关,也可以通过语音识别模块检测语音完成语音控制。

实现的功能总结如下:

  1. 按下开发板上的按键控制风扇的开关(LED灯的开关)
  2. 通过语音控制风扇的开关(LED灯的开关)
    语音由语音模块进行识别。
  3. 在主函数里每500ms采集一次DHT11温度,然后通过OLED显示屏显示。

完整项目源码下载地址: https://download.csdn.net/download/xiaolong1126626497/75318366

基于CC2530设计的智能风扇

2. 硬件介绍

2.1 OLED显示屏

OLED采用0.96寸的SPI接口显示屏。分辨率是128x64.

具体接线如下: 
#define LCD_SCL  P1_2       //SCLK  时钟 D0(SCLK)
#define LCD_SDA  P1_3       //SDA   D1(MOSI) 数据
#define LCD_RST  P1_7       //_RES  hardware reset   复位 
#define LCD_DC  P0_0        //A0  H/L 命令数据选通端,H:数据,L:命令
VCC接3.3V  
GND接GND

基于CC2530设计的智能风扇

2.2 DHT11温湿度传感器

DHT11是单总线数字温湿度传感器,电压兼容3v~5v,单片机可以直接IO口连接模拟时序完成数据读取。

具体接线如下:

DATA接在P0_7口
VCC接3.3V  
GND接GND

基于CC2530设计的智能风扇

2.3 语音模块

语音模块采用LD3320芯片进行识别,可以设置内部识别的词条,支持二次开发编程。

默认内置的识别词条如下:

基于CC2530设计的智能风扇

下面是语音识别模块的实物图:

基于CC2530设计的智能风扇

基于CC2530设计的智能风扇

基于CC2530设计的智能风扇

基于CC2530设计的智能风扇

基于CC2530设计的智能风扇

基于CC2530设计的智能风扇

基于CC2530设计的智能风扇

基于CC2530设计的智能风扇

3. 案例代码

3.1 语音识别模块代码

/*******************************************************
**    CPU: STC11L08XE
**    晶振:22.1184MHZ
**    波特率:9600 bit/S
**  口令模式: 即每次识别时都需要说“小杰”这个口令 ,才能够进行下一级的识别
/*********************************************************/


#include "config.h"
/************************************************************************************/
//    nAsrStatus 用来在main主程序中表示程序运行的状态,不是LD3320芯片内部的状态寄存器
//    LD_ASR_NONE:        表示没有在作ASR识别
//    LD_ASR_RUNING:        表示LD3320正在作ASR识别中
//    LD_ASR_FOUNDOK:        表示一次识别流程结束后,有一个识别结果
//    LD_ASR_FOUNDZERO:    表示一次识别流程结束后,没有识别结果
//    LD_ASR_ERROR:        表示一次识别流程中LD3320芯片内部出现不正确的状态
/***********************************************************************************/
uint8 idata nAsrStatus = 0;
void MCU_init();
void ProcessInt0(); //识别处理函数
void delay(unsigned long uldata);
void User_handle(uint8 dat);//用户执行操作函数
void Delay200ms();
void Led_test(void);//单片机工作指示
uint8_t G0_flag = DISABLE; //运行标志,ENABLE:运行。DISABLE:禁止运行
sbit LED = P4 ^ 2; //信号指示灯

sbit SRD1 = P1 ^ 7;
sbit SRD2 = P1 ^ 6;
sbit SRD3 = P1 ^ 5;
sbit SRD4 = P1 ^ 4;


/***********************************************************
* 名    称: void  main(void)
* 功    能: 主函数    程序入口
* 入口参数:
* 出口参数:
* 说    明:
* 调用方法:
**********************************************************/
void  main(void)
{
    uint8 idata nAsrRes;
    uint8 i = 0;
    P1M0 = 0xFF;
    P1M1 = 0x00;
    SRD1 = SRD2 = SRD3 = SRD4 = 0;
    Led_test();
    MCU_init();
    LD_Reset();
    UartIni(); /*串口初始化*/
    nAsrStatus = LD_ASR_NONE;        //    初始状态:没有在作ASR
    PrintCom("<G>欢迎使用");
    while(1)
    {
        switch(nAsrStatus)
        {
        case LD_ASR_RUNING:
        case LD_ASR_ERROR:
            break;
        case LD_ASR_NONE:
        {
            nAsrStatus = LD_ASR_RUNING;
            if (RunASR() == 0)    /*    启动一次ASR识别流程:ASR初始化,ASR添加关键词语,启动ASR运算*/
            {
                nAsrStatus = LD_ASR_ERROR;
            }
            break;
        }
        case LD_ASR_FOUNDOK: /*    一次ASR识别流程结束,去取ASR识别结果*/
        {
            nAsrRes = LD_GetResult();        /*获取结果*/
            User_handle(nAsrRes);//用户执行函数
            nAsrStatus = LD_ASR_NONE;
            break;
        }
        case LD_ASR_FOUNDZERO:
        default:
        {
            nAsrStatus = LD_ASR_NONE;
            break;
        }
        }// switch
    }// while

}
/***********************************************************
* 名    称:      LED灯测试
* 功    能: 单片机是否工作指示
* 入口参数: 无
* 出口参数:无
* 说    明:
**********************************************************/
void Led_test(void)
{
    LED = ~ LED;
    Delay200ms();
    LED = ~ LED;
    Delay200ms();
    LED = ~ LED;
    Delay200ms();
    LED = ~ LED;
    Delay200ms();
    LED = ~ LED;
    Delay200ms();
    LED = ~ LED;
}
/***********************************************************
* 名    称: void MCU_init()
* 功    能: 单片机初始化
* 入口参数:
* 出口参数:
* 说    明:
* 调用方法:
**********************************************************/
void MCU_init()
{
    P0 = 0xff;
    P1 = 0x00;
    P2 = 0xff;
    P3 = 0xff;
    P4 = 0xff;


    AUXR &= 0x7F;        //定时器时钟12T模式
    TMOD |= 0x01;        //设置定时器模式
    TL0 = 0x00;        //设置定时初值
    TH0 = 0x28;        //设置定时初值
    TF0 = 0;        //清除TF0标志
    TR0 = 1;        //定时器0开始计时
    ET0 = 1;

    LD_MODE = 0;        //    设置MD管脚为低,并行模式读写
    IE0 = 1;
    EX0 = 1;
    EA = 1;
    WDT_CONTR = 0x3D;
}
/***********************************************************
* 名    称:    延时函数
* 功    能:
* 入口参数:
* 出口参数:
* 说    明:
* 调用方法:
**********************************************************/
void Delay200us()        //@22.1184MHz
{
    unsigned char i, j;
    _nop_();
    _nop_();
    i = 5;
    j = 73;
    do
    {
        while (--j);
    }
    while (--i);
}

void  delay(unsigned long uldata)
{
    unsigned int j  =  0;
    unsigned int g  =  0;
    while(uldata--)
        Delay200us();
}

void Delay200ms()        //@22.1184MHz
{
    unsigned char i, j, k;

    i = 17;
    j = 208;
    k = 27;
    do
    {
        do
        {
            while (--k);
        }
        while (--j);
    }
    while (--i);
}

/***********************************************************
* 名    称: 中断处理函数
* 功    能:
* 入口参数:
* 出口参数:
* 说    明:
* 调用方法:
**********************************************************/
void ExtInt0Handler(void) interrupt 0
{
    ProcessInt0();
}
/***********************************************************
* 名    称:用户执行函数
* 功    能:识别成功后,执行动作可在此进行修改
* 入口参数: 无
* 出口参数:无
* 说    明:
**********************************************************/
void     User_handle(uint8 dat)
{
    if(0 == dat)
    {
        G0_flag = ENABLE;
        PrintCom("<G>你好,主人");
        LED = 0;
    }
    else if(ENABLE == G0_flag)
    {
        G0_flag = DISABLE;
        LED = 1;
        switch(dat)
        {
        case CODE_1:     /*命令“开灯”*/
            SRD1 = 1;
            PrintCom("<G>灯已打开");
            break;
        case CODE_2:     /*命令“关灯”*/
            SRD1 = 0;
            PrintCom("<G>灯已关闭\r\n");
            break;
        case CODE_3:        /*命令“打开电视”*/
            SRD2 = 1;
            PrintCom("<G>电视机已打开\r\n");
            break;
        case CODE_4:        /*命令“关闭电视”*/
            SRD2 = 0;
            PrintCom("<G>电视机已关闭\r\n");
            break;
        case CODE_5:        /*命令“打开冰箱”*/
            SRD3 = 1;
            PrintCom("<G>冰箱已打开\r\n");
            break;
        case CODE_6:        /*命令“关闭冰箱”*/
            SRD3 = 0;
            PrintCom("<G>冰箱已关闭\r\n");
            break;
        case CODE_7:        /*命令“打开空调”*/
            SRD4 = 1;
            PrintCom("<G>空条已打开\r\n");
            break;
        case CODE_8:        /*命令“关闭空调”*/
            SRD4 = 0;
            PrintCom("<G>空条已关闭\r\n");
            break;
        case CODE_9:        /*命令“全部打开”*/
            SRD1 = 1;
            SRD2 = 1;
            SRD3 = 1;
            SRD4 = 1;
            PrintCom("<G>已全部打开\r\n");
            break;
        case CODE_10:        /*命令“全部关闭”*/
            SRD1 = 0;
            SRD2 = 0;
            SRD3 = 0;
            SRD4 = 0;
            PrintCom("<G>已全部关闭\r\n");
            break;
        case CODE_11:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_12:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_13:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_14:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_15:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_16:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_17:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_18:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_19:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_20:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_21:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_22:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_23:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_24:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_25:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_26:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_27:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_28:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_29:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_30:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_31:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_32:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_33:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_34:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_35:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_36:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_37:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_38:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_39:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_40:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_41:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_42:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_43:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_44:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_45:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_46:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_47:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_48:        /*命令“.....”*/

            PrintCom("");
            break;
        case CODE_49:        /*命令“.....”*/

            PrintCom("");
            break;
        default:/*text.....*/
            break;
        }
    }
    else
    {
        //PrintCom("请说出一级口令\r\n"); /*text.....*/
    }
}

void tm0_isr() interrupt 1
{
    TL0 = 0x00;        //设置定时初值
    TH0 = 0x28;        //设置定时初值
    WDT_CONTR=0x3D;
        
}

3.2 cc2530串口代码

#include "uart.h"
/*
函数功能:串口0初始化
*/
void Init_Uart0(void)
{
  PERCFG&=~(1<<0);  //串口0的引脚映射到位置1,即P0_2和P0_3
  P0SEL|=0x3<<2;   //将P0_2和P0_3端口设置成外设功能
  U0BAUD = 216;     //32MHz的系统时钟产生115200BPS的波特率
  U0GCR&=~(0x1F<<0);//清空波特率指数
  U0GCR|=11<<0;      //32MHz的系统时钟产生115200BPS的波特率
  U0UCR |= 0x80;    //禁止流控,8位数据,清除缓冲器
  U0CSR |= 0x3<<6;  //选择UART模式,使能接收器
}


/*
函数功能:UART0发送字符串函数
*/
void UR0SendString(char *str)
{
 while(*str!='\0')
  {
    U0DBUF = *str;    //将要发送的1字节数据写入U0DBUF
    while(UTX0IF == 0);//等待数据发送完成
    UTX0IF = 0;       //清除发送完成标志,准备下一次发送
    str++;
  }
}

/*
函数功能: 模仿printf风格的格式化打印功能
*/
char USART0_PRINT_BUFF[200]; //格式化数据缓存数据
void USART0_Printf(const char *format,...)
{
  char *str=NULL;
  /*1. 格式化转换*/
  va_list ap; // va_list---->char *
  va_start(ap,format); //初始化参数列表
  vsprintf(USART0_PRINT_BUFF,
        format,
        ap); //格式化打印
  va_end(ap); //结束参数获取
  /*2. 串口打印*/
  str=USART0_PRINT_BUFF;//指针赋值
  while(*str!='\0')
  {
    U0DBUF=*str; //发送一个字节的数据
    str++; //指针自增,指向下一个数据
    while(UTX0IF == 0);//等待数据发送完成
    UTX0IF = 0;       //清除发送完成标志,准备下一次发送
  }
}

3.3 OLED显示屏代码

typedef unsigned char uchar;
typedef unsigned int  uint;


#define LCD_SCL P1_2       //SCLK  时钟 D0(SCLK)
#define LCD_SDA P1_3       //SDA   D1(MOSI) 数据
#define LCD_RST P1_7       //_RES  hardware reset   复位 
#define LCD_DC  P0_0       //A0  H/L 命令数据选通端,H:数据,L:命令

#define XLevelL        0x00
#define XLevelH        0x10
#define XLevel         ((XLevelH&0x0F)*16+XLevelL)
#define Max_Column     128
#define Max_Row        64
#define Brightness     0xCF 
#define X_WIDTH        128
#define Y_WIDTH        64


void DelayMS(unsigned int msec)
{ 
    unsigned int i,j;
    
    for (i=0; i<msec; i++)
        for (j=0; j<530; j++);
}

/*********************LCD 延时1ms************************************/
void LCD_DLY_ms(unsigned int ms)
{                         
    unsigned int a;
    while(ms)
    {
        a=1800;
        while(a--);
        ms--;
    }
    return;
}
/*********************LCD写数据************************************/ 
void LCD_WrDat(unsigned char dat)     
{
    unsigned char i=8, temp=0;
    LCD_DC=1;  
    for(i=0;i<8;i++) //发送一个八位数据 
    {
        LCD_SCL=0;  
        
        temp = dat&0x80;
        if (temp == 0)
        {
            LCD_SDA = 0;
        }
        else
        {
            LCD_SDA = 1;
        }
        LCD_SCL=1;             
        dat<<=1;    
    }
}

/*********************LCD写命令************************************/                                        
void LCD_WrCmd(unsigned char cmd)
{
    unsigned char i=8, temp=0;
    LCD_DC=0;
    for(i=0;i<8;i++) //发送一个八位数据 
    { 
        LCD_SCL=0; 
       
        temp = cmd&0x80;
        if (temp == 0)
        {
            LCD_SDA = 0;
        }
        else
        {
            LCD_SDA = 1;
        }
        LCD_SCL=1;
        cmd<<=1;;        
    }     
}
/*********************LCD 设置坐标************************************/
void LCD_Set_Pos(unsigned char x, unsigned char y) 
{ 
    LCD_WrCmd(0xb0+y);
    LCD_WrCmd(((x&0xf0)>>4)|0x10);
    LCD_WrCmd((x&0x0f)|0x01); 
} 
/*********************LCD全屏************************************/
void LCD_Fill(unsigned char bmp_dat) 
{
    unsigned char y,x;
    for(y=0;y<8;y++)
    {
        LCD_WrCmd(0xb0+y);
        LCD_WrCmd(0x01);
        LCD_WrCmd(0x10);
        for(x=0;x<X_WIDTH;x++)
            LCD_WrDat(bmp_dat);
    }
}
/*********************LCD复位************************************/
void LCD_CLS(void)
{
    unsigned char y,x;    
    for(y=0;y<8;y++)
    {
        LCD_WrCmd(0xb0+y);
        LCD_WrCmd(0x01);
        LCD_WrCmd(0x10); 
        for(x=0;x<X_WIDTH;x++)
            LCD_WrDat(0);
    }
}
/*********************LCD初始化************************************/
void LCD_Init(void)     
{  
    P0SEL &= 0xFE; //让P0.0为普通IO口,
    P0DIR |= 0x01; //让P0.0为为输出

    P1SEL &= 0x73; //让 P1.2 P1.3 P1.7为普通IO口
    P1DIR |= 0x8C; //把 P1.2 P1.3 1.7设置为输出
    
    LCD_SCL=1;
    LCD_RST=0;
    LCD_DLY_ms(50);
    LCD_RST=1;      //从上电到下面开始初始化要有足够的时间,即等待RC复位完毕   
    LCD_WrCmd(0xae);//--turn off oled panel
    LCD_WrCmd(0x00);//---set low column address
    LCD_WrCmd(0x10);//---set high column address
    LCD_WrCmd(0x40);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    LCD_WrCmd(0x81);//--set contrast control register
    LCD_WrCmd(0xcf); // Set SEG Output Current Brightness
    LCD_WrCmd(0xa1);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
    LCD_WrCmd(0xc8);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
    LCD_WrCmd(0xa6);//--set normal display
    LCD_WrCmd(0xa8);//--set multiplex ratio(1 to 64)
    LCD_WrCmd(0x3f);//--1/64 duty
    LCD_WrCmd(0xd3);//-set display offset    Shift Mapping RAM Counter (0x00~0x3F)
    LCD_WrCmd(0x00);//-not offset
    LCD_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequency
    LCD_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
    LCD_WrCmd(0xd9);//--set pre-charge period
    LCD_WrCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    LCD_WrCmd(0xda);//--set com pins hardware configuration
    LCD_WrCmd(0x12);
    LCD_WrCmd(0xdb);//--set vcomh
    LCD_WrCmd(0x40);//Set VCOM Deselect Level
    LCD_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
    LCD_WrCmd(0x02);//
    LCD_WrCmd(0x8d);//--set Charge Pump enable/disable
    LCD_WrCmd(0x14);//--set(0x10) disable
    LCD_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)
    LCD_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7) 
    LCD_WrCmd(0xaf);//--turn on oled panel
    LCD_Fill(0xff);  //初始清屏
    LCD_Set_Pos(0,0);     
} 
上一篇:Android进阶之自定义View(2)高仿钉钉运动步数实现可动的进度圆环(下)


下一篇:大咖说|《商业评论》主编颜杰华:如何看待未来商业的管理趋势?