一、设计内容:
本次设计使用stm8s实现简单的万年历,主要功能是显示时间、调时、设置闹铃。另外还添加了游戏辅助功能。
二、设计要求:
1、主控芯片使用stm8s
2、使用pcb板
3、至少要实现数码管显示时间和调时功能
三、设计过程:
设计总共分为两块,硬件设计和软件设计。首先是构思要实现的功能,然后了解硬件资源再进行软件设计。所以下面首先介绍硬件设计。
1、硬件设计部分
A、元件清单
器件名
型号
数量
Lcd
12864
1
DS1302
1
晶振
32.768KHz
1
Stm8s105s4
1
按键
5
二极管
1n4007
2
电容
220uf
1
10uf
2
104
5
电阻
1k
7
100k
1
10
1
三极管
8550
1
发光led
1
直流蜂鸣器
1
纽扣电池
3v
1
电位器
10k
1
开关
1
电源接口
1
稳压器件
7805
1
B、 原理图
Eda软件使用的是altium designer winter09 ,上面的原理图是从软件中copy出来的。
硬件设计总共分为5个模块。
模块一是电源部分。注意直流电源DC需要9V的电压才能得到5V的稳压输出,因为芯片7805需要一定的电压才能驱动。下面是l7805芯片的额定参数表:
在表中我们可以看到,该芯片的可以承受高达35V的直流电压输入,输出范围是5V-18V。下面还有一张表
从表中我们可以知道,当输入端Ci=0.33uf,C0=104,在输入端给10V直流电时,可以得到最小4.8V的稳压输出。这是该芯片datasheet里面的资料,是最权威的,我们的电源模块也是按照这样接的。
模块二是lcd显示部分。Lcd使用的是12864。12864是一种图形点阵液晶显示器,它主要由行驱动器/列驱动器及128X64全点阵液晶显示器组成,可完成图形显示,也可以显示8X4个(16X16点阵汉字,与外部CPU接口可采用串行或并行方式控制。
模块三是DS1302实时时钟和蜂鸣器。DS1302芯片接的石英晶体是32.768KHz的。另外,接入纽扣电池,实现断电后也可以让DS1302工 作,实现保存时间的功能。蜂鸣器使用的是直流蜂鸣器,用于闹铃提示。直流蜂鸣器内部有个2K的音频驱动源,我们只需加上直流电压就可以让蜂鸣器工作,不 过,使用直流蜂鸣器,我们只能产生一种频率的声音,不过对于闹铃提示来说,已经足够。直流蜂鸣器通过8550PNP管来驱动,主控芯片通过控制8550间 接来控制蜂鸣器。也就是说,io口给出低电平的时候,蜂鸣器就响。这个模块的电阻,主要是用来限流。
模块四是主控芯片。主控芯片使用的stm8s105s4。这块芯片的资源比较丰富。这里只介绍使用的资源。!16M的内部时钟,内部可编程flash rom 达32Kbytes,RAM为2K。44个引脚,有高达38个io端口。多个定时器,我们使用了定时器1。原理图中的两个电容是滤波电容,一个10uf,一个104。用于滤掉高频和低频的干扰。
模块五是按键模块。按键模块用于和用户进行交互。模块中使用了5个按键。电阻为限流电阻。
上面对硬件设计资源进行了概述,我们确定了硬件资源后就开始进行软件设计。
2、软件设计部分
这里使用了模块化编程方法,将各个功能作为一个模块来设计,这样不仅有利于方便的阅读代码,还有利于方便的修改代码和代码的复用等等。
编译器使用的是飞利浦公司提供的免费编译软件ST Visual Develop,该软件主要是用于开发stm系列芯片的。下面是设计的模块截图:
图中显示了各个模块。首先介绍一些配置文件。Stm8s_lib.c实现对主控芯片的硬件配置,主要是初始化主时钟,初始化定时器,初始化io端口和中断 等。设置这个文件为了方便移植和代码复用。相应的stm8s_lib.h是头文件,实现函数的声明。Type.h头文件,实现数据类型的宏定义,也是为了 方便移植和使用。Config.h可以配置一些硬件参数如波特率等等。下面对各个模块进行介绍。
显示模块lcd。文件lcd2864.c是该模块的实现文件,lcd12864.h和lcd_data.h声明了一些与显示相关的数据。具体代码请查看代码附件。
这里我们来看lcd12864.h这个头文件。这里面是12864的驱动函数。
void LcdInit(void);//初始化lcd
void WCmd(uchar cmd); //向显示控制器写命令
void WData(uchar ch); //向显示控制器写数据
uchar RBBF(void); //读忙标志
uchar RData(void); //读数据,由于没有使用到,这里代码不完整
uchar RByte(uchar addr);//读一个字节
void WByte(uchar addr,uchar buf);//写一个字节
//在屏幕上显示数据参数为(地址,数据buffer,汉字数)
void showword(uchar addr,uchar *buf,uchar count);//在屏幕上
//在屏幕上显示数据参数为(地址,数据buffer,字节数)
void showbyte(uchar addr,uchar *buf,uchar count);
//显示选择光标 falg=1 为显示
void ShowCur(uchar flag);
//清屏
void Clear_Screen(uchar addr,uchar count);
void Clear_all(void);
//将模式设置为显示像素点
void Set_Draw(uchar flag);
//高亮显示,参数为(横坐标0-15,纵坐标0-3,显示标志1为显示字符)
//2为显示汉字,3为清除高亮显示,以字的方式。
void High_Show(uchar x,uchar y,uchar flag);
//清除CGROM,将rom写0,避免花屏
void Clear_CGRom(void);
//图像显示初始化
void CG_init(void);
//恢复普通显示
Void CG_leave(void);
这里需要注意延时,给足够的时间显示控制器处理指令。我们主要使用showword函数来显示内容,ShowCur函数用来显示光标,提示用户当前选择。下面是时间显示的显示界面。注意左下角的就是光标。
实时时钟模块。实时时钟模块文件是DS1302.c,头文件是ds1302.h.
展开ds1302.h我们可以看到:
void ds1302_init(void);//ds1302初始化
void Read_Time(void); //读时间
void write_ds1302_com(uchar com);//写命令
void write_ds1302_data(uchar addr,uchar dat);//写数据
uchar read_ds1302_data(uchar addr);//读数据
void set_time(void);//设置时间
void read_time(void);//读时间
void translate(void);//转换时间
我们主要使用ds1302_init来初始化时钟芯片,Read_Time来读取时间,set_time来设置时间。
Uart.c文件模块。这个文件主要是实现串口通信的。在uart.h文件中:
void InitUART2(void); //初始化
void Uart_SendByte(unsigned char ch);//发送一个字节
void Uart_SendString(char *pt); //发送字符串
主要使用Uart_SendString这个函数,用于程序的调试。最终硬件实现是不添加串口通信功能的。所以关于串口通信的代码全部使用宏定义,在调试完成后,去掉宏定义就可以去除串口通信相关的代码了。
现在介绍main.c这个文件。这个主文件,将各个模块的接口连接起来,最终显示我们想要的功能。首先,也是必须的,我们来看看添加到main.c的头文件。
#include "stm8s105s4.h" //芯片头文件
#include "stm8s_lib.h" //这里就调用了配置函数
#include "lcd12864.h" //调用lcd驱动
#include "UART.h" //串口通信
#include "ds1302.h" //实时时钟的调用
#include "type.h" //类型定义
#include "lcd_data.h" //lcd显示数据
#include "beep_data.h" //蜂鸣器数据
有了上面的头文件,就可以实现相应的功能了。
这里我们将按键扫面驱动写在了主文件当中。使用定时器1产生20ms的定时器中断,实现按键扫描。代码如下:
@far @interrupt void TIM1_KEY (void)
{
//////////////////////////////////
TIM1_SR1=0X00;
if(time_counter>0)
{
time_counter--;
if(time_counter==0)
{
BEEP=1;
TIM3_CR1=0x00; //关闭计数
}
Ring_Beep();
}
/////////////////////按键扫描//////////////////////////
if(!KeyCanChange) //按键处理中标志位
return;
KeyCurrent=GetKeyValue();//获得当前键值 ,若没有按键按下 为高,
if(KeyCurrent!=KeyOld) //这里开始按键计时,若按键不同就使 KeyNoChangedTime为0,开始计数按键按下时间
{ //这里判断是否按键改变
KeyNoChangedTime=0;
KeyOld=KeyCurrent;
return;
}
else
{
KeyNoChangedTime++; //按键计时
if(KeyNoChangedTime>=1) //若按键按下时间足够,
{
KeyNoChangedTime=1;
KeyPress=KeyOld; //就保存该键值
KeyDown|=(~KeyLast)&(KeyPress); //按键为0 这里指定位置1,表示该键被按下
KeyUp|=KeyLast&(~KeyPress); //按键为 指定位置1,表示上次按键松开
KeyLast=KeyPress;
}
}
}
这个按键扫描驱动比较强大。可以感应按键的按下和松开。去抖动性能比较好。
现在介绍main函数,硬件启动后,执行到main函数,我们在main函数中实现硬件的初始化,外围芯片的初始化。然后显示启动画面。之后进入主菜单页面。Menu_show函数用于显示主菜单。界面为
-----------------------------------
-》万年历
闹钟设置
调整时间
游戏
---------------------------------------------------------------
然后就是进行菜单的选择。下面进行菜单介绍:
万年历。进入这个菜单后,主要就是读取DS1302的时间,并使用lcd显示出来。
闹铃设置。这里面将数据存在EEPROM中,每次进入万年历菜单和本菜单后,就将EEPROM中的数据读出,用于修改和比较。界面如下:
-----------------------------
闹铃设置
00:00:00
----------------------------------
调整时间。主要是对ds1302进行操作,设置时间。
游戏。