视展LED屏幕RS485对接(C语言)

网友投稿 685 2022-08-31

视展LED屏幕RS485对接(C语言)

视展LED屏幕RS485对接(C语言)

文章目录

​​RS485通信协议​​​​开发包​​​​屏幕显示位置与区域划分​​​​串口收发函数替换​​​​汉字编码​​

​​字库-​​​​编码转换​​

​​遇到的问题​​

​​问题1-无法分行​​​​问题2-颜色问题​​​​问题3-没有显示星期的函数​​

​​LED显示照片​​

一个项目上用到视展LED全彩屏,第一次对接这种LED屏幕,发现这个屏幕的功能还是很强大的!技术支持也挺给力的,两天时间对接完成;这里把主要的东西记录一下,做个笔记。

RS485通信协议

刚开始拿到通信协议,有点懵了,虽然我对十六进制的协议并不陌生,但是协议里涉及到的字段、专用名词比较多,不容易理解,段时间去开发一套通信协议代码也不现实,还好提供了c语言的通信代码,虽然是Windows平台下的代码,稍微改了下就可以用在Linux下了。

开发包

视展提供的sdk代码与软件:

App: 是LED屏幕配套的软件;

EasyProtocolDemo是一个比较精简的内码发送显示的实例,我也是基于这个代码做的;

├── LedUtils.c --- led通信协议打包函数实现├── LedUtils.h├── crc.c ----- 校验计算函数实现├── main.c ----- 测试main函数├── packet.c ----- 网络接口实现,主要是用于网络通信,串口的话就不需要这个文件了├── packet.h ----- 部分协议结构体定义├── system.h ----- 协议中的宏定义、枚举、结构体定义├── uart.c ----- 串口读写接口实现└── uart.h

如上,首先我们要弄清楚屏幕通信控制的执行流程,可以先看下main.c里面的函数:

#include #include #include #include "system.h"#include "packet.h"#include "uart.h"#include "LedUtils.h"char CardHost[16] = "192.168.1.99";int com_port=1;void doprint(BYTE* buffer, DWORD size){/ DWORD i; printf("------------------------------------------\n"); for (i=1; i<=size; i++) { printf("0x%0.2X,", buffer[i-1]); if ((i % 8)==0) printf(" "); if ((i % 16)==0) printf("\n"); } printf("\n----------------------------------------\n");/}void net_send(BYTE* stream){ DWORD size; BYTE buffer[6144]; SOCKET s; DWORD i, K; char ip[16]; WORD port; s=InitSocket(9011); //----generate and send the begin packet---- size=DoBeginPacket(buffer, 0); SocketWrite(s, buffer, size, CardHost, 6666); Sleep(100); size=SocketRead(s, buffer, 6144, ip, &port); if (size>0) printf("==>begin packet ok\n\n"); else printf("==>begin packet time out\n\n"); //----generate and send the data packet---- // first, get the count of data packet K=GetDataPacketCount(stream); // second, generate and send the data packet one by one for (i=1; i<=K; i++) { size=DoDataPacket(stream, i, buffer, 0); SocketWrite(s, buffer, size, CardHost, 6666); Sleep(100); size=SocketRead(s, buffer, 6144, ip, &port); if (size>0) printf("==>data packet %d ok\n\n", i); else printf("==>data packet %d time out\n\n", i); } //----generate and send the end packet---- size=DoEndPacket(buffer, K+1, 0); SocketWrite(s, buffer, size, CardHost, 6666); Sleep(100); size=SocketRead(s, buffer, 6144, ip, &port); if (size>0) printf("==>end packet ok\n\n"); else printf("==>end packet time out\n\n"); CloseSocket(s);}void com_send(BYTE* stream){ DWORD size; BYTE buffer[6144]; DWORD i, K; TDeviceInfo dev; uart_Initialize(com_port); //----generate and send the begin packet---- size=DoBeginPacket(buffer, 0); uart_Write(buffer, size, NULL); Sleep(100); size=uart_Read(buffer, 6144, &dev); if (size>0) printf("==>begin packet ok\n\n"); else printf("==>begin packet time out\n\n"); //----generate and send the data packet---- // first, get the count of data packet K=GetDataPacketCount(stream); // second, generate and send the data packet one by one for (i=1; i<=K; i++) { size=DoDataPacket(stream, i, buffer, 0); uart_Write(buffer, size, NULL); Sleep(100); size=uart_Read(buffer, 6144, &dev); if (size>0) printf("==>data packet %d ok\n\n", i); else printf("==>data packet %d time out\n\n", i); } //----generate and send the end packet---- size=DoEndPacket(buffer, K+1, 0); uart_Write(buffer, size, NULL); Sleep(100); size=uart_Read(buffer, 6144, &dev); if (size>0) printf("==>end packet ok\n\n"); else printf("==>end packet time out\n\n"); uart_Destroy();}void demo_string(){ BYTE stream[65536]; char str1[]="HELLO WORLD!"; char str2[]="你好"; //genrate the display program data //this is a demo that there are two text display in the screen //one display in the rect (0, 0, 256, 16), another display in the rect (0, 16, 256, 32) // /---------------\ // | HELLOW WORLD! | // | hellow world! | // \---------------/ MakeRoot(stream); AddChapter(0x7fffffff, PLAY_MODE_WAIT); AddRegion(0, 0, 256, 32); AddLeaf(0x7fffffff, PLAY_MODE_WAIT); AddString(0, 0, 256, 16, str1, FONT_SET_16, RGB(255,255,0), 1, 0, 2, 0, 0, 0, 5000); //display in yellow AddString(0, 16, 256, 16, str2, FONT_SET_16, RGB(0,255,0), 1, 0, 2, 0, 0, 0, 5000); //display in green //send to screen //net_send(stream); //this is the network (udp) com_send(stream); //this is the rs232}void main(void){ while (1) { demo_string(); Sleep(5000); }}

代码比较简单,我们关注的函数就是:demo_string(),这个函数在这里就是实现了向屏幕发送要显示的内容:

MakeRoot

AddChapter

AddRegion

AddLeaf

AddString

串口发送

AddString就是添加要显示的文字内码,LED屏幕支持内码发送和文本发送,内码发送就是发送的国标内码,文本文字就是将文字转换为点阵数据发送,这种方式数据量比较大,建议直接用内码发送。

如果想要发送的文字过长时滚动,需要将AddString的第8个参数(inmethod)传入2。

如果需要屏幕自动保存内码,则需要使用-内码的方式(ROOT_DOWNLOAD):

void MakeRoot(BYTE* buffer){ DWORD size; root=(PRoot)buffer; size=sizeof(TRoot); memset(root, 0, size); root->id=ROOT_PLAY; //修改这里ROOT_DOWNLOAD可以让-的内码保存 root->color=LED_THREE; root->count=0; root->survive=0xffffffff; root->Reserved=0; root->size=size; BufferSeek=size;}

屏幕显示位置与区域划分

AddStringDateTime: 是添加显示时间,这个时间是屏幕自己计时,需要屏幕控制卡的程序支持; AddStringWeek : 是添加显示“星期”; AddString: 就是添加显示内码文字; 这几个函数每调用一次就相当于产生一个显示对象(区域),LED屏幕上根据传入的坐标显示在不同的位置。

屏幕可以指定更新一个局部的显示对象,比如使用AddString添加的一个内容,需要定时更新,那么只需要调用定时更新对象的函数即可(我把sdk里的函数改造了一下):

void demo_update_object(int objectindex, const char* str, long left, long top, long width, long height){ BYTE stream[65536]; char outStr[512]={0}; u2g((char *)str,strlen(str),outStr,sizeof(outStr)); MakeObject(stream, 0, 0, 0, (long)objectindex); AddStrings(left, top, width, height, 1); AddChildString(outStr, FONT_SET_16, RGB(240,0,0), 2, 0, 0, 0, 0, 0, 5000); com_send(stream);}

串口收发函数替换

Windows下与Linux下主要串口部分需要改下,别的代码不用修改,我把uart.c里的串口收发函数的实现改为了我这边Linux里的封装:

int uart_send(const void *pdata, int len){ int ret = -1;#ifdef _TEST_ ret = 0; dPrint(WARN, ">%s\n", hexdump(pdata, len).c_str());#else ret = gs_pSerial->sendData(pdata, len); if ( ret <= 0 ) { dPrint(ERROR, "led screen send error.\n"); }#endif return ret;}int uart_read(void *pdata, int len){ int ret = -1;#ifdef _TEST_ ret = 0;#else ret = readable_timeo(gs_pSerial->getObjectFd(), 10); if ( ret <= 0 ) { dPrint(ERROR, "led screen read timeout : %d.\n",ret); return ret; } ret = gs_pSerial->readData(pdata, len); if ( ret <= 0 ) { dPrint(WARN, "led screen send error.\n"); }#endif return ret;}

我函数名字改了,如果函数名字不改的话,com_send函数就不用动了。

汉字编码

LED是采用的GB2312编码,使用内码进行通信时,需要LED事先-好内码,-内码是使用配套的软件进行-的。

字库-

编码转换

我们设备里面采用的UTF8编码,所以汉字的显示需要做一下内码转换,这里没有自己去写函数转换,直接移植了iconv库,用iconv库函数去做的转换,下面是从网上查找到的封装代码:

/*代码转换:从一种编码转为另一种编码*/static int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen){ iconv_t cd; int rc; char **pin = &inbuf; char **pout = &outbuf; cd = iconv_open(to_charset,from_charset); if (cd==0) return -1; memset(outbuf,0,outlen); if (iconv(cd,pin,(size_t*)&inlen,pout,(size_t*)&outlen)==-1) return -1; iconv_close(cd); return 0;}/*UTF8码转为GB2312码*/static int u2g(char *inbuf,int inlen,char *outbuf,int outlen){ return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);}/*GB2312码转为UTF8码*/static int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen){ return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);}

这样在发送内码的地方统一做一次转换即可。

遇到的问题

问题1-无法分行

我用的这个屏幕是32032的,汉字是1616点阵,只能在第一行显示,即使把y坐标设置为16,还是在0处显示,这个问题是控制卡软件的问题,找技术支持升级后解决了。

问题2-颜色问题

即RGB的染色值顺序变了,这个在软件上可以配置R、G、B的顺序,可以配置为RGB、RBG、GBR等

问题3-没有显示星期的函数

这个首先可以通过发内码来解决,如果自己不想写这部分代码,可以找找支持,我这边找技术支持给加了一个函数~

整体上调试海思比较顺利的。

LED显示照片

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:[笔记]机器学习之机器学习模型及案例分析《一》
下一篇:go语言打造个人博客系统(二)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~