单片机串行口与74LS164的正确配合使用方法

在单片机系统中,如果并行口的io资源不够,那么我们可以使用74ls164来扩展并行io口,节约单片机io资源。74ls164是一个串行输入并行输出的移位寄存器,并带有清除端。
时序分析,单片机串行口时序单片机串行口作显示端口时应工作在方式发送状态,其时序如图所示。从时序图中可以看出,当一个数据输入到串行口发送缓冲器sbuf时,串行口将8位数据以fosc/12的波特率从低位到高位(即从d0~d7)依次通过rxd引脚输出,当位发送完以后,中断标志ti置“1”,结束一个发送过程。这里应当注意的是串行口物出一个字节数字的次序,它是单片机串行口与74ls164正确配合的关键所在。
图2所示为8位串行输入、并行输出移位寄存器74ls164的工作时序。从图2中我们可以看出,使能端b(引脚2)为低电平时,寄存器禁止输入数据,当b为高电平时,数据可以从a端(引脚1)输人。图2中表明,先输入的数据首先qa从(引脚3)输出。当寄存器74ls164接收完8位数据时,先输入的1位移至q(引脚13)输出,而qa端输出的则是最后接收到的1位。
软件与硬件的正确配合 从以上对单片机串行口及74ls164的时序分析可知,移位寄存器首先块收到单片机串行口输出的最低位d0。,最后接收到该字节的最高位d7。因此,当接收完8位数据后,移位寄存器qh端输出的是d0。,而qa输出的是d7。以上谈到的两文中所出现的错误原因,就是忽视了这一重要特点。他们给出的硬件电路如图3所示。字形代码及真值表如表所示。
从表1可以看出,字形代码把段码a当作d0位,把段码h当作d7位依次对应。在移位寄存器接收到一个完整的字形码时,qa输出的不是段码a,而是段码h(h为小数点,也可不接。)这样处理的结果,使输出的段码次序刚好相反,所以,显示出的字形就不对了。表1右侧列出了(h连小数点时的)错显字形。若要显示正确字形,在使用图3所示电路时字形码应做调整,调整后的字形代码和真值表如表2所示。这种字形码输入到74ls164内时,在其输出脚qa~qh上依次输出段码a~h,从而正确显示出要显示的内容。
在某些场合,设计者仍想使用表1所列的字形码,那么只需把显示器与74ls164的连接做一调整即可。硬件电路如图4所示
通过对单片机串行口和74ls164时序的分析,给出了两种正确的软件与硬件组合方法。笔者在研制成功的智能离心开关断开测速仪中利用表2所列的字形码与图3所示硬件相配合,使用结果令人满意。另外,有的设计中也可能遇到8位并入串行输出移位寄存器74ls165与单片机串行口的配合间题,其研究方法仍然应从时序入手,与本文所介绍方法类同,此不赘述
proteus仿真图和代码附上。
#include《reg51.h》
#define high 1
#define low 0
#define seg_port p0
sbit data = p0^4;
sbit clk = p0^5;
unsigned char timer0irqevent = 0;
unsigned char time1secevent = 0;
unsigned int timecount = 0;
unsigned char segcurposition = 0;
code unsigned char segcode[10] = {~0x3f,~0x06,~0x5b,~0x4f,~0x66,~0x6d,~0x7d,~0x07,~0x7f,~0x6f};
code unsigned char segposition[4] = {0xfe,0xfd,0xfb,0xf7};
unsigned char segbuf[4] = {0};
void ls164_data(unsigned char x)
{
if(x)
{
data = 1;
}
else
{
data = 0;
}
}
void ls164_clk(unsigned char x)
{
if(x)
{
clk = 1;
}
else
{
clk = 0;
}
}
/**********************************************************
*函数名称:ls164send
*输 入:byte单个字节
*输 出:无
*功 能:74ls164发送单个字节
***********************************************************/
void ls164send(unsigned char byte)
{
unsigned char j;
for(j=0;j《=7;j++)
{
if(byte&(1《《(7-j)))
{
ls164_data(high);
}
else
{
ls164_data(low);
}
ls164_clk(low);
ls164_clk(high);
}
}
/**********************************************************
*函数名称:segrefreshdisplaybuf
*输 入:无
*输 出:无
*功 能:数码管刷新显示缓存
***********************************************************/
void segrefreshdisplaybuf(void)
{
segbuf[0] = timecount%10;
segbuf[1] = timecount/10%10;
segbuf[2] = timecount/100%10;
segbuf[3] = timecount/1000%10;
}
/**********************************************************
*函数名称:segdisplay
*输 入:无
*输 出:无
*功 能:数码管显示数据
***********************************************************/
void segdisplay(void)
{
unsigned char t;
seg_port = 0x0f;
t = segcode[segbuf[segcurposition]];
ls164send(t);
seg_port = segposition[segcurposition];
if(++segcurposition 》= 4)
{
segcurposition = 0;
}
}
/**********************************************************
*函数名称:timerinit
*输 入:无
*输 出:无
*功 能:定时器初始化
***********************************************************/
void timerinit(void)
{
th0 = (65536 - 5000)/256;
tl0 = (65536 - 5000)%256;
tmod = 0x01;
}
/**********************************************************
*函数名称:timer0start
*输 入:无
*输 出:无
*功 能:定时器启动
***********************************************************/
void timer0start(void)
{
tr0 = 1;
et0 = 1;
}
/**********************************************************
*函数名称:portinit
*输 入:无
*输 出:无
*功 能:i/o初始化
***********************************************************/
void portinit(void)
{
p0 = p1 = p2 = p3 = 0xff;
}
/**********************************************************
*函数名称:main
*输 入:无
*输 出:无
*功 能:函数主题
***********************************************************/
void main(void)
{
portinit();
timerinit();
timer0start();
segrefreshdisplaybuf();
ea = 1;
while(1)
{
if(timer0irqevent)
{
timer0irqevent = 0;
if(time1secevent)
{
time1secevent = 0;
if(++timecount 》= 9999)
{
timecount = 0;
}
segrefreshdisplaybuf();
}
segdisplay();
}
}
}
/**********************************************************
*函数名称:timer0irq
*输 入:无
*输 出:无
*功 能:定时器中断函数
***********************************************************/
void timer0irq(void) interrupt 1
{
static unsigned int cnt = 0;
th0 = (65536 - 5000)/256;
tl0 = (65536 - 5000)%256;
timer0irqevent = 1;
if(++cnt 》= 200)
{
cnt = 0;
time1secevent = 1;
}
}

晶闸管投切电容器的触发电路
哈工大的史诗级成果:DPP-EUV光源
汽车智能座舱的HDMI信号高速接口测试和仿真
十家AR眼镜来势汹汹,谷歌会被后来者居上吗
极进网络(Extreme Networks )Extreme VDX 6940 交换机光模块配置方案
单片机串行口与74LS164的正确配合使用方法
永磁同步电动机无传感器控制技术综述
天津市进一步支持发展智能制造的政策措施
热点分享|新型工业化成为中国经济发展领域的高频热词
特斯拉自动驾驶量产仍面临挑战
一种具有AI人脸识别功能的红外热成像测温仪
实测苹果iPhone 12系列兼容主流PD充电器
台达存储系统新应用,创新电源混合独立式电源系统
韩国研究人员提出以硫化铜为电极材料 可延长钠离子电池可循环性
基于DSP的光纤高温测量仪的软件设计
肖特基和快恢复二极管区别
深度学习低光图像增强综述(译)
苹果A13性能强悍,表现超越目前所有的智能手机芯片!
PCB电路板设计的基本流程介绍
逆功率保护装置实际案例分析