硬汉嵌入式论坛

 找回密码
 立即注册
查看: 130|回复: 9
收起左侧

[emWin] 在emwin框架内使用串口接收中断处理数据偶尔出现乱码是什么原因

[复制链接]

2

主题

5

回帖

11

积分

新手上路

积分
11
发表于 前天 11:43 | 显示全部楼层 |阅读模式
求助:

    硬件:F429+7寸触摸屏。
    程序功能:通过自定义的串口协议接收数据包,并把这些数据显示在emwin界面上,串口接收数据采用中断接收方法,但是这样的话就会时不时出现一个乱码的数据包;在不和emwin界面集成到一起时,我自己使用F429例程里的串口收发程序改一改测试串口协议,试了串口数据包收发是没问题的,不会出现乱码,这是什么原因呢,是哪里配置的中断时序影响的吗?


串口相关主要程序:
1.usart.c

void USART1_IRQHandler(void)
{
        static uint8_t RxState = 0;                //定义表示当前状态机状态的静态变量
        static uint8_t pRxPacket = 0;        //定义表示当前接收数据位置的静态变量
       
        if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)                //判断是否是USART1的接收事件触发的中断
        {
                uint8_t RxData = USART_ReceiveData(USART1);                                //读取数据寄存器,存放在接收的数据变量
               
                /*使用状态机的思路,依次处理数据包的不同部分*/
               
                /*当前状态为0,接收数据包包头1*/
                if (RxState == 0)
                {
                        if (RxData == 0x7E)                        //如果数据确实是包头
                        {
                                RxState = 1;                        //置下一个状态
                                pRxPacket = 0;                        //数据包的位置归零
                        }
                //中间省略,定义了一些数据格式
                /*当前状态为6,接收数据包包尾*/
                else if (RxState == 6)
                {
                        if (RxData == 0x23)                        //如果数据确实是包尾部
                        {
                                RxState = 0;                        //状态归0
                                Serial_RxFlag = 1;                //接收数据包标志位置1,成功接收一个数据包
                        }
                }
               
                USART_ClearITPendingBit(USART1, USART_IT_RXNE);                //清除标志位
        }
}

2.mainTask.c

void MainTask(void)
{
        extern uint8_t  tstate;
        int i = 0;
        float X1, Y1, X2, Y2, POWER1, POWER2;
        float resultsA[3], resultsB[3], resultsAB[6];


        Debug_USART_Config();

    while (1)
    {

                if (Serial_GetRxFlag() == 1)
                {
                       
                       
                 if (tstate == 5)
                        {
                          for (i = 0; i < 6; i++) {
              resultsAB = hex_array_to_float(&Serial_RxPacketAB[i * 4]);
              } //处理串口接收到的数据并显示
                          
                          X1 = resultsAB[0];
                  Y1 = resultsAB[1];
                  POWER1 = resultsAB[2];
                  X2 = resultsAB[3];
                  Y2 = resultsAB[4];
                  POWER2 = resultsAB[5];
                          
                          printf("X1 = %.4f\n",  X1);
                          printf("Y1 = %.4f\n",  Y1);
                          printf("POWER1 = %.4f\n",  POWER1);
              printf("X2 = %.4f\n",  X2);
                          printf("Y2 = %.4f\n",  Y2);
                          printf("POWER2 = %.4f\n",  POWER2);
                          
                        }
                       
                }
    }
}


直接用上述程序测试串口数据接收是没问题的,但是将上面程序集成到emwin程序框架后,数据就会偶尔出现乱码,调试时数据是使用串口调试助手发送的,间隔为100ms。

3.emwin程序框架中的main.c程序,在最后调用了mainTask.c(感觉主要是一些初始化)



#include <stdio.h>

/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* 开发板硬件bsp头文件 */
#include "./led/bsp_led.h"
#include "./beep/bsp_beep.h"
#include "./usart/bsp_debug_usart.h"
#include "./TouchPad/bsp_touchpad.h"
#include "./lcd/bsp_lcd.h"
#include "./touch/gt9xx.h"
#include "./key/bsp_key.h"
#include "./sdram/bsp_sdram.h"
/* STemWIN头文件 */
#include "GUI.h"
#include "DIALOG.h"
/* FATFS */
#include "ff.h"
#include "diskio.h"
#include "integer.h"

/**************************** 任务句柄 ********************************/
/*
* 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
* 这个句柄可以为NULL。
*/
/* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED任务句柄 */
static TaskHandle_t LED_Task_Handle = NULL;
/* Touch任务句柄 */
static TaskHandle_t Touch_Task_Handle = NULL;
/* GUI任务句柄 */
static TaskHandle_t GUI_Task_Handle = NULL;

/******************************* 全局变量声明 ************************************/
/*
* 当我们在写应用程序的时候,可能需要用到一些全局变量。
*/
FATFS   fs;                                                                /* FatFs文件系统对象 */
FIL     file;                                                        /* file objects */
UINT    bw;                            /* File R/W count */
FRESULT result;
FILINFO fno;
DIR dir;

static void AppTaskCreate(void);

static void LED_Task(void* parameter);
static void Touch_Task(void* parameter);
static void GUI_Task(void* parameter);

static void BSP_Init(void);
static void AP6181_PDN_INIT(void);

/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{
        BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
       
        /* 开发板硬件初始化 */
        BSP_Init();
       
        xReturn = xTaskCreate((TaskFunction_t)AppTaskCreate,/* 任务入口函数 */
                                                                                         (const char*    )"AppTaskCreate",/* 任务名称 */
                                                                                         (uint16_t       )512,                                        /* 任务栈大小 */
                                                                                         (void*          )NULL,                                        /* 任务入口函数参数 */
                                                                                         (UBaseType_t    )1,                                                /* 任务的优先级 */
                                                                                         (TaskHandle_t   )&AppTaskCreate_Handle);/* 任务控制块指针 */
        /* 启动任务调度 */
        if(pdPASS == xReturn)
                vTaskStartScheduler();/* 启动任务,开启调度 */
        else
                return -1;
       
        while(1);/* 正常不会执行到这里 */
}

/**
  * @brief 任务创建函数
  * @note 为了方便管理,所有的任务创建都放在这个函数里面
  * @param 无
  * @retval 无
  */
static void AppTaskCreate(void)
{
        BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
       
        taskENTER_CRITICAL();//进入临界区
       
//        xReturn = xTaskCreate((TaskFunction_t)LED_Task,/* 任务入口函数 */
//                                                                                         (const char*    )"LED_Task",/* 任务名称 */
//                                                                                         (uint16_t       )128,       /* 任务栈大小 */
//                                                                                         (void*          )NULL,      /* 任务入口函数参数 */
//                                                                                         (UBaseType_t    )4,         /* 任务的优先级 */
//                                                                                         (TaskHandle_t   )&LED_Task_Handle);/* 任务控制块指针 */
//        if(pdPASS == xReturn)
//                printf("创建LED1_Task任务成功!\r\n");
       
        xReturn = xTaskCreate((TaskFunction_t)Touch_Task,/* 任务入口函数 */
                                                                                         (const char*      )"Touch_Task",/* 任务名称 */
                                                                                         (uint16_t         )256,     /* 任务栈大小 */
                                                                                         (void*            )NULL,    /* 任务入口函数参数 */
                                                                                         (UBaseType_t      )3,       /* 任务的优先级 */
                                                                                         (TaskHandle_t     )&Touch_Task_Handle);/* 任务控制块指针 */
        if(pdPASS == xReturn)
                printf("创建Touch_Task任务成功!\r\n");
       
        xReturn = xTaskCreate((TaskFunction_t)GUI_Task,/* 任务入口函数 */
                                                                                         (const char*      )"GUI_Task",/* 任务名称 */
                                                                                         (uint16_t         )1024,      /* 任务栈大小 */
                                                                                         (void*            )NULL,      /* 任务入口函数参数 */
                                                                                         (UBaseType_t      )2,         /* 任务的优先级 */
                                                                                         (TaskHandle_t     )&GUI_Task_Handle);/* 任务控制块指针 */
        if(pdPASS == xReturn)
                printf("创建GUI_Task任务成功!\r\n");
       
        vTaskDelete(AppTaskCreate_Handle);//删除AppTaskCreate任务
       
        taskEXIT_CRITICAL();//退出临界区
}

/**
  * @brief LED任务主体
  * @note 无
  * @param 无
  * @retval 无
  */
static void LED_Task(void* parameter)
{
        while(1)
        {
                LED3_TOGGLE;
                vTaskDelay(1000);
        }
}

/**
  * @brief 触摸检测任务主体
  * @note 无
  * @param 无
  * @retval 无
  */
static void Touch_Task(void* parameter)
{
        while(1)
        {
                GT9xx_GetOnePiont();//触摸屏定时扫描
                vTaskDelay(20);
        }
}

/**
  * @brief GUI任务主体
  * @note 无
  * @param 无
  * @retval 无
  */
static void GUI_Task(void* parameter)
{
        /* 初始化STemWin */
  GUI_Init();
        /* 开启多缓冲 */
        WM_MULTIBUF_Enable(1);
       
        while(1)
        {
                MainTask();
        }
}

/**
  * @brief 板级外设初始化
  * @note 所有板子上的初始化均可放在这个函数里面
  * @param 无
  * @retval 无
  */
static void BSP_Init(void)
{
        /* CRC和emWin没有关系,只是他们为了库的保护而做的
   * 这样STemWin的库只能用在ST的芯片上面,别的芯片是无法使用的。
   */
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
       
        /*
         * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
         * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
         * 都统一用同一个优先级分组,千万不要再分组,切记。
         */
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
       
        /* LED 初始化 */
        LED_GPIO_Config();
        /* 串口初始化        */
        Debug_USART_Config();
        /* 蜂鸣器初始化 */
        Beep_GPIO_Config();
        /* 初始化触摸屏 */
        GTP_Init_Panel();
        /* SDRAM初始化 */
  SDRAM_Init();
        /* LCD初始化 */
        LCD_Init();
  /* 禁用WiFi模块 */
        AP6181_PDN_INIT();
  /* 挂载文件系统,挂载时会对SD卡初始化 */
  result = f_mount(&fs,"0:",1);
        if(result != FR_OK)
        {
                printf("1\n");
                while(1);
        }
}

/**
  * @brief AP6181_PDN_INIT
  * @note 禁止WIFI模块
  * @param 无
  * @retval 无
  */
static void AP6181_PDN_INIT(void)-省略




   
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115434
QQ
发表于 前天 13:13 | 显示全部楼层
串口中断抢占优先级设置到最高试试
回复

使用道具 举报

10

主题

678

回帖

708

积分

金牌会员

积分
708
发表于 前天 14:37 | 显示全部楼层
串口接收加上校验CRC。
回复

使用道具 举报

2

主题

5

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 前天 16:24 | 显示全部楼层
eric2013 发表于 2025-4-23 13:13
串口中断抢占优先级设置到最高试试

调到最高也是有乱码,感觉是什么设置了会定时中断一下数据的接收,因为乱码的数字是没按照规定协议接收的错位数字,能看出来还是在原设置的发送数据里,但是位置不对了,比如设定接收1234、5678,错位的是接收成了2345、6789
回复

使用道具 举报

2

主题

5

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 前天 16:25 | 显示全部楼层
hqgboy 发表于 2025-4-23 14:37
串口接收加上校验CRC。

数据包格式是上位机规定好的,不能添加校验位
回复

使用道具 举报

10

主题

678

回帖

708

积分

金牌会员

积分
708
发表于 前天 19:19 | 显示全部楼层
FFSTTYU 发表于 2025-4-23 16:25
数据包格式是上位机规定好的,不能添加校验位

做个最简单EMWIN和串口通讯试试,其他功能先屏蔽。
回复

使用道具 举报

2

主题

5

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 前天 20:21 | 显示全部楼层
hqgboy 发表于 2025-4-23 19:19
做个最简单EMWIN和串口通讯试试,其他功能先屏蔽。

目前就是把对话框等功能全部屏蔽了,主程序里只有串口通讯函数,就出现这个问题
回复

使用道具 举报

2

主题

22

回帖

28

积分

新手上路

积分
28
发表于 昨天 08:47 | 显示全部楼层
中断里面对帧进行处理不好,宜放在一个单独的任务中。中断只接收数据,写到缓冲区。
回复

使用道具 举报

10

主题

678

回帖

708

积分

金牌会员

积分
708
发表于 昨天 08:53 | 显示全部楼层
上工具吧。示波器测试一下串口数据。串口监控一下发送的数据。
回复

使用道具 举报

8

主题

31

回帖

55

积分

初级会员

积分
55
发表于 昨天 17:51 | 显示全部楼层
弱弱问一下,MainTask这样写会不会因为没sleep一直跑导致跑死?Serial_GetRxFlag()这个也不像会pending任务。。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-4-25 19:10 , Processed in 0.306162 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表