一、 前言
在之前我完成了FastBond基础部分的内容,展示了桌面时钟的框图,决定使用stm32进行制作。
基础部分的活动链接:FastBond3基础部分-基于stm32的多功能桌面时钟
完成了FastBond挑战部分的内容,以下展示制作项目的原理图,pcb,等内容。
设计框图:
二、 原理图
原理图和pcb使用了立创EDA进行绘制,设计时以简单可靠为宗旨。
此项目使用了FastBond活动要求的芯片:来自STMicroelectronics的STM32F103C8T6。为了节省成本和方便维修和改造,将stm32f103c8t6以开发板的形式安装至电子钟主体电路板上。
简易电子钟的屏幕选用了i2c协议通信的1.2寸OLED屏幕,OLED使用杜邦线和电子时钟的主体电路板链接,可以安装在和电路板不在同一平面的外壳上。也可以直接安装在电路板上的直插上。
考虑到之后进行升级和功能上的拓展,还预留了几个空闲的io口用于升级改造,而引出io口时使用的排针是FastBond活动要求的制造商Molex制造的0423751855。
在完成原理图后立即进行pcb的设计。在这之前我并没有设计pcb的经验,为了完成这个项目我简单学习了如何设计简单的pcb电路板。
一、 实物制作
Pcb电路板:
焊接完成后的样子:
主要代码展示:
#include "sys.h"
#include "delay.h"
#include "BEEP.h"
#include "key.h"
#include "DS1302.h"
#include "oled.h"
#include "stdio.h"
uchar time_data[6]={0};//读取DS1302当前时间缓存矩阵
uchar bell_data[3]={0};//闹铃设置界面
uchar bell_flag=0;//闹铃功能开关
uchar bell_onoff=0;//闹铃开关
void display_year(uchar a,uchar flag)//flag为1 时,显示数据,0时对应清除屏幕
{
if(flag)
{
OLED_ShowChar(24, 0, a/10+'0');//年
OLED_ShowChar(32, 0, a%10+'0');
}
else
{
//清除年位
OLED_ClearChar(24, 0);
}
}
void display_month(uchar a,uchar flag)
{
if(flag)
{
OLED_ShowChar(56, 0, a/10+'0');//月
OLED_ShowChar(64, 0, a%10+'0');
}
else
{
//清除月位
OLED_ClearChar(56, 0);
}
}
void display_day(uchar a,uchar flag)
{
if(flag)
{
OLED_ShowChar(88, 0, a/10+'0');//日
OLED_ShowChar(96, 0, a%10+'0');
}
else
{
//清除日位
OLED_ClearChar(88, 0);
}
}
void display_hour(uchar a,uchar flag)
{
if(flag)
{
OLED_ShowChar24(16, 3, a/10+'0');//时
OLED_ShowChar24(28, 3, a%10+'0');
}
else
{
//清除时位
OLED_ClearChar24(16, 3);
}
}
void display_min(uchar a,uchar flag)
{
if(flag)
{
OLED_ShowChar24(52, 3, a/10+'0');//分
OLED_ShowChar24(64, 3, a%10+'0');
}
else
{
//清除分位
OLED_ClearChar24(52, 3);
}
}
void display_sec(uchar a,uchar flag)
{
if(flag)
{
OLED_ShowChar24(88, 3, a/10+'0');//秒
OLED_ShowChar24(100, 3, a%10+'0');
}
else
{
//清除秒位
OLED_ClearChar24(88, 3);
}
}
void display(uchar a,uchar flag,uchar shift)
{
switch(shift)
{
case 0: display_sec(a,flag); break;
case 1: display_min(a,flag); break;
case 2: display_hour(a,flag); break;
case 3: display_day(a,flag); break;
case 4: display_month(a,flag); break;
case 5: display_year(a,flag); break;
default : break;
}
}
void show_time(uchar show_data[6])//时间打印函数
{
OLED_ShowChar(24, 0, show_data[0]/10+'0');//年
OLED_ShowChar(32, 0, show_data[0]%10+'0');
OLED_ShowChar(56, 0, show_data[1]/10+'0');//月
OLED_ShowChar(64, 0, show_data[1]%10+'0');
OLED_ShowChar(88, 0, show_data[2]/10+'0');//日
OLED_ShowChar(96, 0, show_data[2]%10+'0');
OLED_ShowChar24(16, 3, show_data[3]/10+'0');//时
OLED_ShowChar24(28, 3, show_data[3]%10+'0');
OLED_ShowChar24(40, 3, ':');
OLED_ShowChar24(52, 3, show_data[4]/10+'0');//分
OLED_ShowChar24(64, 3, show_data[4]%10+'0');
OLED_ShowChar24(76, 3, ':');
OLED_ShowChar24(88, 3, show_data[5]/10+'0');//秒
OLED_ShowChar24(100, 3, show_data[5]%10+'0');
}
int main(void)
{
uchar set_run=0;//按键run状态标识符
uchar set_bell=0;//按键bell状态标识符
uchar set_shift=0;//调时位置标识符
uchar set_shift_bell=0;//bell调时位置标识符
uchar init_time[6]={21,12,31,23,59,15};//初始化时间参数
delay_init();
delay_ms(50);
BEEP_GPIO_Init();
KEY_Init(); //按键初始化
OLED_Init();
DS1302_init(init_time);
OLED_Clear();
OLED_ShowNum(8,0, 20, 2,0);
OLED_ShowCH(40,0,"年");
OLED_ShowCH(72,0,"月");
OLED_ShowCH(104,0,"日");
BEEP=0;
while(1)
{
/*按键逻辑*/
switch(KEY_Scan())
{
case 1: //按下run键
set_run=1;
//读取当前时间并显示
DS1302_Readtime();
show_time(time_data);
while(set_run)
{
//对应设置位闪烁
display(time_data[5-set_shift],0,set_shift);
delay_ms(50);
display(time_data[5-set_shift],1,set_shift);
switch(KEY_Scan())
{
case 1: DS1302_SetTime(time_data);set_run = 0; break;//第二次按下run键保存时间并退出设置
case 2: if(set_shift++>4)set_shift=0;break;//移位
case 3: break;
case 4: time_data[5-set_shift]++;break;//up
case 5: time_data[5-set_shift]--;break;//down
default : break;
}
} break;
case 2: bell_onoff=0;BEEP=0; break;//关闭闹铃
case 3: set_bell=1;//按下闹铃设置键
//读取当前设定时间并显示
display_hour(bell_data[0],1);
display_min(bell_data[1],1);
display_sec(bell_data[2],1);
while(set_bell)
{
//对应设置位闪烁
display(bell_data[2-set_shift_bell],0,set_shift_bell);
delay_ms(50);
display(bell_data[2-set_shift_bell],1,set_shift_bell);
switch(KEY_Scan())
{
case 1: bell_flag=!bell_flag;show_bell(bell_flag);
break;//开启或关闭闹钟使能
case 2: if(set_shift_bell++>1)set_shift_bell=0;break;//移动调整位置
case 3: set_bell=0;break;//退出时间设置
case 4: bell_data[2-set_shift_bell]++;break;//up
case 5: bell_data[2-set_shift_bell]--;break;//down
default : break;
}
} break;
case 4: break;
case 5: break;
default : break;
};
DS1302_Readtime();
show_time(time_data);
if(bell_data[0]==time_data[3] && bell_data[1]==time_data[4] && bell_data[2]==time_data[5])//触发闹铃
{
bell_onoff=1;
}
if(bell_flag && bell_onoff)
{
BEEP=!BEEP;
}
}
}
小插曲:导致OLED屏幕的scl端口没有正确连接到对应的io口,幸好之前为了升级改造预留的io口,可以通过飞线解决这个问题
进行初始化设置后观察到时钟正常走动
二、 活动总结
非常感谢硬禾学堂举办的FastBond2活动,这是我人生中第一个电子小制作,但我相信他一定不会是最后一个。我平时虽然一直对电子技术感兴趣,但是一直没有动力自己去做些什么,这次Fast活动让我有机会和动力去琢磨和学习一些课堂上无法学到的知识和经验,让我受益良多。我想我今后也会继续做些什么,哪怕做不成什么特别有用的东西,但有时候我总想创造些什么,可以让自己的生活更有乐趣。