单片机最小系统设计6683645

更新时间:2024-05-24 19:28:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

(此文档为word格式,下载后您可任意编辑修改!)

单片机最小系统设计与制作

1.1 单片机最小系统电路板硬件设计

单片机的主要功能是负责整个系统的控制,承担复杂的数据处理任务,因此在设计单片机最小系统时通常选用AT89C5l、AT89C52、AT89S51、AT89S52(S系列芯片支持ISP功能)等型号的8位单片机作为MCU。

一个典型的单片机最小系统一般由时钟电路、复位电路、片外RAM、片外ROM、按键、数码管、液晶显示器、外部扩展接口等部分组成,图3.1 、图3.2分别给出了单片机最小系统的结构框图、原理图。

图3.1 单片机最小系统的结构框图

图3.2原理图

单片机最小系统时钟、复位、译码电路简介 1、时钟源电路

单片机内部具有一个高增益反相放大器,用于构成振荡器。通常在引脚XTALl和XTAL2跨接石英晶体和两个补偿电容构成自激振荡器,结构如图2 中Y1、C16、C17。可以根据情况选择6MHz、12MHz或24MHz等频率的石英晶体,补偿电容通常选择30pF左右的瓷片电容。 2、复位电路

单片机小系统采用上电自动复位和手动按键复位两种方式实现系统的复位操作。上电复位要求接通电源后,自动实现复位操作。

手动复位要求在电源接通的条件下,在单片机运行期间,用按钮开关操作使单片机复位。其结构如图2 中R24、R26、C18和K17。上电自动复位通过电容C18充电来实现。手动按键复位是通过按键将电阻R26与VCC接通来实现。 3、地址译码电路

最小系统上的全部硬件除EEPROM以外均是采用总线方式进行扩展的,每一个硬件均占用特定的物理地址。为了减少芯片的使用数量和降低PCB板布线的复杂度,本系统使用小规模可编程逻辑器件GAL代替74系列芯片实现译码电路。具体硬件见图2 中U24。 1.2 键盘显示电路设计 1.2.1键盘接口电路及程序设计

单片机键盘通常使用机械触点式按键开关,其主要功能是把机械上的通断转换成为电气上的逻辑关系。也就是说,它能提供标准的TTL逻辑电平,以便与通用数字系统的逻辑电平相容。小系统上设置了一个2行乘8列的阵列式键盘,系统硬件电路如图4所示。电路结构采用总线扩展方式进行设计,同时使用P13和P14进行行选择,按键信号通过一片74LS245挂接到数据总线上,片选信号为KEY_CS,为其分配的物理地址为0xA100。

图3.3 键盘接口电路

由于系统的键盘接口采用的是总线方式,因此读取按键数值变得相当方便,下面是使用C编写的读取键盘程序:

#define KEY XBYTE [0xA100] //键盘地址 sbit first_row = P1^4; //键盘第一行控制 sbit second_row = P1^3; //键盘第二行控制 uchar M_key; //键盘数值暂存单元 first_row = 0; //读取第一行键盘数值 second_row = 1; M_key = KEY;

first_row = 1; //读取第二行键盘数值 second_row = 0; M_key = KEY;

系统采用定时扫描的方式(扫描间隔为4ms,内部定时器定时中断间隔为2ms,每两次定时中断进行一次键盘扫描)进行键盘识别,设计程序时通常要进行以下四个方面的处理:

(1)每隔4ms读取一次键盘的数值,判断有无按键按下。具体方法是令first_row = 0,second_row = 0,M_key = KEY,判断M_key的值是否为0xFF,如果等于0xFF说明没有按键按下,如果不等于0xFF说明有按键按下。

(2)去除按键的机械抖动影响。通过设置状态标志位

first_getkey来判断连续两次扫描键盘是否都检测到有按键按下。如果没有连续两次都检测到按键按下则按照键抖动处理;否则,认为确实有按键按下。

(3)准确输出按键值keynum,并提供获得有效按键标志getkey。 (4)防止按键冲突。在获得有效按键以后设定状态标志位keyon来实现每次只处理一个按键,且无论一次按键时间有多长,系统仅执行一次按键功能程序。

键盘识别程序流程如图3.4所示。程序代码将在介绍完数码管显示器以后统一给出。

图3.4键盘识别程序流程

1.2.2数码管接口电路及程序设计

本系统共设置了8个7段码数码管显示器,电路结构如图3.5所

示。

图3.5 8个7段码数码管显示器电路

电路结构同样采用总线扩展方式进行设计,其中使用的数码管为连4位的共阳型数码管。通过芯片U15(74HC573)锁存,为数码管提供段码数据。通过芯片U14(74HC573)、U13(74HC138)以及三极管Q1—Q8将低三位地址A2..0进行硬件译码,为每个数码管提供一个唯一的物理地址,具体地址为0xA000—0xA007。此外本电路结构还考虑了不同数码管进行显示切换时的消隐问题,在编写程序时不用通过额外的处理进行消隐。由于为每个数码管都分配了一个固定的物理地址,在编写程序时只要将相应的段码数据写入到对应的地址当中便可以完成显示,例如要在第二个数码管上显示“1”,使用C语言办成实现如下:

#define 7SEG_LED2 XBYTE [0xA001] //第二个数码管的地址定义 7SEG_LED2 = 0xF9; //将“1”的段码数据“0xF9”输出到段码锁 //存器U15上,同时低三位地址A2..0“001” //经过硬件译码使位码LED2为高。

通过上面一条语句便可以实现在第二个数码管上显示“1”的操作。但由于全部数码管的段码线共用,在同一时刻只能点亮一个数码管,所以在实际应用中必须采用动态扫描的方 式进行8个数码管的显示。具体实现方法是使用内部定时器每2ms产生一次定时中断,系统在每进入到一次定时中断后更新一次显示内容,对于每个数码管来说其显示的周期为16ms,由于显示频率足够高人眼感觉不到闪烁的存在。数码管显示程序流程如下:

图3.6 数码管显示程序流程

在编写程序时考虑到单片机的资源利用情况,使用一个定时器为键盘扫描和数码管显示更新提供定时服务,定时中断函数流程如图3.7所示。定时器定时间隔为2ms,每次进入中断调用一次显示更新函数,每两次进入中断调用一次扫描键盘函数。图3.8给出了利用以上给出的键盘扫描和数码管显示以及中断函数实现一个最简单系统的主程序流程图。在主程序中通过查询方式判断getkey(获得有效按键标志位,当获得一个有效按键后键盘扫描函数讲其置为1),当获得有效按键后令所有的数码管显示按键的数值。

图3.7 定时中断函数流程

图3.8主程序流程图

C程序代码如下: #include #include #include

#define uchar unsigned char /*数码管物理地址*/

#define LED1 XBYTE [0xA000] #define LED2 XBYTE [0xA001] #define LED3 XBYTE [0xA002] #define LED4 XBYTE [0xA003] #define LED5 XBYTE [0xA004] #define LED6 XBYTE [0xA005] #define LED7 XBYTE [0xA006] #define LED8 XBYTE [0xA007] /*键盘物理地址*/

#define KEY XBYTE [0xA100] /*扫描键盘使用的变量 */

sbit first_row = P1^4; //键盘第一行控制 sbit second_row = P1^3; //键盘第二行控制

bit first_getkey = 0,control_readkey = 0; //读键盘过程中的标志位

bit getkey = 0; //获得有效键值标志位,等于1时代表得到一个有效键值 bit keyon = 0; //防止按键冲突标志位

uchar keynum = 0; //获得的有效按键值寄存器 /*数码管显示使用的变量和常量*/

uchar lednum = 0; //数码管显示位控制寄存器

uchar code segtab[18] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6, 0xa1,0x86,0x8e,0x8c,0xff}; //七段码段码表

// \ /*函数声明*/

void leddisp(void); //数码管显示更新函数 void readkey(void); //键盘扫描函数 / *T0 定时中断处理函数*/ void intT0() interrupt 1 {

TH0 = -4230/256; //定时器中断时间间隔 2ms TL0 = -4230%6;

leddisp(); //每次定时中断显示更新一次

if(control_readkey == 1) //每两次定时中断扫描一次键盘 {

readkey(); }

control_readkey = !control_readkey; }

/*主函数*/ void main(void) {

TMOD = 0x01; //设定定时器T0工作模式为模式1 TH0 = -4230/256; //定时器中断时间间隔 2ms TL0 = -4230%6; TCON = 0x10; ET0 = 1; EA = 1;

while(1) //等待获得有效按键 {

if(getkey == 1) //判断是否获得有效按键 {

getkey = 0; //当获得有效按键时,清除标志位。 led[0] = keynum; //令全部数码管显示按键值 led[1] = keynum; led[2] = keynum; led[3] = keynum; led[4] = keynum; led[5] = keynum; led[6] = keynum; led[7] = keynum; } } }

/*************************************************** 键盘扫描函数

原型: void readkey(void);

功能: 当获得有效按键时,令getkey=1,keynum为按键值

****************************************************/ void readkey(void) {

uchar M_key = 0; ////键盘数值暂存单元 first_row = 0; second_row = 0; M_key = KEY;

if(M_key != 0xff) //如果有连续两次按键按下,认为有有效按键按下。消除按键抖动 {

if(first_getkey == 0) {

first_getkey = 1; }

else //当有有效按键按下时,进一步识别是哪一个按键 {

if(keyon == 0) //防止按键冲突,当还有未释放的按键时不对其它按键动作响应 {

first_row = 0; //扫描第一行按键 second_row = 1; M_key = KEY; if(M_key != 0xff) {

switch(M_key) {

case 0xfe:

keynum = 0x00; break; case 0xfd:

keynum = 0x01; break; case 0xfb: keynum = 0x02; break; case 0xf7:

keynum = 0x03; break; case 0xef:

keynum = 0x04; break; case 0xdf:

keynum = 0x05; break; case 0xbf:

keynum = 0x06; break; case 0x7f:

keynum = 0x07; break; } } else {

second_row = 0; //扫描第二行按键 first_row = 1;

M_key = KEY; switch(M_key) {

case 0xfe:

keynum = 0x08; break; case 0xfd:

keynum = 0x09; break; case 0xfb:

keynum = 0x0a; break; case 0xf7:

keynum = 0x0b; break; case 0xef:

keynum = 0x0c; break; case 0xdf:

keynum = 0x0d; break;

case 0xbf: keynum = 0x0e; break; case 0x7f:

keynum = 0x0f; break; } }

getkey = 1; //获得有效按键数值

keyon = 1; //防止按键冲突,当获得有效按键时将其置1 } } } else {

first_getkey = 0;

keyon = 0; //防止按键冲突,当所有的按键都释放时将其清0 } }

/*************************************************** 数码管显示函数

原型: void leddisp(void);

功能: 每次调用轮流显示一位数码管

****************************************************/ void leddisp(void) {

switch(lednum) //选择需要显示的数码位 {

case 0:

LED1 = segtab[led[0]]; break; case 1:

LED2 = segtab[led[1]]; break; case 2:

LED3 = segtab[led[2]]; break;

case 3:

LED4 = segtab[led[3]]; break; case 4:

LED5 = segtab[led[4]]; break; case 5:

LED6 = segtab[led[5]]; break; case 6:

LED7 = segtab[led[6]]; break; case 7:

LED8 = segtab[led[7]]; break; }

if(lednum == 0) //更新需要显示的数码管位置 {

lednum = 7; } else {

lednum = lednum-1; } }

1.3液晶接口电路及程序设计

传统的显示器件数码管已经不能满足显示复杂操作界面的要求。因此最小系统中除了数码管显示器以外,还接入了一个液晶显示模块,其型号为SGM12864C,可以显示64行128列的点阵数据,通过编写相应的程序可以显示英文、汉字或图形,可以实现比较复杂的用户操作界面。硬件接口电路如图3.9所示。液晶模块的结构及操作控制请参阅SMG12864C.PDF。

图3.9 硬件接口电路

在硬件设计中使用译码电路提供的LCD_R_CS、LCD_L_CS、

本文来源:https://www.bwwdw.com/article/6ww7.html

Top