51单片机语音播报模块:
以8位STC89C52单片机为控制核心,利用DHT11、GY-30、MQ-2传感器实时采集温湿度、光照强度、气体浓度等环境参数,用户可以通过LCD1602液晶查看当前环境参数数据。NY3P035芯片控制语音播报,加入蓝牙通信接口电路,手机连接蓝牙模块,下位机和上位机进行通信,手机蓝牙串口界面可以接收当前的环境数据,手机发命令给单片机,可控制语音的播报。
实物图:
单片机源程序如下:
- #include <reg51.h>
- #include <intrins.h>
- #include <uart.h>
- #define uchar unsigned char
- #define uint unsigned int
- uchar write_add[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80}; //数据的地址
- uchar read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};
- uchar code table3[]=" "; //清屏内容
- sbit rs=P1^0; //LCD1602
- sbit rw=P1^1; //LCD1602
- sbit e=P2^5; //LCD1602
- sbit SCL=P1^5; //IIC时钟引脚定义 //BH1750fvi光照强度传感器
- sbit SDA=P1^6; //IIC数据引脚定义
- sbit cs=P3^6; //TLC2543
- sbit clk=P2^7;
- sbit sdi=P2^6;
- sbit sdo=P2^4;
- sbit flag=P3^4;
- sbit bit7=B^7;
- sbit Data =P1^3; //DHT11
- int temperature; //全局变量 温度
- int Count; //T0中断次数
- sbit KEY1=P3^5; //播放语音
- //sbit KEY2=P3^6; //暂停
- sbit BUSY=P2^0; //语音芯片
- sbit DATA=P2^1; //语音芯片
- sbit RST=P2^2; //语音芯片
- void delay_ms( uint ms);
- void delay1();
- void ADC_read( uint ch);
- void volt_result();
- void disp_volt(uint value);
- uchar y;
- uchar first,second,third,forth;
- bit date;
- uint adval=0;
- uint volt=0;
- uchar temppp=0;
- uchar flag_table[3]={0};
- uchar flagx;
- bit SetFlag=0; //更新时间标志位
- uchar shi,ge;
- uchar temp,tempp; //八个bit数据位的变量
- uchar comdata; //总线接收到的数据
- uchar T_data_H_temp,T_data_L_temp,RH_data_H_temp,RH_data_L_temp,checkdata_temp,temp_data;
- uchar T_data_H,T_data_L,RH_data_H,RH_data_L,checkdata;
- void music(uchar k);
- uchar uart_wendu_shi,uart_wendu_ge,uart_shidu_shi,uart_shidu_ge;
- uchar uart_sun_shi,uart_sun_ge;
- #define SlaveAddress 0x46 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改
- //ALT ADDRESS引脚接地时地址为0x46,接电源时地址为0xB8
- typedef unsigned char BYTE;
- typedef unsigned short WORD;
- BYTE BUF[8]; //接收数据缓存区
- uchar gee,shii,bai,qian,wan; //显示变量
- int dis_data;
- void delay_nms(unsigned int k);
- void Init_BH1750(void);
- void WriteDataLCM(uchar dataW);
- void WriteCommandLCM(uchar CMD,uchar Attribc);
- void DisplayOneChar(uchar X,uchar Y,uchar DData);
- void conversion(uint temp_data);
- void Single_Write_BH1750(uchar REG_Address); //单个写入数据
- uchar Single_Read_BH1750(uchar REG_Address); //单个读取内部寄存器数据
- void Multiple_Read_BH1750(); //连续的读取内部寄存器数据
- //------------------------------------
- void Delay5us();
- void Delay5ms();
- void BH1750_Start(); //起始信号
- void BH1750_Stop(); //停止信号
- void BH1750_SendACK(bit ack); //应答ACK
- bit BH1750_RecvACK(); //读ack
- void BH1750_SendByte(BYTE dat); //IIC单个字节写
- BYTE BH1750_RecvByte(); //IIC单个字节读
- /*********************************************************************************************************************/
- void delay1(uint z) //延时1ms函数
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=80;y>0;y--);
- }
- /***********************************
- 延时 BH1750
- ************************************/
- /**************************************
- 延时5微秒(STC90C52RC@12M)
- 不同的工作环境,需要调整此函数,注意时钟过快时需要修改
- 当改用1T的MCU时,请调整此延时函数
- **************************************/
- void Delay5us()
- {
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- }
- /**************************************
- 延时5毫秒(STC90C52RC@12M)
- 不同的工作环境,需要调整此函数
- 当改用1T的MCU时,请调整此延时函数
- **************************************/
- void Delay5ms()
- {
- WORD n = 560;
- while (n--);
- }
- //毫秒延时**************************
- void delay_nms(unsigned int k)
- {
- unsigned int i,j;
- for(i=0;i<k;i++)
- {
- for(j=0;j<121;j++)
- {;}}
- }
- /*******************************/
- void write_com(uchar com) //写指令函数
- {
- rw=0;
- delay1(5);
- rs=0;
- delay1(5);
- e=1;
- delay1(5);
- P0=com;
- delay1(5);
- e=0;
- delay1(5);
- }
- void write_date(uchar date) //写数据函数
- {
- rw=0;
- delay1(5);
- rs=1;
- delay1(5);
- e=1;
- delay1(5);
- P0=date;
- delay1(5);
- e=0;
- delay1(5);
- }
- void LCDinit() //初始化函数
- {
- uchar num;
- e=0; // 时序表e初始为0
- write_com(0x38); //设置16*2显示,5*7点阵,8位数据接口
- write_com(0x0c); //设置光标
- write_com(0x06); //光标自动加1,光标输入方式
- write_com(0x01); //清屏
- write_com(0x80); //设置初始显示位置
- for(num=0;num<16;num++)
- {
- // write_date(table1[num]);
- delay1(5);
- }
- write_com(0x80+0x40);
- for(num=0;num<16;num++)
- {
- // write_date(table2[num]);
- delay1(5);
- }
- }
- void SetTime_dispaly(uchar add,uchar dat) //第一个:参数的地址,第二个:参数的内容
- {
- shi=dat/10; //把温度的十位提取出来
- ge=dat%10; //把温度的个位提取出来
- write_com(add); //要写的地址
- write_date(0x30+shi); //十位的内容 1602字符库
- write_date(0x30+ge); //个位的内容 1602字符库
- }
- void Date_dispaly(uchar add,uchar dat) //第一个:参数的地址,第二个:参数的内容
- {
- // uchar shi,ge;
- shi=dat/16; //把温度的十位提取出来
- ge=dat%16; //把温度的个位提取出来
- write_com(add); //要写的地址
- write_date(0x30+shi); //十位的内容 1602字符库
- write_date(0x30+ge); //个位的内容 1602字符库
-
- }
- void LCD_Clean(uchar i) //液晶屏清除显示
- {
- uchar num;
- if(i==1)
- {
- write_com(0x80); //设置初始显示位置
- for(num=0;num<16;num++) //显示第一行内容
- {
- write_date(table3[num]);
- delay1(1);
- }
- }
- if(i==2)
- {
- write_com(0x80+0x40);
- for(num=0;num<16;num++) //显示第二行内容
- {
- write_date(table3[num]);
- delay1(1);
- }
- }
- }
- void LCD_Display_String(unsigned char line,unsigned char *string)
- { //液晶屏显示内容,把要显示的内容写到对应的位置
- unsigned char i;
- unsigned char address=0;
- if(line==1)
- {
- address=0x80; //0X80是第1行的第1个位置 ,0x81第2位
- }
- else if(line==2)
- {
- address=0x80+0x40; //0X80+0x40是第2行的第1个位置 ,0X80+0x40+1是第2行第2位
- }
-
- for(i=0;i<16;i++)
- {
- write_com(address);
- write_date(string[i]);
- address++;
- }
- }
- /***********************************************语音*****************************************************************/
- void music(uchar k)
- {
- RST=1;
- delay(2);
- RST=0; //发送复位脉冲,即起始信号
- delay(2);
- while(k>0) //发送K个脉冲,播放第K段内容
- {
- DATA=1;
- delay(1);
- DATA=0;
- delay(1);
- k--;
- }
- }
- void Voice(void)
- {
-
- if(KEY1==0) //按键按下,播放温湿度。
- {
- delay_nms(10);
- if(KEY1==0)
- {
- music(23); //你好
- while(!BUSY);
- delay(1000); //中间间隔约1s
- // music(24); //我是语音播报环境测试仪
- // while(!BUSY);
- // delay(500); //中间间隔约0.5s
- music(19); //播放“现在温度是
- while(!BUSY); //等待播完
- if(T_data_H/10==1) //温度大于10小于20
- {
- music(12); //播放“十”
- while(!BUSY); //等待播完
- }
- if(T_data_H/10>1) //温度大于20
- {
- music(T_data_H/10+2); //播放“高位”
- while(!BUSY); //等待播完
- music(12); //播放“十”
- while(!BUSY); //等待播完
- }
- if((T_data_H%10)!=0) //低位不等于0
- {
- music(T_data_H%10+2); //播放“低位”
- while(!BUSY); //等待播完
- }
- if(T_data_H==0) //温度等于0
- {
- music(1); //播放“低位”
- while(!BUSY); //等待播完
- }
- music(18); //播放“度”
- while(!BUSY); //等待播完
- delay(1000); //中间间隔约1s
- music(20); //播放“现在湿度是”
- while(!BUSY); //等待播完
- music(17); //播放“百分之”
- while(!BUSY); //等待播完
- if(RH_data_H/10==1) //湿度大于10小于20
- {
- music(12); //播放“十”
- while(!BUSY); //等待播完
- }
- if(RH_data_H/10>1) //湿度大于20
- {
- music(RH_data_H/10+2); //播放“高位”
- while(!BUSY); //等待播完
- music(12); //播放“十”
- while(!BUSY); //等待播完
- }
- if((RH_data_H%10)!=0) //低位不等于0
- {
- music(RH_data_H%10+2); //播放“低位”
- while(!BUSY); //等待播完
- }
- if(RH_data_H==0) //湿度等于0
- {
- music(2); //播放“低位”
- while(!BUSY); //等待播完
- }
- delay(1000); //间隔1S
- music(21); //光照强度是
- while(!BUSY);
- if(tempp/10==1) //光照强度大于10小于20
- {
- music(12); //播放“十”
- while(!BUSY); //等待播完
- }
- if(tempp/10>1) //光照强度大于20
- {
- music(tempp/10+2); //播放“高位”
- while(!BUSY); //等待播完
- music(12); //播放“十”
- while(!BUSY); //等待播完
- }
- if((tempp%10)!=0) //低位不等于0
- {
- music(tempp%10+2); //播放“低位”
- while(!BUSY); //等待播完
- }
- if(tempp==0) //光照强度等于0
- {
- music(2); //播放“低位”
- while(!BUSY); //等待播完
- }
-
- delay(1000);
- music(22);
- while(!BUSY);
- music(17);
- while(!BUSY);
- if(volt/10==1) //烟雾浓度大于10小于20
- {
- music(12); //播放“十”
- while(!BUSY); //等待播完
- }
- if(volt/10>1) //烟雾浓度大于20
- {
- music(volt/10+2); //播放“高位”
- while(!BUSY); //等待播完
- music(12); //播放“十”
- while(!BUSY); //等待播完
- }
- if((volt%10)!=0) //低位不等于0
- {
- music(volt%10+2); //播放“低位”
- while(!BUSY); //等待播完
- }
- if(volt==0) //烟雾浓度等于0
- {
- music(2); //播放“低位”
- while(!BUSY); //等待播完
- }
-
- }
- }
- }
- /*******************************温湿度DHT11*************************************************/
- void Delay_DHT(uint j)
- {
- uchar i;
- for(;j>0;j--)
- {
- for(i=0;i<27;i++);
- }
- }
- void Delay_10us(void) //使用12M晶振的时间刚好为10us
- {
- uchar i;
- i--;
- i--;
- i--;
- i--;
- i--;
- i--;
- }
- void COM(void)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- while(!Data);
- Delay_10us();
- Delay_10us();
- Delay_10us();
- Delay_10us();
- Delay_10us();
- temp=0;
- if(Data) //判断数据位是0还是1,发出低电平数据开始信号后,数据拉高,高电平的时间决定数据位为1或者0,
- temp=1; //当高电平时间小于30us时为0,大于30us且小于70us为1,大于70us则进入下一个bit
- while(Data); //等待数据接受完
- comdata<<=1; //左移一位
- comdata|=temp;//将该位赋给comdata
- }
- }
- void RH(void)
- {
- //主机拉低18ms
- Data=0;
- Delay_DHT(180);
- Data=1;
- //总线由上拉电阻拉高 主机延时20us
- Delay_10us();
- Delay_10us();
- Delay_10us();
- Delay_10us();
- //主机设为输入 判断从机响应信号
- Data=1;
- //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
- if(!Data) //T !
- {
- //判断从机是否发出 80us 的低电平响应信号是否结束
- while(!Data);
- //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
- while(Data);
- //数据接收状态
- //部分用于以后扩展 , 现读出为零 . 操作流程如下 :
- //一次完整的数据传输为 40bit, 高位先出。
- //数据格式 :8bit 湿度整数数据 +8bit 湿度小数数据
- COM(); //+8bi 温度整数数据 +8bit 温度小数数据
- RH_data_H_temp=comdata;
- COM();
- RH_data_L_temp=comdata;
- COM();
- T_data_H_temp=comdata;
- COM();
- T_data_L_temp=comdata;
- COM();
- checkdata_temp=comdata;
- Data=1; //总线拉高,进入空闲模式
-
- temp=(T_data_H_temp+T_data_L_temp+RH_data_H_temp+RH_data_L_temp);
- if(temp==checkdata_temp) //数据校验
- {
- RH_data_H=RH_data_H_temp;
- RH_data_L=RH_data_L_temp;
- T_data_H=T_data_H_temp; //温湿度的分辨率都为1,小数部分都是0
- T_data_L=T_data_L_temp;
- checkdata=checkdata_temp;
- }
- }
- }
- /*********************************************************************************************************************/
- void Timer_init(void)
- {
- TMOD=0x11; //设置定时器0为工作方式1
- TH0=(65536-50000)/256; //50MS定时
- TL0=(65536-50000)%256;
- EA=1; //开定时器T0的中断 总中断
- ET0=1; //允许T0中断
- TR0=1; //开启定时器
- }
- /************************************************************************
- 光照强度BH1750
- *************************************************************************/
-
- void SetBH1750_dispaly(uchar addd,uchar temp_data) //第一个:参数的地址,第二个:参数的内容
- {
- uchar wan,qian,bai,shii,gee;
- wan=temp_data/10000;
- temp_data=temp_data%10000;
- qian=temp_data/1000%10;
- temp_data=temp_data%1000;
- bai=temp_data/100%10;
- temp_data=temp_data%100;
- shii=temp_data/10%10;
- temp_data=temp_data%10;
- gee=temp_data/1%10;
- write_com(addd);
- write_date(0x30+wan);
- write_date(0x30+qian);
- write_date(0x30+bai);
- write_date(0x30+shii);
- write_date(0x30+gee);
-
- }
- /**************************************
- 起始信号
- **************************************/
- void BH1750_Start()
- {
- SDA = 1; //拉高数据线
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SDA = 0; //产生下降沿
- Delay5us(); //延时
- SCL = 0; //拉低时钟线
- }
- /**************************************
- 停止信号
- **************************************/
- void BH1750_Stop()
- {
- SDA = 0; //拉低数据线
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SDA = 1; //产生上升沿
- Delay5us(); //延时
- }
- /**************************************
- 发送应答信号
- 入口参数:ack (0:ACK 1:NAK)
- **************************************/
- void BH1750_SendACK(bit ack)
- {
- SDA = ack; //写应答信号
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- /**************************************
- 接收应答信号
- **************************************/
- bit BH1750_RecvACK()
- {
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- CY = SDA; //读应答信号
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- return CY;
- }
- /**************************************
- 向IIC总线发送一个字节数据
- **************************************/
- void BH1750_SendByte(BYTE dat)
- {
- BYTE i;
- for (i=0; i<8; i++) //8位计数器
- {
- dat <<= 1; //移出数据的最高位
- SDA = CY; //送数据口
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- BH1750_RecvACK();
- }
- /**************************************
- 从IIC总线接收一个字节数据
- **************************************/
- BYTE BH1750_RecvByte()
- {
- BYTE i;
- BYTE dat = 0;
- SDA = 1; //使能内部上拉,准备读取数据,
- for (i=0; i<8; i++) //8位计数器
- {
- dat <<= 1;
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- dat |= SDA; //读数据
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- return dat;
- }
- void Single_Write_BH1750(uchar REG_Address)
- {
- BH1750_Start(); //起始信号
- BH1750_SendByte(SlaveAddress); //发送设备地址+写信号
- BH1750_SendByte(REG_Address); //内部寄存器地址,
- // BH1750_SendByte(REG_data); //内部寄存器数据,
- BH1750_Stop(); //发送停止信号
- }
- //*********************************************************
- //
- //连续读出BH1750内部数据
- //
- //*********************************************************
- void Multiple_read_BH1750(void)
- { uchar i;
- BH1750_Start(); //起始信号
- BH1750_SendByte(SlaveAddress+1); //发送设备地址+读信号
-
- for (i=0; i<3; i++) //连续读取2个地址数据,存储中BUF
- {
- BUF[i] = BH1750_RecvByte(); //BUF[0]存储0x32地址中的数据
- if (i == 3)
- {
- BH1750_SendACK(1); //最后一个数据需要回NOACK
- }
- else
- {
- BH1750_SendACK(0); //回应ACK
- }
- }
- BH1750_Stop(); //停止信号
- Delay5ms(); //加延时
- }
- //初始化BH1750,根据需要请参考pdf进行修改****
- void Init_BH1750()
- {
- Single_Write_BH1750(0x01);
- }
- //2543
- void ADC_read( uint ch)
- {
- uchar i;
- sdo=1;
- clk=0;
- cs=1;
- delay_nms(1);
- cs=0;
- B=ch;
- for(i=8;i>0;i--)
- {
- date=sdo;
- sdi=bit7;
- clk=1;
- B=B<<1;
- clk=0;
- temppp=temppp<<1;
- if(date==1)
- {temppp++;}
- }
- adval=temppp;
- adval=adval<<4;
- for(i=4;i>0;i--)
- {
- date=sdo;
- temppp=temppp<<1;
- if(date==1)
- {temppp++;}
- clk=1;
- clk=0;
- }
- cs=1;
- adval=adval+temppp;
- volt=adval;
- }
- void ADC_dispaly(uchar adddd,uchar value)
- {
- first=(uchar)(value/1000);
- delay_nms(1);
- second=(uchar)(value%1000/100);
- delay_nms(1);
- third=(uchar)(value%100/10);
- delay_nms(1);
- forth=(uchar)(value%10);
- delay_nms(1);
- write_com(adddd);
- write_date(0x30+first);
- write_date(0x30+second);
- write_date(0x30+third);
- write_date(0x30+forth);
-
- if(first>4)
- {flagx=0;}
- else
- {flagx=1;}
- flag_table[0]=flag_table[1] ;
- flag_table[1]=flag_table[2] ;
- flag_table[2]=flagx ;
- }
- void main()
- {
- delay_nms(100); //延时100ms
- BUSY=0; //语音芯片
- DATA=0; //语音芯片
- RST=0;
- LCDinit(); //液晶初始化
- Init_BH1750(); //初始化BH1750
- Timer_init();
- init(); //串口初始化
-
- while(1)
- {
-
- if(Count>=10) //每0.5秒采一次温湿度,避免显示错乱,10*50ms=0.5s
- {
- RH(); //读取温湿度
- uart_wendu_shi=T_data_H/10;
- uart_wendu_ge=T_data_H%10;
- uart_shidu_shi=RH_data_H/10;
- uart_shidu_ge=RH_data_H%10;
-
-
- SetTime_dispaly(0x80+2,T_data_H); //显示温度
- SetTime_dispaly(0x80+0x40+2,RH_data_H); //显示湿度
-
-
- write_com(0x80);
- write_date(0x54); //写 T 温度
- write_com(0x80+0x40);
- write_date(0x52); //写 R 湿度
- write_com(0x80+6);
- write_date(0x53); //写 S 光照强度
- write_com(0x80+0x40+6);
- write_date(0x57); //写 W 气体烟雾
-
- write_com(0x80+4);
- write_date(0x43); //写 C
- write_com(0x80+0x40+4);
- write_date(0x25); //写 %
- write_com(0x80+13);
- write_date(0x4C); //写 L
- write_com(0x80+14);
- write_date(0x78); //写 x
- write_com(0x80+0x40+12);
- write_date(0x25); //写 %
-
- Count=0; //清零
-
-
- Single_Write_BH1750(0x01); // power on
- Single_Write_BH1750(0x10); // H- resolution mode
- delay_nms(180); //延时180ms
- Multiple_Read_BH1750(); //连续读出数据,存储在BUF中
- dis_data=BUF[0];
- dis_data=(dis_data<<8)+BUF[1]; //合成数据,即光照数据
- tempp=(float)dis_data/1.2;
-
- SetBH1750_dispaly(0x80+8,tempp);
- uart_sun_shi=tempp/10; //串口
- uart_sun_ge=tempp%10; //
-
- if(K2==0)
- {
- delay_nms(20);
- if(!K2)
- {
- while(!K2);
- send(uart_wendu_shi,uart_wendu_ge,uart_shidu_shi,uart_shidu_ge,uart_sun_shi,uart_sun_ge);
- }
- }
- ADC_read();
- volt=volt*5000/4095;
- ADC_dispaly(0x80+0x40+8,volt);
-
- y=SBUF;
- SetFlag=1;
- switch(y)
- {
- case 0x01 :KEY1=0;break;
-
- }
-
- Voice();
- }
- }
- }
- void Timer0() interrupt 1 //定时器T0中断函数
- {
- TH0=(65536-50000)/256; //赋初值=50ms
- TL0=(65536-50000)%256; //TH0=3C,TL0=B0
- Count++; //每中断一次,Count加一,计数20次,表示1s的时间到
- }
复制代码
APP:无
上位机:无
单片机程序和原理图下载(仅供参考):
51单片机语音播报.7z
(7.55 MB, 下载次数: 98)
|