TIMEOUT در میکروکنترلر ها ( پورت سریال )
بعضی وقت ها نیاز داریم تا از پورت سریال میکروکنترلر ها استفاده کنیم و برای این پورت برنامه بنویسیم .
معمولا ما در هنگام برنامه نویسی ، از دستورات استاندارد برنامه نویسی ( کتابخانه stdio.h ) یا به صورت مستقیم از رجیستر ها برای تبادل داده بر مبنای این پروتکل استفاده کنیم . در این رابطه بحث های زیادی در سطح انجمن و کتب برنامه نویسی انجام شده و کلیه دستورات مذکور قبلا معرفی شدن .
دستورات زیر از جمله دستورات استاندارد برنامه نویسی پروتکل uart یا rs232 در زبان سی هستند :
[PHP]printf(string)
putchar()
fputc()
putc (cdata)
value = getc()
value = fgetc(stream)
value=getch()
value=getchar()
[/PHP]
برای ارسال داده به دستگاه جانبی مشکلی وجود نداره ، ما با یکی از دستورات printf یا putchar یا fputc یا putc رشته ، متغیر یا کاراکتر مورد نظرمون رو با یک نرخ انتقال داده ثابت به دستگاه جانبی ارسال میکنیم .
برای دریافت داده از دستگاه جانبی از دستورات getc و fgetc و getch و getchar و... استفاده میشه . معمولا با اجرا شدن این دستورات ،در درون کتابخانه ها حلقه زیر اجرا میشه :
کد:
while (!(RXRDY)); // Wait for new char
return (*Rx Buffer );
مثلا برای میکروکنترلر arm اتمل ، کلیه هدر های ارائه شده ، در نهایت دستور زیر رو برای دریافت یک کاراکتر از پورت سریال اجرا میکنن :
کد:
while (!((*AT91C_US0_CSR) & AT91C_US_RXRDY)); // Wait for Empty Rx Buffer
return (*AT91C_US0_RHR );
یا در کامپایلر mplab دستور زیر در هنگام دریافت داده از پورت سریال اجرا میشود :
کد:
while (! U1STAbits.URXDA); // wait until data is available
return U1RXREG; // return received character over UART
همون طور که مشاهده میکنید در تمامی حلقه های بالا اگر بعد از اجرای دستورات getc و fgetc و getch و getchar و.. داده ای به بافر پورت سریال وارد نشه ، میکروکنترلر در حلقه while موجود برای همیشه گیر میکنه .
این حالت ممکنه در هنگام ارتباط با یک کامپیوتر و به دلیل هنگ کردن نرم افزار کامپیوتری ، در هنگام دریافت داده از یک ماژول و به دلیل قطع شدن تغذیه ماژول ، در هنگام دریافت داده از یک میکروکنترلر و ایجاد خطا در داده دریافتی و و در هنگام ارتباط با هر نوع وسیله جانبی دیگر و به دلیل بروز مشکلاتی مانند قطع شدن سیم ها ، عدم اتصال صحیح سیم ها و... میکروکنترلر ما هنگ کنه و نتونه سایر دستورات رو اجرا کنه .
مثال:
http://www.iranmicro.ir/forum/showthread.php?t=8752
http://www.iranmicro.ir/forum/showthread.php?t=5389
http://www.iranmicro.ir/forum/showthread.php?t=10582
http://www.iranmicro.ir/forum/showthread.php?t=9626
و... نمونه برنامه های نوشته برای پورت سریال هستند که در آنها بروز اختلال در پروتکل سریال پیشبینی نشده است ، میکروکنترلر های موجود در این پروژه ممکنه در آینده به دلیل بروز اختلال در پروتکل rs232 عملکردی غیر قابل پیشبینی داشته باشن .
برای رفع این مشکل باید از TIMEOUT استفاده کنیم . TIMEOUT رو میشه هم به صورت سخت افزاری و هم به صورت نرم افزاری برای میکروکنترلر اجرا کرد (مثلا میکروکنترلر های arm از TIMEOUT سخت افزاری پشتیبانی میکنن . اما میکروکنترلر pic و avr فاقد TIMEOUT سخت افزاری هستند و ما باید TIMEOUT رو به صورت نرم افزاری برای اونا اجرا کنیم ).
چند تا نکته :
- TIMEOUT نرم افزاری فقط در کامپایلر های قابل اجرا هست که به کاربران امکان ویرایش کتابخونه ها رو دادن .
- برای برخی از کامپایلر مثل bascom avr یا ccs pic c جهت TIMEOUT دستوراتی در نظر گرفته شده ، برای کسب اطلاعات بیشتر دستور TIMEOUT رو در راهنمای اونا جستوجو کنید ، مثال برای بسکام :http://avrhelp.mcselec.com/_timeout.htm
- استفاده از دستورات TIMEOUT ، قابلیت جدیدی رو به برنامه اضافه نمیکنه و بدون لحاظ کردن این ویژگی ،برنامه بدون هیچ مشکلی کار میکنه . این اموزش صرف برای افرادی هست که میخوان به صورت حرفه ای برنامه نویسی کنند .
در ادامه با یک مثل ، نحوهی استفاده از قابلیت TIMEOUT برای میکروکنترلر های PIC و ATM اتمل توضیح داده شده است :
اجرای دستور TIMEOUT در کامپایلر CCS PIC C :
برای استفاده از TIMEOUT در این کامپایلر باید در هنگام راه اندازی واحد UART دو دستور ERRORS و TIMEOUT=X رو در پیکربندی پروتکل وارد کنید ، مثال :
کد:
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS,TIMEOUT=70)
در پیکربندی بالا TIMEOUT برابر با 70 میلی ثانیه تنظیم شده
برای استفاده از TIMEOUT باید بعد از دستورات getc و fgetc و getch و getchar و.. ، دستور زیر رو قرار بدید :
کد:
if (c==0 && RS232_ERRORS==0) break;
در این حالت اگه تا 70 میلی ثانیه ، داده ای توسط پورت سریال دریافت نشه ، میکروکنترلر از کلیه دستورات getc و fgetc و getch و getchar و.. عبور میکنه ( از داخل حلقه مربوط به دریافت داده خارج میشه ) .
مثال عملی :
در برنامه زیر اگر بعد از گذشت 2 ثانیه داده ای از دستگاه جانبی دریافت نشود ، رشته "TIMEOUT , type faster" به دستگاه جانبی ارسال میگردد . [PHP]#include <16F877A.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES PUT //Power Up Timer
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS,TIMEOUT=2000)
void main()
{
char c;
while(true){
printf("Perss any key...\r");
c=getc();
if (c==0 && RS232_ERRORS==0)
printf("TIMEOUT , type faster\r" );
else
printf("Enter key is:%c\r",c );
}
}
[/PHP]
مثال عملی
در برنامه ای ، باید یک رشته از پورت سریال دریافت شود ،در این حالت باید از کتابخانه input.c استفاده کنیم ، این کتابخونه فاقد دستورات لازم جهت timeout هست و ما باید دستور شرطی زیر رو در کتابخانه input.c و بعد از دستور c=getc(); قرار بدیم .
کد:
if (c==0 && RS232_ERRORS==0) break;
برنامه :[PHP]#include <16F877A.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES PUT //Power Up Timer
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS,TIMEOUT=2000)
#INCLUDE <INPUT.C>
void main()
{
char c[10];
while(true){
printf("Enter string..\r");
get_string(c, 10);
printf("Enter sting is:%s\r",c);
}
}[/PHP]
تابع جدید get_string :[PHP]void get_string(char* s, unsigned int8 max) {
unsigned int8 len;
char c;
--max;
len=0;
do {
c=getc();
if (c==0 && RS232_ERRORS==0){
printf("TIMEOUT , type faster\r" );
break;
}
if(c==8) { // Backspace
if(len>0) {
len--;
putc(c);
putc(' ');
putc(c);
}
} else if ((c>=' ')&&(c<='~'))
if(len<=max) {
s[len++]=c;
putc(c);
}
} while(c!=13);
s[len]=0;
}
[/PHP]
به زودی نحوه ی استفاده از TIMEOUT برای میکروکنترلر های avr و arm رو توضیح میدم .