برد STM

پیاده‌سازی کتابخانه ۴۱-STDIO برای stm32f4

نوشته شده توسط اروند طباطبایی

پس از آنکه آموزش استفاده از printf را برای stm32f4 قرار دادیم. به این نتیجه رسیدیم که یک کتابخانه برای printf و تابع های دیگری که اطلاعات را خروجی میگیرند بنویسیم. این کتابخانه به شما اجازه میدهد تا به صورت ساده از خروجی های نامحدودی از استریم ها بهره ببرید. ولی فقط یکی از آن‌ها را میتوان برای استفاده با prinft استفاده کرد. و بقیه آن‌ها را در نهایت میتوانید با تابعی مثل fprintf استفاده کنید.

کتابخانه

ویژگی‌ها :

خروجی رشته‌ها با printf و دیگر تابع ها مانند fprintf

هر تابع قابلیت خروجی اطلاعات برای استریم کردن را دارد

استریم های نامحدود برای خروجی میتوان استفاده کرد

پشتیبانی از خواندن با ورودی استاندارد stdin به صورت استریم یا …

نیازمندی ها :

cmsis

stm32f4xx

tm

defines.h

attributes.h

فرمت خروجی :

با توجه به کتابخانه stdio مخصوصARM شما میتوانید printf یا هر تابع خروجی استریمی را استفاده کنید. انواع این خروجی های ممکن در سایت رسمی ARM آمده است

Printf format

printf

تابع اصلی این قسمت همین printf است . با صدا کردن آن میتوانید رشته خود را استریم کرده و آن را به خروجی دلخواه خود ارسال کنید. این خروجی میتواند usart یا lcd باشد. ولی با printf فقط میتوانید یک استریم خروجی داشته باشید. بزارید آن را usart1 بنامیم. حال اگر بخواهیم خروجی را روی lcd نیز نمایش دهید شما نیاز به یک روش دیگر برای انجام آن دارید مانند استفاده از fprintf . در این قسمت به شما یاد میدهم که چطور از printf با کتابخانه من استفاده کنید.

ساده است؛فقط نیاز دارید تا کتابخانه من را قرار داده و یک تابع در آن ایجاد کنید. اینکار اطلاعات را برای شما خروجی خواهد گرفت. شما میتوانید یک تابع را در هرجای پروژه خود بسازید و این مهم است که اسم و پارامتر صحیحی داشته باشد. تابعی که میسازید باید همانند زیر باشد

/* Handle printf actions */

int TM_STDIO_StdoutHandler(int ch, FILE* f) {

/* Do with your character what you need here */

/* Return ch, it means OK */

return ch;

/* If you want to return error, then you have to send EOF (-1) */

//return -1;

}

حال اگر میخواهید اطلاعات را با printf بر روی usart1 خروجی بگیرید نیاز به بارگذاری آن در یک جایگاه اصلی دارید . سپس نیاز دارید تا تابعی مانند زیر بنویسید

/* Handle printf actions */

int TM_STDIO_StdoutHandler(int ch, FILE* f) {

/* Send data to USART1 */

TM_USART_Putc(USART1, (char) ch);

/* Return ch, it means OK */

return ch;

/* If you want to return error, then you have to send EOF (-1) */

//return -1;

}

حال شما میتوانید pprintf را در هرجایی که بخواهید استفاده کنید.

استریم های خروجی بیشتر

اگر شما میخواهید رشته‌های بیشتری را برای خروجی استریم کنید باید آن‌ها را تکه‌تکه کنید و سپس باید بدانید که هر استریم را روی کجا خروجی بدهید . این کار را میتوانید با fprintf و vfpintf انجام دهید. اولین آرگومان این تابع همان نشانگر خروجی استریم است پس وقتی شما از تابع خروجی استریم استفاده میکنید شما میدانید که کدام استریم را میخواهید خروجی بگیرید.

برای اینکار من چند چیز به کتابخانه ام اضافه کرده‌ام . ابتدا نیاز داریم تا متغیر هایی را که با هم تا حد امکان متفاوت هستند ایجاد کنیم. اگر میخواهید خروجی را برای usrat یا lcd استفاده کنیدمیتوانید از همان دستور printf استفاده کنید و یک روش دیگر نیز برای خروجی lcd وجود دارد.

ابتدا یک متغیر بسازید

FILE LCD_Stream;

سپس تابعی با اسم دلخواه ایجاد کنید اما پارامتر ها را دقیقاً همانند مثال قرار دهید.

int LCD_Stream_OutputFunction(int ch, FILE* f) {

/* Do your stuff here with new character */

/* Return ch, it means OK */

return ch;

/* If you want to return error, then you have to send EOF (-1) */

//return -1;

}

اما استریم هنوز نمیداند که کدام تابع را صدا کند و شما باید این را بگویید پس کد زیر آن را برایمان انجام خواهد داد

/* Add output function for LCD_Stream */

TM_STDIO_SetOutputFunction(&LCD_Stream, LCD_Stream_OutputFunction);

حال اگر شما تابع را مانند زیر صدا بزنید شما قادر خواهید بود تا خروجی اطلاعات را روی lcd بگیرید.

/* Print something on LCD */

fprintf(&LCD_Stream, "Hello world");

استریم ورودی

شما همچنین قادرید تا اطلاعات را از یک استریم دریافت کنید. برای اینکار ما دوباره یک تابع استاندارد با نام stdin داریم و همچنین میتوانیم توابعی با نام های مشابه نیز برای قابلیت‌های دلخواه ایجاد کنیم. برای اجرای stdin نیاز به نوشت کد زیر دارید :

/* Handle stdin actions */

int TM_STDIO_StdinHandler(FILE* f) {

/* Return your data here */

/* End of data, string is valid */

/* You have to send -1 at the end of string */

return -1;

}

حال با صدا زدن تابع fget میتوانید رشته را از استریم دریافت کنید.

برای استریم های کاستوم نیز مانند استریم usart6 شما باید ابتدا یک تابع کاستوم ایجاد کنید تا اطلاعات ورودی استریم usrat6 را مدیریت کند. میتوانید به آن هر اسمی بدهید ولی ساختار آن باید درست باشد

/* Handle USART6 stream input = custom function name, linked with USART6 stream in the beginning of main() function */

int USART6_Stream_InputFunction(FILE* f) {

/* If any data at USART, return them */

if (!TM_USART_BufferEmpty(USART6)) {

return (int)TM_USART_Getc(USART6);

}

/* End of data, string is valid */

/* You have to send -1 at the end of string */

return -1;

}

و شما نیاز به لینک کرددن تابع ورودی با یک استریم دارید در ابتدای main باید چنین کدی را اضافه کنید.

/* Add input function for USART6_Stream */

TM_STDIO_SetInputFunction(&USART6_Stream, USART6_Stream_InputFunction);

تمام شد؛ حالا میتوانید از تابع استاندارد ورودی نیز استفاده کنید

تابع ها و شمارش ها

/**

* File structure for stdio stream output

*

* Parameters:

* - int (*outputFuncPointer)(int, FILE *):

* Pointer to function to call when need to output data

* - int (*inputFuncPointer)(FILE *):

* Pointer to function to call when trying to get data from stream

*/

struct __FILE {

int (*outputFuncPointer)(int, FILE *);

int (*inputFuncPointer)(FILE *);

};

/**

* Link file output stream with output put character function

*

* Parameters:

* - FILE* f

* Pointer to file stream

* - int (*outputFuncPointer)(int, FILE *)

* Pointer to function that will be used to output data to stream

*

* No return

*/

extern void TM_STDIO_SetOutputFunction(FILE* f, int (*outputFuncPointer)(int, FILE *));

/**

* Link file input stream with input get character function

*

* Parameters:

* - FILE* f:

* Pointer to file stream

* - int (*inputFuncPointer)(FILE *):

* Pointer to function that will be used to input data from stream

*

* No return

*/

extern void TM_STDIO_SetInputFunction(FILE* f, int (*inputFuncPointer)(FILE *));

/**

* Default output handler for standard output (stdout)

* Needs to be implemented by user if you want to use printf function.

* This function has __weak parameters to prevent link errors if it is not implemented by user

*

* Parameters:

* - int c:

* Character for output to the stream

* - FILE* f:

* Pointer to file stream

*

* Returns character value if write is OK

* Returns -1 if you want to stop write at any time

*/

__weak int TM_STDIO_StdoutHandler(int c, FILE* f);

/**

* Default input handler for standard input (stdin)

* Needs to be implemented by user if you want to get data from standard input.

* This function has __weak parameter to prevent link errors if it is not implemented by user

*

* Parameters:

* - FILE* f:

* Pointer to file stream

*

* Returns character value if exists

* Returns -1 if at the end of string or no data available

*/

__weak int TM_STDIO_StdinHandler(FILE* f);

مثال :

در این مثال اطلاعات در ۳ کانال usart پخش خواهند شد :

/**

* Keil project for STDIO output & input

*

* Before you start, select your target, on the right of the "Load" button

*

* @author Tilen Majerle

* @email tilen@majerle.eu

* @website http://stm32f4-discovery.com

* @ide Keil uVision 5

*/

/* Include core modules */

#include "stm32f4xx.h"

/* Include my libraries here */

#include "defines.h"

#include "tm_stm32f4_usart.h"

#include "tm_stm32f4_stdio.h"

#include "tm_stm32f4_delay.h"

/* You can use only 1 thing for printf */

/* If you want more, then you can use fprintf */

/* For this you need FILE pointer for each */

/* Create global variables for fprintf function */

/* for USART2 and USART6 */

FILE USART2_Stream, USART6_Stream;

/* Output stream for USART2 and USART6 function references */

int USART2_Stream_OutputFunction(int ch, FILE* f);

int USART6_Stream_OutputFunction(int ch, FILE* f);

/* Input stream for USART2 and USART6 function references */

int USART2_Stream_InputFunction(FILE* f);

int USART6_Stream_InputFunction(FILE* f);

int main(void) {

char str[100];

/* Initialize system */

SystemInit();

/* Initialize delay */

TM_DELAY_Init();

/* Initialize USART1, TX = PB6, RX = PB7, 115200 bauds */

TM_USART_Init(USART1, TM_USART_PinsPack_2, 115200);

/* Initialize USART2, TX = PD5, RX = PD6, 115200 bauds*/

TM_USART_Init(USART2, TM_USART_PinsPack_2, 115200);

/* Initialize USART6, TX = PC6, RX = PC7, 115200 bauds */

TM_USART_Init(USART6, TM_USART_PinsPack_1, 115200);

/* Add output function for USART2_Stream */

TM_STDIO_SetOutputFunction(&USART2_Stream, USART2_Stream_OutputFunction);

/* Add input function for USART2_Stream */

TM_STDIO_SetInputFunction(&USART2_Stream, USART2_Stream_InputFunction);

/* Add output function for USART6_Stream */

TM_STDIO_SetOutputFunction(&USART6_Stream, USART6_Stream_OutputFunction);

/* Add input function for USART6_Stream */

TM_STDIO_SetInputFunction(&USART6_Stream, USART6_Stream_InputFunction);

/* Print something on USART1 */

printf("Hello USART1 usern");

/* Print something on USART2 */

fprintf(&USART2_Stream, "Hello USART2 usern");

/* Print something on USART6 */

fprintf(&USART6_Stream, "Hello USART6 usern");

while (1) {

/* If data are available on stream */

/* Check data on standard header, USART1 */

/* stdin or standard input */

if (fgets(str, 100, stdin) != NULL) {

/* Send data back */

/* Statement below is the same as of use printf function */

fprintf(stdout, (char *)str);

}

/* Check data on USART2 stream */

if (fgets(str, 100, &USART2_Stream) != NULL) {

/* Send data back */

/* Send data to USART2 stream */

fprintf(&USART2_Stream, (char *)str);

}

/* Check data on USART6 stream */

if (fgets(str, 100, &USART6_Stream) != NULL) {

/* Send data back */

/* Send data to USART2 stream */

fprintf(&USART6_Stream, (char *)str);

}

/* Some delay */

/* If you call your gets too often, then it can happen that USART characters are not in buffer yet */

/* and function will not do as it should */

Delayms(1000);

}

}

/* Handle stdout actions = default name and can not be changed */

int TM_STDIO_StdoutHandler(int ch, FILE* f) {

/* Send data to USART1 */

TM_USART_Putc(USART1, (char) ch);

/* Return ch, it means OK */

return ch;

/* If you want to return error, then you have to send EOF (-1) */

//return -1;

}

/* Handle stdin actions */

int TM_STDIO_StdinHandler(FILE* f) {

/* If any data at USART, return them */

/* Do your custom implementation here when string ends */

if (!TM_USART_BufferEmpty(USART1)) {

return (int)TM_USART_Getc(USART1);

}

/* End of data, string is valid */

/* You have to send -1 at the end of string */

return -1;

}

/* USART2 output stream handler = custom function name, linked with USART2 stream in the beginning of main() function */

int USART2_Stream_OutputFunction(int ch, FILE* f) {

/* Send char via USART2 */

TM_USART_Putc(USART2, (char) ch);

/* Return ch, it means OK */

return ch;

/* If you want to return error, then you have to send EOF (-1) */

//return -1;

}

/* Handle USART2 stream input = custom function name, linked with USART2 stream in the beginning of main() function */

int USART2_Stream_InputFunction(FILE* f) {

/* If any data at USART, return them */

/* Do your custom implementation here when string ends */

if (!TM_USART_BufferEmpty(USART2)) {

return (int)TM_USART_Getc(USART2);

}

/* End of data, string is valid */

/* You have to send -1 at the end of string */

return -1;

}

/* USART6 output stream handler = custom function name, linked with USART6 stream in the beginning of main() function */

int USART6_Stream_OutputFunction(int ch, FILE* f) {

/* Send char via USART6 */

TM_USART_Putc(USART6, (char) ch);

/* Return ch, it means OK */

return ch;

/* If you want to return error, then you have to send EOF (-1) */

//return -1;

}

/* Handle USART6 stream input = custom function name, linked with USART6 stream in the beginning of main() function */

int USART6_Stream_InputFunction(FILE* f) {

/* If any data at USART, return them */

/* Do your custom implementation here when string ends */

if (!TM_USART_BufferEmpty(USART6)) {

return (int)TM_USART_Getc(USART6);

}

/* End of data, string is valid */

/* You have to send -1 at the end of string */

return -1;

}

TM STM32F4 STDIO Library

موفق باشید 

درباره نویسنده

اروند طباطبایی

بنیانگذار دیجی اسپارک: اولین مرجع تخصصی امبدد سیستم به زبان فارسی / کارشناس سئو و تولید محتوا

هرچه می آموزم میبینم که خیلی کم آموختم. علاقه به رباتیک و تکنولوژی دارم. امیدوارم بتونم دانشی را که آموخته‌ام، به روش‌های مختلفی به کاربران علاقمند منتقل کنم.

تبادل نظر و رفع عیب با ثبت دیدگاه