做業地址:
github.com/HustWolfzzb…
Git/GCC/GDB/QEMU等工具的使用。
FreeRTOS多任務同步和通訊機制的掌握。git
在github上,Fork例程項目(github.com/cbhust/STM3… 到本身的我的帳號。
clone項目到本地電腦的Ubuntu虛擬機中(虛擬機環境在第一次做業中已搭建)。
按照/Projects/Demo1/README.md中的提示編譯Demo1例程並經過Qemu運行例程。
在Demo1的框架基礎上完成本身的本次編程做業(具體要求見第3點)。
代碼完成後提交到本身的github帳號上,確保助教能夠正常的clone並編譯運行。
在做業博客上給出代碼的github連接、代碼說明以及運行結果展現。github
建立三個任務:Sender_Task,Receiver_Task, Monitor_Taskweb
說明:編程
說明:ubuntu
說明:建立一個新的隊列。爲新的隊列分配所需的存儲內存,並返回一個隊列處理。
注意:項目經過複製而不是引用排隊,所以,所需的字節數,將複製給每一個項目。隊列中每一個項目必須分配一樣大小。
返回:若是隊列成功建立,則返回一個新建隊列的處理。若是不能建立隊列,將返回0。bash
說明:這個與xQueueSend 是同樣的,參照xQueueSend 的用法app
說明:這個項目經過複製接收,所以緩衝器必須提供足夠大的空間。這個函數必定不能在中斷服務程序中使用當隊列空時,確定複製傳遞不成功,則等待xTicksToWait 個滴答週期後再複製,但若是xTicksToWait 設置爲0,調用將當即返回。
返回:若是項目成功被隊列接收爲pdTRUE ,不然爲 pdFALSE。框架
~~ ~~ ~ ~~~eclipse
# 做業過程(多圖預警)複製代碼
~ ~ ~~ ~~ ~~ ~~ ~electron
本例程使用qemu-system-gnuarmeclipse,該qemu分支對stm32f4有更好的支持,主要面向Eclipse開發環境,本文檔給出在Ubuntu 16.04命令行環境下單獨使用的方式。
#cd ~/work
#tar xvf gnuarmeclipse-qemu-debian64-2.8.0-201612271623-dev.tgz
#chmod -R -w ./qemu
export PATH=~/work/qemu/2.8.0-201612271623-dev/bin/:$PATH複製代碼
#qemu-system-gnuarmeclipse --version複製代碼
如正常則會顯示版本信息爲2.8.0。
說明:qemu-system-gnuarmeclipse當前版本不支持STM32F4的浮點,相應的,FreeRTOS使用的portable目錄沒有使用ARM_CM4F而是使用ARM_CM3。
在Demo1目錄下提供了一個qemu.sh腳本文件,內容以下:
#!/bin/bash
qemu-system-gnuarmeclipse --verbose --verbose --board STM32F429I-Discovery --mcu STM32F429ZI -d unimp,guest_errors --image hello_rtos.elf --semihosting-config enable複製代碼
在Demo1目錄下運行腳本文件:
#./qemu.sh複製代碼
則qemu開始執行hello_rtos.elf文件,在彈出的GUI中看到程序執行的效果。
Ubuntu缺省安裝中沒有gdb-arm-none-eabi工具,須要先安裝
#sudo apt-get install gdb-arm-none-eabi複製代碼
在Demo1目錄下運行qemu_gdb腳本文件,該文件中添加了--gdb tcp::1234 -S
qemu啓動後等待來自gdb的調試指令,打開另一個終端窗口,運行
#arm-none-eabi-gdb複製代碼
在gdb界面內運行:
(gdb)target remote localhost:1234
(gdb)continue複製代碼
能夠看到qemu開始執行程序,GUI界面上能夠看到程序執行效果。
本例程啓動了FreeRTOS的trace功能。
##6.自主編程實現三個同步通訊的函數:Sender_Task,Receiver_Task,Monitor_Task;
我採用了Mac編程,而後經過git的方式同步到ubuntu,不只鍛鍊了團隊寫做的神器--「Git」的使用技巧,同時也優化了本身的編程環境
說一下個人思路:
首先,採用全局變量來統領發送的數據和接收到的數據,經過在main函數外聲明瞭一個發送數據的和,一個接收數據的和,一個隊列用於傳遞因爲週期不對等的發送和接受的數據。而後Sender_Task用於2ms發送一個數據,從1-10000循環,Receiver_Task 用於1000ms接收一波數據,大概是500個左右,因此隊列的大小我定爲510 ,雖然有不小的浪費,可是至少不會數據溢出。最後的Monitor_Task用於斷定是否爭取的發送和接受,因此這個時候就要用到兩個全局變量,在10000ms的週期內斷定一次是否兩個數據和相等,若是發送的數據之和等於接受的數據之和,那麼就毫無疑問的,發送沒有問題。並且因爲我規定,優先級上,Monitor>Receiver>Sender ,因此能夠保證不會發生數據競爭致使的錯漏。若是正確,那就亮綠燈,錯誤就是紅燈,事實顯示,一直是正確的!!
/**
******************************************************************************
* @file IO_Toggle/main.c
* @author MCD Application Team
* @version V1.0.0
* @date 19-September-2011
* @brief Main program body
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f429i_discovery.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
/** @addtogroup STM32F4_Discovery_Peripheral_Examples
* @{
*/
/** @addtogroup IO_Toggle
* @{
*/
/* Private typedef -----------------------------------------------------------*/
GPIO_InitTypeDef GPIO_InitStructure;
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
void Hardware_Init(void);
void Red_LED_On(void);
void Red_LED_Off(void);
void Green_LED_On(void);
void Green_LED_Off(void);
void ToggleLED1_Task(void*);
void ToggleLED2_Task(void*);
/**
* @brief Main program
* @param None
* @retval None
*/
//張照博本身寫的--START
int32_t Send_Sum=0;
int32_t Received_Sum=0;
//創建隊列
xQueueHandle MyQueue;
void Sender_Task(void *pvParameters)
{
int32_t Send_Num = 1;
for( ;; )
{
vTaskDelay( 2 / portTICK_RATE_MS );
if (Send_Num>10000)
{
Send_Num=1;
}
/* 向隊列中填充內容 */
xQueueSendToBack( MyQueue, ( void* )&Send_Num, 0 );
*((int32_t*)pvParameters)+=Send_Sum;
Send_Num++;
}
}
void Receiver_Task(void *pvParameters)
{
int32_t Received_Num = 0;
for( ;; )
{
/* 從隊列中獲取內容 */
if( xQueueReceive( MyQueue, &Received_Num, 1000 / portTICK_RATE_MS ) == pdTRUE)
{
*((int32_t*)pvParameters)+=Received_Num;
Received_Num=*((int32_t*)pvParameters);
}
}
}
void Monitor_Task(void *pvParameters)
{
vTaskDelay( 10000 / portTICK_RATE_MS );
if(Send_Sum-Received_Sum<5 && Send_Sum-Received_Sum>-5)
{
Green_LED_On();
Red_LED_Off();
Send_Sum=0;
Received_Sum=0;
}
else
{
Green_LED_Off();
Red_LED_On();
Send_Sum=0;
Received_Sum=0;
}
}
//張照博本身寫的--END
int main(void)
{
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
file (startup_stm32f4xx.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_stm32f4xx.c file
*/
Hardware_Init();
// 初始化硬件平臺
//prvSetupHardware();
//建立全局變量
MyQueue = xQueueCreate( 510 , sizeof( int32_t ) );
// 創建任務
xTaskCreate( Sender_Task, ( signed portCHAR * ) "Sender_Task", configMINIMAL_STACK_SIZE,(void*)&Send_Sum, tskIDLE_PRIORITY+3, NULL );
xTaskCreate( Receiver_Task, ( signed portCHAR * ) "Receiver_Task", configMINIMAL_STACK_SIZE,(void*)&Received_Sum, tskIDLE_PRIORITY+4, NULL );
xTaskCreate( Monitor_Task, ( signed portCHAR * ) "Monitor_Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+5, NULL );
//啓動OS
vTaskStartScheduler();
return 0;
//個人第一次調試,須要去掉後面的
/* Init and start tracing*/
vTraceEnable(TRC_INIT);
vTraceEnable(TRC_START);
// /* Create tasks */
// xTaskCreate(
// ToggleLED1_Task, /* Function pointer */
// "Task_LED1", /* Task name - for debugging only*/
// configMINIMAL_STACK_SIZE, /* Stack depth in words */
// (void*) NULL, /* Pointer to tasks arguments (parameter) */
// tskIDLE_PRIORITY + 3UL, /* Task priority*/
// NULL /* Task handle */
// );
// xTaskCreate(
// ToggleLED2_Task, /* Function pointer */
// "Task_LED2", Task name - for debugging only
// configMINIMAL_STACK_SIZE, /* Stack depth in words */
// (void*) NULL, /* Pointer to tasks arguments (parameter) */
// tskIDLE_PRIORITY + 2UL, /* Task priority*/
// NULL /* Task handle */
// );
// /* Start the scheduler. */
// vTaskStartScheduler();
// /* If all is well, the scheduler will now be running, and the following line
// will never be reached. If the following line does execute, then there was
// insufficient FreeRTOS heap memory available for the idle and/or timer tasks
// to be created. See the memory management section on the FreeRTOS web site
// for more details. */
// for( ;; );
//個人第一次調試,去掉的位置結尾
}
/**
* Hardware_Init:
*/
void Hardware_Init(void)
{
/* GPIOG Periph clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
/* Configure PG13, PG14 in output pushpull mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13| GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOG, &GPIO_InitStructure);
}
/**
* Red_LED_On:
*/
void Red_LED_On(void)
{
// GPIO_SetBits(GPIOG, GPIO_Pin_14);
GPIOG->ODR |= 0x4000;
}
/**
* Red_LED_Off:
*/
void Red_LED_Off(void)
{
// GPIO_ResetBits(GPIOG, GPIO_Pin_14);
GPIOG->ODR &= 0xBFFF;
}
/**
* Green_LED_On:
*/
void Green_LED_On(void)
{
// GPIO_SetBits(GPIOG, GPIO_Pin_13);
GPIOG->ODR |= 0x2000;
}
/**
* Green_LED_Off:
*/
void Green_LED_Off(void)
{
// GPIO_ResetBits(GPIOG, GPIO_Pin_13);
GPIOG->ODR &= 0xDFFF;
}
/**
* ToggleLED1_Task: Toggle LED1 via RTOS Timer
*/
void ToggleLED1_Task(void *pvParameters)
{
int led = 0;
while (1)
{
if(led == 0)
{
Red_LED_On();
led = 1;
}
else
{
Red_LED_Off();
led = 0;
}
/*
Delay for a period of time. vTaskDelay() places the task into
the Blocked state until the period has expired.
The delay period is spacified in 'ticks'. We can convert
yhis in milisecond with the constant portTICK_RATE_MS.
*/
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
/**
* ToggleLED2_Task: Toggle LED2 via RTOS Timer
*/
void ToggleLED2_Task(void *pvParameters)
{
int led = 0;
while (1)
{
if(led == 0)
{
Green_LED_On();
led = 1;
}
else
{
Green_LED_Off();
led = 0;
}
/*
Delay for a period of time. vTaskDelay() places the task into
the Blocked state until the period has expired.
The delay period is spacified in 'ticks'. We can convert
yhis in milisecond with the constant portTICK_RATE_MS.
*/
vTaskDelay(2000 / portTICK_RATE_MS);
}
}
void vApplicationTickHook( void )
{
}
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
void vApplicationMallocFailedHook( void )
{
/* vApplicationMallocFailedHook() will only be called if
configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook
function that will get called if a call to pvPortMalloc() fails.
pvPortMalloc() is called internally by the kernel whenever a task, queue,
timer or semaphore is created. It is also called by various parts of the
demo application. If heap_1.c or heap_2.c are used, then the size of the
heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
to query the size of free heap space that remains (although it does not
provide information on how the remaining heap might be fragmented). */
taskDISABLE_INTERRUPTS();
for( ;; );
}
/*-----------------------------------------------------------*/
void vApplicationIdleHook( void )
{
/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
task. It is essential that code added to this hook function never attempts
to block in any way (for example, call xQueueReceive() with a block time
specified, or call vTaskDelay()). If the application makes use of the
vTaskDelete() API function (as this demo application does) then it is also
important that vApplicationIdleHook() is permitted to return to its calling
function, because it is the responsibility of the idle task to clean up
memory allocated by the kernel to any task that has since been deleted. */
}
/*-----------------------------------------------------------*/
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
( void ) pcTaskName;
( void ) pxTask;
/* Run time stack overflow checking is performed if
configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook
function is called if a stack overflow is detected. */
taskDISABLE_INTERRUPTS();
for( ;; );
}
/*-----------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**
* @}
*/
/**
* @}
*/
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/複製代碼