在线时间109 小时
UID3332856
注册时间2016-11-28
NXP金币370
TA的每日心情 | 擦汗 2024-11-7 09:48 |
---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到
金牌会员
 
- 积分
- 1252
- 最后登录
- 2025-8-5
|
这个活动好:【Battle没你不行】无限火力—全民游戏 - 活动专区 - 恩智浦技术社区 (nxpic.org.cn)。无限火力—使用EW-win不要做游戏不要太爽
1、UI页面
二话不说先看效果,第一个模拟飞行
下载到板子上的演示:
然后在根据范例模板快速修修改,生成独立的打砖块。
2、这个都是使用embedded-wizard辅助开发的工具,使用了非常丝滑的插件,因为使用了独特的图形化插件,开发的速度是用小时计,而不是以前的需要花掉头发的代价。
这个输出的代码,可以输入到MCUXpressoIDE 中去进一步加工,快速实现嵌入式开发。
3、软件和硬件
3.1 需要的软件embedded-wizard Simplify Your GUI Development - Embedded Wizard (embedded-wizard.de)
MCUXpressoIDE
3.2 使用的硬件LPCXpresso54628
Getting Started with the LPCXpresso54628 Development Board | NXP Semiconductors
该板由LPC54628目标器件和板载CMSIS-DAP/SEGGER®J-Link兼容的硬件调试器组成。板载硬件调试器与MCUXpresso IDE及Keil™和IAR®等其他领先的工具链兼容。
这个是一个强悍的ARM-M4内核的芯片,功能丰富。LPC546XX:基于Arm® Cortex®-M4内核的高效微控制器(MCU),带先进外设。
显示屏是272x480彩色电容式触摸屏LCD10/100Mbps以太网(RJ45连接器)Winbond 128 Mb W25Q128JVFIM四通道SPI闪存Winbond 128 Mb W9812G6JB-6I SDRAM全尺寸SD/MMC卡插槽恩智浦MMA8652FCR1加速度传感器Knowles SPH0641LM4H数字麦克风立体声音频编解码器,带线路输入/输出
4、开发过程
4.1 embedded-wizard开发,启动代码,
然后进入主控brick积木构件中,开发主要只是围绕application这个定制模块进行,很像android studio使用一个所见即所得的交互界面,但是代码更简单,都是用一个个更低层级的brick组成,从程序逻辑就是逐步按照对象编程,一只写代码到底层函数和变量赋值,确实需要的代码,用和brick模块关联的inline嵌入式代码就可以搞定。
模块之间,通过slot机制,进行任务触发,直接形成程序链。这个自动假设模块,正确选择已经内置的各种仪表盘,然后选择动画机制,是effect效果模块,就可以非常简便形成模拟飞行的过程。
增加对于touch响应的WipeTouchHandle,形成一个slot,对应实现全局变量的修改,在图像自动刷新的过程中,就实现了飞行姿态的控制和响应,
- case Core::Direction.Left : BankAngle = BankAngle - 5.0;
- case Core::Direction.Right : BankAngle = BankAngle + 5.0;
- case Core::Direction.Top : AttackAngle = AttackAngle - 5.0;
- case Core::Direction.Bottom : AttackAngle = AttackAngle + 5.0;
- default: ;
- }
- /* limit calculated values */
- if ( BankAngle < -45.0 )
- BankAngle = -45.0;
- if ( BankAngle > 45.0 )
- BankAngle = 45.0;
- if ( AttackAngle < -45.0 )
- AttackAngle = -45.0;
- if ( AttackAngle > 45.0 )
- AttackAngle = 45.0;
- /* restart autopilot... */
- AutoPilotTimer.Enabled = false;
- AutoPilotTimer.Enabled = true;
复制代码
界面如下图,这个对于飞行控阔以,但是大部分不爱玩,那么下一个打砖块是消灭时间利器,可以尝试一下。
4.2 直接下载到办卡
embedded-wizard提供了独立的开发和下载工具,直接在GCC下可以编译,使用NXP的redlink下载二进制代码。当开发环境配置好以后就非常简单,第一步make
再一步 make install
完全不用再进入MCUxpresso IDE
5、打砖块
5.1 同上启动打砖块的开发界面,创建工程,一定选中开发平台,是NXP的,这个ew-win是一个跨平台开发工具,可以在windows上同样的代码开发。
然后选择到application的交互界面,
这个已经更换背景为无限火力的热图,不过有些太酷炫了,在打砖块的时候砖块不是很清晰,这个代码首先启动的init初始化,根据关卡设置砖块布置,然后开始启动计时和计分,代码逻辑部分异常简单,就是不断更新砖块,小球等的相对位置
- <blockquote>super( aState );
复制代码
中间最关键的逻辑判断就是碰撞函数,根据碰撞情况改变状态和
- var int32 noOfBricks = 0;
- /* first check for collisions with any bricks */
- noOfBricks = noOfBricks + BrickRow1.CheckCollision( aBall );
- noOfBricks = noOfBricks + BrickRow2.CheckCollision( aBall );
- noOfBricks = noOfBricks + BrickRow3.CheckCollision( aBall );
- noOfBricks = noOfBricks + BrickRow4.CheckCollision( aBall );
- noOfBricks = noOfBricks + BrickRow5.CheckCollision( aBall );
- /* check if level is completed */
- if ( noOfBricks == 0 )
- {
- /* add 50 bonus points */
- Data.Score = Data.Score + 50;
- /* next level */
- Data.Level = Data.Level + 1;
- postsignal PrepareLevel;
- /* increase speed ;-) */
- if ( Data.Level < 25 )
- speedFactor = speedFactor + 0.005;
- }
- /* hit left/right border */
- if ( ( aBall.Bounds.x1 <= 0 && aBall.SpeedX < 0.0 ) || ( aBall.Bounds.x2 >= Bounds.w && aBall.SpeedX > 0.0 ) )
- aBall.SpeedX = -aBall.SpeedX;
- /* hit top border */
- if ( aBall.Bounds.y1 <= 0 && aBall.SpeedY < 0.0 )
- aBall.SpeedY = -aBall.SpeedY;
- /* hit the paddle */
- if ( aBall.Bounds.y2 > Paddle.Bounds.y1 && aBall.Bounds.y2 < Paddle.Bounds.y2 && aBall.SpeedY > 0.0 )
- {
- /* left corner corner of the paddle */
- if ( aBall.Bounds.x1 < Paddle.Bounds.x1 && aBall.Bounds.x2 > Paddle.Bounds.x1 )
- {
- var int32 dx = aBall.Bounds.x2 - Paddle.Bounds.x1;
- var int32 dy = aBall.Bounds.y2 - Paddle.Bounds.y1;
- if ( math_pow(dx,2.0) + math_pow(dy,2.0) < math_pow(aBall.Bounds.w,2.0) && dy < Paddle.Bounds.h/2 )
- {
- aBall.SpeedY = -aBall.SpeedY;
- aBall.SpeedX = aBall.SpeedX + (float)( aBall.Bounds.center.x - Paddle.Bounds.center.x ) / (float)(Paddle.Bounds.w);
- }
- }
- /* right corner corner of the paddle */
- if ( aBall.Bounds.x2 > Paddle.Bounds.x2 && aBall.Bounds.x1 < Paddle.Bounds.x2 )
- {
- var int32 dx = Paddle.Bounds.x2 - aBall.Bounds.x1;
- var int32 dy = aBall.Bounds.y2 - Paddle.Bounds.y1;
- if ( math_pow(dx,2.0) + math_pow(dy,2.0) < math_pow(aBall.Bounds.w,2.0) && dy < Paddle.Bounds.h/2 )
- {
- aBall.SpeedY = -aBall.SpeedY;
- aBall.SpeedX = aBall.SpeedX + (float)( aBall.Bounds.center.x - Paddle.Bounds.center.x ) / (float)(Paddle.Bounds.w);
- }
- }
- /* center of paddle */
- else if ( aBall.Bounds.x1 > Paddle.Bounds.x1 && aBall.Bounds.x2 < Paddle.Bounds.x2 )
- {
- aBall.SpeedY = -aBall.SpeedY;
- aBall.SpeedX = aBall.SpeedX + (float)( aBall.Bounds.center.x - Paddle.Bounds.center.x ) / (float)(Paddle.Bounds.w);
- }
- }
- /* ball is out :-( */
- if ( aBall.Bounds.y1 >= Bounds.y2 )
- {
- ballMove = false;
-
- /* increase the ball lost counter */
- Data.Lost = Data.Lost + 1;
- /* decrease 100 points */
- Data.Score = Data.Score - 100;
- }
复制代码 4.2 编译和模拟运行,这个过程就直接点击build,虽然是嵌入式开发,但是在windows也可以顺利跑所见即所得的模拟器
5 导入MCUxpressoIDE
5.1 正确配置开发环境后,同时生成一个generated文件夹,这个就是可直接导出的,启动MCUxpresso导入工程
这个就是可以直接编译的
然后下载
这样就在开发板上直接跑起来了。
5.2 代码分析
生成的主代码main.c只提供了一个框架,同时启动了freeRTOS,但是这个只是为了给其他任务提供交互接口,对于ew-win是有独立的屏幕刷新和时钟控制的。主要的代码在ewmain.c中,实现初始化,update更新等功能,整个代码其实都已经封装好了,对于UI界面以及完成,除非是非常熟悉搞事情,完全没有必要再深入这个循环中。
而且仔细读代码之后,整个控制逻辑完全在embedded-wizard的图形化开发界面实现,代码简洁,可读性非常好。
唯一的问题,就是核心的驱动是有segger提供的封装库中提供,限制代码范围的是免费版,如果希望解锁高级工程,那么就需要licence了。
- int EwInit( void )
- {
- /* initalize system clocks */
- EwBspClockInit();
- /* set RTC, if current RTC time is before the minimum time */
- if ( EwBspClockGetTime() < RTC_MINIMUM_TIME )
- EwBspClockSetTime( RTC_DEFAULT_TIME );
- /* initialize display */
- EwPrint( "Initialize Display... " );
- CHECK_HANDLE( EwBspDisplayInit( EwScreenSize.X, EwScreenSize.Y, &DisplayInfo ));
- /* initialize touchscreen */
- EwPrint( "Initialize Touch Driver... " );
- CHECK_HANDLE( EwBspTouchInit( EwScreenSize.X, EwScreenSize.Y, &DisplayInfo ));
- #if EW_MEMORY_POOL_SIZE > 0
- /* initialize heap manager */
- EwPrint( "Initialize Memory Manager... " );
- EwInitHeap( 0 );
- EwAddHeapMemoryPool( (void*)EW_MEMORY_POOL_ADDR, EW_MEMORY_POOL_SIZE );
- #if EW_EXTRA_POOL_SIZE > 0
- EwAddHeapMemoryPool( (void*)EW_EXTRA_POOL_ADDR, EW_EXTRA_POOL_SIZE );
- #endif
- EwPrint( "[OK]\n" );
- #endif
- /* initialize the Graphics Engine and Runtime Environment */
- EwPrint( "Initialize Graphics Engine... " );
- CHECK_HANDLE( EwInitGraphicsEngine( 0 ));
- /* create the applications root object ... */
- EwPrint( "Create Embedded Wizard Root Object... " );
- RootObject = (CoreRoot)EwNewObjectIndirect( EwApplicationClass, 0 );
- CHECK_HANDLE( RootObject );
- EwLockObject( RootObject );
- CoreRoot__Initialize( RootObject, EwScreenSize );
- /* create Embedded Wizard viewport object to provide uniform access to the framebuffer */
- EwPrint( "Create Embedded Wizard Viewport... " );
- Viewport = EwInitViewport( EwScreenSize, EwNewRect( 0, 0, DisplayInfo.BufferWidth, DisplayInfo.BufferHeight ),
- 0, 255, DisplayInfo.FrameBuffer, DisplayInfo.DoubleBuffer, 0, 0 );
- CHECK_HANDLE( Viewport );
- /* initialize your device driver(s) that provide data for your GUI */
- DeviceDriver_Initialize();
- return 1;
- }
- /*******************************************************************************
- * FUNCTION:
- * EwDone
- *
- * DESCRIPTION:
- * EwDone() is responsible to shutdown the application and to release all
- * used resources.
- *
- * ARGUMENTS:
- * None
- *
- * RETURN VALUE:
- * None.
- *
- *******************************************************************************/
- void EwDone( void )
- {
- /* deinitialize your device driver(s) */
- DeviceDriver_Deinitialize();
- /* destroy the applications root object and release unused resources and memory */
- EwPrint( "Shutting down Application... " );
- EwDoneViewport( Viewport );
- EwUnlockObject( RootObject );
- EwReclaimMemory();
- EwPrint( "[OK]\n" );
- /* deinitialize the Graphics Engine */
- EwPrint( "Deinitialize Graphics Engine... " );
- EwDoneGraphicsEngine();
- EwPrint( "[OK]\n" );
- #if EW_MEMORY_POOL_SIZE > 0
- /* deinitialize heap manager */
- EwDoneHeap();
- #endif
- EwPrint( "Deinitialize Touch Driver... " );
- EwBspTouchDone();
- EwPrint( "[OK]\n" );
- /* deinitialize display */
- EwBspDisplayDone( &DisplayInfo );
- Viewport = 0;
- RootObject = 0;
- }
- /*******************************************************************************
- * FUNCTION:
- * EwProcess
- *
- * DESCRIPTION:
- * EwProcess() implements one cycle of the main loop. This function has to be
- * called in an (endless) loop and contains typically the following steps:
- * 1. Processing data from your device driver(s)
- * 2. Processing key events
- * 3. Processing cursor or touch screen events
- * 4. Processing timers
- * 5. Processing signals
- * 6. Updating the screen
- * 7. Triggering the garbage collection
- * For more information concerning the integration of an Embedded Wizard
- * generated GUI application into your main application, please see
- * https://doc.embedded-wizard.de/main-loop
- *
- * ARGUMENTS:
- * None.
- *
- * RETURN VALUE:
- * 1, if further processing is needed, 0 otherwise.
- *
- *******************************************************************************/
- int EwProcess( void )
- {
- int timers = 0;
- int signals = 0;
- int events = 0;
- int devices = 0;
- XEnum cmd = CoreKeyCodeNoKey;
- int noOfTouch;
- XTouchEvent* touchEvent;
- int touch;
- int finger;
- XPoint touchPos;
- /* process data of your device driver(s) and update the GUI
- application by setting properties or by triggering events */
- devices = DeviceDriver_ProcessData();
- /* receive keyboard inputs */
- cmd = EwGetKeyCommand();
- if ( cmd != CoreKeyCodeNoKey )
- {
- if ( cmd == CoreKeyCodePower )
- return 0;
- /* feed the application with a 'press' and 'release' event */
- events |= CoreRoot__DriveKeyboardHitting( RootObject, cmd, 0, 1 );
- events |= CoreRoot__DriveKeyboardHitting( RootObject, cmd, 0, 0 );
- }
- /* receive (multi-) touch inputs and provide it to the application */
- noOfTouch = EwBspTouchGetEvents( &touchEvent );
- if ( noOfTouch > 0 )
- {
- for ( touch = 0; touch < noOfTouch; touch++ )
- {
- /* get data out of the touch event */
- finger = touchEvent[ touch ].Finger;
- touchPos.X = touchEvent[ touch ].XPos;
- touchPos.Y = touchEvent[ touch ].YPos;
- /* begin of touch cycle */
- if ( touchEvent[ touch ].State == EW_BSP_TOUCH_DOWN )
- events |= CoreRoot__DriveMultiTouchHitting( RootObject, 1, finger, touchPos );
- /* movement during touch cycle */
- else if ( touchEvent[ touch ].State == EW_BSP_TOUCH_MOVE )
- events |= CoreRoot__DriveMultiTouchMovement( RootObject, finger, touchPos );
- /* end of touch cycle */
- else if ( touchEvent[ touch ].State == EW_BSP_TOUCH_UP )
- events |= CoreRoot__DriveMultiTouchHitting( RootObject, 0, finger, touchPos );
- }
- }
- /* process expired timers */
- timers = EwProcessTimers();
- /* process the pending signals */
- signals = EwProcessSignals();
- /* refresh the screen, if something has changed and draw its content */
- if ( devices || timers || signals || events )
- {
- if ( CoreRoot__DoesNeedUpdate( RootObject ))
- EwUpdate( Viewport, RootObject );
- /* just for debugging purposes: check the memory structure */
- EwVerifyHeap();
- /* after each processed message start the garbage collection */
- EwReclaimMemory();
- /* print current memory statistic to console interface */
- #ifdef EW_PRINT_MEMORY_USAGE
- EwPrintProfilerStatistic( 0 );
- #endif
- /* evaluate memory pools and print report */
- #ifdef EW_DUMP_HEAP
- EwDumpHeap( 0 );
- #endif
- }
- else
- {
- /* otherwise sleep/suspend the UI application until a certain event occurs or a timer expires... */
- EwBspEventWait( EwNextTimerExpiration());
- }
- return 1;
- }
- /*******************************************************************************
- * FUNCTION:
- * EwUpdate
- *
- * DESCRIPTION:
- * The function EwUpdate performs the screen update of the dirty area.
- *
- * ARGUMENTS:
- * aViewPort - Viewport used for the screen update.
- * aApplication - Root object used for the screen update.
- *
- * RETURN VALUE:
- * None
- *
- *******************************************************************************/
- static void EwUpdate( XViewport* aViewport, CoreRoot aApplication )
- {
- XBitmap* bitmap;
- GraphicsCanvas canvas = EwNewObject( GraphicsCanvas, 0 );
- XRect updateRect = {{ 0, 0 }, { 0, 0 }};
- if ( !canvas )
- return;
- if ( DisplayInfo.UpdateMode == EW_BSP_DISPLAY_UPDATE_NORMAL )
- {
- bitmap = EwBeginUpdate( aViewport );
- /* redraw the dirty area of the screen */
- if ( bitmap )
- {
- GraphicsCanvas__AttachBitmap( canvas, (XHandle)bitmap );
- updateRect = CoreRoot__UpdateGE20( aApplication, canvas );
- GraphicsCanvas__DetachBitmap( canvas );
- EwEndUpdate( aViewport, updateRect );
- }
- }
- else
- {
- int regions = CoreRoot__BeginUpdate( aApplication );
- while ( regions-- )
- {
- /* get rectangular area of the update region for scratch-pad buffer */
- if ( DisplayInfo.UpdateMode == EW_BSP_DISPLAY_UPDATE_SCRATCHPAD )
- updateRect = CoreRoot__GetUpdateRegion( aApplication, regions );
- /* iterate through all update areas */
- while ( EwBspDisplayGetUpdateArea( &updateRect ))
- {
- /* update the current subarea */
- bitmap = EwBeginUpdateArea( aViewport, updateRect );
- GraphicsCanvas__AttachBitmap( canvas, (XHandle)bitmap );
- CoreRoot__UpdateCanvas( aApplication, canvas, updateRect.Point1 );
- GraphicsCanvas__DetachBitmap( canvas );
- EwEndUpdate( aViewport, updateRect );
- }
- if ( DisplayInfo.UpdateMode != EW_BSP_DISPLAY_UPDATE_SCRATCHPAD )
- break;
- }
- CoreRoot__EndUpdate( aApplication );
- }
- }
复制代码
|
-
|