① 8051单片机IO口不够用,又不想用IO扩展芯片,怎么办
使用串行方式驱动液晶只需要3个IO口这是程序
/****************************************************************************/
/***************************12864LCD驱动程序*********************************/
/*****连接关系: ********************************************************/
/**** CS----->PA0 ********************************************************/
/**** SID---->PA1 ********************************************************/
/**** CLK---->PA2 ********************************************************/
/****************************************************************************/
/****创建日期:2009.8.21*****************************************************/
/********作者:孙嘉瑞 *****************************************************/
/****************************************************************************/
#include"LCD12864.H"
#define LCDDELAY Delay_1us(10)
/*向LCD写一字节数据*/
void WriteLcdByte( byte date )
{
byte i = 0;
byte temp = 0;
SIDOUT;
CLKOUT;
CSOUT;
LCDDELAY;
for(i = 0;i<8;i++)
{
temp = date&(1<<(7-i));
if(temp)
{
SIDH;
}
else
{
SIDL;
}
CLKL;
LCDDELAY;
CLKH ; //产生上升沿,锁存数据
LCDDELAY;
}
}
/*从LCD读取一字节数据*/
byte ReadLcdByte()
{
byte Ret = 0;
byte i;
SIDIN;
CLKH;
for(i = 0;i < 8;i++)
{
CLKL ; /*产生下降沿,输出一位数据*/
LCDDELAY;
if(SIDSTA)
{
Ret|=1<<(7-i);
}
else
{
Ret&=~(1<<(7-i));
}
CLKH;
LCDDELAY;
}
return Ret;
}
/*读忙标志*/
byte BusyCheck(void)
{
byte temp = 0;
byte ldata = 0;
byte hdata = 0;
CSH;
LCDDELAY;
WriteLcdByte(RLCDDAT);
hdata = ReadLcdByte();
ldata = ReadLcdByte();
CSL;
LCDDELAY;
temp = hdata&(1<<7);
return (temp);
}
/*写LCD命令*/
void WriteComd(byte data)
{
byte ldata = 0;
byte hdata = 0;
while(BusyCheck());
ldata = data<<4; //数据的低四位
hdata = data&0xf0; //数据的高四位
CSL;
LCDDELAY;
CSH;
LCDDELAY;
WriteLcdByte(WLCDCOM);
WriteLcdByte(hdata);
WriteLcdByte(ldata);
CSL;
LCDDELAY;
}
/*写LCD数据*/
void WriteData( byte data )
{
byte ldata = 0;
byte hdata = 0;
while(BusyCheck());
ldata = data<<4; //数据的低四位
hdata = data&0xf0; //数据的高四位
CSL;
LCDDELAY;
CSH;
LCDDELAY;
WriteLcdByte(WLCDDAT);
WriteLcdByte(hdata);
WriteLcdByte(ldata);
CSL;
LCDDELAY;
}
/*液晶初始化*/
void LcdInit(void)
{
WriteComd(0x30);//0x30
WriteComd(0x04);
WriteComd(0x0C);
WriteComd(0x01);
WriteComd(0x02);
WriteComd(0x80);
}
/*写入若干字节*/
void WritenByte(byte *p,byte lengh)
{
while(lengh--)
{
WriteData(*p);
p++;
}
}
/*************************************************/
/*****功能:设定显示的坐标 ******************/
/*入口参数:row: 1-4 选择行坐标******************/
/**********line: 1-1选择列坐标********************/
/*************************************************/
unsigned char LcdSetxy(byte row,byte line)
{
//坐标选择
if(row>=1&&row<=4&&line>=1&&line<=16)
{
switch(row)
{
case 1: WriteComd(0x80+line-1);break;
case 2: WriteComd(0x90+line-1);break;
case 3: WriteComd(0x88+line-1);break;
case 4: WriteComd(0x98+line-1);break;
}
return 1;
}
else
{
return 0;
}
}
/*************************************************/
/*功能:在液晶的任意位置写入单个字符******************/
/*入口参数:row : 1-4 选择要显示的行**************/
/***********line: 1-16 选择要显示的列**************/
/*********** data: 要显示的字符************/
/*************************************************/
void WriteCode( byte row,byte line,byte data)
{
byte checkerr = 0;
checkerr = LcdSetxy(row, line);
if(checkerr) //坐标正确设定
{
WriteData( data);
}
else //坐标错误
{
WriteComd(ClearScreen);
WriteComd(0x80);
WritenByte("坐标输入错误!!",15);
}
}
/*************************************************/
/*功能:在液晶的任意位置写入字符串******************/
/*入口参数:row : 1-4 选择要显示的行**************/
/***********line: 1-16 选择要显示的列**************/
/*********** *P: 要显示的字符串的指针************/
/*************************************************/
void WriteString( byte row,byte line,byte *p)
{
byte checkerr = 0;
byte length = 0;
length = strlen(p); //计算字符串的长度
checkerr = LcdSetxy(row, line);
if(checkerr) //坐标正确设定
{
WritenByte(p, length);
}
else //坐标错误
{
WriteComd(ClearScreen);
WriteComd(0x80);
WritenByte("坐标输入错误!!",15);
}
}
/*************************************************/
/*功能:在液晶的任意位置写入整形数据**************/
/*入口参数:row : 1-4 选择要显示的行**************/
/***********line: 1-8 选择要显示的列**************/
/*********** num: 要显示的整形数字***************/
/*************************************************/
void WriteInteger( byte row,byte line, word num )
{
byte checkerr = 0;
byte tab[5];
byte i = 0;
//取出各位数字
tab[0] = num / 10000;
tab[1] = num / 1000 % 10;
tab[2] = num / 100 % 10;
tab[3] = num % 100 / 10;
tab[4] = num % 10;
checkerr = LcdSetxy(row, line);
if(checkerr) //坐标正确设定
{
for(i = 0;i<5;i++)
{
WriteData(tab[i]+48);
}
}
else //坐标错误
{
WriteComd(ClearScreen);
WriteComd(0x80);
WritenByte("坐标输入错误!!",15);
}
}
void Dispicture(byte *str)
{
byte i = 0;
byte j = 0;
WriteComd(ClosPict);
for(i = 0;i<32;i++)
{
WriteComd(0x80+i);
WriteComd(0x80);
for(j = 0;j<16;j++)
{
WriteData(str[16*i+j]);
}
}
for(i = 0;i<32;i++)
{
WriteComd(0x80+i);
WriteComd(0x88);
for(j = 0;j<16;j++)
{
WriteData(str[16*32+16*i+j]);
}
}
WriteComd( OpenPict ); //关闭绘图显示);
}
② 有没有什么单片机有200个io的
单片机IO口不够用,有如下解决办法:
1 IO口扩展:
扩展的方法很多,锁存器;输出串并转换/输入并串转换;I²C总线等等……
不过公子一般都是喜欢采用138或者164来扩展的,以138为例,
这款芯片的作用是把串行输入的数据并行输出。注意,它没有锁存功能,在允许输出的情况下,每一个时钟的上升沿,数据依次从最低位移向最高位。因此,在做数码管的输出显示的时候会出现拖影的想象,下面我们再看看它的真值表,有了真值表才知道如何正确的去编写程序去驱动它(其它复杂的器件还需要对照时序图编写相应的驱动程序)。
当Reset为低电平时不管时钟为高电平还是低电平也不管输入引脚A1,A2为何值,输出的并行数据均为低电平。当Reset为高电平时,只有在时钟的上升沿,A1A2上的值才被移位输出。
2 再接一个单片机:
当一个单片机的引脚不够的时候,需要在外接一个单片机就可以了,让两个单片机的TXD与RXD相连就可以了,不过,如果是两块单片机同时处理一个传感器(比如说:摄像头,TFT LCD),那么你需要考虑时序的问题,特别是当两块单片机的处理速度不一样的时候,这个需要特别注意。
3 端口复用与重映射:
在学习STM32的时候,那么以STM32为例。
端口复用
STM32用很多内置外设而且都是和GPIO复用的,也就是GPIO可以设置成一些常用的外设如串口的外设等等,数据手册有详细说明,需要时就查表。
GPIO作为内置外设使用时就叫复用,也就是图中的默认复用功能,不把GPIO口当作单纯的I/O口而是赋予它一个外设的含义。
端口重映射
端口重映射通过设置重映射寄存器的方式,把这个外设的接口映射到其它的端口,方便PCB布线,虚拟增加外设。
复用功能串口1是PA9 PA10,但是如果我们觉得PB6 PB7更方便是就可以重映射使用这两个I/O口,重映射还分完全重映射和部分重映射,完全重映射就是功能外设的所有引脚都全部映射,如果映射串口,那么串口所有相关外设都映射到,这就是完全重映射,否则只映射部分需要的就是部分重映射。
③ 当单片机的i/o口不够时,如何运用74LS164,使单片机的信号可以在数码管中显示
在数码管动态显示电路中,74LS164的A、B接单片机的串行数据发送,CLK接串行时钟输出,MR接+5V,Q0—Q7接数码管的字段,则可将单片机的8根段选线简化为二根串口线;如果是显示用8位数码管,则还可再用一片74LS164作为位选,用法同上,只是这时Q0—Q7接8个数码管的位选线(公共端)。
另外如果将N片74LS164级联,还可实现N位数码管的静态显示。
④ 单片机的4个并行I/O端口不够用时,有哪些扩展方法
单片机的I/O端口扩展方法有锁存器扩展,串行口转并行口扩展,专用芯片扩展。