c#代码Bug怎么解决

发布时间:2022-01-05 17:00:41 作者:iii
来源:亿速云 阅读:136

本篇内容介绍了“c#代码Bug怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

BUG记录5——数组访问越界,导致软件进入HardFault

这是一个比较常见也比较容易忽略的问题,从学习C语言数组开始,我们就被告知数组的下标从0开始,但是我们在实际的案例应用中,序号一般都是从1开始。在一次实际的应用中,采集板采集通道1-通道6的数值,主控板也对应的定义了一个大小为6的数据缓冲区,index从0到5,采集板采集完六个通道的数据,将数据按照帧首、通道号、采样值、帧尾的格式进行打包,然后发送给主控板,主控则对应的根据通道号将采样值存储到缓冲区,因为疏忽编码时采集板的通道号是从1到6写入数据帧的,所以当主控板接收到通道号为6的数据帧就出现了数组越界存储了,此时软件就进入HardFault死循环里面了。

void HardFault_Handler(void){
  /* Go to infinite loop when Hard Fault exception occurs */  while (1)
  {
  }
}
BUG记录6——左右移运算符<<、>>和按位与或运算符&、|的优先级问题
//Righthost_control_slave[2] = (gRtcDate&0xFF0000) >> 16;
host_control_slave[3] = (gRtcDate&0xFF00) >> 8;
host_control_slave[4] =  gRtcDate & 0xFF;//Errorhost_control_slave[2] = gRtcDate & 0xFF0000 >> 16;
host_control_slave[3] = gRtcDate & 0xFF00 >> 8;
host_control_slave[4] =  gRtcDate & 0xFF;

左右移运算符和按位与或运算符的结合性都是自左向右,前者的优先级高于后者,所以上面两段代码块会得出不同的结果,后面一段代码会先进行右移运算,再进行按位与的运算。我比较懒,一般不怎么去记优先级顺序表,一般都是用()来框起来,这样也有一定的弊端,就是太多括弧看起来也很费劲,所以还是建议常用的一些运算符优先级顺序还是要记一下。

BUG记录7——GPIO模式的配置问题
void GpioConfigInit(void){
 GPIO_InitTypeDef  GPIO_InitStructure;
  
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
 
    //设置GPIOC_12为推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;     
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    //设置GPIOC_13为上拉输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;     
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
 GPIO_Init(GPIOC, &GPIO_InitStructure);           
}

在实际的嵌入式项目中,操作GPIO是比较普遍的,但是也隐藏了一些潜在的坑,上面的初始化函数在配置完GPIOC_12和GPIO_13之后,GPIOC_12的推挽输出其实是没有配置成功的,因为此函数中在最后进行了一次结构体初始化的操作,相当于只是把GPIOC_13的模式写入了结构体参数,所以此时两个IO口的模式均为上拉输入,具体我们来分析下GPIO这个结构体的成员参数:

/** 
  * @brief  GPIO Init structure definition  
  */typedef struct{   uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */}GPIO_InitTypeDef;/**
  * @brief  Initializes the GPIOx peripheral according to the specified
  *         parameters in the GPIO_InitStruct.
  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param  GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
  *         contains the configuration information for the specified GPIO peripheral.
  * @retval None
  */void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct){
  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  uint32_t tmpreg = 0x00, pinmask = 0x00;
  /* Check the parameters */  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  
  /*---------------------------- GPIO Mode Configuration -----------------------*/  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
  { 
    /* Check the parameters */    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
    /* Output mode */    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
  }/*---------------------------- GPIO CRL Configuration ------------------------*/  /* Configure the eight low port pins */  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
  {
    tmpreg = GPIOx->CRL;
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = ((uint32_t)0x01) << pinpos;
      /* Get the port pins position */      currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        /* Clear the corresponding low control register bits */        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits */        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << pinpos);
        }
        else        {
          /* Set the corresponding ODR bit */          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
          {
            GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
          }
        }
      }
    }
    GPIOx->CRL = tmpreg;
  }/*---------------------------- GPIO CRH Configuration ------------------------*/  /* Configure the eight high port pins */  if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
  {
    tmpreg = GPIOx->CRH;
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = (((uint32_t)0x01) << (pinpos + 0x08));
      /* Get the port pins position */      currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        /* Clear the corresponding high control register bits */        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits */        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
        /* Set the corresponding ODR bit */        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
        {
          GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
      }
    }
    GPIOx->CRH = tmpreg;
  }
}

上述的函数会把GPIO的引脚、速度、模式,写入到相关的寄存器中去,在GpioConfigInit()函数中如果只写入一次引脚、速度、模式等参数,那么只会以最后一次的参数为准,因为这里定义的结构体变量为局部变量,在配置GPIOC_13时又重新被赋值,然后再被写入,所以就会出现GPIOC_12模式配置失败的问题,正确的配置函数为:

void GpioConfigInit(void){
 GPIO_InitTypeDef  GPIO_InitStructure;
  
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
 
    //设置GPIOC_12为推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;     
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOC, &GPIO_InitStructure); 
    
    //设置GPIOC_13为上拉输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;     
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOC, &GPIO_InitStructure);           
}
BUG记录8——触摸屏刷新频率,并不是越快越好

提高触摸屏的刷新频率主要是为了提高用户体验感,让用户用起来感觉更加流畅,但是也不是越快越好,最好要参考触摸屏厂商提供的推荐刷新频率来设置,如下为某款触摸屏的推荐参数:

MCU不要频繁向串口屏发送数据,否则串口屏的内部缓存区会满,从而导致数据丢失(缓冲区大小:标准型8K,基本型4.7K)
1) 一般情况下,控制MCU向串口屏发送数据的周期大于100ms,就可以避免数据丢失的问题;
2) 如果仍然有数据丢失的问题,请判断串口屏的BUSY引脚,为高时不能发送数据给串口屏。

我之前试过10ms来刷新一些参数,然后发现触摸屏的其他一些操作就非常卡顿,因为触摸屏自带的MCU一直在不断的进入数据接收中断并需要不断的处理,有时候还会出现数据乱码,其原因也就是内部的一级缓冲区产生了溢出。

BUG记录9——指针数组的错误寻址

在编程过程中,我一般将指针数组用来存放字符串信息,如下代码块:

const char *ErrInf[5] = 
{
 "光子计数器故障!",
 "空杯测试故障!",
 "温控仪通讯故障!",
 "打印机缺纸!",
 "过温或欠温!"};

那我们看下这些字符串信息如何在内存中存储:

c#代码Bug怎么解决

/*! 
*  \brief     文本框更新
*  \param  screen_id 画面ID
*  \param  control_id 控件ID
*/void WriteTextValue(uint16 screen_id, uint16 control_id, uint8 *pData, uint16 nDataLen){
    BEGIN_CMD();
    TX_8(0xB1);
    TX_8(0x10);
    TX_16(screen_id);
    TX_16(control_id);
    SendNU8(pData, nDataLen);
    END_CMD();
}

如果需要更新上面的第一个字符串信息,就该按照如下来调用文本框更新函数:

//RightWriteTextValue(0x01, 0x01, (uint8*)ErrInf[0], strlen(ErrInf[0]));//ErrorWriteTextValue(0x01, 0x01, (uint8*)&ErrInf[0], strlen(ErrInf[0]));

因为第一个字符串存储的首地址为ErrInf[0],而非&ErrInf[0],&ErrInf[0]是ErrInf[0]的地址,这两个地址是有区别的,所以千万不要加取地址符&。

BUG记录10——自减运算符引发的问题
typedef struct{ char  *HybDenName;
 u8  SetHybDenTemp[2];
 u32 SetHybDenTime[2];
}HybDenPrgPara_TypeDef;typedef struct{ u8 HybDenRow;
 u8 HybRow;
 u8 MulRow;
 u8 HybDenCol;
 u8 MulCol;
}PrgFlowIndex_TypeDef;

HybDenPrgPara_TypeDef HybDenFlowPara[PRG_FLOW_NUM_MAX] = 
{
 {"DenHyb01", 0, 0, 0, 0},
 {"DenHyb02", 0, 0, 0, 0},
 {"DenHyb03", 0, 0, 0, 0},
 {"DenHyb04", 0, 0, 0, 0},
 {"DenHyb05", 0, 0, 0, 0},
 {"DenHyb06", 0, 0, 0, 0},
 {"DenHyb07", 0, 0, 0, 0},
 {"DenHyb08", 0, 0, 0, 0},
 {"DenHyb09", 0, 0, 0, 0},
 {"DenHyb10", 0, 0, 0, 0},
};

PrgFlowIndex_TypeDef       PrgFlowIndex = {0x00, 0x00, 0x00, 0x00, 0x00};//code blockcase LoadPgUp:
{
    if(0x00 == PrgFlowIndex.HybDenRow)
    {
     PrgFlowIndex.HybDenRow = PRG_FLOW_NUM_MAX-0x01;
    }
    else    {
     PrgFlowIndex.HybDenRow--;
    }

 //在程序加载界面、运行界面、名称编辑写入新的程序名称 SetTextValue(HybDenLoad, LoadName,       (u8*)HybDenFlowPara[PrgFlowIndex.HybDenRow].HybDenName);
 SetTextValue(HybDenRun, LoadName, (u8*)HybDenFlowPara[PrgFlowIndex.HybDenRow].HybDenName);
 SetTextValue(HybDenNameEdit, LoadName, (u8*)HybDenFlowPara[PrgFlowIndex.HybDenRow].HybDenName);

 break;
}

如果将PrgFlowIndex.HybDenRow--放置到if-else之前会引发什么问题?当PrgFlowIndex.HybDenRow等于0时,再自减1,其值就变成了255,下面的SetTextValue()函数在写入结构体数组参数时就会写入到非法的内存中去,也会造成HardFault错误。

“c#代码Bug怎么解决”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

推荐阅读:
  1. 升级Hbase,解决bug问题
  2. 解决FastJson 1.2.39的bug

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

上一篇:.NET中的底层服务该怎么优化

下一篇:Smartbi有什么功能

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》