<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 一個URAT(RS232)低層驅動 中間層軟件示例

          一個URAT(RS232)低層驅動 中間層軟件示例

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

          #include

          #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<#define PARITY_ERROR (1<#define DATA_OVERRUN (1<#define DATA_REGISTER_EMPTY (1<#define RX_COMPLETE (1<
          // 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
          inr26,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
          popr26
          outsreg,r26
          popr31
          popr30
          popr27
          popr26
          #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
          inr26,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
          popr26
          outsreg,r26
          popr31
          popr30
          popr27
          popr26
          #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

          // 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接口代碼是一個非常好的、高效可靠,并且值得認真學習和體會的。其特點如下:
          l.它采用兩個8字節(jié)的接收和發(fā)送緩沖器來提高MCU的效率,如當主程序調(diào)用Putchar()發(fā)送數(shù)據(jù)時,如果UART口不空閑,就將數(shù)據(jù)放入發(fā)送緩沖器中,MCU不必等待,可以繼續(xù)執(zhí)行其它的工作。而UART的硬件發(fā)送完一個數(shù)據(jù)后,產(chǎn)生中斷,由中斷服務程序負責將發(fā)送緩沖器中數(shù)據(jù)依次送出。
          2.數(shù)據(jù)緩沖器結構是一個線性的循環(huán)隊列,由讀、寫和隊列計數(shù)器3個指針控制,用于判斷隊列是否空、溢出,以及當前數(shù)據(jù)在隊列中的位置。
          3.用編譯控制命令#pragma savereg-和#pragma savereg+,使得由CVAVR在生成的中斷服務程序中不進行中斷保護(CVAVR生成中斷保護會將比較多的寄存器壓入堆棧中),而在中斷中嵌入?yún)R編,只將5個在本中斷中必須要保護的寄存器壓棧。這樣提高了UART中斷處理的速度,也意味著提高了MCU的效率。
          4.由于在接口程序Putchar()、Getchar()和中斷服務程序中都要對數(shù)據(jù)緩沖器的讀、寫和隊列計數(shù)器3個指針判斷和操作,為了防止沖突,在Putchar()、Getchar()中對3個指針操作時臨時將中斷關閉,提高了程序的可靠性。
          建議讀者能逐字逐句地仔細分析該段代碼,真正理解和領會每一句語句(包括編譯控制命令的作用)的作用,從中體會和學習如何編寫效率高,可靠性好,結構優(yōu)良的系統(tǒng)代碼。這段程序使用的方法和技巧,對編寫SPI、I2C的串行通信接口程序都是非常好的借鑒。
          作為現(xiàn)在的單片機嵌入式系統(tǒng)的工程師,不僅要深入全面的掌握芯片和各種器件的性能,具備豐富的硬件設計能力;同時也必須提高軟件的設計能力。要學習和掌握有關數(shù)據(jù)結構、操作系統(tǒng)、軟件工程、網(wǎng)絡協(xié)議等方面的知識,具有設計編寫大的復雜系統(tǒng)程序的能力。

          USART應用實例
          使用ATmega128實現(xiàn)一個工業(yè)設備的主控制板,它與由ATmega8管理的按鍵和LED顯示構成的控制面板距離在2米左右,兩者之間采用USART通信聯(lián)系??紤]到在實際應用中,倆者之間交換的數(shù)據(jù)很少,通信速度也不需要很高,重要的是保證通信的可靠和抗干擾,因此在硬件設計上采用電流環(huán)的連接方式,見圖5.4。
          在圖中通信雙方采用光隔和三極管,將USART的電平變化變成電流變化后傳送連接,如同工業(yè)上使用的20mA電流環(huán)通信一樣,大大提高了通信的抗干擾能力。
          通信協(xié)議和規(guī)程的制定:
          l.通信速率采用2400bps(速率太高時電流環(huán)的變化會跟不上)。
          2. 用戶數(shù)據(jù)包采用定長格式,每個數(shù)據(jù)包長度為6個字節(jié),其中第1個字節(jié)是數(shù)據(jù)包起始字節(jié)0xBB,第6字節(jié)為數(shù)據(jù)包結束字節(jié)0xEE,其它為用戶命令、數(shù)據(jù)和系統(tǒng)狀態(tài)參數(shù)。
          3.每次通信由A端發(fā)起,下發(fā)一個數(shù)據(jù)包;B端收到一個正確的數(shù)據(jù)包后,必須返回一個數(shù)據(jù)包應答。
          4.A端下發(fā)一個數(shù)據(jù)包后,在300ms內(nèi)沒有正確收到應答包時(在2400bps時傳送6個字節(jié)的時間約為30ms),將再次重發(fā);3次重發(fā)均不能正確收到應答包則報警。
          5.在系統(tǒng)正常工作時,A端每隔250ms下發(fā)一個數(shù)據(jù)包,B端如果在1s內(nèi)沒有正確收到一個下發(fā)的數(shù)據(jù)包,將進入安全保護程序。
          在這個應用實例中,USART接口的發(fā)送程序與前面給出的典型例程中的一樣,而對USART的接收程序進行了改動和簡化,使其更加符合在本系統(tǒng)中使用。

          #define UART_BEGIN_STX0xBB
          #define UART_END_STX0xEE
          #define RX_BUFFER_SIZE06

          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
          inr26,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
          popr26
          outsreg,r26
          popr31
          popr30
          popr27
          popr26
          #endasm
          }
          #pragma savereg+
          …………
          void main(void)
          {
          while(1)
          {
          if (Uart_RecvFlag)
          {
          …………//處理收到的數(shù)據(jù)包
          Uart_RecvFlag = 0;//允許USART接受新的數(shù)據(jù)包
          }
          …………//處理其它任務
          }
          }

          在這段代碼中,接收中斷服務程序直接對數(shù)據(jù)包的起始字符和結束字符進行判斷,并完成對整個數(shù)據(jù)包的接收。當接收到正確的6個字符的數(shù)據(jù)包后,將“Uart_RecvFlag”標志置位,通知上層程序處理收到的數(shù)據(jù)。一旦“Uart_RecvFlag”標志置位后,中斷服務程序將不再接收新的數(shù)據(jù)(放棄掉收到的字節(jié)),使得數(shù)據(jù)緩沖區(qū)不會溢出。
          上層程序的設計,應保證以200ms左右的間隔對“Uart_RecvFlag”標志位進行一次判斷。一旦判斷“Uart_RecvFlag”標志置位后,馬上進行處理,回送應答數(shù)據(jù)。處理完后將“Uart_RecvFlag”標志清除,允許USART接收新的數(shù)據(jù)包。
          還可以考慮在數(shù)據(jù)包中增加“數(shù)據(jù)包編號”和“數(shù)據(jù)校驗”2個字節(jié),以進一步提高通信的可靠性。


          評論


          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();