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

《低功耗MCU运行FreeRTOS》培训课程(五)信号量实现人机交互

[复制链接]
wolfgang 发布时间:2018-5-12 18:25
试验三:信号量应用
创建FreeRTOS任务中断和同步(信号量方式)
21.jpg
, U. l, c- C3 v- L8 c3 l, q
其实可以这里可以延伸利用信号量来实现串口数据的不定长收发,定长收发使用
“HAL_UART_Receive_IT(&huart2,Rx_Buffer,RxBufferSize);”即可,而不定长的方法在论坛中有网友也举了详细的创建方法(可在论坛中搜索“不定长”),也有修改HAL_UART_Receive_IT 函数的方法实现。
  试验设想:这里是利用FreeRTOS信号量机制实现,主要结合不定长数据的接收,加上FreeRTOS信号量的控制,再通过串口数据接收任务中的消息解析操作,可实现简单的人机交互功能。
# @( J9 d; X+ _) |% G3 a% k
交互机制的选择:
  面对消息队列、事件标志组、 信号量等多种交互机制下,可以参考下表进行任务间的交互。
22.jpg
- I7 n% j- ~4 u  H1 _, k$ q
本实验选择互斥信号量来实现,相关的FreeRTOS 信号量 API 函数如下图:
19_1.jpg

" c. J+ ?0 L# [; a: R
使用CubeMX配置串口 DMA的内容略过(参考论坛的不定长DMA配置,FreeRTOS的配置见前篇),待工程建立好后,在代码中增加以下的内容:
/ i/ l- c3 G: M' O" Y3 b
在main.h中增加定义:
  1. #define RXBUFFERSIZE 255
复制代码
1 a+ ]. T6 r( Z  x# k7 k
在main.c中增加定义:
  1. extern SemaphoreHandle_t xScanSemaphore;   //串口中断处理的任务
    " Q7 O6 _1 X7 K' L# ]! j* I9 J) C

  2. 8 A5 R! B* s# I1 s0 z0 B, q+ k
  3. uint8_t ReceiveBuff[RXBUFFERSIZE] = { 0 }; //接收缓冲区7 G: H7 Q( p" b/ |( K0 m
  4. uint8_t ReceiveInfo[RXBUFFERSIZE]={ 0 };   //接收待识别字符数组
    3 _/ i, p0 f! i4 o/ ?7 H$ d0 A* o
  5. 4 g' T% m, [! j" D
  6. uint8_t Rx_BuffLen, Rx_InfoLen;+ b. ]$ o! O$ s9 D6 r

  7. & A% D3 ^+ L) b) E
  8. void vStartLPUart1ScanTask(void const * argument);
    + {0 o* O) q- Y+ \7 I9 U9 F, n9 D
  9. #define Uart_TASK_PRIORITY   ( tskIDLE_PRIORITY + 3UL )
复制代码
& R( |! i! ~; w; y/ X
在main函数中,调整增加部分代码内容:
  1. int main(void){- A! M  o% T/ W* c, t" v
  2.   HAL_Init();
    . V3 k. H" v- w" G5 a4 C
  3.   SystemClock_Config();
    ! h% O$ \! Q" C
  4. ) c% Y& g7 G0 `0 @, u& y
  5.   MX_GPIO_Init();
    % F# n" f# ]' a7 O1 F
  6.   MX_DMA_Init();6 H+ ~- B0 c- ]
  7.   MX_LPUART1_UART_Init();# d5 n: n& o/ @0 X- Z4 @
  8.   MX_USB_OTG_FS_PCD_Init();
    2 ]% u0 z- m0 M7 k) N
  9. . q' E0 m/ y5 H9 p9 D2 u
  10.   MX_NVIC_Init();  //中断初始化中,增加空闲中断的捕获 __HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_IDLE);
    2 ^, c. c2 k* L- S

  11. ! c0 o: p; [& X+ A% V
  12.   /*        开启下一次接收        */) a1 W  F" ~; H+ i, ?( K  ]8 D7 f
  13.   HAL_UART_Receive_DMA(&hlpuart1,(uint8_t*)ReceiveBuff,RXBUFFERSIZE);
    3 r# ?, A+ |0 l' k
  14.   //创建信号量
    $ J$ w2 X4 T( m0 q: w' w6 h
  15.   xScanSemaphore = xSemaphoreCreateBinary();5 {0 W5 Y) ?* k$ h( {6 T, a9 J4 `
  16.   //增加交互任务6 y4 R$ L3 \* a, ?9 m
  17.   xTaskCreate((TaskFunction_t) vStartLPUart1ScanTask, //任务函数3 F% _2 G7 i' X4 O5 q$ v4 t
  18.                     "LPUart1S",              //任务名称8 l- ]& y2 p  Q  M' n
  19.                     200,                     //任务栈大小( D4 A5 ]  O5 x5 W
  20.                     NULL,                    //任务函数参数
    9 U2 U% m" Y  o
  21.                     Uart_TASK_PRIORITY,      //任务执行等级& X! ?* R& i$ H( H* ~
  22.                     (TaskHandle_t *) NULL);  //任务句柄3 w% l. u% w) n1 @- z
  23.    //启动任务2 D1 l0 X$ |' O
  24.    vTaskStartScheduler();
    9 O+ f' @1 h8 I% z( @1 O) \! W! h0 w. l
  25. }  F  Q; Y4 l/ O

  26. ( j8 N/ Y& i5 i; a

  27. ) S, Z0 m# P7 X5 [  _6 Q0 W
复制代码

- m9 X7 u; j6 Z) o; u# p( ]
创建串口中断任务内容
  1. void vStartLPUart1ScanTask(void const * argument){6 `7 C! f. i! Y  n% d% k
  2.     uint8_t *strp,*strp1;
    & y0 [6 z: E3 I' j6 ~1 G4 c$ K
  3.     configASSERT(xScanSemaphore);& k* N( x( `2 @& e
  4.     //获取信号量,等待时间为0,则xSemaphoreTake()在信号量无效时会立刻返回
    - Q4 y* d) o( l; T1 N0 @) m
  5.     xSemaphoreTake(xScanSemaphore, Scan_BLOCK);
    ) Q- ^; K# T4 V9 l- p/ f3 S
  6.     for (;;) {! a8 r0 P* F9 Z
  7.        //获取信号量,超时时间为portMAX_DELAY值
    - O, M2 e" A7 i( ?  y6 i5 P
  8.        xSemaphoreTake(xScanSemaphore, portMAX_DELAY);
    2 x* F7 j: k* P- Q2 _4 ?
  9.        /*        打印接收到的数据长度 */
    7 b7 J; j) j- f2 O
  10.        printf("rx_len=%d:\n%s \n", Rx_InfoLen,ReceiveInfo);
    2 F" [5 I6 v! T
  11. 2 |* G3 d3 P1 l- ?
  12.         //回答Hello7 ?: z4 w# W* q4 d9 S, \
  13.         strp=strstr((char *)ReceiveInfo,(char *)"Hello");
    " C0 L2 W0 A& a: k
  14.         if (NULL != strp){
    4 N; R, D9 y4 }( I( _- P3 a
  15.             printf("\n Nice to meet you! \n");2 z# C) z( P/ E9 M8 ^; F/ `
  16.         };( h2 z. W' h  l9 }$ U& H

  17. # w; `# L: X+ E( Y
  18.          //回答guten tag/ guten morgen/ guten abend / guten nacht" ^: U4 v4 E: `7 {- x# ^, r
  19.          strp=strstr((char *)ReceiveInfo,(char *)"Guten");; Z& h1 ?0 E; k4 a. d
  20.          if (NULL != strp){
    0 x8 w& t: `, m6 ~; J' @
  21.             strp1=strstr((char *)ReceiveInfo,(char *)"morgen");. h6 ]5 u, @) S& i
  22.             if (NULL != strp1){% h* a. K' E/ ]7 o6 N
  23.                 printf("\n Guten Morgen ! \n");
    ; W& r5 Q" k! s
  24.             }
    : n, h, p) T2 U4 v# K/ \3 Y
  25.             strp1=strstr((char *)ReceiveInfo,(char *)"tag");' D0 E) [0 I3 U) f& s& r
  26.             if (NULL != strp1){
    3 V1 N, h% M3 q
  27.                  printf("\n Guten Tag ! \n");! z- I) u- I; U
  28.             }
    ! ~; M4 F' f9 `, I
  29.             strp1=strstr((char *)ReceiveInfo,(char *)"abend");
    % C- q7 |0 B. D* @8 F
  30.             if (NULL != strp1){2 e; e6 R7 F, p% b" r8 Z3 {
  31.                  printf("\n Guten Abend ! \n");
    1 ?% n3 `* ]1 H1 O, p
  32.             }) Y, Y- G/ T3 D3 o
  33.             strp1=strstr((char *)ReceiveInfo,(char *)"nacht");0 d4 U5 o1 {- a8 }
  34.             if (NULL != strp1){
    * {8 [" [% A1 I" `- J
  35.                 printf("\n Guten Nacht ! \n");
    7 y3 O8 D( p: j' [. ?7 l
  36.             }; ?# v) l' Z7 R, Z0 y4 t2 J2 q
  37.        }) s5 Q& y4 N1 Z9 m, F* Z
  38.        /*        清空接收到的数据        */ # g2 W  \8 P7 E  ], _
  39.        memset(ReceiveInfo, 0x00, Rx_InfoLen);
    " F/ H; T% o% g7 W& C( c8 C
  40.        Rx_InfoLen=0;6 ~+ [8 X7 y' n4 a2 g, M
  41.        </font>
复制代码
严格意义上需要词法、语法分析器,这里就不多说,往深的说就就可以实现类似“micropython”的系统了。这里就不离FreeRTOS 信量太远

% `% G! w) r+ {0 k- I
在stm32l4xx_it.c 文件中设置以下内容
  1. <font face="新宋体" size="3">extern SemaphoreHandle_t xScanSemaphore;
    ; b3 T% A7 m' P! }! P0 p1 z* K+ h
  2. extern uint8_t ReceiveInfo[RXBUFFERSIZE];
    0 d$ }/ ~& }; w7 j& E7 G+ H! w3 A
  3. extern uint8_t  Rx_BuffLen, Rx_InfoLen;
    / j* j$ P/ m2 j# q; Z% J
  4. 3 Y# X( A+ J  Z- M1 M$ j+ c. K' s
复制代码
将CubeMX生成的LPUART1_IRQHandler(void)函数中增加以下内容:
  1. void LPUART1_IRQHandler(void) {" g) e+ p$ N  L0 r" J
  2.     ………) y: Q! }1 R$ o+ o
  3.     uint32_t temp;& [* ?% b- Y: ?0 {
  4.     static BaseType_t xHigherPriorityTaskWoken;- M$ `: N3 ]/ ^+ s
  5.     HAL_UART_IRQHandler(&hlpuart1);
    ; n  c' n$ M3 z' a

  6. 4 z: |6 q# C1 O# |  m! z2 Q8 H" P
  7.     /* 如果是串口1IDLE中断        */- V0 q( T# j% E
  8.     if (RESET != __HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_IDLE)) {
    , J1 c1 N: B6 f3 g' T0 R3 b4 q# u
  9.        /*        停止DMA接收        */1 ^, ^8 b' D8 v9 x5 c
  10.        HAL_UART_DMAStop(&hlpuart1);
    + M( k* H: c+ K

  11. ' V5 R8 A% {7 g% V* [, x
  12.        /*        获取DMA当前还有多少未填充        */9 u5 I6 t" Z: y$ R3 B  [
  13.        temp = __HAL_DMA_GET_COUNTER(&hdma_lpuart_rx);
    . i+ u: C" V+ l+ |5 H' q* c: D: S6 D1 O

  14. 5 y. R6 e/ `! `: [
  15.        /*        清除中断标志        */% Q8 x/ `" U/ ^4 s/ h. Z+ J) _
  16.        __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
    ' U9 S# T7 i9 K1 M; l2 z( L
  17. " ~! y+ w9 u* ]* g# M2 I
  18.        /*        计算串口接收到的数据个数        */
    & G; N) W- q; t9 s  `/ }+ Q) Y! ]
  19.        Rx_BuffLen = RXBUFFERSIZE - temp;$ G. V; R. F9 g5 `7 M- i9 B4 R/ j
  20.        Rx_InfoLen = Rx_BuffLen;
    3 I5 i( ~; _5 R' w3 @/ h4 I2 O
  21.        memcpy(ReceiveInfo,ReceiveBuff,Rx_InfoLen);
    9 I: ^) S. V( e! g/ E3 M
  22.        memset(ReceiveBuff, 0x00, Rx_BuffLen);
    - X$ s, c8 x. Z5 `& w) x, b* m& y
  23.        /*        接收数据长度清零        */* H; }1 ?5 L1 b; \4 w
  24.        Rx_BuffLen = 0;( W5 I/ X7 m; F! V7 |2 W
  25.     }
      i9 `% z+ y$ ?5 R8 w( n
  26. $ L! A) a, V( @. l, A
  27.     if (utime_tick >= 200) {  j1 I4 @' R) y$ O8 z1 v: ]5 r! z
  28.         xSemaphoreGiveFromISR(xScanSemaphore, &xHigherPriorityTaskWoken);( Z! }3 p% k9 P. G! m
  29.         utime_tick = 0;3 A- U! P2 t- i
  30.      }1 A# G% ?. D' U: `/ J$ y+ K# ^
  31.      portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
    ' K% r* e3 _% ^# m; k8 d. `
  32.      …………* Q6 N* [1 z( c- k
  33. }/ `0 b0 B: O6 ^& T

  34. ( n% B: A# [' y1 G+ U9 W
复制代码

0 B& E4 E" p/ o3 y0 B- _
编译项目,下载执行,打开串口工具,分别输入 Hello、Guten morgen、Gutentag、Guten abend、Guten nacht能从串口中得到开发板返回的以下内容:

& d$ C/ G' N& Z( m2 B- D
19_2.jpg

/ O! c) \. y' K! j  D+ ?4 N3 t! c
没有严格的词法、语法分析, 就不能正确识别处理 “ Hello Guten tag" 之类的指令了,当然回复也是错误的。人机交互的内容就可参考状态机、模糊逻辑、人工智能等内容。
3 u& A$ L+ X( B) e( F$ M5 u
在增加这个信号量任务的时候,还可以将LED的任务、按键中断同时执行,通过控制LED的不同闪烁,同步返回不同的状态。
也可以配合音频文件、音频流等方式,发出标准的语音模式。可以将实验更加丰富、更加有趣。
+ K( p( y1 L5 `2 y! a: @3 i) {9 a
这样基本的基于FreeRTOS的信号量的人机交互就初步完成。
注意,创建多个任务时“FreeRTOSConfig.h”中#define configTOTAL_HEAP_SIZE 的值大小,太小了,某些任务不会被成功创建;

7 y1 I' |5 R7 r

0 C* ?" y+ d' G. Q! Q9 u
《低功耗MCU运行FreeRTOS》培课程的准备内容(一)5 w: Z1 ^$ \6 B: Z' \# e/ M
《低功耗MCU运行FreeRTOS》培课程回顾(二), \0 n) d. F% Y: `/ e' e
《低功耗MCU运行FreeRTOS》培训课程(三) Atollic环境实验& `2 Z4 N+ J% m; z
《低功耗MCU运行FreeRTOS》培训课程(四) 创建任务( d6 f$ y$ w  A5 {& A4 S, w$ e! f/ d
《低功耗MCU运行FreeRTOS》培训课程(六)消息队列的使用
- [, I% R1 s+ C% W0 a9 e/ ^7 {# b2 D  t% p  c& S: C; W$ d
收藏 3 评论0 发布时间:2018-5-12 18:25

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版