Operácie

Sériové komunikačné rozhranie: Rozdiel medzi revíziami

Z SensorWiki

(Nová stránka: == Sériové komunikačné rozhranie (UART) == === Úlohy === # Nahrajte si knižnice pre prácu so sériovou linkou, preštudujte využitie knižnice <stdio.h> a demonštrujte. #...)
 
(printf() na jednočipe?)
(10 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 1: Riadok 1:
 +
__NOTOC__
 
== Sériové komunikačné rozhranie (UART) ==
 
== Sériové komunikačné rozhranie (UART) ==
  
Riadok 4: Riadok 5:
  
  
# Nahrajte si knižnice pre prácu so sériovou linkou, preštudujte využitie knižnice <stdio.h> a demonštrujte.
+
# Nakonfigurujte USART na asynchrónnu prevádzku s parametrami N,9600,8,1
# Oboznámte sa s programom StampPlot a zobrazte časový priebeh teploty z termistora.
+
# Vyskúšajte demonštračný program, na strane PC použite terminál
# Vyhodnotením prechodového deja identifikujte veľkosť kondenzátora vo výstupnom filtri.
+
# Vytvorte si knižnice pre prácu so sériovou linkou, preštudujte využitie knižnice <stdio.h> a demonštrujte.
 +
# Oboznámte sa s programom StampPlot a zobrazte časový priebeh.
  
  
Riadok 15: Riadok 17:
 
* Ako používať USART: [[AVR Serial.c|knižnica a príklady...]]
 
* Ako používať USART: [[AVR Serial.c|knižnica a príklady...]]
  
 +
=== 1. Základný princíp prenosu cez USART ===
  
 +
Ukážkový program s vysvetlivkami - nahrajte si do AVRstudia a odkrokujte.
  
=== USART ===
+
<source lang="c">
 +
#include <avr/io.h>
 +
 
 +
#define BAUDRATE      9600
 +
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)
 +
 
 +
 
 +
int main (void)
 +
{
 +
  char ReceivedChar;
 +
 
 +
  /* Initialize UART */
 +
                                                       
 +
  UBRR0 = (unsigned char)BAUD_PRESCALE;                // Set baud rate: Load the UBRR register
 +
 
 +
  UCSR0B = (1 << RXEN0) | (1 << TXEN0);                // Enable receiver and transmitter
 +
 
 +
  UCSR0C = (1<<USBS0)|(3<<UCSZ00);                      // Set format: 8data, 2stop bit
 +
 
 +
  for (;;)                                              // Loop forever
 +
  {
 +
      while ((UCSR0A & (1 << RXC0)) == 0)                // Wait for data to be received
 +
  {
 +
    // Do nothing until data have been recieved and is ready to be read from UDR
 +
  };
 +
      ReceivedChar = UDR0;                              // Fetch the recieved byte
 +
 
 +
 
 +
      while ( !( UCSR0A & (1<<UDRE0)) )                  // Wait for empty transmit buffer
 +
    {
 +
  // Do nothing until UDR is ready for more data to be written to it
 +
  };
 +
      UDR0 = ReceivedChar+1;                            // Echo back the modified received byte
 +
  }
 +
 
 +
 
 +
}
 +
 
 +
</source>
 +
 
 +
 
 +
Ak vám program fungoval, nahrajte ho do procesora a otestujte komunikáciu s terminálom.
 +
Na prácu so sériovou linkou na vašom PC odporúčame program [http://braypp.googlepages.com/terminal Terminal by Bray], ale môžete
 +
to skúsiť aj s Hyperterminálom.
 +
 
 +
* [http://braypp.googlepages.com/terminal Terminal by Bray] ([http://braypp.googlepages.com/Terminal20080315.zip download])
 +
 
 +
 
 +
=== 2. Jednoduchá knižnica ===
 +
 
 +
Nebudeme sa zaoberať detailmi implementácie sériového komunikačného rozhrania procesorov AVR, pre naše účely postačí jednoduchá knižnica, ktorá obsahuje základné funkcie na prenos jedného znaku. Parametre prenosu pre túto knižnicu sú 9600,n,8,1.
  
 
'''serial.h'''
 
'''serial.h'''
 
<source lang="c">
 
<source lang="c">
 
/* ************************************************************************* */
 
/* ************************************************************************* */
/*                                                                          */
 
/* Description      : Header file for serial.c                              */
 
/*                    Based on AppNote AVR109 - Self-programming            */
 
/*                                                                          */
 
 
/* FileName          : serial.h                                              */
 
/* FileName          : serial.h                                              */
/* Compiler          : AVR-GCC/avr-libc(>= 1.2.5), TODO: IAR C 3.10C        */
 
/* Revision          : 1.7                                                  */
 
/* Date              : 30. November 2008                                    */
 
/* Updated by        : Richard Balogh                                        */
 
/* Target platform  : ATmega88, TODO: All AVRs with bootloader support      */
 
/*                                                                          */
 
 
/* ************************************************************************* */
 
/* ************************************************************************* */
 
 
         void inituart( void );
 
         void inituart( void );
 
         void sendchar( unsigned char );
 
         void sendchar( unsigned char );
Riadok 47: Riadok 90:
 
/*                    Based on AppNote AVR109 - Self-programming            */
 
/*                    Based on AppNote AVR109 - Self-programming            */
 
/*                                                                          */
 
/*                                                                          */
/* FileName          : serial.h                                             */
+
/* FileName          : serial.c                                             */
/* Compiler          : AVR-GCC/avr-libc(>= 1.2.5), TODO: IAR C 3.10C        */
 
/* Revision          : 1.7                                                  */
 
/* Date              : 30. November 2008                                    */
 
/* Updated by        : Richard Balogh                                        */
 
/* Target platform  : ATmega88, TODO: All AVRs with bootloader support      */
 
 
/*                                                                          */
 
/*                                                                          */
 
/* ************************************************************************* */
 
/* ************************************************************************* */
Riadok 58: Riadok 96:
 
#include <avr\io.h>
 
#include <avr\io.h>
  
/* baud rate register value calculation */
+
// Following calculation assumes that F_CPU is assigned in 'Project/Options'
#define CPU_FREQ 18432000UL     // If CKDIV8 checked, then /8!
+
#define BAUDRATE      9600      
#define BAUD_RATE 9600
+
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)
                            // BAUD = f / 16 * (UBR+1) alebo UBR = CPUFREQ/16/BAUD_RATE-1
 
#define BRREG_VALUE 119  // hodnota z tabulky v datashhete pre 18,4320MHz, 2x=0, 9600Baud, error = 0%   
 
  
  
/* definitions for UART control */      // upravene pre ATmega88
+
/* definitions for UART control */       
#define BAUD_RATE_LOW_REG UBRR0L // ??? (Staci Low Byte, < 255 )
+
                                        // Valid for ATmega328
 +
#define BAUD_RATE_REG         UBRR0  //  
 +
#define UART_STATUS_REG UCSR0A // OK, checked (but also control reg.)
 
#define UART_CONTROL_REG_B UCSR0B  // OK, checked
 
#define UART_CONTROL_REG_B UCSR0B  // OK, checked
 +
#define UART_CONTROL_REG_C      UCSR0C  // Added for mode setting
 
#define ENABLE_TRANSMITTER_BIT TXEN0  // OK, checked
 
#define ENABLE_TRANSMITTER_BIT TXEN0  // OK, checked
 
#define ENABLE_RECEIVER_BIT RXEN0  // OK, checked
 
#define ENABLE_RECEIVER_BIT RXEN0  // OK, checked
#define UART_STATUS_REG UCSR0A  // OK, checked (but also control reg.)
 
 
#define DATA_REGISTER_EMPTY_BIT UDRE0  // Added, for possible speed-up
 
#define DATA_REGISTER_EMPTY_BIT UDRE0  // Added, for possible speed-up
 
#define TRANSMIT_COMPLETE_BIT TXC0    // OK, checked
 
#define TRANSMIT_COMPLETE_BIT TXC0    // OK, checked
 
#define RECEIVE_COMPLETE_BIT RXC0    // OK, checked
 
#define RECEIVE_COMPLETE_BIT RXC0    // OK, checked
#define UART_CONTROL_REG_C      UCSR0C  // Added for mode setting
 
 
#define UART_DATA_REG UDR0    // OK, checked
 
#define UART_DATA_REG UDR0    // OK, checked
 
  
  
 
void inituart(void)
 
void inituart(void)
 
{
 
{
  BAUD_RATE_LOW_REG = BRREG_VALUE;                 // OK, preddelic pre 9600
+
BAUD_RATE_REG = (unsigned char)BAUD_PRESCALE;   // Set baud rate: Load the UBRR register
                                                  // bit 2x = 0
+
 
  UART_CONTROL_REG_C = (1<<UCSZ01)|(1<<UCSZ00);   // Added: Async. UART, None  
+
UART_CONTROL_REG_B = (1 << ENABLE_RECEIVER_BIT)|
 +
                    (1 << ENABLE_TRANSMITTER_BIT); // Enable receive + transmit
 +
 
 +
UART_CONTROL_REG_C = (3<<UCSZ00);                 // Added: Async. UART, None  
 
                                                   // Parity, 8-data, 1 stopbit
 
                                                   // Parity, 8-data, 1 stopbit
  UART_CONTROL_REG_B = (1 << ENABLE_RECEIVER_BIT)|
 
                    (1 << ENABLE_TRANSMITTER_BIT); // enable receive + transmit
 
 
                                                    
 
                                                    
 
}
 
}
Riadok 106: Riadok 143:
 
</source>
 
</source>
  
Testovací program. Testujeme len posielanie, naše káble nemajú privedené RxD.
+
Testovací program:
  
 
'''main.c'''
 
'''main.c'''
Riadok 121: Riadok 158:
 
   
 
   
 
  inituart();
 
  inituart();
 +
 
  sendchar('O');
 
  sendchar('O');
 
  sendchar('K');
 
  sendchar('K');
Riadok 156: Riadok 194:
 
}
 
}
 
</source>
 
</source>
 +
 
Takto potom môžete používať naozaj aj funkciu printf() so všetkými jej vymoženosťami...
 
Takto potom môžete používať naozaj aj funkciu printf() so všetkými jej vymoženosťami...
 
Úplne rovnako sa dá implementovať printf() aj na LCD displej, len ho treba na začiatku zinicializovať a namiesto funkcie sendchar napísať niečo ako LCDsendchar().
 
Úplne rovnako sa dá implementovať printf() aj na LCD displej, len ho treba na začiatku zinicializovať a namiesto funkcie sendchar napísať niečo ako LCDsendchar().
  
 +
Kompletný vstup/výstup potom vyzerá takto:
  
[[MMP Cvičenie 9|Návrat na cvičenie 9...]]
+
<source lang="c">
  
[[Category: AVR]][[Category: MMP]]
+
FILE uart_output = FDEV_SETUP_STREAM(sendchar, NULL, _FDEV_SETUP_WRITE);
 +
FILE uart_input = FDEV_SETUP_STREAM(NULL, recchar, _FDEV_SETUP_READ);
  
 +
int main(void) {
  
Nebudeme sa zaoberať detailmi implementácie sériového komunikačného rozhrania procesorov
+
    inituart();
AVR, pre naše účely postačí jednoduchá knižnica, ktorá obsahuje základné funkcie odladené
+
    stdout = &uart_output;
pre dosku MiniMEXLE s procesorom ATmega88 a oscilátorom 18,432 MHz.
+
    stdin = &uart_input;
Máte k dispozícii jednoduchú knižnicu pre prácu so sériovou linkou na procesore
+
               
ATmega88, stiahnite a pozrite si [[AVR Serial.c|príklady...]]
+
    char input;
  
Parametre prenosu pre túto knižnicu sú 9600,n,8,1.
+
    while(1) {
 +
        puts("Hello world!");
 +
        input = getchar();
 +
        printf("You wrote %c\n", input);
 +
    }
 +
       
 +
    return 0;
 +
}
  
Na prácu so sériovou linkou na vašom PC odporúčame program Terminal by Bray, ale môžete
+
</source>
to skúsiť aj s Hyperterminálom.
 
  
* [http://braypp.googlepages.com/terminal Terminal by Bray] ([http://braypp.googlepages.com/Terminal20080315.zip download])
+
Pozn.: pre MiniMEXLE - Prevod TTL úrovní na RS-232 je realizovaný takto -
 +
[[Media:232Converter.png|schéma zapojenia]], ktorá vychádza z [http://www.kmitl.ac.th/~kswichit/ap275/ap275.htm tohoto návodu].
  
Keby niekoho zaujímalo, ako je realizovaný prevod TTL úrovní na RS-232, tak tu je
 
[[Media:232Converter.png|schéma zapojenia]], ktorá vychádza z [http://www.kmitl.ac.th/~kswichit/ap275/ap275.htm tohoto návodu].
 
  
=== Vizualizácia ===
+
=== 3. Vizualizácia ===
  
 
Vizualizáciu dát môžeme robiť rozlične. Jeden z možných spôsobov je vypisovať
 
Vizualizáciu dát môžeme robiť rozlične. Jeden z možných spôsobov je vypisovať
Riadok 191: Riadok 238:
 
konfiguračné príkazy.  
 
konfiguračné príkazy.  
  
Download: [http://www.selmaware.com/stampplotlite/StampPlotLite_V17.zip StampPlotLite1.7]
+
Download: [http://www.parallax.com/Portals/0/Downloads/sw/spl.zip StampPlotLite1.7]
  
 
Príklad: [[AVR StampPlotExample.c]]
 
Príklad: [[AVR StampPlotExample.c]]
 
Manual: [[Stamp Plot Manual]]
 
Manual: [[Stamp Plot Manual]]
 
 
 
  
 
=== Download ===
 
=== Download ===
Riadok 204: Riadok 248:
 
[[Obrázok:Icon_Terminal.png]] [http://braypp.googlepages.com/Terminal20080315.zip Terminal 1.9b]
 
[[Obrázok:Icon_Terminal.png]] [http://braypp.googlepages.com/Terminal20080315.zip Terminal 1.9b]
  
[[Obrázok:Icon_StampPlotLite.png]] [http://www.selmaware.com/stampplotlite/StampPlotLite_V17.zip StampPlot Lite 1.7]
+
[[Obrázok:Icon_StampPlotLite.png]] [http://www.parallax.com/Portals/0/Downloads/sw/spl.zip StampPlot Lite 1.7]
  
  
Riadok 210: Riadok 254:
  
  
[[Monolitické mikropočítače#Cvi.C4.8Denia|Návrat na zoznam cvičení...]]
 
  
[[Category:AVR]][[Category:MMP]]
+
[[Category:AVR]][[Category:MMP]][[Category:DVPS]]

Verzia zo dňa a času 10:11, 20. november 2013

Sériové komunikačné rozhranie (UART)

Úlohy

  1. Nakonfigurujte USART na asynchrónnu prevádzku s parametrami N,9600,8,1
  2. Vyskúšajte demonštračný program, na strane PC použite terminál
  3. Vytvorte si knižnice pre prácu so sériovou linkou, preštudujte využitie knižnice <stdio.h> a demonštrujte.
  4. Oboznámte sa s programom StampPlot a zobrazte časový priebeh.


Literatúra:

1. Základný princíp prenosu cez USART

Ukážkový program s vysvetlivkami - nahrajte si do AVRstudia a odkrokujte.

#include <avr/io.h>

#define BAUDRATE       9600
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)


int main (void)
{
   char ReceivedChar;

   /* Initialize UART */
                                                         
   UBRR0 = (unsigned char)BAUD_PRESCALE;                 // Set baud rate: Load the UBRR register

   UCSR0B = (1 << RXEN0) | (1 << TXEN0);                 // Enable receiver and transmitter

   UCSR0C = (1<<USBS0)|(3<<UCSZ00);                      // Set format: 8data, 2stop bit 

   for (;;)                                              // Loop forever
   {
      while ((UCSR0A & (1 << RXC0)) == 0)                // Wait for data to be received 
	  {
	    // Do nothing until data have been recieved and is ready to be read from UDR
	  }; 
      ReceivedChar = UDR0;                               // Fetch the recieved byte 

   
      while ( !( UCSR0A & (1<<UDRE0)) )                  // Wait for empty transmit buffer 
   	  {
	   // Do nothing until UDR is ready for more data to be written to it
	  };
      UDR0 = ReceivedChar+1;                             // Echo back the modified received byte 
   }


}


Ak vám program fungoval, nahrajte ho do procesora a otestujte komunikáciu s terminálom. Na prácu so sériovou linkou na vašom PC odporúčame program Terminal by Bray, ale môžete to skúsiť aj s Hyperterminálom.


2. Jednoduchá knižnica

Nebudeme sa zaoberať detailmi implementácie sériového komunikačného rozhrania procesorov AVR, pre naše účely postačí jednoduchá knižnica, ktorá obsahuje základné funkcie na prenos jedného znaku. Parametre prenosu pre túto knižnicu sú 9600,n,8,1.

serial.h

/* ************************************************************************* */
/* FileName          : serial.h                                              */
/* ************************************************************************* */
         void inituart( void );
         void sendchar( unsigned char );
unsigned char recchar( void );

serial.c

/* ************************************************************************* */
/*                                                                           */
/* Description       : UART communication routines                           */
/*                     Based on AppNote AVR109 - Self-programming            */
/*                                                                           */
/* FileName          : serial.c                                              */
/*                                                                           */
/* ************************************************************************* */

#include <avr\io.h>

// Following calculation assumes that F_CPU is assigned in 'Project/Options'
#define BAUDRATE       9600      
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)


/* definitions for UART control */      
                                        // Valid for ATmega328
#define	BAUD_RATE_REG	        UBRR0   // 
#define	UART_STATUS_REG		UCSR0A  // OK, checked (but also control reg.)
#define	UART_CONTROL_REG_B	UCSR0B  // OK, checked
#define UART_CONTROL_REG_C      UCSR0C  // Added for mode setting
#define	ENABLE_TRANSMITTER_BIT	TXEN0   // OK, checked
#define	ENABLE_RECEIVER_BIT	RXEN0   // OK, checked
#define DATA_REGISTER_EMPTY_BIT UDRE0   // Added, for possible speed-up
#define	TRANSMIT_COMPLETE_BIT	TXC0    // OK, checked
#define	RECEIVE_COMPLETE_BIT	RXC0    // OK, checked
#define	UART_DATA_REG		UDR0    // OK, checked


void inituart(void)
{
 BAUD_RATE_REG = (unsigned char)BAUD_PRESCALE;    // Set baud rate: Load the UBRR register

 UART_CONTROL_REG_B = (1 << ENABLE_RECEIVER_BIT)|
                    (1 << ENABLE_TRANSMITTER_BIT); // Enable receive + transmit 

 UART_CONTROL_REG_C = (3<<UCSZ00);                 // Added: Async. UART, None 
                                                   // Parity, 8-data, 1 stopbit
                                                   
}


void sendchar(unsigned char c)
{
  UART_DATA_REG = c;                                   // prepare transmission
  while (!(UART_STATUS_REG & (1 << TRANSMIT_COMPLETE_BIT)));// wait until byte sendt
  UART_STATUS_REG |= (1 << TRANSMIT_COMPLETE_BIT);          // delete TXCflag
}


unsigned char recchar(void)
{
  while( !(UART_STATUS_REG & (1 << RECEIVE_COMPLETE_BIT)) );  // wait for data
  return UART_DATA_REG;
}

Testovací program:

main.c

#include <avr\io.h>
#include "serial.h"              // Nasa kniznica... 

int main(void) 
{
 char c;

  DDRD = 0b00000010;
 PORTD = 0b00000011;    // Set TxD pin as an output, RxD input
 
 inituart();

 sendchar('O');
 sendchar('K');
 sendchar('\n');

 for (c=32;c<=127;c++) 
   sendchar(c);

 for (;;) {
     /* Do nothing */
          }
}


printf() na jednočipe?

Ak si napíšete vlastnú funkciu na zobrazenie jedného znaku na displej, alebo pre vyslanie jedného znaku po sériovej linke, potom môžete používať naozaj aj funkciu printf so všetkými jej vymoženosťami. Využívame pre tom knižnicu stdio.h, ktorá sa používa takto:

...
#include <stdio.h>

FILE mystdout = FDEV_SETUP_STREAM(sendchar, NULL, _FDEV_SETUP_WRITE);
                              // 'sendchar' je nova funkcia pre jeden znak

int main(void)
{ 
 inituart();	               // Inicializacia seriovej linky
 stdout = &mystdout;           // Odteraz funguje printf();

 printf("Hello, world!");
 return 0;
}

Takto potom môžete používať naozaj aj funkciu printf() so všetkými jej vymoženosťami... Úplne rovnako sa dá implementovať printf() aj na LCD displej, len ho treba na začiatku zinicializovať a namiesto funkcie sendchar napísať niečo ako LCDsendchar().

Kompletný vstup/výstup potom vyzerá takto:

FILE uart_output = FDEV_SETUP_STREAM(sendchar, NULL, _FDEV_SETUP_WRITE);
FILE uart_input = FDEV_SETUP_STREAM(NULL, recchar, _FDEV_SETUP_READ);

int main(void) {

    inituart();
    stdout = &uart_output;
    stdin = &uart_input;
                
    char input;

    while(1) {
        puts("Hello world!");
        input = getchar();
        printf("You wrote %c\n", input);
    }
        
    return 0;
}

Pozn.: pre MiniMEXLE - Prevod TTL úrovní na RS-232 je realizovaný takto - schéma zapojenia, ktorá vychádza z tohoto návodu.


3. Vizualizácia

Vizualizáciu dát môžeme robiť rozlične. Jeden z možných spôsobov je vypisovať po sériovej linke v pravidelných intervaloch holé data a tie potom uložiť ako maticu do Matlabu a tam nakresliť graf, priebeh, čo treba...

Iná možnosť je použiť napr. program StampPlot, ktorý kreslí prichádzajúce data priamo ako graf, s výnimkou reťazcov, ktoré začínajú znakom '!', tie považuje za konfiguračné príkazy.

Download: StampPlotLite1.7

Príklad: AVR StampPlotExample.c Manual: Stamp Plot Manual

Download

Icon Terminal.png Terminal 1.9b

Icon StampPlotLite.png StampPlot Lite 1.7