一些經(jīng)典技術(shù)_第1頁
一些經(jīng)典技術(shù)_第2頁
一些經(jīng)典技術(shù)_第3頁
一些經(jīng)典技術(shù)_第4頁
一些經(jīng)典技術(shù)_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、.芆膇蒆袆膂膆薈肂肈膅蝕襖羄膄螃蚇節(jié)芃蒂袃膈節(jié)薅蚅肄節(jié)螇袁肀芁蕆螄羆芀蕿罿芅艿蟻螂膁羋螃羈肇芇蒃螀羃莆薅羆衿莆蚈蝿膇蒞莇羄膃莄薀袇聿莃螞肂羅莂螄裊芄莁蒄蚈膀莀薆袃肆蒀蠆蚆羂葿莈袂袈蒈蒁蚅芆蕆蚃羀膂蒆螅螃肈蒅蒅羈羄蒅薇螁芃薄蠆羇腿薃螂蝿肅薂蒁羅羈膈蚄螈羇膈螆肅芆膇蒆袆膂膆薈肂肈膅蝕襖羄膄螃蚇節(jié)芃蒂袃膈節(jié)薅蚅肄節(jié)螇袁肀芁蕆螄羆芀蕿罿芅艿蟻螂膁羋螃羈肇芇蒃螀羃莆薅羆衿莆蚈蝿膇蒞莇羄膃莄薀袇聿莃螞肂羅莂螄裊芄莁蒄蚈膀莀薆袃肆蒀蠆蚆羂葿莈袂袈蒈蒁蚅芆蕆蚃羀膂蒆螅螃肈蒅蒅羈羄蒅薇螁芃薄蠆羇腿薃螂蝿肅薂蒁羅羈膈蚄螈羇膈螆肅芆膇蒆袆膂膆薈肂肈膅蝕襖羄膄螃蚇節(jié)芃蒂袃膈節(jié)薅蚅肄節(jié)螇袁肀芁蕆螄羆芀蕿罿芅艿蟻螂膁羋螃

2、羈肇芇蒃螀羃莆薅羆衿莆蚈蝿膇蒞莇羄膃莄薀袇聿莃螞肂羅莂螄裊芄莁蒄蚈膀莀薆袃肆蒀蠆蚆羂葿莈袂袈蒈蒁蚅芆蕆蚃羀膂蒆螅螃肈蒅蒅羈羄蒅薇螁芃薄蠆羇腿薃螂蝿肅薂蒁羅羈膈蚄螈羇膈螆肅芆膇蒆袆膂膆薈肂肈膅蝕襖羄膄螃蚇節(jié)芃蒂袃膈節(jié)薅蚅肄節(jié)螇袁肀芁蕆螄羆芀蕿 一些經(jīng)典技術(shù)轉(zhuǎn)自1 . 用預(yù)處理指令#define 聲明一個常數(shù),用以表明1年中有多少秒(忽略閏年問題)  #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL  2 . 寫一個“標準”宏MIN ,這個宏輸入兩個參數(shù)并返回較小的一個。  #define M

3、IN(A,B) (A) <= (B) ? (A) : (B)   3. 預(yù)處理器標識#error的目的是什么?  如果你不知道答案,請看參考文獻1。這問題對區(qū)分一個正常的伙計和一個書呆子是很有用的。只有書呆子才會讀C語言課本的附錄去找出象這種問題的答案。當然如果你不是在找一個書呆子,那么應(yīng)試者最好希望自己不要知道答案。  死循環(huán)(Infinite loops)  4. 嵌入式系統(tǒng)中經(jīng)常要用到無限循環(huán),你怎么樣用C編寫死循環(huán)呢?  while(1)   

4、0;?  5. 用變量a給出下面的定義  a) 一個整型數(shù)(An integer)   int a;  b)一個指向整型數(shù)的指針( A pointer to an integer)  int *a;  c)一個指向指針的的指針,它指向的指針是指向一個整型數(shù)( A pointer to a pointer to an integer) int *a; d)一個有10個整型數(shù)的數(shù)組( An array of 10 integers)  int a10;

5、0; e) 一個有10個指針的數(shù)組,該指針是指向一個整型數(shù)的。(An array of 10 pointers to integers) int *a10;  f) 一個指向有10個整型數(shù)數(shù)組的指針( A pointer to an array of 10 integers)  int (*a)10; g) 一個指向函數(shù)的指針,該函數(shù)有一個整型參數(shù)并返回一個整型數(shù)(A pointer to a function that takes an integer as an argument and returns an integer) int (*

6、a)(int)  h)一個有10個指針的數(shù)組,該指針指向一個函數(shù),該函數(shù)有一個整型參數(shù)并返回一個整型數(shù)( An array of ten pointers to functions that take an integer argument and return an integer ) int (*a10)(int); 6. 關(guān)鍵字static的作用是什么?  在C語言中,關(guān)鍵字static有三個明顯的作用:  在函數(shù)體,一個被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過程中維持其值不變。  在模塊內(nèi)(但在函數(shù)體外),一個

7、被聲明為靜態(tài)的變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問。它是一個本地的全局變量。  在模塊內(nèi),一個被聲明為靜態(tài)的函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用。那就是,這個函數(shù)被限制在聲明它的模塊的本地范圍內(nèi)使用。  大多數(shù)應(yīng)試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第三部分。這是一個應(yīng)試者的嚴重的缺點,因為他顯然不懂得本地化數(shù)據(jù)和代碼范圍的好處和重要性。  7關(guān)鍵字const有什么含意?  去年Dan Saks已經(jīng)在他的文章里完全概括了const的所有用法,因此ESP(譯者:Embe

8、dded Systems Programming)的每一位讀者應(yīng)該非常熟悉const能做什么和不能做什么.如果你從沒有讀到那篇文章,只要能說出const意味著“只讀”就可 以了。盡管這個答案不是完全的答案,但我接受它作為一個正確的答案。 下面的聲明都是什么意思?  const int a; a是一個常整型數(shù)。 int const a; a是一個常整型數(shù)。 const int *a;  a是一個指向常整型數(shù)的指針(也就是,整型數(shù)是不可修改的,但指針可以) int * const a; a是一個指向整型數(shù)的常指針(也就是說,指針指向的整型數(shù)是可以修改的,但指

9、針是不可修改的) int const * a const; a是一個指向常整型數(shù)的常指針(也就是說,指針指向的整型數(shù)是不可修改的,同時指針也是不可修改的) 關(guān)鍵字const的作用是為給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數(shù)為常量是為了告訴了用戶這個參數(shù)的應(yīng)用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學(xué)會感謝這點多余的信息。 通過給優(yōu)化器一些附加的信息,使用關(guān)鍵字const也許能產(chǎn)生更緊湊的代碼。  合理地使用關(guān)鍵字const可以使編譯器很自然地保護那些不希望被改變的參數(shù),防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現(xiàn)。 &#

10、160;8. 關(guān)鍵字volatile有什么含意?并給出三個不同的例子。  一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個變量的值了。精確地說就是,優(yōu)化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個例子:  1并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)  2一個中斷服務(wù)子程序中會訪問到的非自動變量(Non-automatic variables)  3多線程應(yīng)用中被幾個任務(wù)共享的變量  &#

11、160;?; 一個參數(shù)既可以是const還可以是volatile嗎?解釋為什么。  ?; 一個指針可以是volatile 嗎?解釋為什么。  ?; 下面的函數(shù)有什么錯誤:  int square(volatile int *ptr)    return *ptr * *ptr;    下面是答案:  ?; 是的。一個例子是只讀的狀態(tài)寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應(yīng)該試圖去修改它。

12、0; ?; 是的。盡管這并不很常見。一個例子是當一個中服務(wù)子程序修該一個指向一個buffer的指針時。  ?; 這段代碼有點變態(tài)。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由于*ptr指向一個volatile型參數(shù),編譯器將產(chǎn)生類似下面的代碼:  int square(volatile int *ptr)     int a,b;  a = *ptr;  b = *ptr;  return a * b;  

13、0; 由于*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結(jié)果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:  long square(volatile int *ptr)     int a;  a = *ptr;  return a * a;    位操作(Bit manipulation)   9. 嵌入式系統(tǒng)總是要用戶對變量或寄存器進行位操作。給定一個整型變量a,寫兩段代碼,第一個設(shè)置a的bit 3,

14、第二個清除a 的bit 3。在以上兩個操作中,要保持其它位不變。  #define BIT3 (0x1 << 3)  static int a;  void set_bit3(void)   a |= BIT3;    void clear_bit3(void)   a &= BIT3;    訪問固定的內(nèi)存位置(Accessing fixed memory locations)  &#

15、160;10. 嵌入式系統(tǒng)經(jīng)常具有要求程序員去訪問某特定的內(nèi)存位置的特點。在某工程中,要求設(shè)置一絕對地址為0x67a9的整型變量的值為0xaa66。編譯器是一個純粹的ANSI編譯器。寫代碼去完成這一任務(wù)。  這一問題測試你是否知道為了訪問一絕對地址把一個整型數(shù)強制轉(zhuǎn)換(typecast)為一指針是合法的。這一問題的實現(xiàn)方式隨著個人風格不同而不同。典型的類似代碼如下:  int *ptr;  ptr = (int *)0x67a9;  *ptr = 0xaa55;  A more obscure

16、approach is:   一個較晦澀的方法是:  *(int * const)(0x67a9) = 0xaa55;  即使你的品味更接近第二種方案,但我建議你在面試時使用第一種方案。  中斷(Interrupts)   11. 中斷是嵌入式系統(tǒng)中重要的組成部分,這導(dǎo)致了很多編譯開發(fā)商提供一種擴展讓標準C支持中斷。具代表事實是,產(chǎn)生了一個新的關(guān)鍵字 _interrupt。下面的代碼就使用了_interrupt關(guān)鍵字去定義了一個中斷服務(wù)子程序(ISR),請評論一下這段代碼的。 

17、0;_interrupt double compute_area (double radius)     double area = PI * radius * radius;  printf("nArea = %f", area);  return area;    ?; ISR 不能返回一個值。如果你不懂這個,那么你不會被雇用的。  ?; ISR 不能傳遞參數(shù)。如果你沒有看到這一點,你被雇用的機會等同第一項。  

18、?; 在許多的處理器/編譯器中,浮點一般都是不可重入的。有些處理器/編譯器需要讓額處的寄存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點運算。此外,ISR應(yīng)該是短而有效率的,在ISR中做浮點運算是不明智的。  ?; 與第三點一脈相承,printf()經(jīng)常有重入和性能上的問題。如果你丟掉了第三和第四點,我不會太為難你的。不用說,如果你能得到后兩點,那么你的被雇用前景越來越光明了。  代碼例子(Code examples)  12 . 下面的代碼輸出是什么,為什么?  void foo(void) &#

19、160;  unsigned int a = 6;  int b = -20;  (a+b > 6) ? puts("> 6") : puts("<= 6");    這個問題測試你是否懂得C語言中的整數(shù)自動轉(zhuǎn)換原則,我發(fā)現(xiàn)有些開發(fā)者懂得極少這些東西。不管如何,這無符號整型問題的答案是輸出是 ”>6”。原因是當表達式中存在有符號類型和無符號類型時所有的操作數(shù)都自動轉(zhuǎn)換為無符號類型。 因此-20變成了一個非常大的正整數(shù),所以該表達式計

20、算出的結(jié)果大于6。這一點對于應(yīng)當頻繁用到無符號數(shù)據(jù) 類型的嵌入式系統(tǒng)來說是豐常重要的。如果你答錯了這個問題,你也就到了得不到這份工作的邊緣。  13. 評價下面的代碼片斷:  unsigned int zero = 0;  unsigned int compzero = 0xFFFF;   /*1's complement of zero */  對于一個int型不是16位的處理器為說,上面的代碼是不正確的。應(yīng)編寫如下:  unsigned int compzero

21、= 0;  動態(tài)內(nèi)存分配(Dynamic memory allocation)   14. 盡管不像非嵌入式計算機那么常見,嵌入式系統(tǒng)還是有從堆(heap)中動態(tài)分配內(nèi)存的過程的。那么嵌入式系統(tǒng)中,動態(tài)分配內(nèi)存可能發(fā)生的問題是什么?  這里,我期望應(yīng)試者能提到內(nèi)存碎片,碎片收集的問題,變量的持行時間等等。這個主題已經(jīng)在ESP雜志中被廣泛地討論過了(主要是 P.J. Plauger, 他的解釋遠遠超過我這里能提到的任何解釋),所有回過頭看一下這些雜志吧!讓應(yīng)試者進入一種虛假的安全感覺后,我拿出這么一個小節(jié)目:  下面

22、的代碼片段的輸出是什么,為什么?  char *ptr;  if (ptr = (char *)malloc(0) =   NULL)   else  puts("Got a null pointer");  puts("Got a valid pointer");  該代碼的輸出是“Got a valid pointer”。 Typedef   15 Typedef 在C語言中頻繁用以聲明一個已

23、經(jīng)存在的數(shù)據(jù)類型的同義字。也可以用預(yù)處理器做類似的事。例如,思考一下下面的例子:  #define dPS struct s *  typedef struct s * tPS;  以上兩種情況的意圖都是要定義dPS 和 tPS 作為一個指向結(jié)構(gòu)s指針。哪種方法更好呢?(如果有的話)為什么?  這是一個非常微妙的問題,任何人答對這個問題(正當?shù)脑颍┦菓?yīng)當被恭喜的。答案是:typedef更好。思考下面的例子:  dPS p1,p2;  tPS p3,p4; 

24、0;第一個擴展為  struct s * p1, p2;  上面的代碼定義p1為一個指向結(jié)構(gòu)的指,p2為一個實際的結(jié)構(gòu),這也許不是你想要的。第二個例子正確地定義了p3 和p4 兩個指針。  晦澀的語法  16 . C語言同意一些令人震驚的結(jié)構(gòu),下面的結(jié)構(gòu)是合法的嗎,如果是它做些什么?  int a = 5, b = 7, c;  c = a+b;  這個問題將做為這個測驗的一個愉快的結(jié)尾。不管你相不相信,上面的例子是完全合乎語法的。問題是編譯器如何處理它?

25、水平不高的編譯作者實際上會爭論這個問題,根據(jù)最處理原則,編譯器應(yīng)當能處理盡可能所有合法的用法。因此,上面的代碼被處理成:  c = a+ + b;  因此, 這段代碼持行后a = 6, b = 7, c = 12。很基礎(chǔ)的, 最開始學(xué)習(xí)的, 這個main程序能使得端口B上的0xC3 的燈產(chǎn)生0.5s的亮滅。 用TIME0產(chǎn)生0.5s的中斷。 首先預(yù)分頻1024    14.7456M/1024=14.444KHz  一個脈沖的周期為1/14.4444k=69.44us 既是每隔69.44us 計數(shù)器加1計數(shù)。 定時

26、器0為8位的,可以計數(shù)256個   則最大計數(shù)為256*69.44us=17.7777ms 我們要500ms  則要開發(fā)全局計數(shù)器 我們用10ms產(chǎn)生中斷,全局計數(shù)器要500/10=50次后觸發(fā)LED。 我們用10ms/69.44us=144(10ms的中斷), 256-144112為計數(shù)器的初值。 所以timecount=50 /ICC-AVR application builder : 2006-7-13 16:11:26 / Target : M128 / Crystal: 14.7456Mhz #include <iom128v.h>

27、 #include <macros.h> unsigned int timecount=0; void port_init(void) PORTA = 0x00; DDRA  = 0x00; PORTB = 0xFF; DDRB  = 0xFF; /B端口輸出,初值為FF PORTC = 0x00; /m103 output only DDRC  = 0x00; PORTD = 0x00; DDRD  = 0x00; PORTE = 0x00; DDRE  = 0x00; PORTF

28、 = 0x00; DDRF  = 0x00; PORTG = 0x00; DDRG  = 0x00; /TIMER0 initialize - prescale:1024 / WGM: Normal / desired value: 14.44444444KHz / actual value: -0.001KHz (1444544.4%) void timer0_init(void) TCCR0 = 0x00; /stop ASSR  = 0x00; /set async mode TCNT0 = 0x00; /set count O

29、CR0  = 0x00; TCCR0 = 0x07; /start timer 預(yù)分頻為1024 #pragma interrupt_handler timer0_ovf_isr:17 void timer0_ovf_isr(void) TCNT0 =112; /reload counter value置計數(shù)初值112 if (+timecount=50)/軟件計數(shù)器為50      PORTB=PORTB0xc3; /取反          timecount=0; /ca

30、ll this routine to initialize all peripherals void init_devices(void) /stop errant interrupts until set up CLI(); /disable all interrupts XDIV  = 0x00; /xtal divider XMCRA = 0x00; /external memory port_init(); timer0_init(); MCUCR = 0x00; EICRA = 0x00; /extended ext ints EICRB = 0x00; /ext

31、ended ext ints EIMSK = 0x00; TIMSK = 0x00; /timer interrupt sources ETIMSK = 0x00; /extended timer interrupt sources SEI(); /re-enable interrupts /all peripherals are now initialized void main(void)     port_init();   timer0_init();   init_devices();  

32、60;TIMSK=0x01;   #asm("sei")   while(1)        ;    利用定時器產(chǎn)生不同占空比的PWM波形輸出. /ICC-AVR application builder : 2006-7-14 16:54:48 / Target : M128 / Crystal: 14.7456Mhz #include <iom128v.h> #include <macros.h> /#define PWM_select 

33、 (PINC&3) void port_init(void) PORTA = 0xFF; DDRA  = 0x00; PORTB = 0xFF; DDRB  = 0xFF; PORTC = 0x03; /輸入,上拉電阻使能 DDRC  = 0xFf; PORTD = 0xFF; DDRD  = 0x00; PORTE = 0xFF; DDRE  = 0x00; PORTF = 0xFF; DDRF  = 0x00; PORTG = 0x1F; DDRG

34、60; = 0x00; /TIMER1 initialisation - prescale:8 / WGM: 0) Normal, TOP=0xFFFF / desired value: 1Hz / actual value: Out of range void timer1_init(void) TCCR1B = 0x00; /stop TCNT1H = 0x00 /*INVALID SETTING*/; /setup TCNT1L = 0x00 /*INVALID SETTING*/; OCR1AH = 0x00 /*INVALID SETTING*/; OCR1AL = 0x0

35、0 /*INVALID SETTING*/; OCR1BH = 0x00 /*INVALID SETTING*/; OCR1BL = 0x00 /*INVALID SETTING*/; OCR1CH = 0x00 /*INVALID SETTING*/; OCR1CL = 0x00 /*INVALID SETTING*/; ICR1H  = 0x00 /*INVALID SETTING*/; ICR1L  = 0x00 /*INVALID SETTING*/; TCCR1A = 0x91;/8位PWM, TCCR1B = 0x02; /預(yù)分頻8 /cal

36、l this routine to initialise all peripherals void init_devices(void) /stop errant interrupts until set up CLI(); /disable all interrupts XDIV  = 0x00; /xtal divider XMCRA = 0x00; /external memory port_init(); timer1_init(); MCUCR = 0x00; EICRA = 0x00; /extended ext ints EICRB = 0x00; /exte

37、nded ext ints EIMSK = 0x00; TIMSK = 0x00; /timer interrupt sources ETIMSK = 0x00; /extended timer interrupt sources SEI(); /re-enable interrupts /all peripherals are now initialised void main(void)     unsigned int oldtogs; /storage for past walue of input unsigned int PWM_select

38、=3;   port_init();   timer1_init();   init_devices();     while(1)    /   if (PWM_select !=oldtogs) /         /           oldtogs=PWM_select;     

39、;       switch (PWM_select)                          case 0:                     OCR1A=25;  /10%     

40、;                    break;              case 1:                     OCR1A=51;  /20%       

41、0;                 break;                                  case 2:              

42、       OCR1A=76;  /30%                         break;                  case 3:           

43、         OCR1A=102;  /40%                         break;                 /            

44、; 使能輸入捕捉功能, 測量計算輸入的脈沖寬度: /ICC-AVR application builder : 2006-7-14 10:13:46 / Target : M128 / Crystal: 14.7456Mhz #include <iom128v.h> #include <macros.h> /define PORT B as output for pulse width #define pulse_out PORTB /define ICP so we can read the pin #define ICP PIND4 unsigned char ov

45、_counter; unsigned int  rising_edge, falling_edge; unsigned long pulse_clocks; void port_init(void) PORTA = 0x00; DDRA  = 0x00; PORTB = 0xFF; DDRB  = 0xFF; PORTC = 0x00; /m103 output only DDRC  = 0x00; PORTE = 0x00; DDRE  = 0x00; PORTF = 0x00; DDRF&#

46、160; = 0x00; PORTG = 0x00; DDRG  = 0x00; /TIMER0 initialize - prescale:1024 / WGM: Normal / desired value: 14.44444444KHz / actual value: -0.001KHz (1444544.4%) void timer1_init(void) TCCR1B = 0xc4; /start timer 預(yù)分頻為64 #pragma interrupt_handler timer1_ovf_isr:15 void timer1_ovf_isr(vo

47、id)   ov_counter+; #pragma interrupt_handler timer1_capt_isr:13 void timer1_capt_isr(void) if (ICP)   rising_edge=ICR1;  /save start time for pulse   TCCR1B&=0xBF; /set to trigger on falling edge next   ov_counter=0; else   falling_edge

48、 =ICR1;   TCCR1B|=0x40;    pulse_clocks= (unsigned long) falling_edge - (unsigned long) rising_edge                 +(unsigned long) ov_counter*0x10000;   pulse_out=pulse_clocks/230;    /call this routine to initialise all peripherals void init_devices(void) /stop errant interrupts until set up CLI(); /disable all interrupts XDIV  = 0x00; /xtal divider XMCRA = 0x00; /

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論