|
2015/7/28 上午 10:52:19
請教各位前輩,以下為我的code
/* Kernel includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h"
/* Standard include. */ #include <stdio.h>
/* The ITM port is used to direct the printf() output to the serial window in the Keil simulator IDE. */ #define mainITM_Port8(n) (*((volatile unsigned char *)(0xE0000000+4*n))) #define mainITM_Port32(n) (*((volatile unsigned long *)(0xE0000000+4*n))) #define mainDEMCR (*((volatile unsigned long *)(0xE000EDFC))) #define mainTRCENA 0x01000000 #define ioMAX_MSG_LEN ( 100 ) /* * The tasks as described in the accompanying PDF application note. */ static void vReceiveTask( void *pvParameters ); static void vSendTask( void *pvParameters );
/* * Redirects the printf() output to the serial window in the Keil simulator * IDE. */ int fputc( int iChar, FILE *pxNotUsed ); void vPrintString(const char *pcString); void vPrintString2(const char *pcString, int Number);
/*-----------------------------------------------------------*/
/* The queue used by both tasks. */ xQueueHandle xQueue1, xQueue2;
/* One array position is used for each task created by this demo. The variables in this array are set and cleared by the trace macros within FreeRTOS, and displayed on the logic analyzer window within the Keil IDE - the result of which being that the logic analyzer shows which task is running when. */ unsigned long ulTaskNumber[ configEXPECTED_NO_RUNNING_TASKS ];
/*-----------------------------------------------------------*/ long lValue = 0;
int main(void) { xQueue1 = xQueueCreate( 1, sizeof(unsigned long) ); xQueue2 = xQueueCreate( 1, sizeof(unsigned long) ); xTaskCreate( vReceiveTask, "Receiver", 100, (void *) lValue, 1, NULL ); xTaskCreate( vSendTask, "Sender", 100, (void *) lValue, 1, NULL );
vTaskStartScheduler();
for( ;; ); } /*-----------------------------------------------------------*/
|
|
|
2015/7/28 上午 10:53:17
static void vSendTask( void *pvParameters ) { const portTickType xTicksToWait = 10 / portTICK_RATE_MS; portBASE_TYPE xStatus; portBASE_TYPE xStatus2; long lSendValue; lSendValue = (long) pvParameters;
for( ;; ) { xStatus = xQueueReceive(xQueue2, &lSendValue, xTicksToWait); if(xStatus == pdTRUE && lSendValue == lValue) { vPrintString2("vSendTask Receive from Queue: ", (char)lValue); lValue++; lSendValue++; xStatus2 = xQueueSend( xQueue1, &lValue, 0); if(xStatus2 == pdTRUE) { vPrintString2("vSendTask Send to Queue: ", (char)lValue); } } else { vPrintString("No Send\r\n"); } } } static void vReceiveTask( void *pvParameters ) { const portTickType xTicksToWait = 10 / portTICK_RATE_MS; portBASE_TYPE xStatus3; portBASE_TYPE xStatus4; long lReceiveValue; lReceiveValue = (long) pvParameters; xStatus3 = xQueueSend( xQueue2, &lReceiveValue, 0); if(xStatus3 == pdTRUE) { vPrintString2("vReceiveTask Send to Queue: ", (char)lValue); } for( ;; ) { xStatus3 = xQueueReceive(xQueue1, &lReceiveValue, xTicksToWait); if(xStatus3 == pdTRUE && lReceiveValue == lValue) { vPrintString2("vReceiveTask Receive from Queue: ", (char)lValue); lValue++; lReceiveValue++; xStatus4 = xQueueSend( xQueue2, &lValue, 0); if(xStatus4 == pdTRUE) { vPrintString2("vReceiveTask Send to Queue: ", (char)lValue); } } else { vPrintString("No Receive\r\n"); } } } int fputc( int iChar, FILE *pxNotUsed ) { /* Just to avoid compiler warnings. */ ( void ) pxNotUsed;
if( mainDEMCR & mainTRCENA ) { while( mainITM_Port32( 0 ) == 0 ); mainITM_Port8( 0 ) = iChar; }
return( iChar ); }
void vPrintString2(const char *pcString, int Number) { taskENTER_CRITICAL(); { printf("%s : %d\r\n", pcString, Number); fflush(stdout); } taskEXIT_CRITICAL(); }
void vPrintString(const char *pcString) { taskENTER_CRITICAL(); { printf("%s", pcString); fflush(stdout); } taskEXIT_CRITICAL(); }
|
|
|
2015/7/28 上午 10:56:51
想請問的問題為 : 正常的情況下會先Send後Receive ,但有時候會出現Receive後又Receive的情況,請教該如何解決,和這是為什麼會發生這樣的scheduler,感恩!
|
|
|
2015/7/28 下午 06:29:41
>想請問的問題為 : 正常的情況下會先Send後Receive , >但有時候會出現Receive後又Receive的情況, >請教該如何解決,和這是為什麼會發生這樣的scheduler,感恩!
你所用的fflush()函式是一個不穩定的函式, 在不同版本與不同平台的C++編譯器之中, 它的支援有許多差別。 有的版本不支援fflush()的多執行緒, 有的新版本則有支援fflush(), 詳細情況要問現在有在做程式開發的大大, 才能得到進一步的了解。
|
|
|
2015/7/29 上午 09:51:07
這是MCU的程式,看到使用FreeRTOS,表示fflush()相關細節必須由使用者自己去注意。Compiler無法得知使用RTOS型式,故無法提供多執行緒相關保護。 fflush()會影響printf(),而printf()的底層是fputc()。所以問題在fputc()上。 fputc()確實沒有做多執行緒保護是會產生問題。另一個問題是它使用Busy Loop,這個使行為強迫變成單工,又因無法退出回歸FreeRTOS去管理,會破壞執行緒應有行為。就形成樓主問題。 在RTOS下,請不要使用Busy Loop,一但使用,行為就不會依作業系統應有行為執行。 FreeRTOS有許多範例,請參照正確範例。因為改版很快,我還在使用7.4版,可能有版本差異。還是找到自己版本的範例去執行。
|
|
|
2015/7/29 下午 12:35:53
謝謝大大的說明!
|
|
|
2015/7/30 上午 10:26:43
>這是MCU的程式,看到使用FreeRTOS,表示fflush()相關細節必須由使用者自己去注意。Compiler無法得知使用RTOS型式,故無法提供多執行緒相關保護。 >fflush()會影響printf(),而printf()的底層是fputc()。所以問題在fputc()上。 >fputc()確實沒有做多執行緒保護是會產生問題。另一個問題是它使用Busy Loop,這個使行為強迫變成單工,又因無法退出回歸FreeRTOS去管理,會破壞執行緒應有行為。就形成樓主問題。 >在RTOS下,請不要使用Busy Loop,一但使用,行為就不會依作業系統應有行為執行。 >FreeRTOS有許多範例,請參照正確範例。因為改版很快,我還在使用7.4版,可能有版本差異。還是找到自己版本的範例去執行。
謝謝前輩,我會努力精進的!
|
|
|
2015/7/31 下午 03:37:56
謝謝各位前輩
小弟找出問題點了
原來是我只有把print的字串 數字 用CRITICAL SECTION 包起來 變數遞增的地方沒有包到 所以出了error!
所以 critical section 是相當好用的 function !
|
|
|
|
|
|
資訊類作業 |
 |
|
|
專家等級 |
評價 |
|
|
一代宗師 |
10000 |
|
|
曠世奇才 |
5000 |
|
|
頂尖高手 |
3000 |
|
|
卓越專家 |
1500 |
|
|
優秀好手 |
750 |
|
|
|
|
|
|
|
|
|
Microsoft Internet Explorer
6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/ |
|
|