一、系統(tǒng)方案 1、本設(shè)計(jì)采用STM32單片機(jī)作為主控器。 2、DHT11檢測濕度,液晶OLED顯示,聲音檢測聲音,有聲音或尿床,蜂鳴器報(bào)警。 3、手機(jī)APP可以控制音樂播放。
1.jpg (4.72 KB, 下載次數(shù): 35)
下載附件
2023-11-16 19:30 上傳
二、硬件設(shè)計(jì) 原理圖如下:
2.jpg (110.33 KB, 下載次數(shù): 23)
下載附件
2023-11-16 19:30 上傳
三、單片機(jī)軟件設(shè)計(jì) 1、首先是系統(tǒng)初始化 void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PA,PD端口時(shí)鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //LED0-->PA.8 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根據(jù)設(shè)定參數(shù)初始化GPIOA.8 GPIO_SetBits(GPIOB,GPIO_Pin_2); //PA.8 輸出高
}
2、液晶顯示程序 /************************************************************************************ * Copyright (c), 2014, HelTec Automatic Technology co.,LTD. * All rights reserved. *
* * File name: OLED_I2C.c * Project : HelTec.uvprij * Processor: STM32F103C8T6 * Compiler : MDK fo ARM * * Author : 小林 * Version: 1.00 * Date : 2014.4.8 * Modification: none * * Description:128*64點(diǎn)陣的OLED顯示屏驅(qū)動(dòng)文件,僅適用于惠特自動(dòng)化的SD1306驅(qū)動(dòng)IIC通信方式顯示屏 * * Others: none; * * Function List: * 1. void I2C_Configuration(void) -- 配置CPU的硬件I2C * 2. void I2C_WriteByte(uint8_t addr,uint8_t data) -- 向寄存器地址寫一個(gè)byte的數(shù)據(jù) * 3. void WriteCmd(unsigned char I2C_Command) -- 寫命令 * 4. void WriteDat(unsigned char I2C_Data) -- 寫數(shù)據(jù) * 5. void OLED_Init(void) -- OLED屏初始化 * 6. void OLED_SetPos(unsigned char x, unsigned char y) -- 設(shè)置起始點(diǎn)坐標(biāo) * 7. void OLED_Fill(unsigned char fill_Data) -- 全屏填充 * 8. void OLED_CLS(void) -- 清屏 * 9. void OLED_ON(void) -- 喚醒 * 10. void OLED_OFF(void) -- 睡眠 * 11. void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) -- 顯示字符串(字體大小有6*8和8*16兩種) * 12. void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) -- 顯示中文(中文需要先取模,然后放到codetab.h中) * 13. void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]) -- BMP圖片 * * History: none; * *************************************************************************************/
#include "OLED_I2C.h" #include "delay.h" #include "codetab.h"
void I2C_Configuration(void) { I2C_InitTypeDef I2C_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
/*STM32F103C8T6芯片的硬件I2C: PB6 -- SCL; PB7 -- SDA */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//I2C必須開漏輸出 GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);//使用I2C1 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x30;//主機(jī)的I2C地址,隨便寫的 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 400000;//400K
I2C_Cmd(I2C1, ENABLE); I2C_Init(I2C1, &I2C_InitStructure); }
void I2C_WriteByte(uint8_t addr,uint8_t data) { while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1, ENABLE);//開啟I2C1 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默認(rèn)0x78 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, addr);//寄存器地址 while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1, data);//發(fā)送數(shù)據(jù) while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1, ENABLE);//關(guān)閉I2C1總線 }
void WriteCmd(unsigned char I2C_Command)//寫命令 { I2C_WriteByte(0x00, I2C_Command); }
void WriteDat(unsigned char I2C_Data)//寫數(shù)據(jù) { I2C_WriteByte(0x40, I2C_Data); }
void OLED_Init(void) { delay_ms(100); //這里的延時(shí)很重要
WriteCmd(0xAE); //display off WriteCmd(0x20); //Set Memory Addressing Mode WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7 WriteCmd(0xc8); //Set COM Output Scan Direction WriteCmd(0x00); //---set low column address WriteCmd(0x10); //---set high column address WriteCmd(0x40); //--set start line address WriteCmd(0x81); //--set contrast control register WriteCmd(0xff); //亮度調(diào)節(jié) 0x00~0xff WriteCmd(0xa1); //--set segment re-map 0 to 127 WriteCmd(0xa6); //--set normal display WriteCmd(0xa8); //--set multiplex ratio(1 to 64) WriteCmd(0x3F); // WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content WriteCmd(0xd3); //-set display offset WriteCmd(0x00); //-not offset WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency WriteCmd(0xf0); //--set divide ratio WriteCmd(0xd9); //--set pre-charge period WriteCmd(0x22); // WriteCmd(0xda); //--set com pins hardware configuration WriteCmd(0x12); WriteCmd(0xdb); //--set vcomh WriteCmd(0x20); //0x20,0.77xVcc WriteCmd(0x8d); //--set DC-DC enable WriteCmd(0x14); // WriteCmd(0xaf); //--turn on oled panel }
void OLED_SetPos(unsigned char x, unsigned char y) //設(shè)置起始點(diǎn)坐標(biāo) { WriteCmd(0xb0+y); WriteCmd(((x&0xf0)>>4)|0x10); WriteCmd((x&0x0f)|0x01); }
void OLED_Fill(unsigned char fill_Data)//全屏填充 { unsigned char m,n; for(m=0;m<8;m++) { WriteCmd(0xb0+m); //page0-page1 WriteCmd(0x00); //low column start address WriteCmd(0x10); //high column start address for(n=0;n<128;n++) { WriteDat(fill_Data); } } }
void OLED_CLS(void)//清屏 { OLED_Fill(0x00); }
//-------------------------------------------------------------- // Prototype : void OLED_ON(void) // Calls : // Parameters : none // Description : 將OLED從休眠中喚醒 //-------------------------------------------------------------- void OLED_ON(void) { WriteCmd(0X8D); //設(shè)置電荷泵 WriteCmd(0X14); //開啟電荷泵 WriteCmd(0XAF); //OLED喚醒 }
//-------------------------------------------------------------- // Prototype : void OLED_OFF(void) // Calls : // Parameters : none // Description : 讓OLED休眠 -- 休眠模式下,OLED功耗不到10uA //-------------------------------------------------------------- void OLED_OFF(void) { WriteCmd(0X8D); //設(shè)置電荷泵 WriteCmd(0X10); //關(guān)閉電荷泵 WriteCmd(0XAE); //OLED休眠 }
//-------------------------------------------------------------- // Prototype : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) // Calls : // Parameters : x,y -- 起始點(diǎn)坐標(biāo)(x:0~127, y:0~7); ch[] -- 要顯示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16) // Description : 顯示codetab.h中的ASCII字符,有6*8和8*16可選擇 //-------------------------------------------------------------- void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) { unsigned char c = 0,i = 0,j = 0; switch(TextSize) { case 1: { while(ch[j] != '\0') { c = ch[j] - 32; if(x > 126) { x = 0; y++; } OLED_SetPos(x,y); for(i=0;i<6;i++) WriteDat(F6x8[c][ i]); x += 6;
j++;
}
}break;
case 2:
{
while(ch[j] != '\0')
{
c = ch[j] - 32;
if(x > 120)
{
x = 0;
y++;
}
OLED_SetPos(x,y);
for(i=0;i<8;i++)
WriteDat(F8X16[c*16+i]);
OLED_SetPos(x,y+1);
for(i=0;i<8;i++)
WriteDat(F8X16[c*16+i+8]);
x += 8;
j++;
}
}break;
}
}
//--------------------------------------------------------------
// Prototype : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
// Calls :
// Parameters : x,y -- 起始點(diǎn)坐標(biāo)(x:0~127, y:0~7); N:漢字在codetab.h中的索引
// Description : 顯示codetab.h中的漢字,16*16點(diǎn)陣
//--------------------------------------------------------------
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
unsigned char wm=0;
unsigned int adder=32*N;
OLED_SetPos(x , y);
for(wm = 0;wm < 16;wm++)
{
WriteDat(F16x16[adder]);
adder += 1;
}
OLED_SetPos(x,y + 1);
for(wm = 0;wm < 16;wm++)
{
WriteDat(F16x16[adder]);
adder += 1;
}
}
//--------------------------------------------------------------
// Prototype : void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
// Calls :
// Parameters : x0,y0 -- 起始點(diǎn)坐標(biāo)(x0:0~127, y0:0~7); x1,y1 -- 起點(diǎn)對角線(結(jié)束點(diǎn))的坐標(biāo)(x1:1~128,y1:1~8)
// Description : 顯示BMP位圖
//--------------------------------------------------------------
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
unsigned int j=0;
unsigned char x,y;
if(y1%8==0)
y = y1/8;
else
y = y1/8 + 1;
for(y=y0;y<y1;y++)
{
OLED_SetPos(x0,y);
for(x=x0;x<x1;x++)
{
WriteDat(BMP[j++]);
}
}
}
3、按鍵程序
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA,PORTC時(shí)鐘
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//關(guān)閉jtag,使能SWD,可以用SWD模式調(diào)試
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//PA15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //設(shè)置成上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA15
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//PC5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //設(shè)置成上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOC5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0設(shè)置成輸入,默認(rèn)下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0
}
//按鍵處理函數(shù)
//返回按鍵值
//mode:0,不支持連續(xù)按;1,支持連續(xù)按;
//返回值:
//0,沒有任何按鍵按下
//KEY0_PRES,KEY0按下
//KEY1_PRES,KEY1按下
//WKUP_PRES,WK_UP按下
//注意此函數(shù)有響應(yīng)優(yōu)先級,KEY0>KEY1>WK_UP!!
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按鍵按松開標(biāo)志
if(mode)key_up=1; //支持連按
if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
{
delay_ms(10);//去抖動(dòng)
key_up=0;
if(KEY0==0)return KEY0_PRES;
else if(KEY1==0)return KEY1_PRES;
else if(WK_UP==1)return WKUP_PRES;
}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;
return 0;// 無按鍵按下
}
4、核心算法程序
int main(void)
{
u8 t=0,num=0,cnt;
u8 temperature;
u8 humidity;
u8 hh=60;
delay_init(); //延時(shí)函數(shù)初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設(shè)置NVIC中斷分組2:2位搶占優(yōu)先級,2位響應(yīng)優(yōu)先級
uart_init(9600); //串口初始化為9600
I2C_Configuration();
OLED_Init();
KEY_Init(); //初始化與按鍵連接的硬件接口
OLED_Fill(0xFF);//全屏點(diǎn)亮
delay_ms(2);
OLED_Fill(0x00);//全屏滅
delay_ms(2);
while(DHT11_Init()) //DHT11初始化
{
}
LED_Init();
HW_Init();
while(1){
if(Res=='1')
{
LED0=0;
}
if(Res=='2')
{
LED0=1;
}
num=KEY_Scan(0); //得到鍵值
switch(num)
{
case KEY0_PRES:
if(hh>=1) hh--;
break;
break;
case KEY1_PRES:
case WKUP_PRES:
hh++;
if(hh>100) hh=99;
break;
}
OLED_ShowStr(0,0,"TEMP:",2); //測試8*16字符
OLED_ShowStr(0,2,"HUMI:",2); //測試8*16字符
OLED_ShowStr(0,4,"Alar:",2); //測試8*16字符
if(hw==0)
{
OLED_ShowStr(80,4,"sound",2); //測試8*16字符
printf("sound\n");
}
else
{
OLED_ShowStr(80,4," ",2); //測試8*16字符
}
if(humidity>=hh)
{
OLED_ShowStr(0,6,"bed-wetting",2); //測試8*16字符
printf("bed-wetting\n");
}
else
OLED_ShowStr(0,6," ",2); //測試8*16字符
delay_ms(2);
if(t%5==0)//每100ms讀取一次
{
DHT11_Read_Data(&temperature,&humidity); //讀取溫濕度值
display(40,0,temperature/10);
display(48,0,temperature%10);
display(40,2,humidity/10);
display(48,2,humidity%10);
display(40,4,hh/10);
display(48,4,hh%10);
printf("TEMP:%d\n",temperature);
printf("HUMI:%d\n",humidity);
//LCD_ShowNum(60+40,150,temperature,2,16); //顯示溫度
//LCD_ShowNum(60+40,170,humidity,2,16); //顯示濕度
}
delay_ms(10);
t++;
if(t==10)
{
t=0;
}
//printf("t:%d\n",t);
//delay_ms(500);
//t++;
}
}
四、 proteus仿真設(shè)計(jì) Proteus軟件是一款應(yīng)用比較廣泛的工具,它可以在沒有硬件平臺的基礎(chǔ)上通過自身的軟件仿真出硬件平臺的運(yùn)行情況,這樣就可以通過軟件仿真來驗(yàn)證我們設(shè)計(jì)的方案有沒有問題,如果有問題,可以重新選擇器件,連接器件,直到達(dá)到我們設(shè)定的目的,避免我們搭建實(shí)物的時(shí)候,如果當(dāng)初選擇的方案有問題,我們器件都已經(jīng)焊接好了,再去卸載下去,再去焊接新的方案的器件,測試,這樣會浪費(fèi)人力和物力,也給開發(fā)者帶來一定困惑,Proteus仿真軟件就很好的解決這個(gè)問題,我們在設(shè)計(jì)之初,就使用該軟件進(jìn)行模擬仿真,測試,選擇滿足我們設(shè)計(jì)的最優(yōu)方案。最后根據(jù)測試沒問題的仿真圖紙,焊接實(shí)物,調(diào)試,最終完成本設(shè)計(jì)的作品。
|