1. gzyueqian
      13352868059
      首頁 > 新聞中心 > > 正文

      URAT(RS232)低層驅(qū)動(dòng)+中間層軟件示例

      更新時(shí)間: 2006-03-13 17:23:54來源: 粵嵌教育瀏覽量:2175

        一般教科書上提供的UART收發(fā)的程序往往是一段采用輪循(Polling)方式完成收發(fā)的簡單代碼。但對(duì)于高速的AVR來講,采用這種方式大大降低了MUC的效率。在使用AVR時(shí),應(yīng)根據(jù)芯片本身的特點(diǎn)(片內(nèi)大容量數(shù)據(jù)存儲(chǔ)器RAM,更適合采用語言編寫系統(tǒng)程序),編寫高效可靠的UART收發(fā)接口(低層)程序。下面是一個(gè)典型的USART的接口程序。

      #include <mega128.h>

      #define RXB8 1
      #define TXB8 0
      #define UPE 2
      #define OVR 3
      #define FE 4
      #define UDRE 5
      #define RXC 7

      #define FRAMING_ERROR (1<<FE)
      #define PARITY_ERROR (1<<UPE)
      #define DATA_OVERRUN (1<<OVR)
      #define DATA_REGISTER_EMPTY (1<<UDRE)
      #define RX_COMPLETE (1<<RXC)

      // USART0 Receiver buffer
      #define RX_BUFFER_SIZE0 8
      char rx_buffer0[RX_BUFFER_SIZE0];
      unsigned char rx_wr_index0,rx_rd_index0,rx_counter0;
      // This flag is set on USART0 Receiver buffer overflow
      bit rx_buffer_overflow0;

      // USART0 Receiver interrupt service routine
      #pragma savereg-
      interrupt [USART0_RXC] void uart0_rx_isr(void)
      {
      char status,data;
      #asm
      push r26
      push r27
      push r30
      push r31
      in r26,sreg
      push r26
      #endasm
      status=UCSR0A;
      data=UDR0;
      if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
      {
      rx_buffer0[rx_wr_index0]=data;
      if (++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
      if (++rx_counter0 == RX_BUFFER_SIZE0)
      {
      rx_counter0=0;
      rx_buffer_overflow0=1;
      };
      };
      #asm
      pop r26
      out sreg,r26
      pop r31
      pop r30
      pop r27
      pop r26
      #endasm
      }


      #pragma savereg+

      #ifndef _DEBUG_TERMINAL_IO_
      // Get a character from the USART0 Receiver buffer
      #define _ALTERNATE_GETCHAR_
      #pragma used+
      char getchar(void)
      {
      char data;
      while (rx_counter0==0);
      data=rx_buffer0[rx_rd_index0];
      if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
      #asm("cli")
      --rx_counter0;
      #asm("sei")
      return data;
      }
      #pragma used-
      #endif

      // USART0 Transmitter buffer
      #define TX_BUFFER_SIZE0 8
      char tx_buffer0[TX_BUFFER_SIZE0];
      unsigned char tx_wr_index0,tx_rd_index0,tx_counter0;

      // USART0 Transmitter interrupt service routine
      #pragma savereg-
      interrupt [USART0_TXC] void uart0_tx_isr(void)
      {
      #asm
      push r26
      push r27
      push r30
      push r31
      in r26,sreg
      push r26
      #edasm
      if (tx_counter0)
      {
      --tx_counter0;
      UDR0=tx_buffer0[tx_rd_index0];
      if (++tx_rd_index0 == TX_BUFFER_SIZE0) tx_rd_index0=0;
      };
      #asm
      pop r26
      out sreg,r26
      pop r31
      pop r30
      pop r27
      pop r26
      #endasm
      }
      #pragma savereg+

      #ifndef _DEBUG_TERMINAL_IO_
      // Write a character to the USART0 Transmitter buffer
      #define _ALTERNATE_PUTCHAR_
      #pragma used+
      void putchar(char c)
      {
      while (tx_counter0 == TX_BUFFER_SIZE0);
      #asm("cli")
      if (tx_counter0 || ((UCSR0A & DATA_REGISTER_EMPTY)==0))
      {
      tx_buffer0[tx_wr_index0]=c;
      if (++tx_wr_index0 == TX_BUFFER_SIZE0) tx_wr_index0=0;
      ++tx_counter0;
      }
      else
      UDR0=c;
      #asm("sei")
      }
      #pragma used-
      #endif

      // Standard Input/Output functions
      #include <stdio.h>

      // Declare your global variables here

      void main(void)
      {

      // USART0 initialization
      // Communication Parameters: 8 Data, 1 Stop, No Parity
      // USART0 Receiver: On
      // USART0 Transmitter: On
      // USART0 Mode: Asynchronous
      // USART0 Baud rate: 9600
      UCSR0A=0x00;
      UCSR0B=0xD8;
      UCSR0C=0x06;
      UBRR0H=0x00;
      UBRR0L=0x67;

      // Global enable interrupts
      #asm("sei")

      while (1)
      {
      // Place your code here

      };
      }

        這段由CVAVR程序生成器產(chǎn)生的UART接口代碼是一個(gè)非常好的、高效可靠,并且值得認(rèn)真學(xué)習(xí)和體會(huì)的。其特點(diǎn)如下:

        l.它采用兩個(gè)8字節(jié)的接收和發(fā)送緩沖器來提高M(jìn)CU的效率,如當(dāng)主程序調(diào)用Putchar()發(fā)送數(shù)據(jù)時(shí),如果UART口不空閑,就將數(shù)據(jù)放入發(fā)送緩沖器中,MCU不必等待,可以繼續(xù)執(zhí)行其它的工作。而UART的硬件發(fā)送完一個(gè)數(shù)據(jù)后,產(chǎn)生中斷,由中斷服務(wù)程序負(fù)責(zé)將發(fā)送緩沖器中數(shù)據(jù)依次送出。

        2.數(shù)據(jù)緩沖器結(jié)構(gòu)是一個(gè)線性的循環(huán)隊(duì)列,由讀、寫和隊(duì)列計(jì)數(shù)器3個(gè)指針控制,用于判斷隊(duì)列是否空、溢出,以及當(dāng)前數(shù)據(jù)在隊(duì)列中的位置。

        3.用編譯控制命令#pragma savereg-和#pragma savereg+,使得由CVAVR在生成的中斷服務(wù)程序中不進(jìn)行中斷保護(hù)(CVAVR生成中斷保護(hù)會(huì)將比較多的寄存器壓入堆棧中),而在中斷中嵌入?yún)R編,只將5個(gè)在本中斷中必須要保護(hù)的寄存器壓棧。這樣提高了UART中斷處理的速度,也意味著提高了MCU的效率。

        4.由于在接口程序Putchar()、Getchar()和中斷服務(wù)程序中都要對(duì)數(shù)據(jù)緩沖器的讀、寫和隊(duì)列計(jì)數(shù)器3個(gè)指針判斷和操作,為了防止沖突,在Putchar()、Getchar()中對(duì)3個(gè)指針操作時(shí)臨時(shí)將中斷關(guān)閉,提高了程序的可靠性。

         建議讀者能逐字逐句地仔細(xì)分析該段代碼,真正理解和領(lǐng)會(huì)每一句語句(包括編譯控制命令的作用)的作用,從中體會(huì)和學(xué)習(xí)如何編寫效率高,可靠性好,結(jié)構(gòu)優(yōu)良的系統(tǒng)代碼。這段程序使用的方法和技巧,對(duì)編寫SPI、I2C的串行通信接口程序都是非常好的借鑒。

        作為現(xiàn)在的單片機(jī)和嵌入式系統(tǒng)的工程師,不僅要深入全面的掌握芯片和各種器件的性能,具備豐富的硬件設(shè)計(jì)能力;同時(shí)也必須提高軟件的設(shè)計(jì)能力。要學(xué)習(xí)和掌握有關(guān)數(shù)據(jù)結(jié)構(gòu)、操作系統(tǒng)、軟件工程、網(wǎng)絡(luò)協(xié)議等方面的知識(shí),具有設(shè)計(jì)編寫大的復(fù)雜系統(tǒng)程序的能力。

        USART應(yīng)用實(shí)例

        使用ATmega128實(shí)現(xiàn)一個(gè)工業(yè)設(shè)備的主控制板,它與由ATmega8管理的按鍵和LED顯示構(gòu)成的控制面板距離在2米左右,兩者之間采用USART通信聯(lián)系。考慮到在實(shí)際應(yīng)用中,倆者之間交換的數(shù)據(jù)很少,通信速度也不需要很高,重要的是保證通信的可靠和抗干擾,因此在硬件設(shè)計(jì)上采用電流環(huán)的連接方式,見圖5.4。

        在圖中通信雙方采用光隔和三極管,將USART的電平變化變成電流變化后傳送連接,如同工業(yè)上使用的20mA電流環(huán)通信一樣,大大提高了通信的抗干擾能力。

        通信協(xié)議和規(guī)程的制定:

        l.通信速率采用2400bps(速率太高時(shí)電流環(huán)的變化會(huì)跟不上)。

        2. 用戶數(shù)據(jù)包采用定長格式,每個(gè)數(shù)據(jù)包長度為6個(gè)字節(jié),其中第1個(gè)字節(jié)是數(shù)據(jù)包起始字節(jié)0xBB,第6字節(jié)為數(shù)據(jù)包結(jié)束字節(jié)0xEE,其它為用戶命令、數(shù)據(jù)和系統(tǒng)狀態(tài)參數(shù)。

        3.每次通信由A端發(fā)起,下發(fā)一個(gè)數(shù)據(jù)包;B端收到一個(gè)正確的數(shù)據(jù)包后,必須返回一個(gè)數(shù)據(jù)包應(yīng)答。

        4.A端下發(fā)一個(gè)數(shù)據(jù)包后,在300ms內(nèi)沒有正確收到應(yīng)答包時(shí)(在2400bps時(shí)傳送6個(gè)字節(jié)的時(shí)間約為30ms),將再次重發(fā);3次重發(fā)均不能正確收到應(yīng)答包則報(bào)警。

        5.在系統(tǒng)正常工作時(shí),A端每隔250ms下發(fā)一個(gè)數(shù)據(jù)包,B端如果在1s內(nèi)沒有正確收到一個(gè)下發(fā)的數(shù)據(jù)包,將進(jìn)入安全保護(hù)程序。

        在這個(gè)應(yīng)用實(shí)例中,USART接口的發(fā)送程序與前面給出的典型例程中的一樣,而對(duì)USART的接收程序進(jìn)行了改動(dòng)和簡化,使其更加符合在本系統(tǒng)中使用。

      #define UART_BEGIN_STX 0xBB
      #define UART_END_STX 0xEE
      #define RX_BUFFER_SIZE0 6

      char rx_buffer0[RX_BUFFER_SIZE0];
      unsigned char rx_counter;
      bit Uart_RecvFlag

      // USART Receiver interrupt service routine
      #pragma savereg-
      interrupt [USART_RXC] void uart_rx_isr(void)
      {
      unsigned char status,data;
      #asm
      push r26
      push r27
      push r30
      push r31
      in r26,sreg
      push r26
      #endasm

      status=UCSRA;
      data=UDR;
      if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
      {
      if (!Uart_RecvFlag)
      {
      rx_buffer[rx_counter] = data;
      switch (rx_counter)
      {
      case 0:
      if (data == UART_BEGIN_STX) rx_counter = 1;
      break;
      case 1:
      case 2:
      case 3:
      case 4:
      rx_counter++;
      break;
      case 5:
      rx_counter = 0;
      if (data == UART_END_STX) Uart_RecvFlag = 1;
      break;
      }
      }
      }
      else
      rx_counter = 0;

      #asm
      pop r26
      out sreg,r26
      pop r31
      pop r30
      pop r27
      pop r26
      #endasm
      }
      #pragma savereg+
      …………
      void main(void)
      {
      while(1)
      {
      if (Uart_RecvFlag)
      {
      ………… //處理收到的數(shù)據(jù)包
      Uart_RecvFlag = 0; //允許USART接受新的數(shù)據(jù)包
      }
      ………… //處理其它任務(wù)
      }
      }

        在這段代碼中,接收中斷服務(wù)程序直接對(duì)數(shù)據(jù)包的起始字符和結(jié)束字符進(jìn)行判斷,并完成對(duì)整個(gè)數(shù)據(jù)包的接收。當(dāng)接收到正確的6個(gè)字符的數(shù)據(jù)包后,將“Uart_RecvFlag”標(biāo)志置位,通知上層程序處理收到的數(shù)據(jù)。一旦“Uart_RecvFlag”標(biāo)志置位后,中斷服務(wù)程序?qū)⒉辉俳邮招碌臄?shù)據(jù)(放棄掉收到的字節(jié)),使得數(shù)據(jù)緩沖區(qū)不會(huì)溢出。

        上層程序的設(shè)計(jì),應(yīng)保證以200ms左右的間隔對(duì)“Uart_RecvFlag”標(biāo)志位進(jìn)行一次判斷。一旦判斷“Uart_RecvFlag”標(biāo)志置位后,馬上進(jìn)行處理,回送應(yīng)答數(shù)據(jù)。處理完后將“Uart_RecvFlag”標(biāo)志清除,允許USART接收新的數(shù)據(jù)包。
      還可以考慮在數(shù)據(jù)包中增加“數(shù)據(jù)包編號(hào)”和“數(shù)據(jù)校驗(yàn)”2個(gè)字節(jié),以進(jìn)一步提高通信的可靠性。

      免費(fèi)預(yù)約試聽課

      亚洲另类欧美综合久久图片区_亚洲中文字幕日产无码2020_欧美日本一区二区三区桃色视频_亚洲AⅤ天堂一区二区三区

      
      

      1. 在线人成亚洲视频免费观看 | 中文字幕永久在线第一页 | 亚洲无线国产观看原创 | 久久精品国产72国产精 | 亚洲激情一区二区三区 | 亚洲欧洲日本精品专线 |