单片微机原理P3:80C51外部拓展系统

发布时间:2024-08-21  

外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。

 

0. IO接口电路概念与存储器拓展

1. 为什么需要IO电路?:1. 协调计算机与外设的速度的差异 2. 输入/输出过程中的状态信号 3. 解决计算机信号与外设信号之间不一致

2. IO传送方式三种:1. 无条件传送(灯,DAC),2. 查询,3. 中断(ADC)。

 

3. DMA存储方式(直接传输数据不通过CPU,这种方式实际上已经很古老了,都快要被淘汰了(当然还存在STM32,51这些低级产品中)。)

  工作流程:

  ①CPU通过指令,把要传送的数据块的长度、传送数据块在内存中的首地址等信息写入DMA控制器。

  ②外设通过DMA控制器向CPU发出DMA请求。

  ③CPU接受DMA请求后,暂停正在执行的程序,并且放弃对总线的控制权,由DMA控制器来接管,外设的数据线和存储器的数据线经过DMA控制器的通道直接连通。

  ④DMA控制器通过地址总线向存储器发出传送数据的地址。

  ⑤如果是外设向存储器传送数据,DMA控制器向外设发出读信号,读出数据,DMA控制器向存储器发出写信号,则写入数据,由于两者的数据线是直接连接的,数据读、写的操作就可以连续进行,很快地完成一次数据传送。

  ⑥数据块长度计数器减1,然后重复以上进程,直到数据块传送完毕。

  ⑦DMA操作结束,CPU再次恢复对总线的控制,继续执行原来的程序。

以上的传送过程,一次数据传输一般只要几个时钟周期就可以完成。

 

4. 在无条件传送方式下,CPU和外设端口之间也要有接口电路。

  1. 在输入端口上会有一个输入缓冲器:

    在不做输入操作时,缓冲器处于高阻状态,CPU实际上和输入外设没有连接;

    需要做输入操作时,地址译码器的输出使缓冲器正常工作,输入设备的信息就可以通过缓冲器读入到CPU。

 

  2. 在输出的端口上一般会有一个输出锁存器:CPU将要输出的信息存入输出锁存器中,外设从锁存器读取信息。

 

  接口电路也至少需要两个端口:状态端口和数据端口,用以分别传送状态信息和数据信息。(这就是ADC芯片所设计的那样的。)

 

5. 单片机从逻辑上有3个存储器寻址空间

片内RAM空间:00H~FFH

片外RAM空间:0000H~FFFFH

片内外统一编址的ROM空间:0000H~FFFFH (注意是片外,如果是片内+片外为0000~0FFFH,然后片外再从1000H开始到FFFFH)

 

6. 扩展ROM时,用控制线PSEN,指令用MOVC

  扩展RAM时,用控制线RD和WR,指令用MOVX

  单片机是通过地址(AB)、数据(DB)和控制总线(CB)与外部交换信息的。

 

1. 存储器的拓展(ROM & RAM)

  1. 拓展程序存储器(以拓展2732为例)(一定要会)

  现在我们来解释一下这些引脚的意思:

  ALE引脚:和我们之前的说的是一样的,就是实现对P0口的分时复用,要注意这个ALE很坑的地方是他是在下降沿P0口的地址输出信号才有效,所以锁存芯片一定要选对(比如这里选的就是373,如果选那些上升沿触发的377之类的,请加个反相器再加上去)。

  PSEN引脚:引脚功能如其名:外部程序存储器选通信号PSEN,所以接2732的使能片很符合常理。(低电平有效)

  2732的CE引脚:片选信号端,用P2.5~2.7进行选通。

  关于时钟,ALE,PSEN,P2,P0的时序图:

  注意ALE和PSEN是同步开始的,P2和P0的信号相对于PSEN和ALE都是有延迟的

  

 

译码器法:(其实就是加了个译码器而已,简单)

  

 

2. 拓展外部RAM(以拓展6116为例)(一定要会)

  SRAM(51的内部内存都是SRAM)通常用于小于64KB的小系统,DRAM(我们的电脑内存是DRAM)用于大于64KB的大系统。

  拓展RAM和ROM的做法其实是差不多的,但是唯一的不一样是ROM是拓展的PSEN,所以PSEN要接ROM的OE,但是对于RAM来说,它读写双向的,所以我们只要拓展把80C51的RD端接6116的OE端,WR端接6116的WE端就可以了,同时注意,6116也是有片选端(CE)的,我们也可以像ROM那样对RAM进行片选。


 

3. 拓展FLASH(RAM + ROM)

  就是把ROM和RAM的拓展方式结合起来,既要接PSEN又要接WR和RD

  注意这里的PSEN,WR,RD,WE,CS和OE都是低电平有效的,一旦哪个引脚低电平了就可以把FLASH对应成相应存储器,比如当PSEN为低电平时,这个Flash就是个程序存储器,WR为低表示以外部RAM写,ED为低则表示以外部RAM读(可能这个电路有点复杂,其实只用仔细看一下就知道只要有一个是低电平CS就会是低,然后你就可以把它看成是什么都行了)。

  注意这里的拓展还用P1拓展了地址,输出的时候注意:


;(写)

MOV P1,#05H

MOV DPTR, #0AAAAH

MOV A, #3FH

MOVX @DPTR, A

 

;(读)

MOV P1,#02H

MOV DPTR, #0AAAAH

MOVX A, @DPTR

;地址由P0,P1.0~2,P2共同决定

当然了我们也可以不占用P1来拓展这个芯片,由于我们只用保证必须要有信号就可以了,所以我们可以用锁存器来继续拓展这个芯片,这样就可以只用P0~P2了(程序设计要麻烦一点而已)。

4. 奇葩拓展芯片2718(有BUSY和READY位告知CPU已经完成转换)

  仔细看下RD和PSEN,他们是通过一个与门来连接同样是低电平有效的OE,这个芯片的特别之处在于他有BUSY位(低电平有效)和RDY(Ready)位,看英文就知道是怎么回事。

 

5. IO口拓展

  这个有个很有趣的例子就是拓展开关和灯泡,拓展IO口可以很巧妙地里用WR和RD不同时为0的特性:

  还记得之前我们是怎么说的吗?输出部分要有锁存器,输入部分要有缓冲电路。74LS244为3态8位缓冲器,一般用作总线驱动器。74LS273是8位D触发器,常用作锁存器。这个图完美的切合了我们之前所说的,由于WR和RD不同时为低,所以我们可以仅用MOVX指令就可以完成IO拓展了(P2.0当总控制口)

上例中按下任意键,对应的LED发光。

CONT:

MOV DPTR, #0FEFFH ;数据指针指向口地址

MOVX A, @DPTR ;检测按键,向74LS244读入数据

MOVX @DPTR, A ;向74LS273输出数据,驱动LED

SJMP CONT ;循环

  总结一下,如果出了设计题,一定要先思考到WR和RD的问题,要记住WR和RD都是低电平有效的,一般和与门进行结合来控制CS端。

 

1. 81C55拓展

1. 81C55参数如下:(要熟记81C55的引脚的作用)

AD7~AD0:三态地址数据总线,用于传送数据、命令和状态字,分时复用线,P0口可以和AD0~AD7直接相连接。

CE:片选信号线。(80C51随便找个P口控制)

RD:存储器读信号线。(一般接80C51的RD线)

WR:存储器写信号线。(一般接80C51的WR线)

ALE:地址及片选信号锁存信号线,高电平有效,其后沿将地址及片选信号锁存到器件中。 (一般接80C51的ALE线)

IO/M:I/O接口与存储器选择信号线,高电平表示选择I/O接口,低电平选择存储器RAM。(80C51随便找个P口控制)

PA7~PA0:A口输入/输出线。

PB7~PB0:B口输入/输出线。

PC3~PC0:C口输入/输出或控制信号线(A口和B口作为选通口时)。

TIMER IN:定时器/计数器输入端

TIMER OUT :定时器/计数器输出端

RESET:复位信号线

 

  81C55各端口地址分配(81C55一共7个端口)(注:那个C/S寄存器就是命令字/状态字寄存器(共用一个地址,但是是不同的两个寄存器),低电平有效)

引脚作用(注意0是操作RAM,1是操作IO)

9f9784482aae835cf71e1b29b73745b1_798615-20170109213406510-1786404102.png

命令字(只能写)

 94f72e0b5aa1c07d723c3add41ddcedf_798615-20170109213628119-1529835705.png

状态字(只能读)

0e51e9b272162452267db852666d5df7_798615-20170109213717213-1312731818.png

TIMER:定时/计数器中断请求标志,定时器/计数器记满时这个位为1,当CPU读取状态后,这个标志位为0

INTE:端口允许中断位,高电平表示允许对应口中断,低电平表示禁止对应端口中断

BF:对应端口的缓冲器状态标志位,高电平表示的是缓冲器填满,低电平表示的是可以接受外设或者单片机的数据。

 

2. 当81C55涉及C寄存器做联络线的问题

  其实这个问题是很简单的,C寄存器的6个口的功能如下

 97b9ab34b2da0aa36656a22b05a102ed_798615-20170109213943510-896882773.png

  我们知道81C55可以很方便地与慢速设备进行连接,当外设需要往PA或者PB输入数据时,外设首先先给BSTX端口一个低电平信号,向81C55表明需要读信号,然后81C55的PX就从外设中开始读数据,到读满端口寄存器时,给ABF/BBF置位(表明缓冲区满),并且向CPU发出中断。CPU(比如80C51)调用中断处理,只需要一条MOVX A,@DPTR(此时DPTR指向对应P口),就可以把数据读进来。

  当需要写数据时,只要80C51一条MOVX @DPTR, A,就可以给对应P口写数据,直到对应P口的寄存器满,对应的BF位置位,外设就可以从P口读数据了,读数据时,BSTB变成低电平。

 

3. 关于81C55的定时器

  81C55的定时器是14位的减1定时器

  定时器寄存器的地址上面有写,需要注意的是,定时器的高8位的最高两位是设定81C55定时器的工作方式的:

 06ceae22fc6b5d5b599b994bd4f1bd8b_798615-20170109214001994-138668238.png

  单负方波:计数期间输出为低电平,记满回“0”后输出高电平。

  连续方波:计数长度的前半部分输出高电平,后半部分输出低电平,如果计数值为奇数个,则高电平为(n+1/2)个,低电平为(n-1/2)个。连续方波输出方式能自 动恢复初值。

  单负脉冲:计数器记满回“0”后输出一个单负脉冲。

  连续脉冲:计数值回“0”后输出单负脉冲,然后自动重装初值,回“0”后又输出单负脉冲,如此循环。

 

  给命令字的TM0和TM1位设定对应值即可开启定时器~

 

  例题:81C55的命令字寄存器的地址是7F00H,要求设定81C55的A口为基本输入方式,B口定义为基本输出方式,C口输入,打开定时器,读取81C55,要求将立即数0AAH写入81C55 RAM的7E25H单元:(P2.0是接CE,P2.7接IO/M)


MOV DPTR,@7F00H

MOV A,#0C2H ;11000010,(打开了计时器A口为输入(0),B口为输出0,PC1:PC0 = 00(A/B基本输入输出,C口输入))

MOVX @DPTR,A

MOV A,#0AAH

MOV DPTR,#7E25H ;写入的是内存,地址是7E25H,刚好符合写入RAM的要求(81C55的RAM只有256B)

MOVX @DPTR,A


2. 矩阵键盘拓展

  矩阵键盘只要记住矩阵键盘的样子:

10d42d994cc74294bb921536b3abd961_798615-20170109214143166-42183383.png

  你就能想到矩阵键盘的扫描方法了(必须按行和列来扫,因为本质上是通过给行/列全部低电平来让判断按钮有没有按下,当某行某列有按钮按下,对应电阻就会产生电压降,我们就可以找到对应的按钮了)。

  来一段我以前写过的C的代码:

#include


sbit encoder_selet=P2^7;

sbit numeric_display=P2^6;


unsigned char leddata[]={ 

                0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 

                0x79, 0x71, 0x76, 0x38, 0x37, 0x3E, 0x73, 0x5C,0x40, 0x00, 0x00  

                };

                

unsigned char lower_key_set[4]={0x0e,0x0d,0x0b,0x07};

unsigned char lower_key_set_colum[4]={0xe0,0xd0,0xb0,0x70};


void delay(unsigned int);

void scan_keyboard(int);

void scan_keyboard_col(int);

void display_key(int);


static int pos= 0;


int main(void)

{

    int pos = 0;

    bstv51_init();

    while(1)

    {

        scan_keyboard_col(0);

        scan_keyboard_col(1);

        scan_keyboard_col(2);

        scan_keyboard_col(3);

    }

    return 0;

}


void scan_keyboard(int line)

{

    unsigned char in, lower_key,in_tmp;

    int selet_key;

    

    lower_key = lower_key_set[line];

    P3 = lower_key|0xf0;                            

    

    in = P3;

    in_tmp= in & 0x0f;

    

    in &= 0xf0;

    in |= lower_key;

    if(in!= (lower_key|0xf0))

    {

        delay(5);

        P3 = lower_key|0xf0;

        in = P3;

        in &= 0xf0;

        in |= lower_key;

        if(in != (lower_key|0xf0))                //软件防抖

        {

            in_tmp = in & 0xf0;

            switch(in_tmp)                        //找到相应的坐标

            {

                case 0xe0:

                    selet_key= 0 + line*4;        

                    break;

                case 0xd0:

                    selet_key= 1 + line*4;

                    break;

                case 0xb0:

                    selet_key= 2 + line*4;

                    break;

                case 0x70:

                    selet_key= 3 + line*4;

                    break;    

            }

            while(in != (lower_key|0xf0))

            {

                in = P3;

                in &=(lower_key|0xf0);

            }

            display_key(selet_key);

        }

    }

}


void scan_keyboard_col(int colum)

{

    unsigned char in, lower_key,in_tmp;

    int selet_key;

    

    lower_key = lower_key_set_colum[colum];

    P3 = lower_key|0x0f;                                

    in = P3;

    in_tmp= in & 0x0f;

    

    in &= 0x0f;

    in |= lower_key;

    if(in!= (lower_key|0x0f))

    {

        delay(5);

        P3 = lower_key|0x0f;

        in = P3;

        in &= 0x0f;

        in |= lower_key;

        if(in != (lower_key|0x0f))                //软件防抖

        {

            in_tmp = in & 0x0f;

            switch(in_tmp)                        //找到相应的坐标

            {

                case 0x0e:

                    selet_key= 0 + colum*4;        

                    break;

                case 0x0d:

                    selet_key= 1 + colum*4;

                    break;

                case 0x0b:

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>