打印
[uCOS/RTOS]

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

[复制链接]
2900|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yljon|  楼主 | 2020-4-29 07:47 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
顶楼:RT-Thread活动前传:
【表扬】东软载波的王永全工程师

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

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












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

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

使用特权

评论回复

相关帖子

沙发
yljon|  楼主 | 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. 硬件连接示意图:



3. 实际硬件图:



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




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



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



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



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



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




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初始化代码如下:

void adc_init(void)
{
        gpio_init_t x;

        /* Initialize ADC pin */
        x.mode = GPIO_MODE_INPUT;
        x.pupd = GPIO_PUSH_UP;
        x.odrv = GPIO_OUT_DRIVE_NORMAL;
        x.flt  = GPIO_FILTER_DISABLE;
        x.type = GPIO_TYPE_CMOS;
        x.func = GPIO_FUNC_0;
        ald_gpio_init(GPIO_CH_PORT, ADC_CH14_PIN, &x);
        
        /* clear adc_handle_t structure */
        memset(&h_adc, 0x0, sizeof(adc_handle_t));
        /* clear adc_nch_conf_t structure */
        memset(&nm_config, 0x0, sizeof(adc_nch_conf_t));        
        /* Initialize adc */
        h_adc.perh = ADC0;
        h_adc.init.data_align              = ADC_DATAALIGN_RIGHT;
        h_adc.init.scan_mode               = DISABLE;
        h_adc.init.cont_mode               = DISABLE;
        h_adc.init.nch_len                 = ADC_NCH_LEN_1;
        h_adc.init.disc_mode                    = ADC_ALL_DISABLE;
        h_adc.init.disc_nbr                = ADC_DISC_NBR_1;
        h_adc.init.conv_res                   = ADC_CONV_RES_12;
        h_adc.init.clk_div                 = ADC_CKDIV_128;
//        h_adc.init.nche_sel                = ADC_NCHESEL_MODE_ALL;
        h_adc.init.neg_ref                    = ADC_NEG_REF_VSS;
        h_adc.init.pos_ref                    = ADC_POS_REF_VDD;
//        h_adc.adc_reg_cplt_cbk             = normal_convert_complete;
//        h_adc.adc_inj_cplt_cbk             = insert_convert_complete;
//        h_adc.adc_out_of_win_cbk           = out_window_complete;
//        h_adc.adc_error_cbk                = error_complete;
//        h_adc.adc_ovr_cbk                  = ovr_complete;
        ald_adc_init(&h_adc);

        /* Initialize normal convert channel */
        nm_config.channel       = ADC_CHANNEL_14;
        nm_config.rank          = ADC_NCH_RANK_1;
        nm_config.samp_time     = ADC_SAMPLETIME_4;
         ald_adc_normal_channel_config(&h_adc, &nm_config);
        
        return;
}



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

ald_adc_start_by_dma(&h_adc, &myvolt, 1, ADC_CHANNEL_0);

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

void key_init(void)
{
        gpio_init_t x;
        exti_init_t exti;

        /* Initialize key exti pin as input */
        x.mode = GPIO_MODE_INPUT;
        x.odos = GPIO_PUSH_PULL;
        x.pupd = GPIO_PUSH_UP;
        x.odrv = GPIO_OUT_DRIVE_NORMAL;
        x.flt  = GPIO_FILTER_DISABLE;
        x.type = GPIO_TYPE_CMOS;
        x.func = GPIO_FUNC_1;
        ald_gpio_init(GPIO_KEY_1_PORT, GPIO_KEY_1_PIN, &x);
        ald_gpio_init(GPIO_KEY_2_PORT, GPIO_KEY_2_PIN, &x);        

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

        /* Clear interrupt flag */
        ald_gpio_exti_clear_flag_status(GPIO_KEY_1_PIN);
        ald_gpio_exti_clear_flag_status(GPIO_KEY_2_PIN);

        /* Configure interrupt */
        ald_gpio_exti_interrupt_config(GPIO_KEY_1_PIN, EXTI_TRIGGER_TRAILING_EDGE, ENABLE);        
        ald_gpio_exti_interrupt_config(GPIO_KEY_2_PIN, EXTI_TRIGGER_TRAILING_EDGE, ENABLE);        
}


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

void gpio_irq_handler(void)
{
        /* Check and clear interrupt flag */
        if (ald_gpio_exti_get_flag_status(GPIO_KEY_1_PIN)) {
                ald_gpio_exti_clear_flag_status(GPIO_KEY_1_PIN);
                //ald_gpio_toggle_pin(LED1_PORT, LED1_PIN);
                ald_gpio_write_pin(LED2_PORT,LED2_PIN,1);
                //
                //这里可以加入防呆
                //
                ald_gpio_write_pin(LED1_PORT,LED1_PIN,0);
                FenLu=1;
        }

        if (ald_gpio_exti_get_flag_status(GPIO_KEY_2_PIN)) {
                ald_gpio_exti_clear_flag_status(GPIO_KEY_2_PIN);
                //ald_gpio_toggle_pin(LED2_PORT, LED2_PIN);
                ald_gpio_write_pin(LED2_PORT,LED2_PIN,0);
                //
                //这里可以加入防呆
                //
                ald_gpio_write_pin(LED1_PORT,LED1_PIN,1);
                FenLu=2;
        }
        return;
}


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

void uart1_init(void)
{
        gpio_init_t x;

        /* Initialize tx pin */
        x.mode = GPIO_MODE_OUTPUT;
        x.odos = GPIO_PUSH_PULL;
        x.pupd = GPIO_PUSH_UP;
        x.odrv = GPIO_OUT_DRIVE_NORMAL;
        x.flt  = GPIO_FILTER_DISABLE;
        x.type = GPIO_TYPE_TTL;
        x.func = GPIO_FUNC_3;
        ald_gpio_init(UART1_TX_PORT, UART1_TX_PIN, &x);

        /* Initialize rx pin */
        x.mode = GPIO_MODE_INPUT;
        x.odos = GPIO_PUSH_PULL;
        x.pupd = GPIO_PUSH_UP;
        x.odrv = GPIO_OUT_DRIVE_NORMAL;
        x.flt  = GPIO_FILTER_DISABLE;
        x.type = GPIO_TYPE_TTL;
        x.func = GPIO_FUNC_3;
        ald_gpio_init(UART1_RX_PORT, UART1_RX_PIN, &x);

        /* clear uart_handle_t structure */
        memset(&h_uart1, 0x0, sizeof(h_uart1));
        /* Initialize tx_buf */
        memset(tx1_buf, 0x55, 32);
        /* Initialize uart */
        h_uart1.perh             = UART1;
        h_uart1.init.baud        = 115200;
        h_uart1.init.word_length = UART_WORD_LENGTH_8B;
        h_uart1.init.stop_bits   = UART_STOP_BITS_1;
        h_uart1.init.parity      = UART_PARITY_NONE;
        h_uart1.init.mode        = UART_MODE_UART;
        h_uart1.init.fctl        = UART_HW_FLOW_CTL_DISABLE;
        h_uart1.tx_cplt_cbk      = uart1_send_complete;
        h_uart1.rx_cplt_cbk      = uart1_recv_complete;
        h_uart1.error_cbk        = uart1_error;
        ald_uart_init(&h_uart1);        
        return;
}

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

ald_uart_send_by_it(&h_uart1, tx1_buf, 10);
ald_uart_recv_by_it(&h_uart1, rx1_buf, 8);


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

void uart1_recv_complete(uart_handle_t *arg)
{
        
        if(rx1_buf[0]==0x01&&rx1_buf[1]==0x06&&rx1_buf[6]==0x88&&rx1_buf[7]==0x99)
        {
                FenLu=rx1_buf[5];
                if(FenLu==1)
                {
                        ald_gpio_write_pin(LED2_PORT,LED2_PIN,1);
                        //
                        //这里可以加入防呆
                        //
                        ald_gpio_write_pin(LED1_PORT,LED1_PIN,0);
                }
                if(FenLu==2)
                {
                        ald_gpio_write_pin(LED2_PORT,LED2_PIN,0);
                        //
                        //这里可以加入防呆
                        //
                        ald_gpio_write_pin(LED1_PORT,LED1_PIN,1);
                }
        }
        return;
}

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

<p>void uart2_init(void)
{
gpio_init_t x;</p><p> /* Initialize tx pin */
x.mode = GPIO_MODE_OUTPUT;
x.odos = GPIO_PUSH_PULL;
x.pupd = GPIO_PUSH_UP;
x.odrv = GPIO_OUT_DRIVE_NORMAL;
x.flt  = GPIO_FILTER_DISABLE;
x.type = GPIO_TYPE_TTL;
x.func = GPIO_FUNC_5;
ald_gpio_init(UART2_TX_PORT, UART2_TX_PIN, &x);</p><p> /* Initialize rx pin */
x.mode = GPIO_MODE_INPUT;
x.odos = GPIO_PUSH_PULL;
x.pupd = GPIO_PUSH_UP;
x.odrv = GPIO_OUT_DRIVE_NORMAL;
x.flt  = GPIO_FILTER_DISABLE;
x.type = GPIO_TYPE_TTL;
x.func = GPIO_FUNC_5;
ald_gpio_init(UART2_RX_PORT, UART2_RX_PIN, &x);</p><p> /* clear uart_handle_t structure */
memset(&h_uart2, 0x0, sizeof(h_uart2));
/* Initialize tx_buf */
memset(tx2_buf, 0x56, 32);
/* Initialize uart */
h_uart2.perh             = UART2;
h_uart2.init.baud        = 115200;
h_uart2.init.word_length = UART_WORD_LENGTH_8B;
h_uart2.init.stop_bits   = UART_STOP_BITS_1;
h_uart2.init.parity      = UART_PARITY_NONE;
h_uart2.init.mode        = UART_MODE_UART;
h_uart2.init.fctl        = UART_HW_FLOW_CTL_DISABLE;
h_uart2.tx_cplt_cbk      = uart2_send_complete;
h_uart2.rx_cplt_cbk      = uart2_recv_complete;
h_uart2.error_cbk        = uart2_error;
ald_uart_init(&h_uart2);

return;
}

</p><p> </p>

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

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

void uart2_recv_complete(uart_handle_t *arg)
{
        

        if(rx2_buf[0]==0x01&&rx2_buf[1]==0x06&&rx2_buf[6]==0x88&&rx2_buf[7]==0x99)
        {
                FenLu=rx2_buf[5];
                if(FenLu==1)
                {
                        ald_gpio_write_pin(LED2_PORT,LED2_PIN,1);
                        //
                        //这里可以加入防呆
                        //                        
                        ald_gpio_write_pin(LED1_PORT,LED1_PIN,0);
                }
                if(FenLu==2)
                {
                        ald_gpio_write_pin(LED2_PORT,LED2_PIN,0);
                        //
                        //这里可以加入防呆
                        //                        
                        ald_gpio_write_pin(LED1_PORT,LED1_PIN,1);
                }
        }               
        return;
}

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



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




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



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



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



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




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


2.东软载波RT-Thread源代码:按照以上步骤配置的源代码只有一个文件《main.c》, main.rar (2.25 KB)
其余涉及东软载波的代码直接直接从官网(http://www.essemi.com)下载即可;涉及RT-Thread的代码直接从RT-Thread官网(https://www.rt-thread.org)下载即可。



3.上位机使用VB写的,只有一个文件《上位机:RT-Thread创新大赛.frm》 上位机:RT-Thread创新大赛.rar (2.28 KB)



七.总结:
1.东软载波板子功能很多,这个演示系统只用到:时钟、中断、ADC、GPIO、UART等几个简单的功能;
2. RT-Thread是一个功能强大的系统,这个演示系统只用到:RT-Thread内核、时钟、中断、延时等几个简单功能,RT-Thread很多高级功能和组件都没有用的,后续持续学习,争取将其完整版的高级功能和组件都尝试一把。
3.特别说明:RT-Thread的文档中心绝对值得所有程序员去学习的地方,是一个快速入手的最佳地方。



最后一个最重要的是这篇文案。 yljon:基于RT-Thread与东软载波的上位机下位机开发.rar (3.84 MB)


使用特权

评论回复
板凳
Fillmore| | 2020-4-29 10:17 | 只看该作者
此处应该艾特王工

使用特权

评论回复
地板
21ic小喇叭| | 2020-5-9 16:44 | 只看该作者
感谢分享,论坛送您1000家园币,可以兑换礼品。以及论坛给您寄出一份礼品,以示鼓励~ 您继续加油,尽快把帖子更新、继续完善,上传方案文档哦~

使用特权

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

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

使用特权

评论回复
6
yljon|  楼主 | 2020-5-12 15:25 | 只看该作者
本帖最后由 yljon 于 2020-5-12 15:26 编辑

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






使用特权

评论回复
7
yljon|  楼主 | 2020-5-13 16:48 | 只看该作者
正式内容还没有上传,就收到礼物里,感谢 @21ic小喇叭 。

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




使用特权

评论回复
8
yljon|  楼主 | 2020-5-20 21:28 | 只看该作者
本帖最后由 yljon 于 2020-5-20 21:30 编辑



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

使用特权

评论回复
9
yljon|  楼主 | 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种控制方式。
体会:上传视频太费劲

使用特权

评论回复
10
21ic小喇叭| | 2020-6-5 11:07 | 只看该作者
大大,我看您写的非常专业,您如果完成了作品,千万别忘记按比赛要求,做成文档,上传到论坛

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

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

使用特权

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

使用特权

评论回复
12
yljon|  楼主 | 2020-6-28 20:46 | 只看该作者
本帖最后由 yljon 于 2020-6-28 20:47 编辑

@21ic小喇叭

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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

23

主题

421

帖子

5

粉丝