# 简单 MCU 课设开源 -- 电子钟

# 设计内容与要求

# 1.1 设计目标

选用合适的 MCU 设计一个电子钟,包含以下的功能

  1. 时间显示

  2. 模式切换

  3. 闹钟功能

  4. 按键输入

  5. 其他发挥

# 1.2 设计要求

设计方案的阐述包括以下内容

  1. 电路的原理图

  2. 元件的选用

  3. 程序的流程图 (包括主程序和子程序)

  4. 对流程图的解释说明

  5. 调试过程

那根据要求,我们大概的方案可以是使用红外接受器来作为接受端,红外遥控来输入,减少硬件上的器件,然后需要一个显示器件,一个实时时钟芯片,一个蜂鸣器,还有保留 3 个基础按键用于未来拓展,剩下就是主控电路的最小系统啥的,比较简单。现在逐个部分来看。

# 元器件选型

# 2.1 主控芯片选型

作为课设主控芯片的选型,主要考虑因素有两点:

  1. 是否课程有硬性要求,如果有就直接用就好
  2. 如果可以任选芯片,那么资料多的芯片首先选用,因为资料多说明用户多,而用户多间接反映了出货量大,也就能能保证价格想读低廉

在这个 blog 中的课程设计我们采用的是 ST 公司的 stm8 系列 MCU,具体型号是 stm8s105c6,选用这款主要是我所在大学社团当年培训用了这块开发板,然后这个开发板用来做样例测试就很方便。当然你可以选用自己熟悉的 MCU,像 51 和 STM32,MSP430,甚至 arduino 都是可以使用,核心的实现逻辑也都是一样。

# 2.2 时钟芯片选型

外部时钟芯片简单来说就是一个低功耗的精确计时器,可以带有后备电源,在外部掉电的情况下也可以正常走时,不会丢失时间。这些芯片的典型代表是 DS1302,DS3231 等等。DS1302 的时钟在每个月会飘逸 2~3 分钟,所以需要设置一个校时补偿的功能。然后晶振的选用和 layout 的布局也会对时间飘逸产生影响,具体可以 Google 相关的文章。相比而言 DS3231,带有集成的温补晶振 (TCXO) 和晶体。该器件包含电池输入端,可保持精确的计时。

综上所述我把两个的优缺点列了以下:
DS1302

  1. 成本低廉
  2. 时间飘逸问题
  3. 性价比很高

DS3231

  1. 带有温度补偿
  2. 准确性教高
  3. 价格略高

综合考虑成本,性价比以及编程难易程度和电子钟对环境的要求之后,我选择了 DS1302 芯片作为实时时钟。因为课设的我们以能够低成本完成为主要的指标。

# 2.3 显示器件选型

显示器件我们选用主要用 OLED 和 LCD 两种方案可选

OLED:

  1. 不需要背光板
  2. 驱动简单
  3. 功耗低
  4. 颜色可选:白色 蓝色 蓝黄色
  5. 价格贵

LCD:

  1. 有背光板
  2. 功耗高
  3. 屏幕大
  4. 价格低

显示这因人而已,主要考虑个人观看的因素,我更偏向于价格低廉和屏幕较大的 LCD Nokia 5110,。

# 2.4 其他部件选型

板子其他器件选用,主要可以使用贴片元件,这样可以直接打板后 SMD,省钱的话也能自己焊接,甚至手工做板的话也是可以的。一般器件的封装我建议是使用 0603 或者 0805 的封装,比较小一些,整个板子设计起来也好看小巧,同时焊接难度也不大,小修小改的余地也有,对新手友好些。

# 硬件部分制作

# 3.1 生产工具

PCB 设计工具:Altium Designer / 立创 EDA / KiCAD / Eagle

打板工具:嘉立创(真香)

推荐用立创 EDA 一站式设计和下单,打板,SMT 非常舒服

# 3.2 原理图设计

# 3.2.1 最小系统

根据 STM8 中文手册的核心板手册建议,采用 104,106 作为滤波电容,同时引出 USB 的接口来供电,同时接外部 16M 晶振,使用 22pf 电容作为晶振的启动,然后引出 ST-Link 接口用于烧录程序。正常设计最小系统的流程走就没啥问题。

# 3.2.2 电源管理

电源管理芯片 AMS117, 同时接入保险丝采用的是 500mA, 能够保证异常电流情况,短路情况下能够保证核心芯片不烧坏以及造成其他器件损坏,然后接入一个 LED 用来显示是否正常工作。也是正常设计的操作。

# 3.2.3 实时时钟

按照 Datasheet 给的推荐电路接入晶振和下拉电阻,同时把后背电源和纽扣电池给安排上,同时别忘记加滤波电容

# 3.2.4 其他简单的部分

这部分简单看图就懂

# Layout

# 3.3.1 布局

因为频率不高,而且实际信号设计的方面较少,所以布局以美观为主,紧凑规整,然后双面走线,顶层

横向为主,底层以竖向为主, 其他采用一般的布线规则就可以了,顶层覆铜是 3.3V 的电源,底层是 GND。

# 3.3.2 顶层

# 3.3.3 底层

# 3.3.4 板子设计效果

背后留有足够的空间,能够设计自己的 Logo 和自己的标识

# 3.3.5 板子的 3D 预览

整体器件可以藏在 LCD 后面,进一步优化的话,可以多加两个固定柱子在前面,这样就比较完备了

# 软件部分

# 4.1 软件环境

编程环境: IAR/Keli5/Clion + OpenOCD

烧录环境: ST-Link v2 / 串口

# 4.2 大概流程图

# 4.3 主要部分解析

LCD菜单切换参考资料
uchar LCD_Display_menu()  
{  
     // 省略次要部分 
    while(1)  
	  {  
	    if(receive_over==1)                         // 数据接收完成后再执行解码及显示函数  
	    {                        
	      receive_over=0;                         
	      decode();                                  // 进行解码  
	      if(ir_code[2] == 0x44 || ir_code[2] == 0x40)  
	      {  
	        if(ir_code[2] == 0x44 && menu_flag == 1)  menu_flag = 4;  
	        else if(ir_code[2] == 0x40 && menu_flag == 4) menu_flag = 1;  
	        else if(ir_code[2] == 0x44) menu_flag = menu_flag >> 1;  
	        else menu_flag = menu_flag << 1;  
	          
	        LCD5110_Put_String_6_8(0,5,getBit(menu_flag,0),"Act");  
	        LCD5110_Put_String_6_8(24,5,getBit(menu_flag,1),"Time");  
	        LCD5110_Put_String_6_8(54,5,getBit(menu_flag,2),"ALarm");  
	      }  
	      else if(ir_code[2] == 0x46)  
	      {  
	         mode_status = ~mode_status;  
	         PD_ODR_ODR4 = 1;  
	      }  
	      else if(ir_code[2] == 0x43)  
	      {  
	         return menu_flag;  
	      }    
	   }  
	   LCD_show_time(mode_status);  
	  }  
}

这这里采用一个位运算的方式,然后用一个变量的某一位来记录现在光标所在的位置,这样能够提升性能也能减少变量空间。

EEPROM逻辑 参考资料
while(1)  
	{
        Alarm_LCD_show_time(alarm_flag);  
	    if(receive_over==1)                            // 数据接收完成后再执行解码及显示函数  
        {                        
            receive_over=0;                         
	      	decode();                                  // 进行解码  
	      	if(ir_code[2] == 0x43)  
	      	{  
	        	mode_status = 1;  
	        	Save_to_EEP(EEP_Save_buffer,alarm_index);  
	        	LCD5110_Clear();   
	         	return 0; //return   
	      	}  
	    	else if(ir_code[2] == 0x15)  
	      	{  
	          	Save_to_EEP(EEP_Save_buffer,alarm_index);  
	          	alarm_index++;  
	      	}  
	      	else
            {  
	        	if(ir_code[2] == 0x44 || ir_code[2] == 0x40)  
	        	{  
	            	if(ir_code[2] == 0x44 && alarm_flag == 1)  alarm_flag = 8;  
	                else if(ir_code[2] == 0x40 && alarm_flag == 8) alarm_flag = 1;  
	                else if(ir_code[2] == 0x44) alarm_flag = alarm_flag >> 1;  
	                else alarm_flag = alarm_flag << 1;  
	           	}  
	            else
                {  
	            	alarm_number = get_key(ir_code[2]);  
	               	for(int i = 0; i < 4;i++)  
	               		if(getBit(alarm_flag,i))  
	                    	EEP_Save_buffer[i] = alarm_number;  
	                       
	                     
	            }      
	      	}  
	    }  
    }

光标逻辑和上面代码一样,然后再闹钟里面能够通过红外遥控直接输入数字,来设置闹钟时间,确认后可以直接存入 EEPROM

软件实现比较简单,没有什么难的,主要思路清晰就可以了。

# 4.4 BUG

调试过程 1:时间校准错误

问题描述:往 DS1302 写入数据时,只写入了年的数据,月份和日还有时间的都写不进去.

解决办法: 多次写入并且在烧录写入多按几下红外遥控,写入需要时间,多次操作就好。

调试过程 2:LCD5110 显示

问题描述:显示不了

解决办法:发现屏幕的接触不是很好,按一按屏幕就好了

More~~

# 4.5 烧录

路径修改

  1. 右键工程,Option > Genernal Option 确认芯片是否一致

  2. 右键工程,Option > C/C++ compiler > Perprocessor 设置当前各个文件的结构如图所示

  3. 右键工程,Option > Debugger > Setup 设置 Driver 为 ST-Link

编译及烧录

  1. Make
  2. Download

完整代码: https://github.com/junwide/MCU-Clock

# 打板

嘉立创

实际做板下来价格为:

  1. 打板 5 块 - 5RMB
  2. 立创商城元器件 5 套 - 88RMB

手工焊接一套大概是 93/5=18.6 元一套,如果不在立创商城购买器件整个价格能够压到 15 以下应该没问题。

# 最后

开源这个小的课设项目,希望能够给一些入门的小伙伴帮助,在基础上取优化和开发更好的东西。

更新于

请我喝[茶]~( ̄▽ ̄)~*

Junwide Xiao 微信支付

微信支付

Junwide Xiao 支付宝

支付宝