完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
注:本文仅用于学习分享,分享自己DIY红外进出门提醒计数器+语音+RTC[第一次发CSDN[后期整理],若有不妥之处,请指正,感谢]
用到的工具有:
①能通过外部两个红外对管记人数并在OLED上显示 粗略计数人数 ②能通过外部两个红外对 判断人进入或出去,并发出语音提示 ag:人进门:[语音]欢迎光临;人出门:[语音]谢谢惠顾 ③语音整点报时 ④OLED上显示实时时间包括:年-月-日-星期-时-分-秒 总体设计 1.基础硬件DIY设计 2.单片机程序设计 3.效果展示 1.基础硬件DIY设计 电路硬件: [MCU]STM8S003P [外部RTC]PCF8563 [语音模块]MY2490 [屏幕]0.96寸12864 OLED 1)整体原理图 2)外部RTC[PCF8563]电路 PCF8563芯片为IIC通信,SDA[5]与SCL[6]引脚需要上拉RTC模块 多接一纽扣电池[3.0V],当整机断电时,纽扣电池为其提供电源,保证时钟还在运行。当单片机供上电时,读取数据为实时的时间,保证了断电时间还在继续运行。 3)PCB电路 4)3D_PCB
2.单片机程序设计 1)PCF8563 I2C通信程序 //pcf8563.c [PCF8563 I2C通信] #include "pbdata.h" u8 time_buf[7]; typedef struct Time //时间信息 结构体全局变量 { u8 year; u8 month; u8 week; u8 day; u8 hour; u8 minite; u8 second; }; void PCF8563_WriteByte(u8 addr,u8 dt) { I2C_Start();//启动信号 I2C_Send_Byte(PCF8563_ADDRESS); I2C_Wait_Ack(); I2C_Send_Byte((u8)(addr)); I2C_Wait_Ack(); I2C_Send_Byte(dt); I2C_Wait_Ack(); I2C_Stop(); } void PCF8563_SetTime(void)//PCF8563初始化设定初始时间 { struct Time TIME={0x18,0x10,0x06,0x21,0x21,0x53,0x30};//设置时间: 年->月->周->日->时->分->秒 //定义时间寄存器地址 PCF8563_WriteByte(0x02,TIME.second); PCF8563_WriteByte(0x03,TIME.minite); PCF8563_WriteByte(0x04,TIME.hour); PCF8563_WriteByte(0x05,TIME.day); PCF8563_WriteByte(0x06,TIME.week); PCF8563_WriteByte(0x07,TIME.month); PCF8563_WriteByte(0x08,TIME.year); } void PCF8563_GetTime(u8 *buf)//得到时间数据包 { I2C_Start(); I2C_Send_Byte(PCF8563_ADDRESS); I2C_Wait_Ack(); I2C_Send_Byte(0x02); I2C_Wait_Ack(); I2C_Start(); I2C_Send_Byte(PCF8563_ADDRESS+1);//A3 I2C_Wait_Ack(); buf[0]=I2C_Read_Byte(1); buf[1]=I2C_Read_Byte(1); buf[2]=I2C_Read_Byte(1); buf[3]=I2C_Read_Byte(1); buf[4]=I2C_Read_Byte(1); buf[5]=I2C_Read_Byte(1); buf[6]=I2C_Read_Byte(0); I2C_Stop(); buf[0]=buf[0]&0x7F;//秒 buf[1]=buf[1]&0x7F;//分 buf[2]=buf[2]&0x3F;//时 buf[3]=buf[3]&0x3F;//日 buf[4]=buf[4]&0x07;//星期 buf[5]=buf[5]&0x1F;//月 buf[0]=HexToBcd(buf[0]); //秒 buf[1]=HexToBcd(buf[1]); //分 buf[2]=HexToBcd(buf[2]); //时 buf[3]=HexToBcd(buf[3]); //日 buf[5]=HexToBcd(buf[5]); //月 buf[6]=HexToBcd(buf[6]); //年 } void PCF8563_Init(void) { PCF8563_WriteByte(0x00,0); PCF8563_WriteByte(0x01,0); //PCF8563_SetTime(); //当设定好时间,关闭初始化设定时间 } void PCF8563_ShowTime(void) { static u8 last_sec=0; //void OLED_ShowNum(u8 x,u8 y,u8 num,u8 len,u8 size2); //void OLED_ShowString(u8 x,u8 y, u8 *p); last_sec=time_buf[0]; PCF8563_GetTime(time_buf); OLED_ShowNum(0,0,20,2,16); OLED_ShowNum(16,0,time_buf[6],2,16); OLED_ShowString(32,0,"-"); OLED_ShowNum(40,0,time_buf[5],2,16); OLED_ShowString(56,0,"-"); OLED_ShowNum(64,0,time_buf[3],2,16); OLED_ShowCHinese(96,0,0);//星期 OLED_ShowCHinese(112,0,time_buf[4]+1);//2 OLED_ShowNum(48,2,time_buf[2],2,16); OLED_ShowString(64,2,":"); OLED_ShowNum(80,2,time_buf[1],2,16); if(last_sec != time_buf[sec]){//产生“:”闪烁效果 if(time_buf[sec]%2 == 0){//偶数显示“:” 奇数显示“ ” OLED_ShowString(96,2,":"); } else{OLED_ShowString(96,2," ");} } OLED_ShowNum(112,2,time_buf[0],2,16); } 2)main函数逻辑 [OLED的显示/红外对管的逻辑监测/语音模块的控制] // main.c [main函数] #include "pbdata.h" //引入自定义公共头文件 u8 Time_Remind_CMD[]={0x7E,0x05,0x41,0x00,0x01,0x45,0xEF};//整点报时 u8 IN_CMD[]={0x7E,0x05,0x41,0x00,0x19,0x5D,0xEF}; //进门声 0x19 -> 0025 u8 OUT_CMD[]={0x7E,0x05,0x41,0x00,0x1A,0x5E,0xEF};//出门声 0x20 -> 0026 u8 IO_flag = 0;//进出标志位 u8 status = 0; u8 People_num=0; BitStatus KEY1; BitStatus IrDA_OUT; BitStatus IrDA_IN; //volatile RTC_INDEX_e rtc_index; //变量rtc_index为 枚举型RTC_INDEX_e volatile表示强调修饰符,则会从内存重新装载内容,而不是直接从寄存器拷贝内容 extern u8 time_buf[]; void On_Time_Alarm(void); //准点报时 void Detection_Number_Of_People(void);//人数检测 int main(void) { Configuration_Init();//硬件配置初始化 while(1) { KEY1 = GPIO_ReadInputPin(GPIOC, GPIO_PIN_7);//播放 PCF8563_ShowTime(); On_Time_Alarm(); Detection_Number_Of_People(); } } void On_Time_Alarm(void)//准点报时 { static u8 once_flag = 0; if(time_buf[sec] ==0 && time_buf[min] == 0 ) { if(once_flag == 0) { Time_Remind_CMD[4]=time_buf[hour]+1; //时间段选号码 Time_Remind_CMD[5]=0x05^0x41^0x00^(Time_Remind_CMD[4]); //生成校验码 UART1_SendString(Time_Remind_CMD,sizeof(Time_Remind_CMD)); once_flag=1; } if(time_buf[day]==0){//午间12点人数清零 People_num=0; } } if(time_buf[min] == 1){once_flag = 0; }//只为一次发送 } void Detection_Number_Of_People(void)//人数检测 { IrDA_OUT = GPIO_ReadInputPin(GPIOA, GPIO_PIN_1);//外侧红外对管 检测到为0 IrDA_IN = GPIO_ReadInputPin(GPIOA, GPIO_PIN_2);//内侧红外对管 检测到为0 if(IO_flag == NONE){ if(IrDA_OUT == 0 && IrDA_IN != 0) { IO_flag = IN; } else if(IrDA_OUT != 0 && IrDA_IN == 0) { IO_flag = OUT; } //进出门 标志位 } if(IO_flag == IN){ if( (IrDA_OUT != 0 && IrDA_IN == 0 ) ||(IrDA_OUT == 0 && IrDA_IN == 0 )) { status = 2; } } else if(IO_flag == OUT){ if( (IrDA_OUT == 0 && IrDA_IN != 0 ) ||(IrDA_OUT == 0 && IrDA_IN == 0 )) { status = 4; } } else {status = 0;} if(status == 2){ UART1_SendString(IN_CMD,sizeof(IN_CMD)); People_num++; status=0; IO_flag=NONE; } if(status == 4){ UART1_SendString(OUT_CMD,sizeof(OUT_CMD)); if(People_num==0){People_num=0;} else{People_num--;} status=0; IO_flag=NONE; } OLED_ShowNum(96,6,People_num,2,16);//显示人数 } 2)实物电路底层图 3).防水盒内部图 4)整体效果图 防误关闭设计 屏幕旁的小孔为电源开关【用一个小棍[例如小螺丝刀]伸入即可做到开关总电源】 可玩性 预留五个调试按键,可改装为音乐播放器【已成功】 改装功能为:①可上下切歌 /②可调节音量大小/③在屏幕显示音量与当前歌名 不过音质较差需要优化音频运放电路 |
|
|
|
只有小组成员才能发言,加入小组>>
3278 浏览 9 评论
2955 浏览 16 评论
3455 浏览 1 评论
8987 浏览 16 评论
4050 浏览 18 评论
1102浏览 3评论
570浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
568浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2301浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1856浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-21 21:12 , Processed in 1.181967 second(s), Total 79, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号