电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
STM32多功能时钟,附源代码
分 享
扫描二维码分享
STM32多功能时钟,附源代码
STM32
时钟
哈里波菜
关注
发布时间: 2020-02-20
丨
阅读: 2442
##一功能概述 今天,我们来介绍一个有趣的STM32时钟项目,利用 DHT12、DS1302、OLED屏、按键,实现一个既有界面显示 温湿度、时间、还有秒表功能,同时还有一个ISD1820模块,可以用于闹钟时间到达时,播放提前录好的铃声,还可以通过串口发送时间到串口助手。 ## 二 各个功能模块简介 ###2.1 DHT11 概述:DHT11 是广州奥松有限公司生产的一款湿温度一体化的数字传感器。 该传感器包括一个电阻式测湿元件和一个 NTC 测温元件,并与一个高性能 8 位 单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集本地湿 度和温度。DHT11 与单片机之间能采用简单的单总线进行通信,仅仅需要一个 I/O 口。传感器内部湿度和温度数据 40Bit 的数据一次性传给单片机,数据采用 校验和方式进行校验,有效的保证数据传输的准确性。DHT11 功耗很低,5V 电 源电压下,工作平均最大电流 0.5mA。 性能指标和特性如下: 1 工作电压范围:3.5V-5.5V 2 工作电流 :平均 0.5mA 3 湿度测量范围:20-90%RH 4 温度测量范围:0-50℃ 5 湿度分辨率 :1%RH 8位 6 温度分辨率 :1℃ 8 位 7 采样周期 :1S 8 单总线结构 9 与 TTL 兼容(5V) 管脚排列如下: ![](https://cf01.ickimg.com/bbsimages/202002/7c54a2856902f027a67a17fa14d46082.jpg) ####DHT11开始发送数据流程 ![](https://cf01.ickimg.com/bbsimages/202002/6ae4017fb992ea9ffa43a8806d761852.jpg) 主机发送开始信号后,延时等待 20us-40us 后读取 DHT11 的回应信号,读取 总线为低电平,说明 DHT11 发送响应信号,DHT11 发送响应信号后,再把总线拉 高,准备发送数据,每一 bit 数据都以低电平开始,格式见下面图示。如果读取响应 信号为高电平,则 DHT11 没有响应,请检查线路是否连接正常。 ####主机复位信号和 DHT11 响应信号 ![](https://cf01.ickimg.com/bbsimages/202002/c49372c7aaa5ad6467337f760bb78a0d.jpg) #### 数字‘0’信号表示方法 ![](https://cf01.ickimg.com/bbsimages/202002/635a837c35c2644b297155e53f709faf.jpg) #### 数字‘1’信号表示方法 ![](https://cf01.ickimg.com/bbsimages/202002/67e0144f4a464d31d8c761d4ca0584c9.jpg) ###2.2 DS1302 时钟芯片 DS1302是一个实时时钟芯片,可以提供秒、分、小时、日期、月、年等信息,并且还有软件自动调整的能力,可以通过配置AM/PM来决定采用24小时格式还是12小时格式。拥有31字节数据存储RAM。串行I/O通信方式,相对并行来说比较节省IO口的使用。DS1302的工作电压比较宽,在2.0~5.5V的范围内都可以正常工作。 ![](https://cf01.ickimg.com/bbsimages/202002/0dc94120a1576ba3510ebd962e9517a4.jpg) ![](https://cf01.ickimg.com/bbsimages/202002/8700aad55d3d9ec9cbe391f0dbe60ecf.jpg) ![](https://cf01.ickimg.com/bbsimages/202002/f77591bc28c58ec6bc023a3938c28808.jpg) ![](https://cf01.ickimg.com/bbsimages/202002/1086ba557f9ab1fd5568f9ff23e1d1ef.jpg) ####2.2.1 DS1302初始化 //DS1302初始化函数 void DS1302_Init() { /@@*1.GPIOC时钟*/ RCC->APB2ENR |= 1<<2; /@@*2. 配置GPIOA_5/6/7模式*/ GPIOA->CRL &= 0X000FFFFF; GPIOA->CRL |= 0X33300000; GPIOA->ODR |=1<<6; //printf("DS1302_Init OK!\n"); } ####2.2.2 DS1302读一个字节函数 ```c //从DS1302读出一字节数据 u8 DS1302_ReadByte(u8 addr) { u8 i,temp; DS1302_RST=0; //这条很重要 DS1302_CLK=0; //先将SCLK置低电平,确保写数居前SCLK被拉低 DS1302_RST=1; //启动DS1302总线 DS1302_OutPut_Mode(); //写入目标地址:addr addr=addr|0x01; //最低位置高,寄存器0位为0时写,为1时读 for(i=0;i<8;i++) { if (addr&0x01) DS1302_OUT=1; else DS1302_OUT=0; DS1302_CLK=1; //写数据 DS1302_CLK=0; addr = addr >> 1; } //从DS1302读出数据:temp DS1302_InPut_Mode(); for(i=0;i<8;i++) { temp=temp>>1; if (DS1302_IN) temp|=0x80; else temp&=0x7F; DS1302_CLK=1; DS1302_CLK=0; } DS1302_CLK=1; //将时钟电平置于已知状态 DS1302_RST=0; //停止DS1302总线 return temp; } ``` ####2.2.3 DS1302写一个字节函数 ```c //向DS1302写入一字节数据 void DS1302_WriteByte(u8 addr,u8 data) { u8 i; DS1302_RST=0; //禁止数据传输 !!!这条很重要 DS1302_CLK=0; //确保写数据前SCLK为低电平 DS1302_RST=1; //启动DS1302总线 DS1302_OutPut_Mode(); addr=addr&0xFE; //最低位置零,寄存器0位为0时写,为1时读 for(i=0;i<8;i++) //写入目标地址:addr { if (addr&0x01) DS1302_OUT=1; else DS1302_OUT=0; DS1302_CLK=1; //时钟上升沿写入数据 DS1302_CLK=0; addr=addr>>1; } for (i=0;i<8;i++) //写入数据:data { if(data&0x01) DS1302_OUT=1; else DS1302_OUT=0; DS1302_CLK=1; //时钟上升沿写入数据 DS1302_CLK=0; data = data >> 1; } DS1302_CLK=1; // 将时钟电平置于高电平状态 ,处于已知状态 DS1302_RST=0; //停止DS1302总线 } ``` ####2.2.4 DS1302读写时间 ```c //向DS1302写入时钟数据,用于时间校准修改 void DS1302_WriteTime() { DS1302_WriteByte(DS1302_CONTROL_ADDR,0x00); //关闭写保护 DS1302_WriteByte(DS1302_SEC_ADDR,0x80); //暂停时钟 //DS1302_WriteByte(DS1302_CHARGER_ADDR,0xa9); //涓流充电 DS1302_WriteByte(DS1302_YEAR_ADDR,time_buf[1]); //年 DS1302_WriteByte(DS1302_MONTH_ADDR,time_buf[2]); //月 DS1302_WriteByte(DS1302_DAY_ADDR,time_buf[3]); //日 DS1302_WriteByte(DS1302_HOUR_ADDR,time_buf[4]); //时 DS1302_WriteByte(DS1302_MIN_ADDR,time_buf[5]); //分 DS1302_WriteByte(DS1302_SEC_ADDR,time_buf[6]); //秒 DS1302_WriteByte(DS1302_WEEK_ADDR,time_buf[7]); //周 DS1302_WriteByte(DS1302_CHARGER_ADDR,0xA5);//打开充电功能 选择2K电阻充电方式 DS1302_WriteByte(DS1302_CONTROL_ADDR,0x80);//打开写保护 } //从DS1302读出时钟数据 void DS1302_ReadTime(void) { time_buf[1]=DS1302_ReadByte(DS1302_YEAR_ADDR); //年 time_buf[2]=DS1302_ReadByte(DS1302_MONTH_ADDR); //月 time_buf[3]=DS1302_ReadByte(DS1302_DAY_ADDR); //日 time_buf[4]=DS1302_ReadByte(DS1302_HOUR_ADDR); //时 time_buf[5]=DS1302_ReadByte(DS1302_MIN_ADDR); //分 time_buf[6]=(DS1302_ReadByte(DS1302_SEC_ADDR))&0x7f; //秒,屏蔽秒的第7位,避免超出59 time_buf[7]=DS1302_ReadByte(DS1302_WEEK_ADDR); //周 } ``` ####2.2.5 DS1302获取时间 ```c //主函数 void DS1302_GetTime() { DS1302_ReadTime(); //读取时间 TimeData.year=(time_buf[0]>>4)*1000+(time_buf[0]&0x0F)*100+(time_buf[1]>>4)*10+(time_buf[1]&0x0F); //计算年份 TimeData.month=(time_buf[2]>>4)*10+(time_buf[2]&0x0F); //计算月份 TimeData.day=(time_buf[3]>>4)*10+(time_buf[3]&0x0F); //计算日期 TimeData.hour=(time_buf[4]>>4)*10+(time_buf[4]&0x0F); //计算小时 TimeData.minute=(time_buf[5]>>4)*10+(time_buf[5]&0x0F); //计算分钟 TimeData.second=(time_buf[6]>>4)*10+(time_buf[6]&0x0F); //计算秒钟 TimeData.week=(time_buf[7]&0x0F); //计算星期 //printf("时间:%d-%d-%d %d:%d:%d %d \n",TimeData.year,TimeData.month,TimeData.day,TimeData.hour,TimeData.minute,TimeData.second,TimeData.week); } ``` 通过以上步骤我们就可以完成对 DS1302的驱动,并获取我们想要显示的时间。下面展示一下我完成的成果吧。 ![](https://cf01.ickimg.com/bbsimages/202002/417f8ca173a0b2547bec5f5ed9062163.jpg) ![](https://cf01.ickimg.com/bbsimages/202002/14a86f3d48bd37e7934dd4e63fa63f3d.jpg) 好了以上就是项目完成之后的成果。以下附上本次项目的代码,有需要的可以自行提取: 链接:https://pan.baidu.com/s/1csFa_Xq5--xbVUq4obnpNA 提取码:k5cm 复制这段内容后打开百度网盘手机App,操作更方便哦
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
哈里波菜
关注
评论
(1)
登录后可评论,请
登录
或
注册
哈里波菜
64
天前...
有问题可以咨询1812669090
0
回复
发布
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交