介绍单片机驱动控制液晶显示器(带触摸屏)的控制系统设计实例,支持modbus通讯协议,采用的是51单片机,驱动控制19寸液晶显示器(可以是15寸,17寸,19寸,30寸,52寸,55寸显示器或电视机)。支持单片机TTL电平串口,RS232串口,RS485串口,以太网连接. 液晶显示控制器系统软件使用人机界面组态软件HMImaker开发,主要有操作画面、参数设置画面、参数修改、系统登录画面、状态监控画面等功能,界面可以自由设计开发,组态软件开发显示与操作界面,“0”编程、"所见即所得"、"0"代码、如"制作PPT"一样简单,快速!。 本设计以51单片机作为LCD液晶显示系统控制器为主线,基于单片机8051,采用单片机的C语言来进行软件设计,指令的执行速度快,节省存储空间。为了便于扩展和更改,软件的设计根据单片机的串口通信协议(易显单片机协议),支持modbus通讯协议。采用模块化结构,使程序设计的逻辑关系更加简洁明了。使硬件在软件的控制下协调运作。其次阐述了部分程序的流程图和实现过程。本文撰写的主导思想是软、硬件相结合,以硬件为基础,来进行各功能模块的编写。以下对所开发的用单片机实现LCD液晶显示器控制原理的设计思想和软、硬件调试作了详细的论述。 以下是单片机8051的通讯协议和程序介绍: //定义数据类型(可以是数据结构) //************************************************************* voidInitUART(void) //串口初始化使用22.1184M晶体 { SCON= 0x50; //选择模式1,8位数据格式,使能UART PCON|= 0x80; //波特率加倍 TMOD=TMOD| 0x20; //定时器1:模式2 ,自动装载初值 //波特率计算公式:TH1=TL1=256-(2*22.1184*1000000)/(32*12*baud) //若选115200波特率则TH1=TL1=256-(2*22.1184*1000000)/(32*12*115200)=0xff //若选19200波特率则TH1=TL1=256-(2*22.1184*1000000)/(32*12*19200)=0xfa TH1= 0xfa; TL1= 0xfa; TR1 = 1; //定时器1计数使能 REN = 1; //允许串口接受使能 } /* ****************************************************************** * 名称: write_byte() * 功能: 向串口发送一个字节的数据 * 入口参数:i为待发送的字节数据 ****************************************************************** */ voidUART_SendByte(unsigned char i) { SBUF=i; //发送本次数据 while(TI==0){}//等待发送完毕 TI=0; } #define m_ReadVarAdr 48 //类型:unsignedint 初始值:40 解释:待读 变量地址 #define m_WriteAdr 52 //类型:unsignedint 初始值:28 解释:待写变量地址 /////////////////////////////////本文件如有不明白的地方,咨询热线:13829764765. QQ:252631158 ///////// ////////////////////////////////////////////////////////////////////////////////// //unsigned int adr表示需要设置的HMI变量的地址, //unsigned shortnBytes表示需要设置的HMI变量占一个字节的空间,如果是int变量就占4个字节,如果是short变量就占2个字节,如果是char变量就占1个字节 //unsigned char*m_VarP表示你要设置的HMI变量数据源的的指针,指针所指向的内容就是在HMI变量的将要被设置成的内容 //小技巧:有的时候希望通过调用一次SetVariable一次性设置3个int变量的HMI变量,只要这3个int变量的地址是连续的,那么只要让nBytes=3*4=12个字节就OK voidSetVariable(unsigned int adr,unsigned short nBytes,unsigned char *m_VarP) { unsigned char temp; unsigned short m_CheckCRC;//命令校验 UART_SendByte(0x81); //开始,固定,一个字节 UART_SendByte(0x0); //命令类型,设置变量 UART_SendByte(0x2); //接收方的设备号 m_CheckCRC=0x81+0x0+0x2;//前面三个字节的校验和 temp=adr&0xff; UART_SendByte(temp); //地址1 m_CheckCRC=m_CheckCRC+temp;//每发送一个字节,计算一次校验和 temp=(adr>>8)&0xff; UART_SendByte(temp); //地址2 m_CheckCRC=m_CheckCRC+temp; temp=0; UART_SendByte(temp); //地址3 固定为0 m_CheckCRC=m_CheckCRC+temp; temp=0; UART_SendByte(temp); //地址4 固定为0 m_CheckCRC=m_CheckCRC+temp; temp=(nBytes)&0xff; UART_SendByte(temp); //个数低8位 m_CheckCRC=m_CheckCRC+temp; temp=(nBytes>>8)&0xff; UART_SendByte(temp); //个数高8位 m_CheckCRC=m_CheckCRC+temp; while(nBytes!=0) { temp=*m_VarP; UART_SendByte(temp); m_CheckCRC=m_CheckCRC+temp; nBytes--; m_VarP++; } UART_SendByte(m_CheckCRC); UART_SendByte(m_CheckCRC>>8); } //unsigned int adr表示需要查询的HMI变量的地址, //unsigned shortnBytes表示需要查询的HMI变量占多少个字节的空间,如果是int变量就占4个字节,如果是short变量就占2个字节,如果是char变量就占1个字节 //小技巧:有的时候希望通过调用一次ReadVariable一次性读取3个int变量的HMI变量,只要这3个int变量的地址是连续的,那么只要让nBytes=3*4=12个字节就OK voidReadVariable(unsigned int adr,unsigned short nBytes) { unsigned char temp; unsigned short m_CheckCRC;//命令校验 UART_SendByte(0x81); //开始,固定,一个字节 UART_SendByte(0x1); //命令类型,查询变量 UART_SendByte(0x2); //接收方的设备号 m_CheckCRC=0x81+0x1+0x2;//前面三个字节的校验和 temp=adr&0xff; UART_SendByte(temp); //地址1 m_CheckCRC=m_CheckCRC+temp; //每发送一个字节,计算一次校验和 temp=(adr>>8)&0xff; UART_SendByte(temp); //地址2 m_CheckCRC=m_CheckCRC+temp; temp=0; UART_SendByte(temp); //地址3 固定为0 m_CheckCRC=m_CheckCRC+temp; temp=0; UART_SendByte(temp); //地址4 固定为0 m_CheckCRC=m_CheckCRC+temp; temp=(nBytes)&0xff; UART_SendByte(temp); //个数低8位 m_CheckCRC=m_CheckCRC+temp; temp=(nBytes>>8)&0xff; UART_SendByte(temp); //个数高8位 m_CheckCRC=m_CheckCRC+temp; UART_SendByte(m_CheckCRC); UART_SendByte(m_CheckCRC>>8); } unsigned char mIndex=0; //定义一个数据索引 unsigned charmCmdAdrBuf[4]; //定义一个缓冲区用于缓冲HMI变量地址 unsigned charmCmdnBytesBuf[2]; //定义一个缓冲区用于缓冲HMI变量字节数量 unsigned charmHmiVarBuf[4]; //定义一个缓冲区用于缓冲HMI变量m_ReadVarAdr内容,因为该变量是4个字节的int变量 unsigned charmHmiVarCheck[2]; unsigned charmReceiveFlag=0; //串口中断成功接收到一个HMI变量设置命令标志 unsigned charmState=0; //命令接收状态 unsigned shortmCheckHe; unsigned intdelay=0;//延时变量 void main(void) { InitUART(); EA=1; //打开中断总开关, ES=1; //打开串口中断 //ET0=1;//打开定时器中断,每隔50MS中断一次 while(1) //进入不断循环 { delay++; if(delay>=65535)//延时一段时间(300MS), { delay=0; ReadVariable(m_ReadVarAdr,4);//读取HMI变量命令发出去。本例子中m_ReadVarAdr的地址是48,是一个unsigned int 变量,占4个字节 } if(mReceiveFlag==1)//如果接收到数据 { mReceiveFlag=0; SetVariable(m_WriteAdr,4,mHmiVarBuf); } } } unsigned charbufcom1; void uart(void)interrupt 4 { if(RI==0) return; RI=0; bufcom1=SBUF;//读串口一的上的数据 if(mState==0)//阶段0,等待接收0x81,命令开始 { mCheckHe=0x81; if(bufcom1==0x81)//如果收到0x81,就进入阶段1 { mState=1; } else mState=0;//接收错误,跳回阶段0 } else if(mState==1)//阶段1,等待接收0x0,是否是工控机发过来的“设置变量命令” { mCheckHe=mCheckHe+bufcom1; if(bufcom1==0x0)// 是工控机发过来的“设置变量命令”,就进入阶段2 { mState=2; } else mState=0;//接收错误,跳回阶段0 } else if(mState==2) //阶段2,等待接收0x2,是否是工控机发过来的设备号 { mCheckHe=mCheckHe+bufcom1; if(bufcom1==0x2) { mState=3; mIndex=0;// 先清0索引,为阶段3做准备 } else mState=0; //接收错误,跳回阶段0 } else if(mState==3) //阶段3,等待接收地址,4个字节 { mCheckHe=mCheckHe+bufcom1; mCmdAdrBuf[mIndex]=bufcom1; mIndex++; if(mIndex==4) //已经接完4个字节的地址 { mState=4; mIndex=0;// 先清0索引,为阶段4做准备 } } else if(mState==4) //阶段4,等待接收字节数,2个字节 { mCheckHe=mCheckHe+bufcom1; mCmdnBytesBuf[mIndex]=bufcom1; mIndex++; if(mIndex==2) //已经接完2个字节 { if((mCmdnBytesBuf[0]==4)&&(mCmdnBytesBuf[1]==0))//如果收到的是4个字节数据 { mState=5; mIndex=0;// 为阶段5做准备 } else mState=0; //接收错误,跳回阶段0 } } else if(mState==5) //阶段5,等待接收4个数据 { mCheckHe=mCheckHe+bufcom1; mHmiVarBuf[mIndex]=bufcom1; mIndex++; if(mIndex==4) //已经接完4个字节 { mState=6; mIndex=0;//为阶段6做准备 } } else if(mState==6) //阶段6,接收2个数据校验和 { mHmiVarCheck[mIndex]=bufcom1; mIndex++; if(mIndex==2) //已经接完2个字节 { mState=0; //接收完毕,从头开始 if(mHmiVarCheck[0]==(mCheckHe%256)) //比较校验和低字节 if(mHmiVarCheck[1]==(mCheckHe/256)) //比较校验和高字节 if(mCmdAdrBuf[0]==m_ReadVarAdr%256) //比较HMI变量地址第0个字节 if(mCmdAdrBuf[1]==(m_ReadVarAdr/256)) //比较HMI变量地址第1个字节 if(mCmdAdrBuf[2]==0x0) //比较HMI变量地址第2个字节 if(mCmdAdrBuf[3]==0x0) //比较HMI变量地址第3个字节 { mReceiveFlag=1;//如果地址和校验和没问题,表示已经成功读到了工控机的m_ReadVarAdr变量 } } } else mState=0;
}
|