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

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

[复制链接]
IZ 发布时间:2017-6-8 13:34
写了一个Modbus从站,起初使用串口8,N,1的配置,所有功能正常,但是设定成带校验之后,整个程序看起来没什么问题,中断接收的数据也是正常的,但是放到缓存里面的时候数据就完全不对,比对自己的代码,唯一的改变就是从无校验改成了带校验,后来查看HAL库,发现了问题。! \8 D, d" V+ y$ _; y9 P
我自己定义了一个结构体,用来给串口用的,相关部分如下/ L9 E0 a2 d! w% l* `# y0 `
__packed typedef struct MODBUS_SLAVE_DRV! c$ T; z; n6 x( g; L' `
    {( h$ w% t- M3 v% a& D
        uint8_t uartBuf;//用于串口中断接收数据用+ P9 o' W+ U2 z
        uint8_t *pucRecBuf;//接收数据帧存放地址7 ~% l; ~5 x; G+ Q% I; X- q+ Z
        uint8_t *pucTranBuf;//发送数据帧存放地址- _4 Y; [8 @8 V1 R( G' Z

7 O" U' ]) t5 z# f( \6 ~. q9 u采用中断接收的时候数据放到uartBuf这里面,HAL_UART_Receive_IT(uart, &pMbSlaveDrv_t->uartBuf, 1);开启中断接收,中断来的时候会进入UART_Receive_IT,这个函数会把你坑死,如果使用了校验,就要设定UART_WORDLENGTH_9B,一旦设定了9B,这个函数会做如下动作
4 ~- [' s( m  Z8 f3 e. pif(huart->Init.WordLength == UART_WORDLENGTH_9B)
3 l3 F; ~) l- K! f, i4 q9 M    {6 Z) P0 f( V7 U4 y# b5 x
      tmp = (uint16_t*) huart->pRxBuffPtr;//这个就是我之前结构体里面的uartBuf,在这里居然被扩成了uint16& L$ i$ l4 n9 p
      if(huart->Init.Parity == UART_PARITY_NONE)//下面进行了uint16的赋值
& L- g2 s3 G. |, Q      {( t; ~7 H- B9 ~) f4 {1 [3 g
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
/ X. O9 X# F9 W2 I# Y9 d        huart->pRxBuffPtr += 2U;/ n7 E) C* A! l: J
      }$ d- }; z: {& W2 O( e; X
      else
7 p& N5 ]. ~* X- {4 ]      {
; Q/ r$ ]& ^9 V; O. g        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
) J0 X. S9 h: H8 X3 {- _        huart->pRxBuffPtr += 1U;& v/ j1 Y* S9 @, }4 z* K; o" v
      }) Z4 d/ {% w  O9 D% [" X
    }- `. K' m) J: H& Q& _1 q1 ?
- h* S0 ^  \$ c+ j( z, \0 m' j( m0 P2 Y. s6 L
以上代码会将紧跟在uartBuf这个后面的内存给写掉,如果你很幸运,你的代码里面uartBuf后面的内存没有放置别的变量,恭喜你,不会有任何问题,杯具的我,后面的缓存指针直接被改写。/ L& U- x. w3 m- G+ [. H" W

; v; Q5 O, J5 z6 z" ?6 i5 [& r所以,如果你使用了HAL库,那么请使用uint16的变量来作为接收数据的缓存,但是在调用HAL_UART_Receive_IT的时候需要进行类型的转换,因为这个函数传入的类型是uint8.
4 P& `  M! _4 x% C: z5 c3 ]我用的F1和F4的HAL库都是这样的。1 m& A, H& g6 F( b: h" j$ |
赞 收藏 评论5 发布时间:2017-6-8 13:34

举报

5个回答
creep 回答时间:2017-6-8 15:14:17
更新后的是先进行是否有奇偶检验再对接收缓存进行类型转换了。+ n, d( l) J! d: N7 O; ^, l7 B
  1.     if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))9 y/ k" b' j3 _# R
  2.     {
    " }2 D/ {0 w$ k* a+ x. H6 ]' v
  3.       tmp = (uint16_t*) huart->pRxBuffPtr ;: P! y" W* |; o* `3 R
  4.       *tmp = (uint16_t)(huart->Instance->RDR & uhMask);
    1 B$ R  o' s6 K( h# {
  5.       huart->pRxBuffPtr +=2;3 u8 f" y2 x/ x" s) k
  6.     }
    * d  v, [4 y. Y6 x4 {& R
  7.     else
    . ]" `( V: q( U. q! A( s# q
  8.     {$ B8 S9 T# i; ?: J& m+ m. [
  9.       *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);" r" C. r9 A0 E: T* E1 U0 |
  10.     }' d- D7 d5 y! ^
复制代码
! Q! {; E& c' L  Y4 S5 @+ M- `1 w
( A$ ]2 R, _$ L5 {
IZ 回答时间:2017-6-8 16:42:09
这里就不应该有这样的操作,外部接口传进来的是uint8,就只能是uint8。现在这样的操作仍然会出现一样的问题。- d$ E* \. |5 z9 B" r9 d# N
我现在用的是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来提取有效数据.所以....你用的是什么代码?
( c& z* D3 q) N- @9 U5 u- q2 n, U# e% @& n$ P
0 e# f1 K" d0 p$ R' f/ j

8 {% R8 b9 H9 F' K/* Computation of UART mask to apply to RDR register */
8 |5 S0 R( c, ]% W0 N    UART_MASK_COMPUTATION(huart);
1 o* W' V) H' k# t7 |    uhMask = huart->Mask;
; \& Q* N9 U) e5 v1 G    $ c8 I3 n7 V8 a- K' _9 |
    /* as long as data have to be received */( \; J6 l: X' O
    while(huart->RxXferCount > 0U)
; {# u, ~4 m; P2 E; I, S    {+ o/ e; M; r" a
      if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)% {' U; ?. L# O) T1 W
      {
! A, F" Y) |) O/ R' `; U* n        return HAL_TIMEOUT;- t4 J. y$ P! m9 E, q7 v1 K' ^
      }$ Z6 c3 G& f# S! n7 f# x, q
      if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE)). H( `2 [! |( L* G! U) l3 }
      {$ A4 k0 Z! H& v! I! G; P
        tmp = (uint16_t*) pData ;
& l* _# j& c/ _3 P% K: y        *tmp = (uint16_t)(huart->Instance->RDR & uhMask);
' d: o# ]; ~( }5 z; V. d: j        pData +=2U;( l/ o; E2 k1 W
      }+ r* O$ i# E4 g
      else. T0 i/ ~6 V' \0 c% E1 Q# J; S
      {% C8 d# T" ?+ M+ z1 L! `6 U: o, X
        *pData++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
+ y# E7 y  \% A* Y; x: P      }
( W- m  ~9 L& |: m9 o      huart->RxXferCount--;
& ?, }; o5 G/ s    }
IZ 回答时间:2018-7-20 23:02:12
butterflyspring 发表于 2018-5-9 15:32
: u# z( @  X% |( N  C# V你这个是什么版本的代码?我手上的代码如下,如果你的数据是9位的,而且不包含校验,才会变16位,否则都是按照8 ...
* j4 x0 c) W9 G& x% i; _
假设如用来接收数据的字节为uint8_t buf,其所在的地址为0x2000000(随便写的),在buf变量后面有另一个变量buf2,地址为0x2000001,当执行tmp = (uint16_t*) pData的时候,bmp会指向0x2000000,那么执行下面的代码 *tmp = (uint16_t)(huart->Instance->RDR & uhMask);,这个时候buf2会被影响,如果要用校验的,那么buf就应该定义成uint_16,这样能保证不会意外操作到别的变量
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版