你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

HAL库串口设定奇偶校验后出现的奇怪问题

[复制链接]
IZ 发布时间:2017-6-8 13:34
写了一个Modbus从站,起初使用串口8,N,1的配置,所有功能正常,但是设定成带校验之后,整个程序看起来没什么问题,中断接收的数据也是正常的,但是放到缓存里面的时候数据就完全不对,比对自己的代码,唯一的改变就是从无校验改成了带校验,后来查看HAL库,发现了问题。
我自己定义了一个结构体,用来给串口用的,相关部分如下
__packed typedef struct MODBUS_SLAVE_DRV
    {
        uint8_t uartBuf;//用于串口中断接收数据用
        uint8_t *pucRecBuf;//接收数据帧存放地址
        uint8_t *pucTranBuf;//发送数据帧存放地址

采用中断接收的时候数据放到uartBuf这里面,HAL_UART_Receive_IT(uart, &pMbSlaveDrv_t->uartBuf, 1);开启中断接收,中断来的时候会进入UART_Receive_IT,这个函数会把你坑死,如果使用了校验,就要设定UART_WORDLENGTH_9B,一旦设定了9B,这个函数会做如下动作
if(huart->Init.WordLength == UART_WORDLENGTH_9B)
    {
      tmp = (uint16_t*) huart->pRxBuffPtr;//这个就是我之前结构体里面的uartBuf,在这里居然被扩成了uint16
      if(huart->Init.Parity == UART_PARITY_NONE)//下面进行了uint16的赋值
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
        huart->pRxBuffPtr += 2U;
      }
      else
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
        huart->pRxBuffPtr += 1U;
      }
    }

以上代码会将紧跟在uartBuf这个后面的内存给写掉,如果你很幸运,你的代码里面uartBuf后面的内存没有放置别的变量,恭喜你,不会有任何问题,杯具的我,后面的缓存指针直接被改写。

所以,如果你使用了HAL库,那么请使用uint16的变量来作为接收数据的缓存,但是在调用HAL_UART_Receive_IT的时候需要进行类型的转换,因为这个函数传入的类型是uint8.
我用的F1和F4的HAL库都是这样的。
收藏 评论5 发布时间:2017-6-8 13:34

举报

5个回答
creep 回答时间:2017-6-8 15:14:17
更新后的是先进行是否有奇偶检验再对接收缓存进行类型转换了。
  1.     if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
  2.     {
  3.       tmp = (uint16_t*) huart->pRxBuffPtr ;
  4.       *tmp = (uint16_t)(huart->Instance->RDR & uhMask);
  5.       huart->pRxBuffPtr +=2;
  6.     }
  7.     else
  8.     {
  9.       *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
  10.     }
复制代码


IZ 回答时间:2017-6-8 16:42:09
这里就不应该有这样的操作,外部接口传进来的是uint8,就只能是uint8。现在这样的操作仍然会出现一样的问题。
我现在用的是FW_F4 V1.15.0
luocheng1234 回答时间:2018-5-9 14:30:07
顶起来,这个问题解决了没有呢?
butterflyspring 回答时间:2018-5-9 15:32:20
你这个是什么版本的代码?我手上的代码如下,如果你的数据是9位的,而且不包含校验,才会变16位,否则都是按照8位来处理,而且有效数据,会在前面的UART_MASK_COMPUTATION(huart);来更新一个mask来提取有效数据.所以....你用的是什么代码?



/* Computation of UART mask to apply to RDR register */
    UART_MASK_COMPUTATION(huart);
    uhMask = huart->Mask;
   
    /* as long as data have to be received */
    while(huart->RxXferCount > 0U)
    {
      if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }
      if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
      {
        tmp = (uint16_t*) pData ;
        *tmp = (uint16_t)(huart->Instance->RDR & uhMask);
        pData +=2U;
      }
      else
      {
        *pData++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
      }
      huart->RxXferCount--;
    }
IZ 回答时间:2018-7-20 23:02:12
butterflyspring 发表于 2018-5-9 15:32
你这个是什么版本的代码?我手上的代码如下,如果你的数据是9位的,而且不包含校验,才会变16位,否则都是按照8 ...

假设如用来接收数据的字节为uint8_t buf,其所在的地址为0x2000000(随便写的),在buf变量后面有另一个变量buf2,地址为0x2000001,当执行tmp = (uint16_t*) pData的时候,bmp会指向0x2000000,那么执行下面的代码 *tmp = (uint16_t)(huart->Instance->RDR & uhMask);,这个时候buf2会被影响,如果要用校验的,那么buf就应该定义成uint_16,这样能保证不会意外操作到别的变量

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版