搜索

[uCOS/RTOS] 【RTOS】+ 基于RT-Thread与东软载波的上位机下位机开发

[复制链接]
1361|12
 楼主 | 2020-4-29 07:47 | 显示全部楼层 |阅读模式
顶楼:RT-Thread活动前传:
【表扬】东软载波的王永全工程师

沙发:RT-Thread活动正文:
【RTOS】+ 基于RT-Thread与东软载波的上位机下位机开发

参加RTT活动,我申请了东软载波的开发板,由于我自己设置不当,
一直没有能够正确烧录程序,晚上22点尝试在群里询问,
东软载波的王(永全)工立即响应回复,不停的为我排查问题,
一直持续到晚上23点30分,终于找到原因:是我设置错误。
前前后后王工持续解答了90分钟,辛苦了!!!
随后,我尝试发一个红包给王工,王工一直没有领取,十分的诚恳,
说明东软载波的服务是靠谱的。


1.png

2.png

3.png

4.png

5.png

在此,特别【表扬】东软载波的王永全工程师。

RT-Thread活动正文将陆续更新在沙发层。

使用特权

评论回复
 楼主 | 2020-4-29 07:48 | 显示全部楼层
本帖最后由 yljon 于 2020-6-28 20:42 编辑

基于RT-Thread与东软载波的上位机下位机开发
作者:李俊(论坛ID:yljon)
一、概述:
1. 下位机系统实现功能:
   1) 电参数自动采集,演示系统用开发板上VR采集ADC,实际系统中用RS-485采配电房交流2000A配电柜;
   2) A/B路合闸开关切换控制,演示系统用开发板上K1,K2,实际系统用隔离IO采集合闸开关;
   3) A/B路合闸开关状态显示,演示系统用开发板上LED,实际系统用隔离IO输出;
   4) 触摸屏显示电流和A/B路状态,触摸屏也可以操作A/B路合闸开关切换;
2. 上位机系统实现功能:
   1) 采集的数据上传到电脑上位机程序中,在上位机程序显示采集数据和状态;
   2) 上位机程序下发控制指令,使A/B路合闸开关进行动作;
   3. 下位机准备用东软载波开发板,MCU型号:ES32F0654LT;
   4. 下位机系统准备用RT-Thread;


二、RT-Thread使用情况概述:
首次接触RT-Thread,感觉比UCOS比FreeRTOS强大,RT-Thread 与其他很多 RTOS 如 FreeRTOS、uC/OS 的主要区别之一是,它不仅仅是一个实时内核,还具备丰富的中间层组件。详细内容参见RT-Thread官网:https://www.rt-thread.org/document/site/tutorial/quick-start/introduction/introduction/
我这个演示项目主要用RT-Thread的内容有:
1. 由于申请的板卡是M0的板卡,那就用RT-Thread精简版的吧,就用:RT-Thread Nano;
2. 虽然这个演示项目足够简单,多线程还是要用的;
3. 各线程里面的延时肯定用RT-Thread自带的,时钟管理要用滴;
4. 由于通信主要用UART,预计接收发送啥的应该用中断;
5. 开发板上的按钮,预计用中断吧;
其它RT-Thread高级功能估计这次用不上了,暂时就不去搞了。


三、硬件框架:

1. 硬件包括:
   1) 开发板:东软载波开发板,MCU型号:ES32F0654LT
   2) 烧录器:东软载波配套的ES-LINK II
   3) 串口屏:型号TJC3224T124_011(这个也是向官方申请的样品)
2. 硬件连接示意图:

1.硬件.png

3. 实际硬件图:

2.硬件实际.jpg

四、软件框架:
1. 先将驱动装起来,由于此次是二姨家配套的板子提供的烧录器是ES-LINK II,到官网(http://www.essemi.com/)下载ES-LINK II的驱动ESburner_1.0.0.98.zip,安装好驱动之后,将ES-LINKII插入电脑,在电脑上会看到如下:


3.驱动.png

打开KEIL,在设置里看见这样,至此驱动安装就OK啦。

4.驱动.png

2.我的开发板是ES32F0654,要将PACK装起来,到官网(http://www.essemi.com/)上下载PACK,我下载的是Eastsoft.ES32_DFP.1.0.5,安装好之后,在KEIL中可以看见如下:

5.PACK.png

3.为了编程方便,先选择一个官网(http://www.essemi.com/)上的DEMO基础程序,我选择的是ES32_SDK_V1.05下的02_send_recv_by_interrupt,

5.程序.png

4.下面就是重点了:移植RT-Thread Nano,精彩的部分即将开始:
1)点击 Manage Run-Time Environment,在 Manage Rum-Time Environment 里 "Software Component" 栏找到 RTOS,Variant 栏选择 RT-Thread,然后勾选 kernel,点击 "OK" 就添加 RT-Thread 内核到工程了。

6.RTT1.png

2)这个时候将在工程里看见添加内容:

6.RTT2.png


3)下面是让这个RT-Thread接管我们的裸机程序:
A. 异常处理函数的接管:删除原来裸机程序irq.c中原来的HardFault_Handler() ,这个在RT-Thread中有重新定义;
B.挂机处理函数的接管:删除原来裸机程序irq.c中原来的PendSV_Handler() ,这个在RT-Thread中有重新定义;
C.时钟处理函数的接管:删除原来裸机程序irq.c中原来的SysTick_Handler() ,这个在RT-Thread中有重新定义;
D. 在main.c 加入RT-Thread的头文件rtthread.h即可。
至此一个RT-Thread程序已经诞生了!!!

5.在移植好的程序里添加需要的功能:
1)添加数据采集功能:
这个系统是A路和B路切换功能,但是采集只需要采集一路即可,使用ADC采集,ADC初始化代码如下:

  1. void adc_init(void)
  2. {
  3.         gpio_init_t x;

  4.         /* Initialize ADC pin */
  5.         x.mode = GPIO_MODE_INPUT;
  6.         x.pupd = GPIO_PUSH_UP;
  7.         x.odrv = GPIO_OUT_DRIVE_NORMAL;
  8.         x.flt  = GPIO_FILTER_DISABLE;
  9.         x.type = GPIO_TYPE_CMOS;
  10.         x.func = GPIO_FUNC_0;
  11.         ald_gpio_init(GPIO_CH_PORT, ADC_CH14_PIN, &x);
  12.         
  13.         /* clear adc_handle_t structure */
  14.         memset(&h_adc, 0x0, sizeof(adc_handle_t));
  15.         /* clear adc_nch_conf_t structure */
  16.         memset(&nm_config, 0x0, sizeof(adc_nch_conf_t));        
  17.         /* Initialize adc */
  18.         h_adc.perh = ADC0;
  19.         h_adc.init.data_align              = ADC_DATAALIGN_RIGHT;
  20.         h_adc.init.scan_mode               = DISABLE;
  21.         h_adc.init.cont_mode               = DISABLE;
  22.         h_adc.init.nch_len                 = ADC_NCH_LEN_1;
  23.         h_adc.init.disc_mode                    = ADC_ALL_DISABLE;
  24.         h_adc.init.disc_nbr                = ADC_DISC_NBR_1;
  25.         h_adc.init.conv_res                   = ADC_CONV_RES_12;
  26.         h_adc.init.clk_div                 = ADC_CKDIV_128;
  27. //        h_adc.init.nche_sel                = ADC_NCHESEL_MODE_ALL;
  28.         h_adc.init.neg_ref                    = ADC_NEG_REF_VSS;
  29.         h_adc.init.pos_ref                    = ADC_POS_REF_VDD;
  30. //        h_adc.adc_reg_cplt_cbk             = normal_convert_complete;
  31. //        h_adc.adc_inj_cplt_cbk             = insert_convert_complete;
  32. //        h_adc.adc_out_of_win_cbk           = out_window_complete;
  33. //        h_adc.adc_error_cbk                = error_complete;
  34. //        h_adc.adc_ovr_cbk                  = ovr_complete;
  35.         ald_adc_init(&h_adc);

  36.         /* Initialize normal convert channel */
  37.         nm_config.channel       = ADC_CHANNEL_14;
  38.         nm_config.rank          = ADC_NCH_RANK_1;
  39.         nm_config.samp_time     = ADC_SAMPLETIME_4;
  40.          ald_adc_normal_channel_config(&h_adc, &nm_config);
  41.         
  42.         return;
  43. }

复制代码


在ADC初始化之后,就可以在主程序中直接使用了,直接将采集数据给myvolt即可,
代码如下:

  1. ald_adc_start_by_dma(&h_adc, &myvolt, 1, ADC_CHANNEL_0);
复制代码

2)由于我设计的数据采集系统支持本地按钮切换操作,按钮才操作使用GPIO的INPUT功能即可,为了方便使用,使用中断方式,GPIO初始化代码如下:

  1. void key_init(void)
  2. {
  3.         gpio_init_t x;
  4.         exti_init_t exti;

  5.         /* Initialize key exti pin as input */
  6.         x.mode = GPIO_MODE_INPUT;
  7.         x.odos = GPIO_PUSH_PULL;
  8.         x.pupd = GPIO_PUSH_UP;
  9.         x.odrv = GPIO_OUT_DRIVE_NORMAL;
  10.         x.flt  = GPIO_FILTER_DISABLE;
  11.         x.type = GPIO_TYPE_CMOS;
  12.         x.func = GPIO_FUNC_1;
  13.         ald_gpio_init(GPIO_KEY_1_PORT, GPIO_KEY_1_PIN, &x);
  14.         ald_gpio_init(GPIO_KEY_2_PORT, GPIO_KEY_2_PIN, &x);        

  15.         /* Initialize external interrupt */
  16.         exti.filter      = ENABLE;
  17.         exti.cks         = EXTI_FILTER_CLOCK_10K;
  18.         exti.filter_time = 10;
  19.         ald_gpio_exti_init(GPIO_KEY_1_PORT, GPIO_KEY_1_PIN, &exti);
  20.         ald_gpio_exti_init(GPIO_KEY_2_PORT, GPIO_KEY_2_PIN, &exti);

  21.         /* Clear interrupt flag */
  22.         ald_gpio_exti_clear_flag_status(GPIO_KEY_1_PIN);
  23.         ald_gpio_exti_clear_flag_status(GPIO_KEY_2_PIN);

  24.         /* Configure interrupt */
  25.         ald_gpio_exti_interrupt_config(GPIO_KEY_1_PIN, EXTI_TRIGGER_TRAILING_EDGE, ENABLE);        
  26.         ald_gpio_exti_interrupt_config(GPIO_KEY_2_PIN, EXTI_TRIGGER_TRAILING_EDGE, ENABLE);        
  27. }

复制代码

初始化完成之后,编写中断处理函数,由于分别使用A路和B路按钮,判断一下按钮即可,代码如下:

  1. void gpio_irq_handler(void)
  2. {
  3.         /* Check and clear interrupt flag */
  4.         if (ald_gpio_exti_get_flag_status(GPIO_KEY_1_PIN)) {
  5.                 ald_gpio_exti_clear_flag_status(GPIO_KEY_1_PIN);
  6.                 //ald_gpio_toggle_pin(LED1_PORT, LED1_PIN);
  7.                 ald_gpio_write_pin(LED2_PORT,LED2_PIN,1);
  8.                 //
  9.                 //这里可以加入防呆
  10.                 //
  11.                 ald_gpio_write_pin(LED1_PORT,LED1_PIN,0);
  12.                 FenLu=1;
  13.         }

  14.         if (ald_gpio_exti_get_flag_status(GPIO_KEY_2_PIN)) {
  15.                 ald_gpio_exti_clear_flag_status(GPIO_KEY_2_PIN);
  16.                 //ald_gpio_toggle_pin(LED2_PORT, LED2_PIN);
  17.                 ald_gpio_write_pin(LED2_PORT,LED2_PIN,0);
  18.                 //
  19.                 //这里可以加入防呆
  20.                 //
  21.                 ald_gpio_write_pin(LED1_PORT,LED1_PIN,1);
  22.                 FenLu=2;
  23.         }
  24.         return;
  25. }
复制代码


3)由于我设计这套系统支持触摸屏切换A路和B路,触摸屏使用串口,所以串口的处理如下,先初始化触摸屏的串口UART1,代码如下:

  1. void uart1_init(void)
  2. {
  3.         gpio_init_t x;

  4.         /* Initialize tx pin */
  5.         x.mode = GPIO_MODE_OUTPUT;
  6.         x.odos = GPIO_PUSH_PULL;
  7.         x.pupd = GPIO_PUSH_UP;
  8.         x.odrv = GPIO_OUT_DRIVE_NORMAL;
  9.         x.flt  = GPIO_FILTER_DISABLE;
  10.         x.type = GPIO_TYPE_TTL;
  11.         x.func = GPIO_FUNC_3;
  12.         ald_gpio_init(UART1_TX_PORT, UART1_TX_PIN, &x);

  13.         /* Initialize rx pin */
  14.         x.mode = GPIO_MODE_INPUT;
  15.         x.odos = GPIO_PUSH_PULL;
  16.         x.pupd = GPIO_PUSH_UP;
  17.         x.odrv = GPIO_OUT_DRIVE_NORMAL;
  18.         x.flt  = GPIO_FILTER_DISABLE;
  19.         x.type = GPIO_TYPE_TTL;
  20.         x.func = GPIO_FUNC_3;
  21.         ald_gpio_init(UART1_RX_PORT, UART1_RX_PIN, &x);

  22.         /* clear uart_handle_t structure */
  23.         memset(&h_uart1, 0x0, sizeof(h_uart1));
  24.         /* Initialize tx_buf */
  25.         memset(tx1_buf, 0x55, 32);
  26.         /* Initialize uart */
  27.         h_uart1.perh             = UART1;
  28.         h_uart1.init.baud        = 115200;
  29.         h_uart1.init.word_length = UART_WORD_LENGTH_8B;
  30.         h_uart1.init.stop_bits   = UART_STOP_BITS_1;
  31.         h_uart1.init.parity      = UART_PARITY_NONE;
  32.         h_uart1.init.mode        = UART_MODE_UART;
  33.         h_uart1.init.fctl        = UART_HW_FLOW_CTL_DISABLE;
  34.         h_uart1.tx_cplt_cbk      = uart1_send_complete;
  35.         h_uart1.rx_cplt_cbk      = uart1_recv_complete;
  36.         h_uart1.error_cbk        = uart1_error;
  37.         ald_uart_init(&h_uart1);        
  38.         return;
  39. }
复制代码

对于触摸屏的发送和接收直接在主函数里处理,代码如下:

  1. ald_uart_send_by_it(&h_uart1, tx1_buf, 10);
  2. ald_uart_recv_by_it(&h_uart1, rx1_buf, 8);
复制代码


对于触摸屏的发送,无需我们处理,但是对于接收,我们必须处理,放在中断里处理,中断处理函数如下:

  1. void uart1_recv_complete(uart_handle_t *arg)
  2. {
  3.         
  4.         if(rx1_buf[0]==0x01&&rx1_buf[1]==0x06&&rx1_buf[6]==0x88&&rx1_buf[7]==0x99)
  5.         {
  6.                 FenLu=rx1_buf[5];
  7.                 if(FenLu==1)
  8.                 {
  9.                         ald_gpio_write_pin(LED2_PORT,LED2_PIN,1);
  10.                         //
  11.                         //这里可以加入防呆
  12.                         //
  13.                         ald_gpio_write_pin(LED1_PORT,LED1_PIN,0);
  14.                 }
  15.                 if(FenLu==2)
  16.                 {
  17.                         ald_gpio_write_pin(LED2_PORT,LED2_PIN,0);
  18.                         //
  19.                         //这里可以加入防呆
  20.                         //
  21.                         ald_gpio_write_pin(LED1_PORT,LED1_PIN,1);
  22.                 }
  23.         }
  24.         return;
  25. }
复制代码

4)在这套系统中,上位机电脑上的程序也是我自己编写,所以通讯速度、格式、协议我都完全掌控,所以采用串口,对串口UART2的初始化如下:

  1. <p>void uart2_init(void)
  2. {
  3. gpio_init_t x;</p><p> /* Initialize tx pin */
  4. x.mode = GPIO_MODE_OUTPUT;
  5. x.odos = GPIO_PUSH_PULL;
  6. x.pupd = GPIO_PUSH_UP;
  7. x.odrv = GPIO_OUT_DRIVE_NORMAL;
  8. x.flt  = GPIO_FILTER_DISABLE;
  9. x.type = GPIO_TYPE_TTL;
  10. x.func = GPIO_FUNC_5;
  11. ald_gpio_init(UART2_TX_PORT, UART2_TX_PIN, &x);</p><p> /* Initialize rx pin */
  12. x.mode = GPIO_MODE_INPUT;
  13. x.odos = GPIO_PUSH_PULL;
  14. x.pupd = GPIO_PUSH_UP;
  15. x.odrv = GPIO_OUT_DRIVE_NORMAL;
  16. x.flt  = GPIO_FILTER_DISABLE;
  17. x.type = GPIO_TYPE_TTL;
  18. x.func = GPIO_FUNC_5;
  19. ald_gpio_init(UART2_RX_PORT, UART2_RX_PIN, &x);</p><p> /* clear uart_handle_t structure */
  20. memset(&h_uart2, 0x0, sizeof(h_uart2));
  21. /* Initialize tx_buf */
  22. memset(tx2_buf, 0x56, 32);
  23. /* Initialize uart */
  24. h_uart2.perh             = UART2;
  25. h_uart2.init.baud        = 115200;
  26. h_uart2.init.word_length = UART_WORD_LENGTH_8B;
  27. h_uart2.init.stop_bits   = UART_STOP_BITS_1;
  28. h_uart2.init.parity      = UART_PARITY_NONE;
  29. h_uart2.init.mode        = UART_MODE_UART;
  30. h_uart2.init.fctl        = UART_HW_FLOW_CTL_DISABLE;
  31. h_uart2.tx_cplt_cbk      = uart2_send_complete;
  32. h_uart2.rx_cplt_cbk      = uart2_recv_complete;
  33. h_uart2.error_cbk        = uart2_error;
  34. ald_uart_init(&h_uart2);

  35. return;
  36. }

  37. </p><p> </p>
复制代码

对上位机的串口发送和接收也直接在主函数里处理即可,由于协议是我自己编写,发送、接收格式和触摸屏发送、接收格式一致,这样就方便许多,代码如下:
  1. ald_uart_send_by_it(&h_uart2, tx1_buf, 10);
  2. ald_uart_recv_by_it(&h_uart2, rx2_buf, 8);
复制代码

对于上位机电脑的发送,无需我们处理,但是对于接收,我们必须处理,放在中断里处理,中断处理函数如下:

  1. void uart2_recv_complete(uart_handle_t *arg)
  2. {
  3.         

  4.         if(rx2_buf[0]==0x01&&rx2_buf[1]==0x06&&rx2_buf[6]==0x88&&rx2_buf[7]==0x99)
  5.         {
  6.                 FenLu=rx2_buf[5];
  7.                 if(FenLu==1)
  8.                 {
  9.                         ald_gpio_write_pin(LED2_PORT,LED2_PIN,1);
  10.                         //
  11.                         //这里可以加入防呆
  12.                         //                        
  13.                         ald_gpio_write_pin(LED1_PORT,LED1_PIN,0);
  14.                 }
  15.                 if(FenLu==2)
  16.                 {
  17.                         ald_gpio_write_pin(LED2_PORT,LED2_PIN,0);
  18.                         //
  19.                         //这里可以加入防呆
  20.                         //                        
  21.                         ald_gpio_write_pin(LED1_PORT,LED1_PIN,1);
  22.                 }
  23.         }               
  24.         return;
  25. }
复制代码

至此,本套系统的全部代码都编写完成了,烧录到板子上进行试验,可以完美运行。

运行.jpg

6.上位机电脑程序的编写,主要功能就是:
A.在上位机上显示A路和B路状态;
B.在上位机上显示采集的数据;
C.在上位机上进行A路和B路切换;
配合下位机可以完美运行:

上位机.png


五.演示视频:
1.使用按钮控制A/B路切换的视频地址;
https://www.bilibili.com/video/BV1Qt4y1C7nz

按钮演示.png

2.使用触摸屏控制A/B路切换的视频地址;
https://www.bilibili.com/video/BV1Fi4y1t7rk

触摸屏演示.png

3.使用上位机控制A/B路切换的视频地址;
https://www.bilibili.com/video/BV1Qp4y1Q7tE

上位机演示.png

4.设计的配电柜A/B路切换的综合演示视频地址:
https://www.bilibili.com/video/BV1rD4y1Q7Yd

综合演示00.png


六.源代码地址:
1.触摸屏源代码:按照以上步骤配置的触摸屏源代码只有一个文件:《触摸屏:RT-Thread创新大赛.HMI》, 触摸屏:RT-Thread创新大赛.rar (234.43 KB, 下载次数: 1)

使用特权

评论回复
| 2020-4-29 10:17 | 显示全部楼层
此处应该艾特王工

使用特权

评论回复
| 2020-5-9 16:44 | 显示全部楼层
感谢分享,论坛送您1000家园币,可以兑换礼品。以及论坛给您寄出一份礼品,以示鼓励~ 您继续加油,尽快把帖子更新、继续完善,上传方案文档哦~

使用特权

评论回复
 楼主 | 2020-5-9 17:41 | 显示全部楼层
21ic小喇叭 发表于 2020-5-9 16:44
感谢分享,论坛送您1000家园币,可以兑换礼品。以及论坛给您寄出一份礼品,以示鼓励~ 您继续加油,尽快把帖 ...

谢谢小喇叭,我正在写上位机

使用特权

评论回复
 楼主 | 2020-5-12 15:25 | 显示全部楼层
本帖最后由 yljon 于 2020-5-12 15:26 编辑

上2张图片,剧透一下 @21ic小喇叭


微信图片_20200512152258.jpg


微信图片_20200512152305.jpg

使用特权

评论回复
 楼主 | 2020-5-13 16:48 | 显示全部楼层
正式内容还没有上传,就收到礼物里,感谢 @21ic小喇叭 。

哎呀,这不得不加快更新了

微信图片_20200513164301.jpg


使用特权

评论回复
 楼主 | 2020-5-20 21:28 | 显示全部楼层
本帖最后由 yljon 于 2020-5-20 21:30 编辑

微信截图_20200520212444.png

@21ic小喇叭 又是送礼物,又是加分,我都不好意思啦。就是时间十分紧张,抽空写了上位机。
这个上位机界面好丑啊

使用特权

评论回复
 楼主 | 2020-5-27 21:01 | 显示全部楼层
本帖最后由 yljon 于 2020-5-27 21:05 编辑

报告 @21ic小喇叭   这个星期主要搞B站了,至少视频可以上传了:


第一个视频:使用按钮控制A/B路切换;
https://www.bilibili.com/video/BV1Qt4y1C7nz

第二个视频:使用触摸屏控制A/B路切换;
https://www.bilibili.com/video/BV1Fi4y1t7rk

第三个视频:使用上位机控制A/B路切换;
https://www.bilibili.com/video/BV1Qp4y1Q7tE

这个系统目前实现这3种控制方式。
体会:上传视频太费劲

使用特权

评论回复
| 2020-6-5 11:07 | 显示全部楼层
大大,我看您写的非常专业,您如果完成了作品,千万别忘记按比赛要求,做成文档,上传到论坛

文档模板在咱们参赛群里有,如果没找到,联系大掌柜单独发给您

提交作品以后,大掌柜给您寄礼品

使用特权

评论回复

评论

yljon 2020-6-5 12:18 回复TA
小喇叭啊,我更新的内容在沙发层,结果你把我的沙发搬到哪里去了啊??? 
 楼主 | 2020-6-17 23:10 | 显示全部楼层
在沙发贴里下载的是ESburner_1.0.0.98.zip,用在这个演示项目里也是这个版本。现在官网上最新版本是ESburner_1.0.1.3.zip,特此备注一下。

使用特权

评论回复
 楼主 | 2020-6-28 20:46 | 显示全部楼层
本帖最后由 yljon 于 2020-6-28 20:47 编辑

@21ic小喇叭

我的文案已经全部完成了,所有的东东都在帖子的沙发层里,包括文案。

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 我要提问 投诉建议 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

关闭

热门推荐上一条 /5 下一条

在线客服 快速回复 返回顶部 返回列表