نحوۀ ساخت کتابخانه در زبان برنامه نویسی C برای میکروکنترلرها

توسط | 22 دی, 1398 | برنامه نویسی | 13 دیدگاه ها

کتابخانه در زبان برنامه نویسی چیست؟ ساخت کتابخانه در نرم افزار CodevisionAVR، کتابخانه با پسوند h، کتابخانه با پسوند c، کتابخانه با پسوند h و c، فراخوانی کتابخانه، کاربرد دستور پیش پردازندۀ #ifndef در نوشتن کتابخانه، فراخوانی کتابخانه از پوشه های مختلف، ساخت کتابخانه در نرم افزار Keil
ساخت-کتابخانه-c-cpp

کتابخانه ها امکانی هستند که به وسیلۀ آنها می توانیم برنامۀ نوشته شده را دسته بندی و مرتب کنیم. در واقع هر برنامه از توابع مختلف تشکیل شده است. نوشتن توابع گوناگون در فایل main باعث شلوغ شدن و ناخوانا شدن برنامه می شود. با استفاده از کتابخانه نویسی می توانیم بخش ها و توابع مختلف را به صورت جداگانه و در دسته بندی های مورد نیاز در فایل هایی دیگر قرار دهیم. کافی است توابع، متغیرها و دیفاین های مربوط به یک وظیفۀ خاص یا یک المان خاص را در یک کتابخانه قرار دهیم و نامی برای آن کتابخانه انتخاب کنیم. در فایل main نیز تنها کافی است آن کتابخانه را فراخوانی کنیم تا بتوانیم از توابع آن استفاده کنیم. در این نوشته می خواهیم با ذکر مثال در نرم افزار کدویژن و Keil به ساخت کتابخانه، فراخوانی کتابخانه و استفاده از توابع آن بپردازیم.

ما معمولاً از دو روش برای ساخت کتابخانه استفاده می کنیم. در روش اول برای کتابخانه تنها یک فایل داریم. این فایل با پسوند h یا c ذخیره می شود که ما اغلب با h آن را ذخیره می کنیم. در روش دوم ساخت کتابخانه، دو فایل داریم. یکی با پسوند h و دیگری با پسوند c. قسمتی از کتابخانه در فایل با پسوند h و قسمتی دیگر در فایل با پسوند c قرار می گیرد. در ادامه روش اول ساخت کتابخانه را بیان می کنیم. منظور ما از پسوند در این نوشته، عبارت تعیین کنندۀ فرمت فایل است. مثلاً فایل delay.h دارای پسوند h است.

فیلم آموزش میکروکنترلرهای AVR مقدماتی

فیلم آموزش ARM STM32 مقدماتی

فیلم آموزش آردوینو مقدماتی

ساخت کتابخانه در کدویژن

فرض کنیم چند تابع برای اسکن صفحه کلید داریم و این توابع را در فایل main نوشته ایم. حال می دانیم قرار است متن توابع اسکن صفحه کلید و تعداد آنها زیاد شود. بنابراین بهتر است این توابع را در فایل دیگری ذخیره کنیم و یک کتابخانه به نام keypad بسازیم. به برنامۀ زیر توجه کنید. در برنامۀ زیر می خواهیم توابع keypad و keypad scan و keypad decode 1 را در یک کتابخانه قرار دهیم.

#define NUMBER 0
#define CHAR1  1
#define CHAR2  2
#define CHAR3  3
#define CHAR4  4
#define CHAR5  5
#define CHAR6  6

#define EXIT                         69      // E ASCII code
#define OK                           79      // O ASCII code
#define DOWN                         68      // D ASCII code
#define UP                           85      // U ASCII code
#define MINUS                        45      // Minus ASCII code
#define DOT                          46      // Dot ASCII code
#define KEY_MAX                      16
#define POSITIVE_SIGN                0
#define NEGATIVE_SIGN                1

#define NO 0
#define YES 1

#include <mega128a.h>
#include <delay.h>
#include <alcd.h>
#include <stdio.h>

unsigned char keypad_scan_out=250;
unsigned char display_refresh=NO;

void keypad(void);
void keypad_scan(void);
void kepad_decode_1(void);

void main(void)
{
char lcd_str[20];

DDRA=(1<<DDA7) | (1<<DDA6) | (1<<DDA5) | (1<<DDA4) | (1<<DDA3) | (1<<DDA2) | (1<<DDA1) | (1<<DDA0);


DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0); 
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

lcd_init(20);
while (1)
      {
        keypad();
		if (display_refresh==YES)
		{
			display_refresh=NO;
			lcd_clear();
			lcd_gotoxy(0,0);
			sprintf(lcd_str,"%d",keypad_scan_out);
			lcd_puts(lcd_str);
			
		}
      }
}

//**********************************************************************************
//********************************* new function ***********************************
void keypad()
{
 static char key_pad_status=0;
 keypad_scan();  
 if((keypad_scan_out!=255)&&(key_pad_status==0))
 {
  key_pad_status=1;
  kepad_decode_1();  
  display_refresh=YES;
 }
 if(keypad_scan_out==255) key_pad_status=0;
}

//**********************************************************************************
//********************************* new function ***********************************
void keypad_scan(void)
{
    unsigned char key=0, i=0;  
    unsigned char key_table[16]={0xEE, 0xED, 0xEB, 0xE7, 0xDE, 0xDD, 0xDB, 0xD7, 0xBE, 0xBD, 0xBB, 0xB7, 0x7E, 0x7D, 0x7B, 0x77};
    unsigned char key_table2[17]={1,4,7,DOT,2,5,8,0,3,6,9,MINUS,UP,DOWN,OK,EXIT,255};   
    
    DDRD=0x0F; PORTD=0xF0; delay_ms(1); key=PIND; 
    DDRD=0xF0; PORTD=0x0F; delay_ms(1); key=key|PIND;
  	 
    if (key != 0xFF)
    {   
  	 for (i=0; i<KEY_MAX; i++)
     {    
  	  if (key_table[i]==key)  break;   
  	 }
  	}  
  	else i=KEY_MAX;
    keypad_scan_out=key_table2[i];
}

//**********************************************************************************
//********************************* new function ***********************************
void kepad_decode_1(void)
{
	//static unsigned char keypad_mode=NUMBER;
}

 

در منوی file روی New و سپس Source File کلیک می کنیم. در این صورت یک فایل با پسوند c در کدویژن باز می شود که نام آن untitled است.

ایجاد-فایل-کتابخانه-کدویژن

تصویر 1 – ساخت فایل کتابخانه در کدویژن

توابع و دیفاین های مربوط به به کی پد را از فایل main به این فایل منتقل می کنیم. در این صورت فایل main به صورت زیر می شود.

#define NO 0
#define YES 1

#include <mega128a.h>
#include <delay.h>
#include <alcd.h>
#include <stdio.h>


void main(void)
{
	char lcd_str[20];

	DDRA=(1<<DDA7) | (1<<DDA6) | (1<<DDA5) | (1<<DDA4) | (1<<DDA3) | (1<<DDA2) | (1<<DDA1) | (1<<DDA0);


	DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
	PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

	lcd_init(20);
	while (1)
	{
		keypad();
		if (display_refresh==YES)
		{
			display_refresh=NO;
			lcd_clear();
			lcd_gotoxy(0,0);
			sprintf(lcd_str,"%d",keypad_scan_out);
			lcd_puts(lcd_str);
			
		}
	}
}

 

فایلی را که ایجاد کرده بودیم به صورت زیر می شود.

#define NUMBER 0
#define CHAR1  1
#define CHAR2  2
#define CHAR3  3
#define CHAR4  4
#define CHAR5  5
#define CHAR6  6

#define EXIT                         69      // E ASCII code
#define OK                           79      // O ASCII code
#define DOWN                         68      // D ASCII code
#define UP                           85      // U ASCII code
#define MINUS                        45      // Minus ASCII code
#define DOT                          46      // Dot ASCII code
#define KEY_MAX                      16
#define POSITIVE_SIGN                0
#define NEGATIVE_SIGN                1

unsigned char keypad_scan_out=250;
unsigned char display_refresh=NO;

void keypad(void);
void keypad_scan(void);
void kepad_decode_1(void);

//**********************************************************************************
//********************************* new function ***********************************
void keypad()
{
 static char key_pad_status=0;
 keypad_scan();  
 if((keypad_scan_out!=255)&&(key_pad_status==0))
 {
  key_pad_status=1;
  kepad_decode_1();  
  display_refresh=YES;
 }
 if(keypad_scan_out==255) key_pad_status=0;
}

//**********************************************************************************
//********************************* new function ***********************************
void keypad_scan(void)
{
    unsigned char key=0, i=0;  
    unsigned char key_table[16]={0xEE, 0xED, 0xEB, 0xE7, 0xDE, 0xDD, 0xDB, 0xD7, 0xBE, 0xBD, 0xBB, 0xB7, 0x7E, 0x7D, 0x7B, 0x77};
    unsigned char key_table2[17]={1,4,7,DOT,2,5,8,0,3,6,9,MINUS,UP,DOWN,OK,EXIT,255};   
    
    DDRD=0x0F; PORTD=0xF0; delay_ms(1); key=PIND; 
    DDRD=0xF0; PORTD=0x0F; delay_ms(1); key=key|PIND;
       
    if (key != 0xFF)
    {   
       for (i=0; i<KEY_MAX; i++)
     {    
        if (key_table[i]==key)  break;   
       }
      }  
      else i=KEY_MAX;
    keypad_scan_out=key_table2[i];
}

//**********************************************************************************
//********************************* new function ***********************************
void kepad_decode_1(void)
{
    //static unsigned char keypad_mode=NUMBER;
}

 

این فایل را با پسوند h در محلی که فایل prj وجود دارد، ذخیره می کنیم.

ذخیره-کتابخانه-با-پسوند-h-در-کدویژن

تصویر 2 – ذخیرۀ کتابخانه با پسوند h در کدویژن

اگر در این حالت برنامه را کامپایل کنیم، به توابعی که از کتابخانۀ keypad در برنامه استفاده شده، ارور گرفته می شود. اکنون با دستور زیر می توانیم فایل کتابخانه را به برنامه اضافه کنیم. باید در فایل main درجایی که کتابخانه ها را فراخوانی کرده ایم. بنویسیم:

#include "keypad.h"

 

در این صورت اگر برنامه را کامپایل کنیم، می بینیم که اروری مشاهده نمی شود. اگر این فایل را با پسوند c ذخیره می کردیم و آن را به صورت زیر فراخوانی می کردیم، باز هم برنامه بدون ارور کامپایل می شد. در واقع تفاوتی بین فایل با پسوند h با فایل با پسوند c وجود ندارد.

#include "keypad.c"

 

برای این که کتابخانه تنها یک بار فراخوانی شود چه کار کنیم؟

برای این کار می توانیم کاری کنیم که کامپایلر چک کند که که یک عبارت دیفاین شده یا نه. در ابتدای هر کتابخانه یک عبارت را دیفاین می کنیم. کامپایلر قبل از آن چک می کند که اگر این عبارت دیفاین شده بود، متن درون کتابخانه را کامپایل نکند. باید از دستورهای پیش پردازنده به صورت زیر استفاده کنیم.

#ifndef __keypad_h__
#define __keypad_h__

... // متن کتابخانه

#endif

 

در اینجا متن کتابخانه تنها یک بار کامپایل می شود. دفعۀ اول، کامپایلر (با #ifndef) چک می کند که آیا keypad h دیفاین شده یا نه. چون برای اولین بار است دیفاین نشده است. در سطر بعدی این عبارت را دیفاین می کند. همچنین متن کتابخانه را کامپایل می کند. اگر در جایی دیگر از برنامه دوباره کتابخانۀ keypad.h فراخوانی شود، کامپایلر چک می کند و می بیند که keypad h قبلاً دیفاین شده است. بنابراین هر چه که درون #ifndef و #endif قرار دارد دیگر کامپایل نمی شود. در واقع کامپایلر در نظر می گیرد که اگر عبارت جلوی #ifndef قبلاً دیفاین نشده باشد، متن زیر #ifndef تا #endif کامپایل شود. اما گر آن عبارت از قبل دیفاین شده باشد (که به معنی این است که کتابخانه قبلاً فراخوانی شده است)، دیگر متن درون #ifndef و #endif کامپایل نمی شود. حال اگر از این دستورهای پیش پردازنده استفاده نکنیم ممکن است کتابخانه دو یا چند بار دیگر فراخوانی شود. در این صورت اگر کامپایلر ارور نگیرد، حافظۀ میکروکنترلر به نسبت تعداد دفعات کامپایل شدن کتابخانۀ مورد نظر، اشغال می شود. در عبارتی که دیفاین کرده ایم می بینیم که در  آن از آندرلاین (_) استفاده کرده ایم. این نوع نوشتار واجب نیست. ولی چون در بین برنامه نویسان عرف شده است ما نیز استفاده می کنیم. در دو طرف عبارت دیفاین شده از دو آندرلاین و برای جدا کردن کلمات نیز از یک آندرلاین استفاده می کنیم. مثل دیفاین و ifndef زیر.

#ifndef __graphic_lcd_h__
#define __graphic_lcd_h__

...

#endif

 

کتابخانه را چگونه از پوشه ای دیگر فراخوانی کنیم؟

در برنامه ای که نوشتیم، فایل کتابخانه در پوشۀ پروژه یعنی پوشه ای که فایل prj قرار داشت، ذخیره کردیم. در این صورت برای فراخوانی آن تنها کافی است بنویسیم:

#include "keypad.h"

 

اگر فایل کتابخانه را در پوشه ای در کامپیوتر ذخیره کرده باشیم، باید آدرس آن را در هنگام فراخوانی بیاوریم. برای مثال در کد زیر فایل کتابخانه در پوشۀ lib در دسکتاپ قرار دارد.

#include "C:\Users\Administrator\Desktop\lib\keypad.h"

 

اگر فایل کتابخانه را در پوشه ای دیگر در پوشۀ پروژه ذخیره کرده باشیم، به صورت زیر کتابخانه را فراخوانی می کنیم:

#include "lib\keypad.h"

 

در تصویر زیر می بینیم که پوشۀ lib در کنار فایل prj در پوشۀ پروژه قرار دارد.

فایل-کتابخانه-در-پوشه-ای-غیر-پوشه-پروژه

تصویر 3 – فایل کتابخانه در محلی به غیر از پوشۀ پروژه

ساخت کتابخانه در keil

ساخت کتابخانه در keil و اتمل استودیو و … شبیه به کدویژن است. در نرم افزار keil می توانیم فایل با پسوند h را بدون #include نیز به برنامه اضافه کنیم. همچنین برای اضافه کردن فایل با پسوند c می توانیم از پنجرۀ Manage Project Items اقدام کنیم. در برنامۀ زیر می بینیم که برای ساخت تابع delay در زبان c در keil دو تابع استفاده شده است. فرض می کنیم میخواهیم توابع delay را به یک کتابخانه انتقال دهیم.

#include "lpc17xx.h"
#include <stdio.h>
#include "CLCD.h"

void delay_us(unsigned int count); 
void delay_ms(unsigned int count); 

int main (void){
	
	unsigned int ADC_RESULT=0;
	char str[32];
	
	  LPC_PINCON->PINSEL1|=(1<<14);
	  LPC_PINCON->PINMODE1|=(1<<15);
	
    LPC_SC->PCLKSEL0|=(1<<24)|(1<<25);       
  	LPC_SC->PCONP|=(1<<12);
	  LPC_ADC->ADCR|=(1<<21)|(1<<10)|(1<<0);
	  
	lcd_init(16,2);
	lcd_clear();
	lcd_puts("ADC0 On P0.23");
	delay_ms(2000);
	while(1)
	{
	    LPC_ADC->ADCR|=(1<<24);
		  while(((LPC_ADC->ADGDR)&(1<<31))==0) {};
		
      ADC_RESULT=LPC_ADC->ADGDR;
		
      ADC_RESULT=ADC_RESULT<<16;
      ADC_RESULT=ADC_RESULT>>20;
     		
		lcd_clear();	
    sprintf(str,"%d",ADC_RESULT);	
		lcd_puts(str);
		delay_ms(50);				
	}
}

//***************************************************
//******************new function*********************
void delay_us(unsigned int count) 
	{
			unsigned int j=0,i=0;
			for(j=0;j<count;j++) for(i=0;i<23;i++);
	}
	
//***************************************************
//******************new function*********************
void delay_ms(unsigned int count) 
	{
			unsigned int i;
			for (i=0;i<count;i++) delay_us(1000);
	}

 

در این صورت در منوی File روی New کلیک می کنیم. در فایلی که باز می شود، توابع مربوط به delay را انتقال می دهیم. بنابر این فایل main به صورت زیر می شود.

#include "lpc17xx.h"
#include <stdio.h>
#include "CLCD.h"

int main (void){
	
	unsigned int ADC_RESULT=0;
	char str[32];
	
	LPC_PINCON->PINSEL1|=(1<<14);
	LPC_PINCON->PINMODE1|=(1<<15);
	
	LPC_SC->PCLKSEL0|=(1<<24)|(1<<25);
	LPC_SC->PCONP|=(1<<12);
	LPC_ADC->ADCR|=(1<<21)|(1<<10)|(1<<0);
	
	lcd_init(16,2);
	lcd_clear();
	lcd_puts("ADC0 On P0.23");
	delay_ms(2000);
	while(1)
	{
		LPC_ADC->ADCR|=(1<<24);
		while(((LPC_ADC->ADGDR)&(1<<31))==0) {};
		
		ADC_RESULT=LPC_ADC->ADGDR;
		
		ADC_RESULT=ADC_RESULT<<16;
		ADC_RESULT=ADC_RESULT>>20;
		
		lcd_clear();
		sprintf(str,"%d",ADC_RESULT);
		lcd_puts(str);
		delay_ms(50);
	}
}

 

فایل کتابخانه را با پسوند h ذخیره می کنیم. نام کتابخانه را نیز delay انتخاب می کنیم. متن این کتابخانه به صورت زیر می شود.

#ifndef __delay_h__
#define __delay_h__

void delay_us(unsigned int count); 
void delay_ms(unsigned int count); 


//***************************************************
//******************new function*********************
void delay_us(unsigned int count) 
	{
			unsigned int j=0,i=0;
			for(j=0;j<count;j++) for(i=0;i<23;i++);
	}
	
//***************************************************
//******************new function*********************
void delay_ms(unsigned int count) 
	{
			unsigned int i;
			for (i=0;i<count;i++) delay_us(1000);
	}
	
#endif

 

همان طور که می بینید از دستورهای پیش پردازنده نیز استفاده کرده ایم. حال برای اضافه کردن کتابخانۀ delay.h به برنامه می توانیم بنویسیم:

#include "delay.h"

 

مطالبی که برای فراخوانی کتابخانه در کدویژن گفته شد (دربارۀ محل ذخیره شدن کتابخانه) در اینجا نیز صادق است. اکنون فرض کنیم کتابخانۀ delay.h را در پوشۀ Libs در کنار فایل پروژه (یا در پوشه ای در محلی دیگر) قرار داده ایم. اگر ما در پنجرۀ Options For Target در سربرگ C/C++ و در قسمت Include Path روی Browse (یعنی سه نقطه …) کلیک کنیم، می توانیم در پنجرۀ Folder Setup پوشۀ Libs را به برنامه اضافه کنیم. در این صورت دیگر نیازی به نوشتن آدرس هنگام #include کردن کتابخانۀ delay.h نیست. یعنی می توانیم بنویسیم:

#include "delay.h"

 

به تصاویر زیر توجه کنید.

باز-کردن-پنجره-options-for-target

تصویر 4 – باز کردن پنجرۀ Options For Target برای اضافه کردن مسیر پوشۀ کتابخانه در keil

باز-کردن-پنجره-folder-setup-برای-افزودن-کتابخانه-در-keil

تصویر 5 – اضافه کردن مسیر پوشۀ کتابخانه در keil

اضافه-کردن-پوشه-کتابخانه-keil

تصویر 6 – اضافه کردن پوشۀ کتابخانه در keil

اضافه-کردن-پوشه-کتابخانه-keil

تصویر 7 – انتخاب پوشۀ حاوی فایل کتابخانه در keil

اگر فایل کتابخانه را با پسوند c ذخیره کنیم نیز می توانیم مانند h آن را فراخوانی کنیم. اگر این فایل در محلی به غیر از پوشۀ پروژه ذخیره شده باشد می توانیم با آوردن آدرس محل ذخیره در هنگام #include کردن، آن را به برنامه اضافه کنیم. مانند آنچه برای کدویژن گفته شد.

همچنین می توانیم از #include استفاده نکنیم. ولی با این حال کتابخانه با پسوند c به برنامه اضافه شود. یعنی ننویسیم:

#include "delay.c"

 

برای این کار باید فایل با پسوند c را از طریق پنجرۀ Manage Project Items به برنامه اضافه کنیم. به تصاویر زیر توجه کنید.

باز-کردن-پنجره-manage-project-items

تصویر 8 – باز کردن پنجرۀ Manage Project Items

در پنجرۀ Manage Project Items اول روی آیکون New یعنی شمارۀ 1 در تصویر زیر کلیک می کنیم. سپس روی پوشۀ جدید کلی می کنیم (شمارۀ 2 در تصویر زیر). بعد از آن روی دکمۀ Add Files کلیک می کنیم (شمارۀ 3). در آخر هم در پنجرۀ باز شده فایل مورد نظر را جست و جو می کنیم و آن را به برنامه اضافه می کنیم. در نهایت در پنجرۀ Manage Project Items روی Ok کلیک می کنیم.

اضافه-کردن-کتابخانه-پسوند-c-به-keil

تصویر 9 – اضافه کردن فایل با پسوند c به نرم افزار keil

 

از بررسی روش ساخت کتابخانه در keil و کدویژن نتیجه می گیریم:

  1. یکی از ابزارهای خوانا کردن برنامه در زبان های برنامه نویسی کتابخانه است. با استفاده از کتابخانه می توانیم توابع، متغیرها و دیفاین های مربوط به یک وظیفه یا یک المان یا ماژول خاص را در یک دسته بندی قرار دهیم.
  2. می توانیم کتابخانه را با پسوند h، c و یا هر دو ذخیره کنیم.
  3. ذخیره کردن فایل کتابخانه با پسوند c یا h از لحاظ شناخته شدن توسط نرم افزار تفاوتی ندارد.
  4. برای اضافه کردن کتابخانه ای که در محل فایل پروژه نیست، در نرم افزار کدویژن و اتمل استودیو باید مسیر را هنگام #include کردن بیاوریم.
  5. در نرم افزار keil علاوه بر این که می توانیم مسیر ذخیرۀ فایل کتابخانه را در هنگام #include کردن بیاوریم، می توانیم از طریق پنجرۀ Options For Target، مسیر محل کتابخانه را به نرم افزار بدهیم. در این صورت دیگر نیازی به آوردن آدرس در #include نیست.
  6. اگر کتابخانه را با پسوند c ذخیره کرده باشیم، در keil می توان بدون #include کردن آن را به برنامه اضافه کرد. در این صورت باید از پنجرۀ Manage Project Items برای اضافه کردن فایل با پسوند c به برنامه اقدام کنیم.
  7. استفاده از دستورهای پیش پردازندۀ #ifndef و #define در ابتدای هر کتابخانه الزامی است.

 

رضا اسدی

رضا اسدی

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

آموزش زبان C و MISRA یوبرد

آموزش زبان C++ و MISRA یوبرد

خدمات برنامه نویسی میکروکنترلر یوبرد

انواع-متغیر-زبان-c-cpp

انواع متغیر در زبان برنامه نویسی C

انواع متغیرها در زبان C، تعریف انواع متغیر در زبان C، انواع متغیر در نرم افزار کدویژن و نرم افزار Keil، آرایه و رشته در زبان برنامه نویسی C، انواع متغیر استراکچر (Structure) و یونیون (union)، typedef در زبان C، متغیر نوع volatile، متغیرهای عمومی (Global)، متغیرهای محلی (Local)

ساخت-کتابخانه-c-cpp

نحوۀ ساخت کتابخانه در زبان برنامه نویسی C برای میکروکنترلرها

کتابخانه در زبان برنامه نویسی چیست؟ ساخت کتابخانه در نرم افزار CodevisionAVR، کتابخانه با پسوند h، کتابخانه با پسوند c، کتابخانه با پسوند h و c، فراخوانی کتابخانه، کاربرد دستور پیش پردازندۀ #ifndef در نوشتن کتابخانه، فراخوانی کتابخانه از پوشه های مختلف، ساخت کتابخانه در نرم افزار Keil

کلاس-حافظه-زبان-c-cpp

کلاس حافظه در C و C++

کلاس حافظه چیست؟ تعریف کلاس حافظه، کلاس حافظه در C و C++، حوزۀ تعریف متغیرها، طول عمر متغیرها، متغیرهای عمومی و محلی، کلاس حافظۀ اتوماتیک (Automatic)، کلاس حافظۀ رجیستر (Register)، کلاس حافظۀ Static محلی و عمومی، کلاس حافظۀ خارجی (External)، کلاس حافظۀ Mutable، کلمۀ کلیدی volatile

مقایسۀ برابری انواع float

در برنامه نویسی، عبارات floating-point نباید از نظر برابری یا نابرابری آزمایش شوند. ماهیت ذاتی انواع float به گونه‌ای است که مقایسۀ برابری آنها اغلب درست نخواهد بود. رفتار چنین مقایسه‌ای را نمی‌توان قبل از اجرا پیش‌بینی کرد و ممکن است از یک اجرا به اجرای دیگر متفاوت باشد. مثلاً نتیجۀ آزمایش if(x == y) وقتی که x و y از نوع float باشند، غیر قابل پیش‌بینی است.

استاندارد MISRA C، قانون 13.3

تاخیر میکروثانیه ای

تأخیرهایی در حد میکروثانیه و به صورت Non-blocking (یعنی تأخیری که کل سیستم را منتظر نگذارد) معمولاً توسط OSها یا پلتفرم‌ها ایجاد نمی‌شوند. زیرا برای این کار باید وقفۀ یک تایمر، حداقل هر یک میکروثانیه اتفاق بیفتد. وقفه‌ای با این سرعت و به صورت پیوسته، باعث افزایش بار پردازشی UPC می‌شود و در بسیاری از پروژه‌ها، معایب این موضوع بیشتر از مزایای آن است. نکات ارائه شده در ویدئوی پیوست کتابخانۀ Delay

توابع و داده های static

در تعریف و اعلان توابع و داده‌هایی که لینک داخلی دارند، یعنی تنها در یک فایل استفاده می‌شوند، باید از مشخص کنندۀ کلاس حافظۀ static استفاده شود. دلیل این موضوع این است که ممکن است دربارۀ این که متغیر یا تابعی، extern یا static است، ابهام به وجود بیاید. استفاده از کلمۀ static این ابهام را برطرف می‌کند.

استاندارد MISRA C، قانون 8.11

آرایه با کلاس حافظۀ خارجی

در زمانی که یک آرایه با کلاس حافظۀ extern اعلان می‌شود، تعداد اعضای آن باید به صورت صریح (قرار دادن عدد در براکت) یا به صورت ضمنی (مقداردهی اولیۀ اعضای آن) مشخص شود. اگرچه می‌توان آرایه‌ها را با کلاس ذخیره سازی extern، بدون مشخص کردن اندازۀ آنها اعلان کرد، اما در زمانی که امکان تعیین اندازۀ آرایه‌ها وجود دارد، انجام این کار ایمن‌تر است.
استاندارد MISRA C، قانون 8.12

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

در هیچ جای برنامه نباید کد مرده وجود داشته باشد. هر کدی که حذف آن، تأثیری بر خروجی برنامه نگذارد، کد مرده است. برای مرور کنندۀ کد مشخص نیست که وجود این کد عمدی است یا به دلیل خطای برنامه نویس رخ داده است. از نمونه‌های کد مرده، کدهای درون ifی است که شرط آن هیچ‌گاه True نمی‌شود. در این صورت کدهای درون if هیچ‌گاه اجرا نمی‌شوند.

استاندارد MISRA C++، قانون 0-1-9

عملگرهای رابطه‌ای برای اشاره‌گرها

عملگرهای <، =<، > و => نباید برای اشاره‌گرها اعمال شوند، مگر در مواردی که اشاره‌گرها به یک آرایۀ یکسان اشاره می‌کنند. اگر دو اشاره‌گر به شیء یکسانی اشاره نکنند، تلاش برای مقایسه بین آنها، رفتار نامشخص ایجاد می‌کند.
استاندارد MISRA C++، قانون 5-0-18

مقداردهی متغیر قبل از خواندن

همۀ متغیرها قبل از استفاده باید مقدار مشخصی داشته باشند. بنابراین قبل از خوانده شدن، باید در آنها نوشت و لزوماً نیاز به مقداردهی اولیه در زمان اعلان نیست. متغیر با مدت زمان ذخیرۀ استاتیک، اگر مقداردهی اولیه نشود، به طور خودکار صفر می‌شود. در عمل، بسیاری از محیط‌های امبدد این کار را نمی‌کنند. متغیر با مدت زمان ذخیرۀ اتوماتیک هم معمولاً به طور خودکار مقداردهی اولیه نمی‌شود. سازنده‌های کلاس هم باید همۀ اعضای غیر ثابت کلاس را مقداردهی اولیه کنند.
استاندارد MISRA C++، قانون 1-5-8

13 دیدگاه ها

  1. سلام. من طبق مطالب شما کتابخانه نوشتم توی نرم افزار Atmel Studio و هیچ مشکلی از بابت فراخوانی و آدرس کتابخانه ها نبود. اما توی نرم افزار KEIL این کار رو انجام دادم ارور میده و مسیرها رو پیدا نمی کنه. علی رقم اینکه مسیر رو به نرم افزار میدم. وقتی چند کتابخونه رو توی هم فراخونی میکنم این اتفاق پیش میاد. این اتفاق که عرض کردم توی Atmel Studio پیش نمیاد. لطف میکنید اگر راهنمایی کنید.

    پاسخ
    • سلام. فراخوانی کتابخانه در نرم افزار Atmel Studio به همون روش هاییه که توضیح داده شد. صرفاً با include کردن کتابخونه فراخونی میشه. حالا آدرس فایل توی include اگر لازم باشه میاد. اما فراخوانی کتابخانه در نرم افزار Keil باید هم آدرس فایل h. به نرم افزار داده بشه و هم فایل c. به نرم افزار اضافه بشه. و وقتی کتابخانه رو به صورت تو در تو فراخوانی کنیم، این طور مشکلات ممکنه به وجود بیاد. چنین مواردی رو توی آدرس دادن باید دقت کنید و مسیرها رو عوض نکنید. اگه مسیری رو عوض کردید باید تو Keil مسیر جدید رو جایگزین کنید.

      پاسخ
  2. بسیار عالی و کار راه انداز

    پاسخ
    • خواهش میکنم. ان شاء الله که مفید بوده باشه

      پاسخ
  3. سلام. میشه توضیح بدید متغیر key_pad_status رو توی تابع keypad() به چه منظوری تعریف و استفاده کردید؟ ممنون

    پاسخ
    • سلام. این متغیر برای این تعریف شده که اگه یکی از کلیدهای کی پد برای مدتی نگه داشته شد، تابع keypad decode 1 فقط یک بار اجرا بشه. در غیر این صورت اگه چند لحظه دست روی یکی از کلیدها قرار بگیره، عملکردی که با اون کلید توی تابع kepad decode 1 انجام میشه، تا موقع نگه داشتن دست روی کلید، دائم تکرار میشه.

      پاسخ
  4. سلام ببخشید میشه درباره مفهوم کتابخانه در زبان C توضیح بدید

    پاسخ
    • سلام. خواهش میکنم. به زبان ساده میشه گفت کتابخانه یه فایله که به پروژه اضافه میشه و میتونیم از توابع و دیفاین ها و متغیرهای اون استفاده کنیم. این فایل شامل دیفاین ها و متغیرها و استراکچرها و توابع و … است که در مجموع با هم عملکردهای (معمولاً) مرتبط با هم رو پیاده میکنن. برای مثال کتابخونۀ string.h شامل توابعی برای کار با رشته هاست. برای استفاده از توابع این کتابخونه، اول اون رو به پروژه اضافه میکنیم. بعدش توابعش رو در جاهایی که نیاز داریم فراخونی میکنیم.

      پاسخ
  5. با سلام
    آیا سایت مرجعی را می شناسید که کتابخانه های ماژول های مختلف را برای AVR بتوانیم در آن پیدا کنیم؟

    پاسخ
    • سایت های مختلفی هست. اما این که تا چه حد جامعیت داشته باشن و تا چه حد کتابخونه برای ماژول های مختلف موجود باشه، به هر حال ناقص هستن. میتونید سایت گیت هاب، سایت nongnu.org و سایت های دیگه رو ببینید. البته بهتره کتابخونه های ماژول های مختلف رو توی گوگل سرچ کنید و از سایت های مختلف بهترینش رو دانلود و استفاده کنید. 

      پاسخ
  6. با سلام…بنده آشنایی نسبی با برنامه ی c دارم و یک برنامه آماده را می خواهم ران کنم چند کتابخانه مثل Rmath.h و …را فراخوانی کرده که متاسفانه این فایل ها داخل پوشه نیستن کلا و موقع ران ارور می دهد…به نظر شما این توابع و کتابخانه های آماده رو باید از جایی دانلود کنم؟ ممنون می شوم راهنمایی کنید.

    پاسخ
    • سلام. کلاً کتابخونه ها رو از یه دیدگاه میشه به دو دسته تقسیم کرد. کتابخونه هایی که با نصب نرم افزار توی محل نصب نرم افزار قرار می گیرن و کتابخونه هایی که خودمون دانلود می کنیم و به پروژه اضافه می کنیم. اگه این کتابخونه ای که می فرمایید از اون دسته از کتابخونه اییه که با نصب نرم افزار دانلود و نصب میشن، احتمالاً موقع نصب مشکلی به وجود اومده یا نیاز بوده به اینترنت متصل بشید. اگه از اون دستۀ دیگه ست خب سایت های مختلفی هست. سایت گیت هاب نمونه شه. github.com.

      اگه سرچ کردید چیزی پیدا نکردید، اسم توابع کتابخونه رو سرچ کنید شاید کتابخونه ای با نام متفاوت به جای این کتابخونه ها پیدا کردید. 

      اگه برنامه رو از کسی گرفتید، احتمالاً کتابخونه هاش هم داره. میتونید ازش بگیرید.

      خواهش میکنم. موفق باشید.

      پاسخ
  7. سلام. ساختن کتابخانه فقط با فرمت .h چه فرقی با ساختن کتابخانه با دو فرمت .h و .c داره؟ چرا کتابخانه های استاندارد معمولا از h و c استفاده میکنن به جای اینکه فقط از h استفاده کنن؟

    پاسخ

یک دیدگاه بنویسید

نشانی ایمیل شما منتشر نخواهد شد.

ضبط پیام صوتی

زمان هر پیام صوتی 4 دقیقه است