1、I/O扩展: 如题,本人尝试使用74LS164和74LS165实现简单I/O扩展,使用Keil C51编写程序,并使用Proteus搭建模型进行验证。 1)、74LS164:8位串入、并出移位寄存器 ①、DSA和DSB:其中之一接高电平做使能端,另一个接输入数据; ②、CP:时钟,每个上升沿数据右移一位; ③、MR:主复位,高电平对输出无影响,低电平强制所有输出为0; ④、Q0~Q7:8位并行输出。 2)、74LS165:8位并入、串出移位寄存器 ①、SH/LD:移位与置位控制端;SH/LD置0,并行口的8位数据将被置入其内部的8个触发器,在SH/LD为1时,并行输入被封锁,移位操作开始; ②、INH:低电平时充许时钟输入,高电平时禁止时钟输入; ③、CLK:时钟输入,上升沿有效; ①、D0~D7:并行输入端。 ⑤、SI:串行输入,用于扩展多个74LS165 的首尾连接端; ⑥、SO(QH):串行输出; QH(反):也是串行输出端,它与 SO(QH)是反相的关系; 2、Proteus模型: 使用4片74LS164级联,作I/O扩展输出,共扩展32位;使用4片74LS165级联,作作I/O扩展输入。 实现功能:①、74LS164扩展I/O输出点亮4个数码管; ②、74LS165读取扩展I/O引脚状态; ③、在LCD1602中同步显示数码管显示的数字。 3、Keil C51程序: 1)、工程文件结构: 2)、main.c /** *************************************************************************************** * 文 件:工程主函数源文件 * 芯 片:AT89S52 * 晶 振:12MHz * 创建人:hug567 * 时 间:2018-4-27 *************************************************************************************** */ #include <regx52.h> //52系列单片机头文件 #include "delay.h" //延时函数实现头文件 #include "lcd1602.h" //LCD1602实现头文件 sbit LS164_DATA = P0^0; //74LS164数据线 sbit LS164_CLK = P0^1; //74LS164时钟线 sbit LS165_SH_LD = P0^2; //74LS165移位控制线 sbit LS165_DATA = P0^3; //74LS165数据线 sbit LS165_CLK = P0^4; //74LS165时钟线 //7段共阳极数码管段码,0~f,不带小数点 unsigned char tube[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E}; unsigned char LED_Num[4]={0,0,0,0}; //存储4个数码管显示的数字 /** *************************************************************************************** * 函 数:74LS164写32位扩展引脚函数 * 参 数:state:要写入的32位数据 * 返回值:无 *************************************************************************************** */ void LS164_Write(unsigned long state) //74LS164写32位扩展引脚函数 { unsigned char i; for(i=0;i<32;i++) //循环写32位扩展引脚状态 { LS164_CLK = 0; if(state & 0x80000000) { LS164_DATA = 1; } else { LS164_DATA = 0; } LS164_CLK = 1; state = state<<1; } } /** *************************************************************************************** * 函 数:74LS165读32位扩展引脚函数 * 参 数:无 * 返回值:state:读取的32位数据 *************************************************************************************** */ unsigned long LS165_Read(void) //74LS165读32位扩展引脚函数 { unsigned char i; //计数变量 unsigned long state = 0; //读取的32位数据 LS165_SH_LD = 0; //并行口的8位数据被置入内部的8个触发器 LS165_SH_LD = 1; //并行输入被封锁,移位操作开始 for(i=0;i<32;i++) { state = state<<1; //数据左移1位 if(LS165_DATA) //若引脚为高电平 { state |= 0x01; //最低位置1 } LS165_CLK = 0; LS165_CLK = 1; //上升沿数据移位 } return state; //返回读取的数据 } /** *************************************************************************************** * 函 数:读取当前4个数码管显示的数字 * 参 数:无 * 返回值:无 *************************************************************************************** */ void Tube_Read(void) //读取当前4个数码管显示的数字 { unsigned char i,j; //计数变量 unsigned long state; //32位扩展引脚状态 state = LS165_Read(); //读取所有扩展引脚状态 LED_Num[0] = (unsigned char)(state&0xFF); //扩展引脚EPA0~8状态 LED_Num[1] = (unsigned char)((state>>8)&0xFF); //扩展引脚EPB0~8状态 LED_Num[2] = (unsigned char)((state>>16)&0xFF); //扩展引脚EPC0~8状态 LED_Num[3] = (unsigned char)((state>>24)&0xFF); //扩展引脚EPD0~8状态 for(i=0;i<4;i++) { for(j=0;j<16;j++) { if(LED_Num[i]==tube[j]) //根据引脚状态判断显示的数字 { LED_Num[i] = j; //数码管i+1显示的数字为j break; } } } } /** *************************************************************************************** * 函 数:指定数码管显示指定数字函数 * 参 数:serial:数码管序号,1~4 * 参 数:num:指定显示的数字,0~9 * 返回值:无 *************************************************************************************** */ void Tube_Write(unsigned char serial, unsigned char num) //指定数码管serial显示指定数字num函数 { unsigned long state; //LS164需写的32位扩展引脚状态 if((serial>=1)&&(serial<=4)&&(num>=0)&&(num<=9)) { state = LS165_Read(); //LS165读取当前所有扩展引脚状态 switch(serial) //指定数码管serial { case 1:{ //指定第1个数码管显示数字num state &= 0xFFFFFF00; state |= tube[num]; break; } case 2:{ //指定第2个数码管显示数字num state &= 0xFFFF00FF; state |= (((unsigned long)tube[num])<<8); break; } case 3:{ //指定第3个数码管显示数字num state &= 0xFF00FFFF; state |= (((unsigned long)tube[num])<<16); break; } case 4:{ //指定第4个数码管显示数字num state &= 0x00FFFFFF; state |= (((unsigned long)tube[num])<<24); break; } } LS164_Write(state); //输出所有32位扩展引脚状态 } } /** *************************************************************************************** * 函 数:工程主函数 * 参 数:无 * 返回值:无 *************************************************************************************** */ void main(void) //工程主函数 { unsigned char i,j; //计数变量 LS164_Write(0xFFFFFFFF); //所有数码管灭 LCD1602_Init(); //LCD1602模块初始化 while(1) { for(i=0;i<10;i++) //4个数码管同时循环显示0~9 { for(j=0;j<4;j++) //分别指定4个数码管显示同一数字 { Tube_Write(j+1,i); //指定数码管显示数字 } Tube_Read(); //读取数码管显示的数字 for(j=0;j<4;j++) //在LCD1602中显示 { LCD1602_DispChar(1,j+1,LED_Num[j]+48); //LCD1602指定行列显示字符 } delay_ms(2000); //延时 } } } 3)、lcd1602.h /** *************************************************************************************** * 文 件:LCD1602模块实现头文件 * 创建人:hug567 * 时 间:2018-4-27 *************************************************************************************** */ sbit LCD1602_RS = P2^0; //LCD1602线 sbit LCD1602_RW = P2^1; //LCD1602线 sbit LCD1602_E = P2^2; //LCD1602线 #define LCD1602_DATA P3 //LCD1602模块8位数据线 void LCD1602_isBusy (void); //LCD1602判断忙函数 void LCD1602_WriteCmd (unsigned char); //LCD1602写指令、写显示地址函数 void LCD1602_WriteData (unsigned char); //LCD1602写数据函数 void LCD1602_DispChar (unsigned char,unsigned char,unsigned char); //LCD1602指定行列位置显示字符函数 void LCD1602_Init (void); //LCD1602初始化函数 4)、lcd1602.c /** *************************************************************************************** * 文 件:LCD1602模块实现源文件 * 创建人:hug567 * 时 间:2018-4-27 *************************************************************************************** */ #include "reg52.h" //52系列单片机头文件 #include "delay.h" //延时函数实现头文件 #include "lcd1602.h" //LCD1602实现头文件 /** *************************************************************************************** * 函 数:LCD1602判断忙函数,忙则循环等待 * 参 数:无 * 返回值:无 *************************************************************************************** */ void LCD1602_isBusy(void) //LCD1602判断忙函数 { unsigned char busy; //忙标志 LCD1602_RS = 0; //RS = 0 LCD1602_RW = 1; //RW = 1 LCD1602_E = 0; //E = 0 do{ LCD1602_E = 1; //E = 1 delay_ms(5); //延时5毫秒 busy = LCD1602_DATA & 0x80; //读忙标志 LCD1602_E = 0; //E = 0 }while(busy); //忙则循环等待 } /** *************************************************************************************** * 函 数:LCD1602写指令、写显示地址函数 * 参 数:cmd:要写入的指令或显示地址 * 返回值:无 *************************************************************************************** */ void LCD1602_WriteCmd(unsigned char cmd) //LCD1602写指令、写显示地址函数 { LCD1602_isBusy(); //判断忙,忙则循环等待 LCD1602_RS = 0; //RS = 0 LCD1602_RW = 0; //RW = 0 LCD1602_E = 0; //E = 0 LCD1602_DATA = cmd; //写入指令或显示地址 LCD1602_E = 1; //E = 1 delay_ms(5); //延时5毫秒 LCD1602_E = 0; //E = 0 } /** *************************************************************************************** * 函 数:LCD1602写数据函数 * 参 数:num:要写入的8位数据 * 返回值:无 *************************************************************************************** */ void LCD1602_WriteData(unsigned char num) //LCD1602写数据函数 { LCD1602_isBusy(); //判断忙,忙则循环等待 LCD1602_RS = 1; //RS = 1 LCD1602_RW = 0; //RW = 0 LCD1602_E = 0; //E = 0 LCD1602_DATA = num; //写入数据 LCD1602_E = 1; //E = 1 delay_ms(5); //延时5毫秒 LCD1602_E = 0; //E = 0 } /** *************************************************************************************** * 函 数:LCD1602指定行列位置显示字符函数 * 参 数:x:行,1~2 * 参 数:y:列,1~16 * 参 数:chr:显示的字符,ASCII字符 * 返回值:无 *************************************************************************************** */ void LCD1602_DispChar (unsigned char x,unsigned char y,unsigned char chr) //LCD1602指定行x列y位置显示字符chr函数 { LCD1602_WriteCmd(0x80+0x40*(x-1)+(y-1)); //显示字符位置:第x行第y列 LCD1602_WriteData(chr); //显示指定字符chr } /** *************************************************************************************** * 函 数:LCD1602初始化函数 * 参 数:无 * 返回值:无 *************************************************************************************** */ void LCD1602_Init(void) //LCD1602初始化函数 { LCD1602_WriteCmd(0x38); //显示模式:8位数据接口,两行显示,5*7点阵字符 LCD1602_WriteCmd(0x08); //显示关,光标关,闪烁关 LCD1602_WriteCmd(0x01); //清除DDRAM,清除AC(清屏) LCD1602_WriteCmd(0x06); //读数据后AC自动加1,读数据后画面不动 LCD1602_WriteCmd(0x0c); //显示开,光标关,闪烁关 } 5)、delay.h /** *************************************************************************************** * 文 件:延时函数实现头文件 * 芯 片:AT89S52 * 晶 振:12MHz * 创建人:hug567 * 时 间:2018-4-27 *************************************************************************************** */ void delay_ms(unsigned long t); //延时ms函数 6)、delay.c /** *************************************************************************************** * 文 件:延时函数实现源文件 * 芯 片:AT89S52 * 晶 振:12MHz * 创建人:hug567 * 时 间:2018-4-27 *************************************************************************************** */ #include "delay.h" //延时函数实现头文件 /** *************************************************************************************** * 函 数:延时ms函数 * 参 数:t:延时ms值,0~4294967295 * 返回值:无 *************************************************************************************** */ void delay_ms(unsigned long t) //延时ms函数 { unsigned char i; //计数变量 for(;t>0;t--) for(i=200;i>0;i--); //不精确,此处循环值需测试 } 4、程序下载地址: 1)、74LS164、74LS165实现I/O扩展的C程序:https://download.csdn.net/download/qtyt567/10377537 2)、74LS164、74LS165实现I/O扩展的Proteus程序:https://download.csdn.net/download/qtyt567/10377540 |
|