27,508
社区成员




#include <reg52.h>
#define uchar unsigned char
uchar xdata volatile TEST _at_ 0xff00
void main(void)
{
P2 = 0x20;
TEST = 0x00; //TEST _at_ 0xff00
//上面一句执行完后P2口的输出是多少? 0xff or 0x20 ?
//如果是 0x20,是怎么实现的?执行 TEST = 0x00的时候 MOV DPH,#0ffh ;MOV DPL,#00h,
// CLR A,然后,MOVX @DPTR,A,执行 MOVX @DPTR,A的时候 P2输出为0xff
//但是执行完后怎么又成了 0x20了? 0x20是我用proteus 仿真的结果,不解?
//要使这样的话,P2口可以即作地址总线,同时做IO口,比如控制1602的引脚RS,WR,
//只是中间 会有数据晃一下 ,只要保证1602的 E (用非P2口控制)引脚在执行MOVX @DPTR,A前后一直
//都为低电平 就行 ?可以这样吗?
while(1);
}
#include "smallPLCmaster.h"
void main(void)
{
uchar idata test[] = "myname";
while(busyP0P2);
init1602();
putString1602(0,&test);
while(1);
}
#include <reg52.h>
#define uchar unsigned char
/*************************全局变量定义*************************/
bit busyP0P2; //P0P2口总线状态标志,使用总线前必须先检测此标志
//此标志位0,方可使用,此标志在使用到总线的子函数中进入处置1,结束处清0
/******************************end*****************************/
/****************************functions define********************/
#include "LCD1602.h"
#include "IO8255.h"
#include "ADC0808.h"
#include "uart.h"
/*******************************end******************************/
/****************************P0P2口地址定义**************************/
uchar volatile xdata LCDbusyRd _at_ 0xf8fe; //1602忙碌状态读取地址 ,高位f8为LCD片选
uchar volatile xdata LCDcmdWr _at_ 0xf8fc; //1602写命令 地址
uchar volatile xdata LCDdatWr _at_ 0xf8fd; //1602写数据 地址
uchar volatile xdata LCDdatRd _at_ 0xf8f8; //1602数据读 地址
/********************************end**********************************/
/***************************1602命令定义******************************/
#define cmd0 0x08 //
#define cmd0DISPLAYOFFand 0xfb //显示关
#define cmd0DISPLAYONor 0x04 //显示开
#define cmd0CURSOROFFand 0xfd //光标关
#define cmd0CURSORONor 0x02 //光标开
#define cmd0CURSORFLASHOFFand 0xfe //光标不闪烁
#define cmd0CURSORFLASHONor 0x01 //光标闪烁
#define cmd1 0x40
#define cmd1SCREENROLLor 0x08 //屏幕滚动
#define cmd1CURSORROLLand 0xf7 //光标滚动
#define cmd1ROLLRIGHTor 0x04 //向右滚动
#define cmd1ROLLLEFTand 0xfb //向左滚动
#define cmd2 0x00
#define cmd2ACUPor 0x02 //AC自动加1
#define cmd2ACDOWNand 0xfd //AC自动减1
#define cmd3CLEAR 0x01 //清除屏幕
#define cmd4ACRESET 0x02 //AC归0
#define addDDRAMBASE 0x80 //DDRAM基地址
/*********************************end**********************************/
/************************1602***functions******************************/
//delay5ms() 1602等待busy flag 变为0需要5ms
void delay5ms(void)
{
uchar i;
uchar j;
i = 255;
while(i--){
j = 20;
while(j--);
}
}/********end delay5ms()*/
//BusyRd1602() 1602忙碌状态读取,返回0时不忙碌
uchar BusyRd1602(void) //没有操作P0P2总线标志,不可在main中调用
{
LCDbusyRd = 0xff;
return LCDbusyRd & 0x80;
}/*******end BusyRd1602()***/
//init1602
void init1602(void)
{
busyP0P2 = 1; //将P0P2总线置为忙碌
LCDcmdWr = 0x38;
delay5ms();
LCDcmdWr = 0x38;
delay5ms();
LCDcmdWr = 0x38;
delay5ms();
LCDcmdWr = 0x38;
delay5ms();
LCDcmdWr = cmd0 & cmd0DISPLAYOFFand; //关闭显示
delay5ms();
LCDcmdWr = cmd3CLEAR; //清除屏幕
delay5ms();
LCDcmdWr = cmd0 | cmd0DISPLAYONor &cmd0CURSOROFFand;//显示开,光标关
busyP0P2 = 0; //释放P0P2总线
}/******end init1602()****/
//putString1602() 在1602屏幕上显示以'\0'结尾的字符串
//IN:startPos,开始位置0~31
//IN: uchar idata *pString,字符指针
void putString1602(uchar startPos,uchar idata *pString)
{
busyP0P2 = 1; //总线忙碌置标
LCDcmdWr = addDDRAMBASE + startPos; //写第一行地址
for( ; *pString != '\0'; pString++,startPos++)
{
if(startPos > 15)
break;
LCDdatWr = *pString;
delay5ms();
}
LCDcmdWr = addDDRAMBASE + (startPos-16) + 0x40;//写第二行地址
for(; *pString != '\0'; pString++, startPos++)
{
if(startPos > 31)
break;
LCDdatWr = *pString;
delay5ms();
}
busyP0P2 = 0; //总线忙碌清除
}/***********end putString1602()***************/