这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 单片机中I/O的扩展

共2条 1/1 1 跳转至

单片机中I/O的扩展

助工
2014-10-07 14:10:24     打赏
在我们的单片机应用系统中,常常会遇到I/O口不够的情况。譬如说接有外部RAM而且要求有16个以上的按键,8位数码管以上的显示。而且还不包括其它的外围器件。这时整个系统的I/O资源就很吃紧了。系统的扩展性也不好。这时我们就需要考虑对单片机的I/O进行扩展了。 
      虽然专门的I/O扩展芯片市场上也有不少,但对于我们一般的应用,没有必要整的那么复杂。用一些简单的移位寄存器芯片一样可以实现我们的目标。下面我们首先来认识一下74HC164这款芯片。这款芯片的作用是把串行输入的数据并行输出。注意,它没有锁存功能,在允许输出的情况下,每一个时钟的上升沿,数据依次从最低位移向最高位。因此,在做数码管的输出显示的时候会出现拖影的想象,在设计此电路时要注意考虑此情况。 
下面是它的引脚图。A1,A2是数据输入端,一般情况下两者连在一起,作为串行数据的输入端。Qa----Qh j就是并行数据的输出端了。CLOCK 和RESET分别为时钟和复位端 


下面我们再看看它的真值表,有了真值表我们才知道如何正确的去编写程序去驱动它(其它复杂的器件还需要对照时序图编写相应的驱动程序) 
   
  呵呵,怎么样,这个表很简单吧,相信大家都能够看的懂。当Reset为低电平时不管时钟为高电平还是低电平也不管输入引脚A1,A2为何值,输出的并行数据均为低电平。当Reset为高电平时,只有在时钟的上升沿,A1A2上的值才被移位输出。看懂了这张表那么剩下的事情就好办多了。 
下面我以级联的8块74HC164驱动8位共阴的数码管为例来阐述它的用途。当然它的用途并不仅仅在于此。你可以发挥你的聪明才智去应用它到你的设计中。 
   
以上的连接中Reset脚要全部接高电平。所有的Clock引脚都要连接在一块。第一块74HC164的AB引脚接在一块作为串行数据的输入端。第二块74HC164的AB引脚接在第一块74HC164并行数据输出端的H脚上。后面的接法依照第二块的接法依次级联下去。 
接好后共引出四根引线。其中电源两根。一根时钟线。一根串行数据输入线。怎么样,节省了不少IO口吧~~ 
下面看看如何写程序去驱动它。(编译器keil Uv3) 
先看看下面的引脚连接及相关宏定义 
sbit io_74hc164_SCK = P3^7 ; 
sbit io_74hc164_SDA = P3^6 ; 
#define IO_74HC164_SCK_HIGH      io_74hc164_SCK = 1 ; 
#define IO_74HC164_SCK_LOW      io_74hc164_SCK = 0 ; 
#define IO_74HC164_SDA_INPUT    io_74hc164_SDA 
下面是数码管的段码表可以根据不同的连接顺序去修改。 
/*********************************************************** 
    a -- 4  b -- 5  c -- 6  d -- 2 
    e -- 0  f -- 1  g -- 3  dp -- 7 

***********************************************************/ 

uint8 code DisplayTable[]= 
{ 
    0x77,0x60,0x3D,0x7C,0x6A,0x5E,0x5F,0x70,0x7F,0x7E,0x7B,0x4F,0x17,0x6D,0x1F,0x1B,0x08/*0    1    2    3  4  5    6    7  8    9  a    b    c    d    e    f    -  */ 
}; 
void v_74hc164WriteData_f( uint8 Dat )          //向74HC164写一个字节的内容 
{                                                  //即可并行输出该字节 
    uint8 i = 0 ; 
      uint8 SendData = Dat ; 
      for( i = 8 ; i > 0 ; i-- ) 
      {    
                IO_74HC164_SCK_LOW 
                SendData <<= 1 ; 
                IO_74HC164_SDA_INPUT = CY ; 
                IO_74HC164_SCK_HIGH 
      } 
} 
void v_HexToBcd_f( uint8 *P, uint16 Dat )              //BCD码的转化 
{ 
uint8 i = 0 ; 
uint8 Temp ; 
if( Dat >= 40000 ) { i  = 4 ; Dat -= 40000 ; } 
if( Dat >= 20000 ) { i += 2 ; Dat -= 20000 ; }  
if( Dat >= 10000 ) { i += 1 ; Dat -= 10000 ; } 
*P++ = i ; 
i = 0 ;          
if( Dat >= 8000 ) { i  = 8 ; Dat -= 8000 ; } 
if( Dat >= 4000 ) { i += 4 ; Dat -= 4000 ; } 
if( Dat >= 2000 ) { i += 2 ; Dat -= 2000 ; } 
if( Dat >= 1000 ) { i += 1 ; Dat -= 1000 ; } 
*P++ = i ; 
i = 0 ; 
if( Dat >= 800 )  { i  = 8 ; Dat -= 800 ; } 
if( Dat >= 400 )  { i += 4 ; Dat -= 400 ; } 
if( Dat >= 200 )  { i += 2 ; Dat -= 200 ; } 
Temp = Dat ;        //这里换成8位数据,是为了加快速度 
if( Temp >= 100 )  { i += 1 ; Temp -= 100 ; } 
*P++ = i ; 
i = 0 ; 
    
if( Temp >= 80 )  { i  = 8 ; Temp -= 80 ; } 
if( Temp >= 40 )  { i += 4 ; Temp -= 40 ; } 
if( Temp >= 20 )  { i += 2 ; Temp -= 20 ; } 
if( Temp >= 10 )  { i += 1 ; Temp -= 10 ; } 
*P++ = i ; 
*P = Temp ;      
} 
/************************************************************************** 
* Function:    void v_74hc164DisplayNumber_f( uint8 data *Seg, uint8 Dot, int16 Dat )                                              * 
* Description: 在8位数码管数值以及两位自定义字符                                                                      * 
*                                          *                                                                                  * 
* Parameter:    *Seg  :  指向存放自定义字符数据的地址                                                            * 
*                  Dot :  小数点相对数值的显示位置(取值范围1~5,当取0 或者大于5的数值时,小数点不显示)                    * 
*                      Dat    :  显示数据(有符号整型数据,取值范围-32768~32767)                                          * 
**************************************************************************/ 
void v_74hc164DisplayNumber_f( uint8 data *Seg, uint8 Dot, int16 Dat ) 
{ 
            bit zf = 1, OverWrite = 1, zf_lock = 1 ; 
            uint8  i , j , k = 4 ; 
            uint8 Buffer[5]  ; 
          if ( Dat < 0 ) 
          { 
                  zf = 0 ; 
                Dat = ABS( Dat ) ;    //如果是负数,则取其绝对值,并将负值标志位清0 
            } 
            v_HexToBcd_f( Buffer, Dat ) ;    //将数据每个位拆分,放在数组中最高位放在数组的第//一个成员 
    for( i = 5 ; i >= 2 ; i-- )        //判断数据的位数(如1234,则位数为4) 
        { 
                  if( Buffer[ 5 - i ] > 0 ) break ;  //判断出最高位不为0即可 
    }  
          if( ( Dot >= i ) && Dot < 6 ) i = Dot ;    //如果小数点打在数字前面,则该数字前面添0.( 数//字12,小数点打在第四位,则合理的显示应该为0.0012) 
          j = 5 - i ; 
        for(  ; i >= 1 ; i-- )    //显示数值 
    { 
                  if( Dot == ( 5 - k ) )    //如果该位有小数,则显示应该加上一个'.' 
                  v_74hc164WriteData_f( DisplayTable[ Buffer[ k ] ] | 0x80 ) ; 
                else 
                v_74hc164WriteData_f( DisplayTable[ Buffer[ k ] ] ) ; 
                  k-- ;    
          } 
        if( zf_lock )    //判断正负,如果为负值则显示'-'号,否则显示空 
    {      
              if( ( zf == 0 )  ) 
              { 
                    v_74hc164WriteData_f( 0x08 ) ; 
            } 
              else 
            { 
                    v_74hc164WriteData_f( 0x00 ) ; 
              } 
                    zf_lock = 0 ; 
        } 
        for( ; j > 0 ; j-- )    //多余的位显示空 
  { 
            v_74hc164WriteData_f( 0x00 ) ; 
        } 
v_74hc164WriteData_f( Seg[ 1 ] ) ;      //显示第一个自定义编码的字符 
v_74hc164WriteData_f( Seg[ 0 ] ) ;      //显示第二个自定义编码的字符 
}

 


院士
2014-10-07 20:50:22     打赏
2楼

这里的IO扩展还仅限于了输出扩展。

楼主 要是输入口不够肿么办啊??


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]