51单片机模拟串口控制lcd12864,显示不完全求解

问题在主函数里有说明,实在不知道是为什么了
百度坑爹的字数限制只能把程序改得好难看····

/**LCD12864-ST7920控制器-并口程序
//-- 04 -- RS(CS) -- 片选,L有效 -- P2^0
//-- 05 -- R/W(SID) -- 串数据线 -- P2^1
//-- 06 -- E(SCLK) -- 串时钟输入 -- P2^2
//--晶振11.0592MHs
********/
#include<reg52.h>

//--宏定义
#define uchar unsigned char
#define uint unsigned int

//--单片机I/0口声明
sbit CS=P2^0; //片选,每次数据操作时必须拉高
sbit SID=P2^1; //串数据线
sbit SCLK=P2^2; //串时钟输入

//--函数声明
void LCD_init(void); //LCD_初始化
void T0_init(void); //定时器_初始化
void I_com(uchar com); //写指令
void I_data(uchar _data); //写数据
void O_bit_8(uchar _bit); //输出8bit
void delay(uint i); //延时

//--全局变量
uchar x=1; //时钟频率H/L值

//--主函数
void main(void)
{
uchar i=0; //循环输出
uchar code a[]="01234567"; // 7没有显示,6在反白里
T0_init(); //T0初始化
LCD_init(); //LCD初始化

I_com(0x80); //地址定位
for(i=0;a[i]!='\0';++i)
{
I_data(a[i]);
}
while(1); /*将这个循环改为整个语句循环放倒“地址定位”处就没有问题了但一直循环输出,纠结 */
}

//--LCD_初始化
void LCD_init(void)
{
delay(40); //延时40ms 稳定液晶
I_com(0x30); //基本指令,8位数据
delay(1);
I_com(0x02); //地址归位
delay(1);
I_com(0x01); //清屏
delay(1);
I_com(0x0F); //显示开,游标开,反白开
delay(1);
}

//--定时器_初始化
void T0_init(void)
{
TMOD=0x02; //T0工作方式2 8位初值自填装

TH0=0xA0; //|-T0初始化 160 晶振11.0592下 仿波特率9600bps
TL0=0xA0; //|
EA=1;
TF0=0; //T0溢出位 溢出硬置1
}

//--写指令
void I_com(uchar com)
{
x=1; //时钟频率H/L值
CS=1; //片选置1 允许数据操作
TR0=1; //启动TO

O_bit_8(0xF8); //输出写指令 指令

O_bit_8(com&0xF0); //输出指令低4位
O_bit_8((com&0x0F)<<4); //输出指令低4位

CS=0; //片选置0 不允许数据操作
TR0=0; //停止T0
}

//--写数据
void I_data(uchar _data)
{
x=1; //时钟频率H/L值
CS=1; //片选置1 允许数据操作
TR0=1; //启动TO

O_bit_8(0xFA); //输出写数据 指令

O_bit_8(_data&0xF0); //输出数据低4位
O_bit_8((_data&0x0F)<<4); //输出数据低4位

CS=0; //片选置0 不允许数据操作
TR0=0; //停止T0
}

//--输出8bit
void O_bit_8(uchar _bit)
{
uchar i=0; //循环输出DIS

while(i!=8)
{
if(TF0==1)
{
TF0=0; //T0溢出位软置0 (溢出时硬置1)
if((SCLK=x=!x)==0) //输出时钟脉冲,并判断脉冲是否为低且T0溢出
{
SID=(bit)( ( ( (_bit<<i) & 0x80) )==0?0:1); //_bit最高位传输
i++; //传输计数,8次则结束大循环
}
}
}
}

//--延时
void delay(uint i) //- 11.0592情况下 延时995.01us 约1ms
{
uint j=0;
for(i;i>0;i--)
for(j=113;j>0;j--);
}
把主函数中的
I_com(0x80); //地址定位
for(i=0;a[i]!='\0';++i)
{
I_data(a[i]);
}
while(1);

改为
while(1)
{
I_com(0x80); //地址定位
for(i=0;a[i]!='\0';++i)
{
I_data(a[i]);
}
}
这样程序最后的一个字符就会输出,但因为频率问题屏幕一闪一闪,很不爽,
最后问题是在void O_bit_8(uchar _bit)函数,很傻瓜得改成
void O_bit_8(uchar _bit)
{
uchar i=0; //循环输出DIS

for(i=0;i<8;i++)
{
SID=(bit)( (_bit<<i) & 0x80); //_bit最高位传输
SCLK=x=!x; //输出时钟脉冲
while(!TF0);
TF0=0;
SCLK=x=!x; //输出时钟脉冲
}
}
就对了,但还是不知道为什么我照上面那样写会错误····
第1种代码:单片机运行到while(1);这条语句后就不会往下走了,一直在这里死循环,运行空语句。就不会给液晶送数据了。
第2种代码:单片机运行到while(1)后会往下执行,进入while循环,循环的给液晶送数据。循环的输出。就是有分号和没分号的区别。
如果没有把while(1);语句放在末尾还是会循环输出,因为在循环的执行main函数。
交流与联系加我扣扣,我账号里的数字是扣扣号。
第1种代码:
---------------------------------------------------------------------------------------------------------------------
void main(void)
{
uchar i=0; //败升循环输出
uchar code a[]="01234567"; // 7没有显示,6在反白里
T0_init(); //T0初始化
LCD_init(); //LCD初始化

I_com(0x80); //地址定位
while(1); /腊枯好*将这个循环改为整个语句循环放倒“地址定位”处就没有问题了但一直循环输出,纠结 */
for(i=0;a[i]!='\0';++i)
{
I_data(a[i]);
}
}
-----------------------------------------------------------------------------------------------------------------------第2种轮铅代码:
void main(void)
{
uchar i=0; //循环输出
uchar code a[]="01234567"; // 7没有显示,6在反白里
T0_init(); //T0初始化
LCD_init(); //LCD初始化

I_com(0x80); //地址定位
while(1) /*将这个循环改为整个语句循环放倒“地址定位”处就没有问题了但一直循环输出,纠结 */
for(i=0;a[i]!='\0';++i)
{
I_data(a[i]);
}
}
其实,问题很简单。
1、你的目的:输出八位后,保持不变,不用再次输出
2、根据你的目的,你并不需要对时钟中断进行复数誉位。由于复位薯谨段,晌旁导致屏幕闪烁。而在后面程序中,你去掉了软件复位,就解决问题了