- Messaggi: 4
- Ringraziamenti ricevuti 0
×
MSP430, Microcontrollori 16 bit Ultra Low Power
codice porte uart
10 Anni 7 Mesi fa #1
da manuele de marco
codice porte uart è stato creato da manuele de marco
qualcuno può spiegarmi il seguente codice per programmazione porta uart e come funziona?? ( lo ho messo anche in allegato)
grazie:
#include "msp430g2553.h"
//
// Hardware-related definitions
//
#define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0)
#define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A)
//
// Conditions for 9600 Baud SW UART, SMCLK = 1MHz
//
#define UART_TBIT_DIV_2 (1000000 / (9600 * 2))
#define UART_TBIT (1000000 / 9600)
//
// Global variables used for full-duplex UART communication
//
unsigned int txData; // UART internal variable for TX
unsigned char rxBuffer; // Received UART character
//
// Function prototypes
//
void TimerA_UART_init(void);
void TimerA_UART_tx(unsigned char byte);
void TimerA_UART_print(char *string);
//
// main()
//
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
DCOCTL = 0x00; // Set DCOCLK to 1MHz
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
P1OUT = 0x00; // Initialize all GPIO
P1SEL = UART_TXD + UART_RXD; // Timer function for TXD/RXD pins
P1DIR = 0xFF & ~UART_RXD; // Set all pins but RXD to output
P2OUT = 0x00;
P2SEL = 0x00;
P2DIR = 0xFF;
__enable_interrupt();
TimerA_UART_init(); // Start Timer_A UART
TimerA_UART_print("G2xx2 TimerA UART\r\n");
TimerA_UART_print("READY.\r\n");
for (;
{
// Wait for incoming character
__bis_SR_register(LPM0_bits);
// Update board outputs according to received byte
if (rxBuffer & 0x01) P1OUT |= 0x01; else P1OUT &= ~0x01; // P1.0
if (rxBuffer & 0x02) P1OUT |= 0x08; else P1OUT &= ~0x08; // P1.3
if (rxBuffer & 0x04) P1OUT |= 0x10; else P1OUT &= ~0x10; // P1.4
if (rxBuffer & 0x08) P1OUT |= 0x20; else P1OUT &= ~0x20; // P1.5
if (rxBuffer & 0x10) P1OUT |= 0x40; else P1OUT &= ~0x40; // P1.6
if (rxBuffer & 0x20) P1OUT |= 0x80; else P1OUT &= ~0x80; // P1.7
if (rxBuffer & 0x40) P2OUT |= 0x40; else P2OUT &= ~BIT2; // P2.2
if (rxBuffer & 0x80) P2OUT |= 0x80; else P2OUT &= ~BIT4; // P2.4
// Echo received character
TimerA_UART_tx(rxBuffer);
}
}
//
// Function configures Timer_A for full-duplex UART operation
//
void TimerA_UART_init(void)
{
TACCTL0 = OUT; // Set TXD Idle as Mark = '1'
TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int
TACTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode
}
//
// Outputs one byte using the Timer_A UART
//
void TimerA_UART_tx(unsigned char byte)
{
while (TACCTL0 & CCIE); // Ensure last char got TX'd
TACCR0 = TAR; // Current state of TA counter
TACCR0 += UART_TBIT; // One bit time till first bit
TACCTL0 = OUTMOD0 + CCIE; // Set TXD on EQU0, Int
txData = byte; // Load global variable
txData |= 0x100; // Add mark stop bit to TXData
txData <<= 1; // Add space start bit
}
//
// Prints a string over using the Timer_A UART
//
void TimerA_UART_print(char *string)
{
while (*string) {
TimerA_UART_tx(*string++);
}
}
//
// Timer_A UART - Transmit Interrupt Handler
//
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
static unsigned char txBitCnt = 10;
TACCR0 += UART_TBIT; // Add Offset to CCRx
if (txBitCnt == 0) { // All bits TXed?
TACCTL0 &= ~CCIE; // All bits TXed, disable interrupt
txBitCnt = 10; // Re-load bit counter
}
else {
if (txData & 0x01) {
TACCTL0 &= ~OUTMOD2; // TX Mark '1'
}
else {
TACCTL0 |= OUTMOD2; // TX Space '0'
}
txData >>= 1;
txBitCnt--;
}
}
//
// Timer_A UART - Receive Interrupt Handler
//
#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A1_ISR(void)
{
static unsigned char rxBitCnt = 8;
static unsigned char rxData = 0;
switch (__even_in_range(TA0IV, TA0IV_TAIFG)) { // Use calculated branching
case TA0IV_TACCR1: // TACCR1 CCIFG - UART RX
TACCR1 += UART_TBIT; // Add Offset to CCRx
if (TACCTL1 & CAP) { // Capture mode = start bit edge
TACCTL1 &= ~CAP; // Switch capture to compare mode
TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0
}
else {
rxData >>= 1;
if (TACCTL1 & SCCI) { // Get bit waiting in receive latch
rxData |= 0x80;
}
rxBitCnt--;
if (rxBitCnt == 0) { // All bits RXed?
rxBuffer = rxData; // Store in global variable
rxBitCnt = 8; // Re-load bit counter
TACCTL1 |= CAP; // Switch compare to capture mode
__bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR)
}
}
break;
}
}
// Definizioni relative all'hardware
//
# define UART_TXD 0x02 / / TXD su P1.1 ( Timer0_A.OUT0 )
# define UART_RXD 0x04 / / RXD su P1.2 ( Timer0_A.CCI1A )
//
// Condizioni di 9600 Baud SW UART , SMCLK = 1MHz
//
# define UART_TBIT_DIV_2 ( 1000000 / ( 9600 * 2) )
# define UART_TBIT (1000000/9600)
//
// Variabili globali utilizzati per la comunicazione UART full-duplex
//
unsigned int txData ; / / UART variabile interna per TX
unsigned char rxBuffer ; / / carattere UART Ricevuto
//
// funzione prototipi
//
void TimerA_UART_init(void);
void TimerA_UART_tx(unsigned char byte);
void TimerA_UART_print(char *string);
//
// main ( )
//
void main ( void)
{
WDTCTL = WDTPW + WDTHOLD ; // Stop watchdog timer
DCOCTL = 0x00 ; / / Set DCOCLK a 1MHz
BCSCTL1 = CALBC1_1MHZ ;
DCOCTL = CALDCO_1MHZ ;
P1OUT = 0x00 ; / / inizializzare tutte le GPIO
P1SEL = UART_TXD + UART_RXD ; / funzione Timer per pin TXD / RXD
P1DIR = 0xFF & ~UART_RXD ; / / Imposta tutti i pin , ma RXD all'uscita
P2OUT = 0x00 ;
P2SEL = 0x00 ;
P2DIR = 0xFF ;
__enable_interrupt () ;
TimerA_UART_init ( ) ; / / Avvio Timer_A UART
TimerA_UART_print ( " G2xx2 TimerA UART \r\ n" ) ;
TimerA_UART_print ( " READY.\r\n" ) ;
for (;
{
// Attesa per il personaggio in arrivo( INCOMING CARACTER)
__bis_SR_register ( LPM0_bits );
// Aggiorna Uscite in secondo byte ricevuto
// Update board outputs according to received byte
if (rxBuffer & 0x01) P1OUT |= 0x01; else P1OUT &= ~0x01; // P1.0
if (rxBuffer & 0x02) P1OUT |= 0x08; else P1OUT &= ~0x08; // P1.3
if (rxBuffer & 0x04) P1OUT |= 0x10; else P1OUT &= ~0x10; // P1.4
if (rxBuffer & 0x08) P1OUT |= 0x20; else P1OUT &= ~0x20; // P1.5
if (rxBuffer & 0x10) P1OUT |= 0x40; else P1OUT &= ~0x40; // P1.6
if (rxBuffer & 0x20) P1OUT |= 0x80; else P1OUT &= ~0x80; // P1.7
if (rxBuffer & 0x40) P2OUT |= 0x40; else P2OUT &= ~BIT2; // P2.2
if (rxBuffer & 0x80) P2OUT |= 0x80; else P2OUT &= ~BIT4; // P2.4
// Echo ricevuto il carattere
TimerA_UART_tx ( rxBuffer ) ;
}
}
/ /
/ / Funzione configura Timer_A per il funzionamento UART full-duplex
/ /
void TimerA_UART_init(void)
{
TACCTL0 = OUT ; / / Set TXD Idle come Mark = '1 '
TACCTL1 = SCS + CM1 + CAP + CCIE ; / / Sync, Neg Edge, Capture , Int
TACTL = TASSEL_2 + MC_2 ; / / SMCLK , avviare in modalità continua
}
/ /
/ / Uscite di un byte usando l' UART Timer_A
/ /
vuoto TimerA_UART_tx ( byte unsigned char )
{
while ( TACCTL0 & CCIE ) ; / / Assicurarsi ultimo carattere ottenuto TX'd
TACCR0 = TAR ; / / Stato attuale del contatore TA
TACCR0 += UART_TBIT ; / / Un po 'di tempo fino al primo bit
TACCTL0 = OUTMOD0 + CCIE ; / / Set TXD su EQU0 , Int
TxData = byte ; / / Carico variabile globale
TxData |= 0x100 ; / / Aggiungere mark bit di stop per TxData
TxData <<= 1; bit / / Aggiungere inizio space
}
/ /
/ / Stampa una stringa sopra utilizzando la UART Timer_A
/ /
TimerA_UART_print void ( char * string )
{
while ( *string ) {
TimerA_UART_tx ( *string++) ;
}
}
/ /
/ / Timer_A UART - Transmit Interrupt Handler
/ /
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
static unsigned char txBitCnt = 10;
TACCR0 += UART_TBIT ; // Aggiungi Differenza CCRX
if ( txBitCnt == 0 ) { // Tutti i bit TXed ?
TACCTL0 & = ~CCIE ; // Tutti i bit TXed , disabilitare interrupt
txBitCnt = 10; / / ricaricare contatore di bit
}
else {
if ( txData & 0x01 ) {
TACCTL0 & = ~OUTMOD2 ; // TX Mark '1 '
}
else {
TACCTL0 |= OUTMOD2 ; // TX Spazio '0 '
}
txData >>= 1 ;
txBitCnt--;
}
}
/ /
/ / Timer_A UART - Receive Interrupt Handler
/ /
#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A1_ISR(void)
{
static unsigned char rxBitCnt = 8;
static unsigned char rxData = 0 ;
switch (__even_in_range(TA0IV, TA0IV_TAIFG)) { // Use calculated branching
case TA0IV_TACCR1: // TACCR1 CCIFG - UART RX
TACCR1 += UART_TBIT; // Add Offset to CCRx
if (TACCTL1 & CAP) { // Capture mode = start bit edge
TACCTL1 &= ~CAP; // Switch capture to compare mode
TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0
}
else {
rxData >>= 1;
if (TACCTL1 & SCCI) { // Get bit waiting in receive latch
rxData |= 0x80;
}
rxBitCnt--;
if (rxBitCnt == 0) { // All bits RXed?
rxBuffer = rxData; // Store in global variable
rxBitCnt = 8; // Re-load bit counter
TACCTL1 |= CAP; // Switch compare to capture mode
__bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR)
}
}
break;
}
}
grazie:
#include "msp430g2553.h"
//
// Hardware-related definitions
//
#define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0)
#define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A)
//
// Conditions for 9600 Baud SW UART, SMCLK = 1MHz
//
#define UART_TBIT_DIV_2 (1000000 / (9600 * 2))
#define UART_TBIT (1000000 / 9600)
//
// Global variables used for full-duplex UART communication
//
unsigned int txData; // UART internal variable for TX
unsigned char rxBuffer; // Received UART character
//
// Function prototypes
//
void TimerA_UART_init(void);
void TimerA_UART_tx(unsigned char byte);
void TimerA_UART_print(char *string);
//
// main()
//
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
DCOCTL = 0x00; // Set DCOCLK to 1MHz
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
P1OUT = 0x00; // Initialize all GPIO
P1SEL = UART_TXD + UART_RXD; // Timer function for TXD/RXD pins
P1DIR = 0xFF & ~UART_RXD; // Set all pins but RXD to output
P2OUT = 0x00;
P2SEL = 0x00;
P2DIR = 0xFF;
__enable_interrupt();
TimerA_UART_init(); // Start Timer_A UART
TimerA_UART_print("G2xx2 TimerA UART\r\n");
TimerA_UART_print("READY.\r\n");
for (;
{
// Wait for incoming character
__bis_SR_register(LPM0_bits);
// Update board outputs according to received byte
if (rxBuffer & 0x01) P1OUT |= 0x01; else P1OUT &= ~0x01; // P1.0
if (rxBuffer & 0x02) P1OUT |= 0x08; else P1OUT &= ~0x08; // P1.3
if (rxBuffer & 0x04) P1OUT |= 0x10; else P1OUT &= ~0x10; // P1.4
if (rxBuffer & 0x08) P1OUT |= 0x20; else P1OUT &= ~0x20; // P1.5
if (rxBuffer & 0x10) P1OUT |= 0x40; else P1OUT &= ~0x40; // P1.6
if (rxBuffer & 0x20) P1OUT |= 0x80; else P1OUT &= ~0x80; // P1.7
if (rxBuffer & 0x40) P2OUT |= 0x40; else P2OUT &= ~BIT2; // P2.2
if (rxBuffer & 0x80) P2OUT |= 0x80; else P2OUT &= ~BIT4; // P2.4
// Echo received character
TimerA_UART_tx(rxBuffer);
}
}
//
// Function configures Timer_A for full-duplex UART operation
//
void TimerA_UART_init(void)
{
TACCTL0 = OUT; // Set TXD Idle as Mark = '1'
TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int
TACTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode
}
//
// Outputs one byte using the Timer_A UART
//
void TimerA_UART_tx(unsigned char byte)
{
while (TACCTL0 & CCIE); // Ensure last char got TX'd
TACCR0 = TAR; // Current state of TA counter
TACCR0 += UART_TBIT; // One bit time till first bit
TACCTL0 = OUTMOD0 + CCIE; // Set TXD on EQU0, Int
txData = byte; // Load global variable
txData |= 0x100; // Add mark stop bit to TXData
txData <<= 1; // Add space start bit
}
//
// Prints a string over using the Timer_A UART
//
void TimerA_UART_print(char *string)
{
while (*string) {
TimerA_UART_tx(*string++);
}
}
//
// Timer_A UART - Transmit Interrupt Handler
//
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
static unsigned char txBitCnt = 10;
TACCR0 += UART_TBIT; // Add Offset to CCRx
if (txBitCnt == 0) { // All bits TXed?
TACCTL0 &= ~CCIE; // All bits TXed, disable interrupt
txBitCnt = 10; // Re-load bit counter
}
else {
if (txData & 0x01) {
TACCTL0 &= ~OUTMOD2; // TX Mark '1'
}
else {
TACCTL0 |= OUTMOD2; // TX Space '0'
}
txData >>= 1;
txBitCnt--;
}
}
//
// Timer_A UART - Receive Interrupt Handler
//
#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A1_ISR(void)
{
static unsigned char rxBitCnt = 8;
static unsigned char rxData = 0;
switch (__even_in_range(TA0IV, TA0IV_TAIFG)) { // Use calculated branching
case TA0IV_TACCR1: // TACCR1 CCIFG - UART RX
TACCR1 += UART_TBIT; // Add Offset to CCRx
if (TACCTL1 & CAP) { // Capture mode = start bit edge
TACCTL1 &= ~CAP; // Switch capture to compare mode
TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0
}
else {
rxData >>= 1;
if (TACCTL1 & SCCI) { // Get bit waiting in receive latch
rxData |= 0x80;
}
rxBitCnt--;
if (rxBitCnt == 0) { // All bits RXed?
rxBuffer = rxData; // Store in global variable
rxBitCnt = 8; // Re-load bit counter
TACCTL1 |= CAP; // Switch compare to capture mode
__bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR)
}
}
break;
}
}
// Definizioni relative all'hardware
//
# define UART_TXD 0x02 / / TXD su P1.1 ( Timer0_A.OUT0 )
# define UART_RXD 0x04 / / RXD su P1.2 ( Timer0_A.CCI1A )
//
// Condizioni di 9600 Baud SW UART , SMCLK = 1MHz
//
# define UART_TBIT_DIV_2 ( 1000000 / ( 9600 * 2) )
# define UART_TBIT (1000000/9600)
//
// Variabili globali utilizzati per la comunicazione UART full-duplex
//
unsigned int txData ; / / UART variabile interna per TX
unsigned char rxBuffer ; / / carattere UART Ricevuto
//
// funzione prototipi
//
void TimerA_UART_init(void);
void TimerA_UART_tx(unsigned char byte);
void TimerA_UART_print(char *string);
//
// main ( )
//
void main ( void)
{
WDTCTL = WDTPW + WDTHOLD ; // Stop watchdog timer
DCOCTL = 0x00 ; / / Set DCOCLK a 1MHz
BCSCTL1 = CALBC1_1MHZ ;
DCOCTL = CALDCO_1MHZ ;
P1OUT = 0x00 ; / / inizializzare tutte le GPIO
P1SEL = UART_TXD + UART_RXD ; / funzione Timer per pin TXD / RXD
P1DIR = 0xFF & ~UART_RXD ; / / Imposta tutti i pin , ma RXD all'uscita
P2OUT = 0x00 ;
P2SEL = 0x00 ;
P2DIR = 0xFF ;
__enable_interrupt () ;
TimerA_UART_init ( ) ; / / Avvio Timer_A UART
TimerA_UART_print ( " G2xx2 TimerA UART \r\ n" ) ;
TimerA_UART_print ( " READY.\r\n" ) ;
for (;
{
// Attesa per il personaggio in arrivo( INCOMING CARACTER)
__bis_SR_register ( LPM0_bits );
// Aggiorna Uscite in secondo byte ricevuto
// Update board outputs according to received byte
if (rxBuffer & 0x01) P1OUT |= 0x01; else P1OUT &= ~0x01; // P1.0
if (rxBuffer & 0x02) P1OUT |= 0x08; else P1OUT &= ~0x08; // P1.3
if (rxBuffer & 0x04) P1OUT |= 0x10; else P1OUT &= ~0x10; // P1.4
if (rxBuffer & 0x08) P1OUT |= 0x20; else P1OUT &= ~0x20; // P1.5
if (rxBuffer & 0x10) P1OUT |= 0x40; else P1OUT &= ~0x40; // P1.6
if (rxBuffer & 0x20) P1OUT |= 0x80; else P1OUT &= ~0x80; // P1.7
if (rxBuffer & 0x40) P2OUT |= 0x40; else P2OUT &= ~BIT2; // P2.2
if (rxBuffer & 0x80) P2OUT |= 0x80; else P2OUT &= ~BIT4; // P2.4
// Echo ricevuto il carattere
TimerA_UART_tx ( rxBuffer ) ;
}
}
/ /
/ / Funzione configura Timer_A per il funzionamento UART full-duplex
/ /
void TimerA_UART_init(void)
{
TACCTL0 = OUT ; / / Set TXD Idle come Mark = '1 '
TACCTL1 = SCS + CM1 + CAP + CCIE ; / / Sync, Neg Edge, Capture , Int
TACTL = TASSEL_2 + MC_2 ; / / SMCLK , avviare in modalità continua
}
/ /
/ / Uscite di un byte usando l' UART Timer_A
/ /
vuoto TimerA_UART_tx ( byte unsigned char )
{
while ( TACCTL0 & CCIE ) ; / / Assicurarsi ultimo carattere ottenuto TX'd
TACCR0 = TAR ; / / Stato attuale del contatore TA
TACCR0 += UART_TBIT ; / / Un po 'di tempo fino al primo bit
TACCTL0 = OUTMOD0 + CCIE ; / / Set TXD su EQU0 , Int
TxData = byte ; / / Carico variabile globale
TxData |= 0x100 ; / / Aggiungere mark bit di stop per TxData
TxData <<= 1; bit / / Aggiungere inizio space
}
/ /
/ / Stampa una stringa sopra utilizzando la UART Timer_A
/ /
TimerA_UART_print void ( char * string )
{
while ( *string ) {
TimerA_UART_tx ( *string++) ;
}
}
/ /
/ / Timer_A UART - Transmit Interrupt Handler
/ /
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
static unsigned char txBitCnt = 10;
TACCR0 += UART_TBIT ; // Aggiungi Differenza CCRX
if ( txBitCnt == 0 ) { // Tutti i bit TXed ?
TACCTL0 & = ~CCIE ; // Tutti i bit TXed , disabilitare interrupt
txBitCnt = 10; / / ricaricare contatore di bit
}
else {
if ( txData & 0x01 ) {
TACCTL0 & = ~OUTMOD2 ; // TX Mark '1 '
}
else {
TACCTL0 |= OUTMOD2 ; // TX Spazio '0 '
}
txData >>= 1 ;
txBitCnt--;
}
}
/ /
/ / Timer_A UART - Receive Interrupt Handler
/ /
#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A1_ISR(void)
{
static unsigned char rxBitCnt = 8;
static unsigned char rxData = 0 ;
switch (__even_in_range(TA0IV, TA0IV_TAIFG)) { // Use calculated branching
case TA0IV_TACCR1: // TACCR1 CCIFG - UART RX
TACCR1 += UART_TBIT; // Add Offset to CCRx
if (TACCTL1 & CAP) { // Capture mode = start bit edge
TACCTL1 &= ~CAP; // Switch capture to compare mode
TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0
}
else {
rxData >>= 1;
if (TACCTL1 & SCCI) { // Get bit waiting in receive latch
rxData |= 0x80;
}
rxBitCnt--;
if (rxBitCnt == 0) { // All bits RXed?
rxBuffer = rxData; // Store in global variable
rxBitCnt = 8; // Re-load bit counter
TACCTL1 |= CAP; // Switch compare to capture mode
__bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR)
}
}
break;
}
}
Si prega Accedi o Crea un account a partecipare alla conversazione.
- manuele de marco
- Autore della discussione
- New Member
Riduci
Di più
10 Anni 7 Mesi fa - 10 Anni 7 Mesi fa #2
da Mauro Laurenti
Rendering Error in layout Message/Item: array_keys(): Argument #1 ($array) must be of type array, null given. Please enable debug mode for more information.
Risposta da Mauro Laurenti al topic codice porte uart
Rendering Error in layout Message/Item: array_keys(): Argument #1 ($array) must be of type array, null given. Please enable debug mode for more information.
Si prega Accedi o Crea un account a partecipare alla conversazione.
Moderatori: Mauro Laurenti, Matteo Garia
Registrati al sito
Accedi a tutte le risorse e articoli non visibili pubblicamente, puoi registrarti con pochi passi.
Login
© LaurTec 2006 - 2024