【原创开源】极具可玩性的高端玩法,使用F429外接32位SDRAM虚拟VNC桌面,无需显示屏
1. 原创开源VNC综合Demo说明:(1).操作这个例子前,务必要看之前发布的综合Demo演示和使用说明:http://www.armbbs.cn/forum.php?mod=viewthread&tid=17330 ,这个例子是由其修改而来的。依然是采用的RTX系统及其所有中间件。
(2). 这个项目的可玩性极高,可以做很多有意思的应用。做一些远程智能控制尤其方便,省去了学习html,xml,js等麻烦,且无需显示屏。
(3).网络协议栈用的RL-TCPnet,而VNC Server是用的emWin自带的功能。这里是用的我们V6开发板带的32位SDRAM虚拟一个800*480分辨率的界面出来。底层已经全部采用F429的DMA2D进行了优化。手机端和电脑端都可以访问的,这样就省去了使用显示屏的繁琐,而且性能可以发挥到F429外接裸屏的30%-50%,即使是这样,比F407+RA8875还是强很多的。电脑端的VNC比较好用,手机端还没有找到好用的。
(4).我们的又一个史诗级网络协议栈教程正在如火如荼的进展中,初步今年9月份前发布:http://www.armbbs.cn/forum.php?mod=viewthread&tid=26034。
2.版本信息:
RTOS: RL-RTX V4.74
File System:RL-FlashFSV4.74
TCP/IP: RL-TCPnet V4.74
USB: RL-USB V4.74
CAN: RL-CAN V4.74
GUI: emWin V5.36
Modbus: Designed by armfly
3.14个任务优先级配置
(1). os_idle_demon, 优先级0:系统空闲任务。
(2). AppTaskStatistic 优先级1:CPU利用率检测。
(3). AppTaskGUI, 优先级3:GUI主任务。
(4). _ServerTask, 优先级4:VNC Server
(5).AppTaskTCPMain,优先级5:TCPnet网络主任务。
(6). AppTaskStart, 优先级7:启动任务。
(7). AppTaskCAN, 优先级8:CAN总线任务。
(8). AppTaskModbus,优先级9:Modbus任务。
(9). AppTaskUSB, 优先级10:USB任务,
(10). AppTaskMusic, 优先级11:音乐任务,用于音乐播放器,视频播放器,录音机和收音机处理。
(11). AppTaskPinDetect, 优先级12:SD卡插拔检测任务。
(12). AppTaskTCPTimer, 优先级13:TCPnet网络定时更新任务。
USB在运行的过程中会创建2两个任务
(14). USBD_RTX_EndPoint0 优先级2:USB设备端点0任务。
(15). USBD_RTX_MSC_EP_BULK_Event优先级2:USB BULK数据传输任务。
4.15个中断安排
NVIC优先级分组采用4,仅抢占优先级,范围0-15。
LTDC中断, 抢占优先级 0
ETH以太网中断, 抢占优先级 0
USB FS中断, 抢占优先级 0
CAN2 TX中断, 抢占优先级 1
CAN2 RX0中断, 抢占优先级 1
DMA2_Steam5中断,抢占优先级 1
DMA2_Steam1中断,抢占优先级 1
EXTI6中断, 抢占优先级 1
USART3中断, 抢占优先级 2
EXTI2中断, 抢占优先级 2
TIM2中断, 抢占优先级 4
USART1中断, 抢占优先级 13
RTC Alarm中断, 抢占优先级 13
SVC中断, 抢占优先级 14
Systick中断, 抢占优先级 15
PendSV中断, 抢占优先级 15
5.内存安排
内部SRAM , CCM SRAM和SDRAM安排。
内部192KB SRAM :80KB用于动态内存分配,其余用于任务堆栈,系统堆栈,文件系统,网络协议栈等。
内部64KB CCM SRAM:用于视频播放器时,JPEG解码。
外部16MB SDRAM :前4MB用于SDRAM的虚部显示屏。
外部16MB SDRAM :后12MB用于emWin动态内存。
6. RTX调试组件效果展示
7.开启MDK4.74最高的3级优化,同时开启相当给力的时间优化
https://img.anfulai.cn/dz/attachment/forum/pw/Fid_12/12_58_8c33af3c9f419c9.png?40
==============================================================
原创开源工程下载:
==============================================================
简易视频效果演示,手机简单拍了个,像素稍差些,主要看性能:
https://v.qq.com/x/page/u051675jkpv.html
==============================================================
电脑端使用VNC Client访问部分效果展示,具体可看上面的视频:
主界面效果:
视频播放器效果(GIF格式图片)
音乐播放器效果(GIF格式图片)
RL-TCPnet主界面:
CAN控制界面:
Modbus控制界面:
模拟U盘控制界面:
万年历:
最后来一张实际效果:
学习 ! 支持老师 这个太赞了 好。。。。。。支持。。。。 太好了,,,, 强烈支持,用这个相当于在线调试了有没有。。。 1024 今天开始加紧收尾,准备开源。 牛掰 牛 顶顶顶 顶了再顶 简直吊炸天 膜拜和感激 老大牛逼啊 RL-CAN有那些功能 CANopen? ??
回 a20084666 的帖子
a20084666:RL-CAN 有那些功能 CANopen? ?? (2017-06-19 23:10) images/back.gif没有哦,就是一个简单的CAN控制,方便使用了。
回 eric2013 的帖子
eric2013:没有哦,就是一个简单的CAN控制,方便使用了。 (2017-06-20 02:42) images/back.gif有没有什么操作系统能够支持这个功能,对can的一些协议做些插件之类的
回 a20084666 的帖子
a20084666:有没有什么操作系统能够支持这个功能,对can的一些协议做些插件之类的 (2017-06-20 13:26) images/back.gif可以看看这个两个:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=29575
http://www.armbbs.cn/forum.php?mod=viewthread&tid=19493 太赞了,以后开发带显示屏的程序都不用带屏了,基本类似于模拟器里完成啊,加快开发速度
我之前搞了个树莓派,都是用远程登录玩的
回 myxiaonia 的帖子
myxiaonia:太赞了,以后开发带显示屏的程序都不用带屏了,基本类似于模拟器里完成啊,加快开发速度我之前搞了个树莓派,都是用远程登录玩的 (2017-06-26 11:34) images/back.gif
6666,想过把emwin底层驱动 用USB实现,直接打点到PC端虚拟器。
看到这个瞬间感觉想法太年轻了。
回 tanic 的帖子
tanic:6666,想过把emwin底层驱动 用USB实现,直接打点到PC端虚拟器。看到这个瞬间感觉想法太年轻了。 (2017-07-18 14:56) images/back.gif
如果真这么做就麻烦了,比如linux的图形界面思路就和你类似,是一个cs结构,对于实现各种远程都很容易,糟糕的是本地性能不咋的
其实完全可以用vnc这种做法解决的呀,各司其职才是最好的 这个还会去做支持V5板子的部分吗?
回 detective 的帖子
detective:这个还会去做支持V5板子的部分吗? (2017-10-04 19:01) images/back.gifV5性能不行,SRAM是16位接口的。 请教硬汉哥, STM32F429+16位SDRAM想实现emwin接RGB接口800*480或1024*600屏幕+VNC桌面可以吗? 另外请教VNC如果不用DM9000这类使用RJ45接口的,而是使用WIFI模块实现功能可以吗? DAPAIBULO 发表于 2022-9-25 21:32
请教硬汉哥, STM32F429+16位SDRAM想实现emwin接RGB接口800*480或1024*600屏幕+VNC桌面可以吗? 另外请教 ...
可以,就是速度差些。 eric2013 发表于 2022-9-26 02:14
可以,就是速度差些。
硬汉哥,有V7版本的例子吗,最近想使用VNC,但是连接不上 yelu 发表于 2024-3-26 22:04
硬汉哥,有V7版本的例子吗,最近想使用VNC,但是连接不上
V7还没弄,后面我搞个。 eric2013 发表于 2024-3-27 10:57
V7还没弄,后面我搞个。
我用的keil的中间件,自动生成的代码没修改,第二张图,连接不上(图三),用wireshark抓包如下(图四,开发板地址是14,电脑是113),调试也发现连接后,GUI_VNC_Process函数立即返回1,然后关闭连接,整了几天了,找不到原因,硬汉哥给点思路 yelu 发表于 2024-3-27 15:48
我用的keil的中间件,自动生成的代码没修改,第二张图,连接不上(图三),用wireshark抓包如下(图四, ...
截图清晰点 yelu 发表于 2024-3-27 16:35
截图清晰点
这个功能在H7下是一定可以使用的。 eric2013 发表于 2024-3-28 09:46
这个功能在H7下是一定可以使用的。
是的,现在可以使用了
主要是多了一个缓冲区,之前我的例子是和例程一样的,连上就断开,找了新版本的例程就可以使用了
static GUI_VNC_CONTEXT _Context;
static struct sockaddr_in _Addr;
static U8 _acBuffer; //多了这个缓冲区
eric2013 发表于 2024-3-28 09:46
这个功能在H7下是一定可以使用的。
但是现在又有一个新的问题,热插拔的问题,现在采用的方案是在检测到linkdown之后重新初始化网络协议栈,就是硬汉哥推荐的方式;但是对于这个VNC的例程插拔网线再重新连接有时候连接上会是黑屏,代码如下:
//检测到 linkdown 之后的重新初始化流程
1. linkdown的时候先 GUI_VNC_X_StopServer
2. 重新初始化网络协议栈
3. GUI_VNC_X_ReStartServer
为什么不直接再次调用函数 GUI_VNC_X_StartServer,实际测试的过程中,发现直接调用该函数的话重新连接就是黑屏,最终通过屏蔽代码的方式发现是 GUI_VNC_AttachToLayer 函数的问题,只要不再次调用 GUI_VNC_AttachToLayer 函数,再次连接可以成功。
但是现在还有一个问题,按照上面所写的流程,大部分的时候是能够连接上的,而且画面都是正常的,但是反复测试(拔网线,重新连接)偶尔会连上就黑屏,而且一旦黑屏后面再连接就一直是黑屏,但是此时网络是能够正常通信的,重启一下,然后再连接画面就正常了,唯一的区别就是GUI也重新初始化了一下。
目前还在看这个问题,硬汉哥有测试这样的情况吗
/*********************************************************************
* SEGGER Microcontroller GmbH *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1996 - 2022SEGGER Microcontroller GmbH *
* *
* Internet: www.segger.com Support:support@segger.com *
* *
**********************************************************************
** emWin V6.30 - Graphical user interface for embedded applications **
AllIntellectual Property rightsin the Software belongs toSEGGER.
emWin is protected byinternational copyright laws.Knowledge of the
source code may not be used to write a similar product.This file may
only be used in accordance with the following terms:
The software has been licensed toARM LIMITED whose registered office
is situated at110 Fulbourn Road,Cambridge CB1 9NJ,England solely
forthepurposesofcreatinglibrariesforARM7, ARM9, Cortex-M
series,and Cortex-R4 processor-baseddevices,sublicensedand
distributed as part of theMDK-ARMProfessionalunder the terms and
conditionsofthe EndUserLicensesuppliedwiththeMDK-ARM
Professional.
Full source code is available at: www.segger.com
We appreciate your understanding and fairness.
----------------------------------------------------------------------
Licensing information
Licensor: SEGGER Software GmbH
Licensed to: ARM Ltd, 110 Fulbourn Road, CB1 9NJ Cambridge, UK
Licensed SEGGER software: emWin
License number: GUI-00181
License model: LES-SLA-20007, Agreement, effective since October 1st 2011
Licensed product: MDK-ARM Professional
Licensed platform: ARM7/9, Cortex-M/R4
Licensed number of seats: -
-------------------------- END-OF-HEADER -----------------------------
File : GUI_VNC_X_Keil.c
Purpose : Starts the VNC server via TCP/IP.
This version works with the Keil MDK-Pro TCP/IP stack.
Enable the BSD socket component.
Start by calling GUI_VNC_X_StartServer.
_ServerTask requires 4096 Bytes of private stack.
Only 1 client is supported.
*/
#include <stdlib.h>
#include <string.h>
#include "RTE_Components.h" // Component selection
#ifdef RTE_CMSIS_RTOS2
#include "cmsis_os2.h" // ::CMSIS:RTOS2
#else
#include "cmsis_os.h" // ::CMSIS:RTOS
#endif
#include "rl_net.h" // Keil::Network:CORE
#include "GUI.h"
#include "GUI_VNC.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
//
// Define maximum number of VNC clients that can connect
//
#define VNC_MAX_CLIENTS1
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static GUI_VNC_CONTEXT _Context;
static struct sockaddr_in _Addr;
static U8 _acBuffer;
/*********************************************************************
*
* Local functions
*
**********************************************************************
*/
/*********************************************************************
*
* _cbVNC_Recv()
*
*Function description
* This function is called indirectly by the server; it's address
* is passed to the actual server code as function pointer. It is
* needed because the server is independent of the TCP/IP stack
* implementation, so details for the TCP/IP stack can be placed
* here.
*
*Parameters
* pData : Where to store the received data.
* NumBytes : Maximum amount of data to receive.
* pConnection: Connection handle (WebSocket context).
*
*Return value
* Amount of data received: >0
* Connection closed : == 0
* Error : <0
*/
static int _cbVNC_Recv(U8* pData, int NumBytes, void* pConnection) {
return recv((long)pConnection, (char*)pData, NumBytes, 0);
}
/*********************************************************************
*
* _cbVNC_Send()
*
*Function description
* This function is called indirectly by the server; it's address
* is passed to the actual server code as function pointer. It is
* needed because the server is independent of the TCP/IP stack
* implementation, so details for the TCP/IP stack can be placed
* here.
*
*Parameters
* pData : Data to send.
* NumBytes : Amount of data to send.
* pConnection: Connection handle.
*
*Return value
* Amount of data sent: >0
* Connection closed: == 0
* Error : <0
*/
static int _cbVNC_Send(const U8* pData, int NumBytes, void* pConnection) {
return send((long)pConnection, (const char*)pData, NumBytes, 0);
}
/*********************************************************************
*
* _ListenAtTCPAddr()
*
*Function description
* Creates a non-blocking socket for accepting a VNC connection.
*
*Parameters
* Port: Port to use for accepting connections.
*
*Return value
* Parent socket handle.
*/
static int _ListenAtTCPAddr(U16 Port) {
int hSock;
struct sockaddr_in InAddr;
hSock = socket(AF_INET, SOCK_STREAM, 0);
if (hSock <= 0) {
while (1);// Should not happen.
}
memset(&InAddr, 0, sizeof(InAddr));
InAddr.sin_family = AF_INET;
InAddr.sin_port = htons(Port);
InAddr.sin_addr.s_addr = INADDR_ANY;
bind(hSock, (struct sockaddr*)&InAddr, sizeof(InAddr));
listen(hSock, 1);
return hSock;
}
/*********************************************************************
*
* _ServerTask
*
*Function description
* This routine is the actual server task.
* It executes some one-time init code, then runs in an ednless loop.
* It therefore does not terminate.
* In the endless loop it
* - Waits for a conection from a client
* - Runs the server code
* - Closes the connection
*/
#ifdef RTE_CMSIS_RTOS2
__NO_RETURN static void _ServerTask(void *arguments) {
#else
__NO_RETURN static void _ServerTask(void const *arguments) {
#endif
int s, Sock, AddrLen;
U16 Port;
(void)arguments;
//
// Prepare socket (one time setup)
//
Port = 5900 + _Context.ServerIndex; // Default port for VNC is is 590x, where x is the 0-based layer index
//
// Loop until we get a socket into listening state
//
do {
s = _ListenAtTCPAddr(Port);
if (s != -1) {
break;
}
osDelay(100); // Try again
} while (1);
//
// Loop once per client and create a thread for the actual server
//
while (1) {
//
// Wait for an incoming connection
//
AddrLen = sizeof(_Addr);
if ((Sock = accept(s, (struct sockaddr*)&_Addr, &AddrLen)) < 0) {
continue; // Error
}
//
// Run the actual server
//
GUI_VNC_Process(&_Context, _cbVNC_Send, _cbVNC_Recv, (void *)Sock);
//
// Close the connection
//
closesocket(Sock);
memset(&_Addr, 0, sizeof(struct sockaddr_in));
}
}
#ifdef RTE_CMSIS_RTOS2
static osThreadId_t s_vncTsakId = NULL;
static uint64_t _ServerTask_stk;
static const osThreadAttr_t _ServerTask_attr = {
.stack_mem= &_ServerTask_stk,
.stack_size = sizeof(_ServerTask_stk)
};
#else
static osThreadDef(_ServerTask, osPriorityNormal, 0, 4096);
#endif
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* GUI_VNC_X_StartServer()
*
*Function description
* This routine starts a separate task for the VNC server. It
* requires that the OS and TCP/IP stack are already initialized.
*
*Parameters
* LayerIndex : Index of the GUI layer that is shown via VNC.
* ServerIndex: Zero-based server index.
*
*Return value
* O.K.: 0
*
*Additional information
* This sample is intended to be used for starting one VNC server.
* In case multiple layers shall be accessed by different server
* instances (ServerIndex) this sample needs to be modified.
*/
int GUI_VNC_X_StartServer(int LayerIndex, int ServerIndex) {
//
// Check if maximum number of VNC clients is not exceeded.
//
if (ServerIndex >= VNC_MAX_CLIENTS) {
return -1;
}
//
// Init VNC context and attach to layer (so context is
// updated if the display-layer-contents change).
//
GUI_VNC_AttachToLayer(&_Context, LayerIndex);
_Context.ServerIndex = (uint16_t)ServerIndex;
//
// Set up pointer to RFB buffer.
//
_Context.pBuffer = _acBuffer;
_Context.SizeOfBuffer = GUI_VNC_BUFFER_SIZE;
//
// Create task for VNC Server
//
#ifdef RTE_CMSIS_RTOS2
s_vncTsakId = osThreadNew(_ServerTask, NULL, &_ServerTask_attr);
#else
osThreadCreate(osThread(_ServerTask),NULL);
#endif
//
// O.k., server has been started
//
return 0;
}
/*********************************************************************
*
* void GUI_VNC_X_StopServer(void)
* 重启服务线程
*/
extern int GUI_VNC_X_ReStartServer(int LayerIndex, int ServerIndex);
int GUI_VNC_X_ReStartServer(int LayerIndex, int ServerIndex) {
(void)LayerIndex;
(void)ServerIndex;
#ifdef RTE_CMSIS_RTOS2
s_vncTsakId = osThreadNew(_ServerTask, NULL, &_ServerTask_attr);
#else
osThreadCreate(osThread(_ServerTask),NULL);
#endif
//
// O.k., server has been started
//
return 0;
}
/*********************************************************************
*
* void GUI_VNC_X_StopServer(void)
* 关掉服务线程
*/
extern void GUI_VNC_X_StopServer(void);
void GUI_VNC_X_StopServer(void)
{
osThreadTerminate(s_vncTsakId);
memset(&_Addr, 0, sizeof(struct sockaddr_in));
memset(_acBuffer,0,sizeof(_acBuffer));
}
/*********************************************************************
*
* GUI_VNC_X_getpeername()
*
*Function description
* Retrieves the IP addr. of the currently connected VNC client.
*
*Parameters
* ServerIndex: Index of server instance.
* pIPAddr: VNC client connected: U32 IP addr. in network endianess.
* No client connected : 0
*/
void GUI_VNC_X_getpeername(int ServerIndex, U32 * pIPAddr) {
struct sockaddr_in Client;
int Len;
void * pConnection;
if ((ServerIndex >= VNC_MAX_CLIENTS) || (ServerIndex < 0)) {
return;
}
if (pIPAddr) {
*pIPAddr = _Addr.sin_addr.s_addr;
}
}
/*************************** End of file ****************************/
页:
[1]
2