ATMega 8 bzw. ATmega328p IO-BOX
Quarz 8 MHz
Files:
Software ATM8-MinBoard_IO.zip
das HEX: main.hex
Eagle Schematic: AT8_MiniBord_V5.sch Boarddatei: AT8_MiniBord_V5.brd
Quarz 8MHz
Board:
LabView Steuersoftware (rein textbasiert)
Board +Gehause
AT8 MiniBoard-IO Doku & Manual
Christof Ermer, 16.11.2020,
Serieller USB Anschluss: Baud 9600,8,N,1, mit FTDI232 USB TTL 5Volt
Mnemonic: ( Befehle )
FORMAT: Frage, Antwort {nur wenn gefordert}; Sonst Standardmäßig „OK“
Befehl[,long][,long]<13>
=> []=Optional. long = +/-32Bit Wert:2= (2^32/2-1) = 2.147.483.647
Antwort ist oft nur ASCII Text als Wert <13> 12345<13>
Immer gesendet mit “Carriage Return” = ASCII13 = <13> = <CR>
BSP. Device,-123,+123<CR>, Ping<13> Pong<13>
AT Mega8 Pin Zuordnung
Interne Belegung:
Alle PINs sind reine TTL (5Volt). Aber intern über 560 Ohm Schutzwiderstand nach außen geführt .
Belastung beachten. Alle Pins sind als reine Input Outputs verwendbar. Oder:
PIN1 = PB1-OC1A Frequenz Out 16 Bit
PIN2 = PB3-OC2 PWM Out 8 Bit
PIN3 = PD5-T1 Frequenz In. TTL
PIN4 = PC0-ADC0 ADC 10 Bit Resolution 0..5V
PIN5 = PC1-ADC1 ADC 10 Bit Resolution 0..5V
PIN6 = PC2-ADC2 ADC 10 Bit Resolution 0..5V
PIN7 = PC3-ADC3 ADC 10 Bit Resolution 0..5V
PIN8 = PC4-ADC4 ADC 10 Bit Resolution 0..5V
PB2= interne Toggle LED //Abschaltbar PB2= interne Toggle LED “TGLON”, “TGLOFF”
Mnemonic Befehle. Empfehlung: Test mit Modemsoftware: COMx,9600 Baud, 8Bit kein Handshake.
Format Pin Nummer bezogen. Bsp: P4 =
Pin4 Befehl: ADCP4<13> Antwort =
Wert 0..1023<13>
OUTPx{0,1} Output Oin[1..8],{0,1} {x=1..8} {0 oder1 auswählen 0=Default}
INPx Input Pin[1..8] Ergebnis: 0=0V, 1=5V, {x=1..8} {0 oder 1 auswählen 0=Default}
SETFRQ-P1, {Frequenz} SETPWM-P,12345
ADCP{4..8} 12Bit = 0 bis 1023 = 0 ..5V. B7t/Volt = 5/1024 = 4.8828mV/Bit
SETPWM-P2,{Frequenz,PWM [0.255]} SETPWM-P2,60,15
READFRQ_P3 Antwort nach 1 Sekunde
Zusätzliche Kommandos, aber nicht relevant:
PING Pong,
Device Aktuelle Info. Mehrere Zeilen
TT Timer & Tick Counter +122.07803125 /Sekunde * Wert= vergangene Zeit
STOPFRQ-P1
STOPPWM-P2
LEDON, LEDOFF, LED,]0,1} Toggle LED
TALKON, TALK OFF, TALK,{0,1} MCU Main-Loops/Sekunde
GOCR1A Register OCR1A, GOCR1B Register OCR1B
ADC,[0..5] 10 BIT = 0..1023 an 0..5V RAW Kommando
GTCNT0 = Get TCNT0, usw. GTCCR0,
GTCNT1, GTCCR1A, GTCCR1B, GOCR1A, GOCR1B,
GTCNT2
BAUD,{Baudrate}
---------------------------------------
Aufkleber
[1]=Auswahlwert, x{0..n} = Auswahl 0 bis n
USB BAUD= 9600, 8Stop, 0-Parity,
0-XONXOFF, 0-Handshake
OUTPx,[0,1] x=1..8 0 oder 5V TTL
INPx x{1..8} 0 oder 1 = 1 oder 5V.
ADCPx {4..8} 0..1023= 0..5V
SETFRQ-P1, {Frequenz} >~50Hz ~genau
SETPWM-P2, x={0..255} PWM [0.255] bei 30Hz
READFRQ_P3 Antwort nach 1 Sekunde
main.c
//------------------------------------------------------------------------------
// Programmed by Christof Ermer
//------------------------------------------------------------------------------
/*
Quarz, BrownOut 4.0V, WatchDog, CKOPT, 8 MHZ
Low Fuse=0x7F High Fuse= 0x89
TIMER 0 = TICK
TIMER 1 = 16 BIt PWM_T1
TIMER 2 = PWM
Processor 1 = links
#define UART_BAUD_RATE 9600
USBasp auf libusb-win32 driver mit Zadig einstellen, NICH!! WIN32
http://www.engbedded.com/fusecalc/
*/
//#define TICK_USED
//#define UART_IS_USED
//alternate Low Fuse=0x9E High Fuse= 0xEF
#define SOFTWARE "Software: ATM8-MinBoard_IO"
#define AUTOR "Christof Ermer"
#define DATUM "30.11.2020"
#define HARDWARE "AT8 8MHz MiniBoard-IO"
#define SHOW_BAUDRATE "9600,8,N,1"
#include <ctype.h>
#include <inttypes.h>
#include <avr\io.h>
#include <avr\pgmspace.h> // <--#include <progmem.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <avr/interrupt.h> // obsolete #include <avr\signal.h>
#include <avr/wdt.h>
//Produziert Fehler...
#include <util/delay.h> //_delay_loop_1 _delay_loop_2 delay_ms
#include "main.h" //witdh Hardware assigns
#include "uart328.h"
#include "TxtFunc.h"
#include "debug.h"
//CONSTANT ARRAYs IN .TEXT = ROM ARREA .DATA IST SRAM !! .BSS SRAM
//const char MCA_DELIMTERSTR[] PROGMEM = { ',',0 };
volatile uint32_t gu32_Ticks; //T2 timeCounter, only NN_Counter for Keypressings
//uint8_t gu8Mode;
volatile uint8_t gu8Status;
volatile uint16_t gu16TCNT1;
volatile float gufT1_MeasureFRQ;
//proto
void READ_FRQ_Start( void ); //Frequenz MESSEN MIT TICK TIME
//TCKcounter
// ****************************************
ISR( TIMER0_OVF_vect ) //ATMEGA8
// ****************************************
{
gu32_Ticks++;
if( !(gu32_Ticks % TICK_1000MS) )
{
if( gu8Status & FRQ_MEASURE_ACTIVE_FLAG ) // FequnqzMessung
{
TCCR1B = 0; //STOP T1
gu16TCNT1 = TCNT1; // Hohle wert = Pulse/sec
TCCR1A = 0;
TCNT1=0;
DDRD &= ~(1<< PD5); // T1
PORTD &= ~(1<< PD5); // T1
gufT1_MeasureFRQ =
gu16TCNT1; //* FRQ_FLOAT_FAKTOR;(1000.0/TICKTIME_FLOAT
)
gu8Status &= ~FRQ_MEASURE_ACTIVE_FLAG;
gu8Status |= FRQ_MEASURE_READY_FLAG;
};
gu8Status |= TICK_EVENT;
}; // Tickcounter
if( gu32_Ticks & 0b111 ) //(2^n-1) binär jeder 2.te
{
UART_TXRX_Check(); //IMMER VORHANDEN !! IN ALLEN LOOPS DIE ZEIT BRAUCHEN
}; // Tickcounter
};
// ************OVL*************************
void Start_TICK_T0(void) //ATMEGA8//244 INT/Sec
// *************************************
{
// 8*10^6 / 256 / 256 = 122.0703125 pro sekunde
cli();
TCNT0= 0;
TIFR = (1 << TOV0); //OVL
TIMSK |= (1 << TOIE0); //OVL
TCCR0 = (1 << CS01); //Scale 8// = 31250
sei();
};
// ********************************************
//ATMEGA8 // MIT CTC MODUS
void SelectBestPreScaler_T1( uint32_t uxSollFrq ) // MIT CTC MODUS
// ********************************************
{
uxSollFrq*= 2; // Toogle = / 2
if( (F_CPU / 1.0 / uxSollFrq ) > 0xFFFF)
{
if( (F_CPU / 8.0 / uxSollFrq ) > 0xFFFF)
{
if( (F_CPU / 64.0 / uxSollFrq ) > 0xFFFF)
{
if( (F_CPU / 256.0 / uxSollFrq ) > 0xFFFF)
{
OCR1A = round(F_CPU / 1024 / uxSollFrq);
TCCR1B = (1<< WGM12) | (1<<CS12) |
(1<< CS10); //CTC 1024
}
else
{
OCR1A = round(F_CPU / 256 / uxSollFrq);
TCCR1B = (1<< WGM12) | (1<<CS12); //CTC
256
};
}
else
{
OCR1A = round(F_CPU / 64 / uxSollFrq);
TCCR1B =
(1<< WGM12) | (1<<CS11) | (1<<CS10); //CTC 64
};
}
else
{
OCR1A = round(F_CPU / 8 / uxSollFrq);
TCCR1B = (1<< WGM12) | (1<<CS11); //CTC 8
};
}
else
{
OCR1A = round(F_CPU / uxSollFrq); // /1
TCCR1B = (1<< WGM12) | (1<<CS10); //CTC 1
};
};
// ***********************************
void T1_CTC( uint32_t uxSollFrq ) //Frequenz Ausgeben
//ATMEGA8
// ***********************************
{
DDRB |= (1<< PB1); //OCR1A
PORTB |= (1<< PB1); // OC1A
TCCR1B = 0;
TCNT1 = 0;
INIT_OC1A_PIN() ;
TCCR1A = (1<< COM1A0); // Toogle OC1A
//OCRx = Quarz / Vorteiler / gewünschte Frequenz
SelectBestPreScaler_T1( uxSollFrq );
};
// ***********************************
// ATMEGA 8
void READ_FRQ_Start( void ) //Frequenz MESSEN MIT TICK TIME
//ATMEGA8
// ***********************************
{ //ClockSOurce = T1
TCCR1B = 0;
DDRD &= ~(1<< PD5); // T1
PORTD &= ~(1<< PD5); // T1 Pullup off
OCR1A = 0xFF;
OCR1B = 0xFF;
TCCR1A = 0;
TCNT1 = 0;
cli();
gu32_Ticks = 0; // Stelle 1 Sec Time auf 0
gu8Status |= FRQ_MEASURE_ACTIVE_FLAG;
TCCR1B = (1<< CS12) | (1<< CS11); //T1 SOURCE Falling Edge
sei();
};
// ***********************************
void T1_STOP_CTC(void ) //nix Frequenz
// ***********************************
{
TCCR1B = 0;
TCNT1 = 0;
CLR_T1_OC1A_PIN();
};
// ***********************************
void READ_FRQ_Stop( void ) //Frequenz MESSEN MIT TICK TIME
//ATMEGA8
// ***********************************
{ //ClockSOurce = T1
gu8Status &= ~FRQ_MEASURE_ACTIVE_FLAG;
DDRD &= ~(1<< PD5); // T1
PORTD &= ~(1<< PD5); // T1
TCCR1B = 0;
TCCR1A = 0;
TCNT1 = 0;
};
// ********************************************
//ATMEGA8 PWM BASE FREQUENZ UND PWM 0..255
void SelectBestPreScaler_T2( uint16_t u16Frq, uint8_t u8PWM ) //FastPWM CLR OC2
// OHNE WGMxx MODUS
// ********************************************
{
TCCR2 = 0;
TCNT2 = 0;
if( (F_CPU / 1.0 / u16Frq) > 0xFF )
{
if( (F_CPU / 8.0 / u16Frq) > 0xFF )
{
if( (F_CPU /32.0 / u16Frq ) > 0xFF )
{
if( (F_CPU / 64.0 / u16Frq ) > 0xFF )
{
if( (F_CPU / 128.0 / u16Frq ) > 0xFF)
{
if( (F_CPU / 256.0 / u16Frq
) > 0xFF)
{
OCR2 =
round(F_CPU / 1024 / u16Frq);
TCCR2 =
(1<<CS22) | (1<<COM21) | (1<< CS20); //CTC 1024
}
else
{
OCR2 =
round(F_CPU / 256 / u8PWM);
TCCR2 =
(1<<CS22) | (1<<CS21); //CTC 256
};
}
else
{
OCR2 = round(F_CPU / 128 /
u8PWM);
TCCR2 = (1<<CS22) |
(1<<CS20); //CTC 128
};
}
else
{
OCR2 = round(F_CPU / 64 / u8PWM);
TCCR2 = (1<<CS22); //CTC 64
};
}
else
{
OCR2 = round(F_CPU / 32 / u8PWM);
TCCR2 = (1<<CS21) | (1<<CS20); //CTC 32
};
}
else
{
OCR2 = round(F_CPU / 8 / u8PWM);
TCCR2 = (1<<COM21); //CTC 8
};
}
else
{
OCR2 = round(F_CPU / u8PWM); // /1
TCCR2 = (1<<CS20); //CTC 1
};
};
// ***********************************
void T2_FastPWM( uint8_t u8SollPWM )
// ***********************************
{
TCCR2 = 0;
TCNT2 = 0;
INIT_OC2DIR();
//TCCR2 = COM21 WGM21 //FAST PWM CLEAR OC2
//OCRx = Quarz / Vorteiler / gewünschte PWM 0..255
//SelectBestPreScaler_T2( u16Frq, u8SollPWM );//TCCR2 = COM21
OCR2 = u8SollPWM;
TCCR2 = (1<<CS22) | (1<<CS21) | (1<< CS20) |
(1<< COM21) | (1<< WGM21) | (1<< WGM20); // Fast PWM;
//CTC 1024 = 30 HZ
};
// ***********************************
void T2_STOPPWM( void )
// ***********************************
{
TCCR2 = 0;
TCNT2 = 0;
SET_OC2_LOW();
};
//****************************************************************
#define ADC_5V_AN_C_USED_ENABLED //SETZE 5V
uint16_t ADC_AT8_10Bit(uint8_t u8Chan) // 0..7
//****************************************************************
{ //REFERENCE = VCC
DDRC &= ~(1<< u8Chan); //Bit loeschen
PORTC &= ~(1<< u8Chan); //Wegen Pullup abschalten
ADCSRA = (1<< ADEN) | (1<< ADPS2) | (1<< ADPS1) | (1<< ADPS0); //ADC EIN UND PreScaler
#ifdef ADC_EXTERN_5V_USED_ENABLED
ADMUX = u8Chan; // ADMUX_REFS0 Select pin ADCx using MUX
#endif
#ifdef ADC_5V_AN_C_USED_ENABLED
ADMUX = (1<< REFS0) | u8Chan; // VCC= REF. ADMUX_REFS0 Select pin ADCx using MUX
#endif
#ifdef ADC_INTERN_BANDGAP_USED_ENABLED
ADMUX = (1<< REFS1) | (1<< REFS0) | u8Chan; // ADMUX_REFS0 Select pin ADCx using MUX
#endif
_delay_us(1);
ADCSRA |= (1<< ADSC); //ADCSRA |= _BV(ADSC); //Start conversion
while( ADCSRA & (1<< ADSC) ) //wait until _BV(ADSC)=0 =converstion completed
{
wdt_reset();
};
return ADC; //ADCW; //get converted value
};
#ifdef UART_USE_ENABLED
// *******************************************************************
void CheckOrder(char *pcStrOrder) //von gcaRxStr
// *******************************************************************
{
// zerlege UART RX Str inseine Delimitrer Bestandteile
TokensRXStr( pcStrOrder ); //und lege diese in gsCmd.ucaCmd ab
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("STOPFRQ-P1") ) ) //B1
{
T1_STOP_CTC();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("STOPPWM-P2") ) ) //B3
{
T2_STOPPWM();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SETFRQ-P1") ) ) //B1
{
T1_CTC( (uint32_t)gsCmd.ixCmdVal_1 );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SETPWM-P2") ) ) // 30HZ B3 Base Frequenz 0..255VLaue 0..255
{
T2_FastPWM( (uint8_t)gsCmd.ixCmdVal_1 );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("READFRQ_P3") ) ) // B1 Timebase
{
READ_FRQ_Start();
// Ab Hier EINE GanzeE SEKUNDE WARTEN, dann kommt automaisch Antwort
// FRQ_MEASURE_READY_FLAG-->
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("OUTP1") ) ) //B1
{
if(TCCR1B)
{
T1_STOP_CTC();
READ_FRQ_Stop();
};
DDRB |= (1<< PB1);
if( gsCmd.ixCmdVal_1 )
{
PORTB |= (1<< PB1);
}
else
{
PORTB &= ~(1<< PB1);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("OUTP2") ) ) //B3
{
if( TCCR2 ) T2_STOPPWM();
DDRB |= (1<< PB3);
if( gsCmd.ixCmdVal_1 )
{
PORTB |= (1<< PB3);
}
else
{
PORTB &= ~(1<< PB3);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("OUTP3") ) ) //D5 = T1 INPUT
{
if( TCCR1B ) {READ_FRQ_Stop();};
DDRD |= (1<< PD5);
if( gsCmd.ixCmdVal_1 )
{
PORTD |= (1<< PD5);
}
else
{
PORTD &= ~(1<< PD5);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("OUTP4") ) ) //PC0
{
DDRC |= (1<< PC0);
if( gsCmd.ixCmdVal_1 )
{
PORTC |= (1<< PC0);
}
else
{
PORTC &= ~(1<< PC0);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("OUTP5") ) ) //PC1
{
DDRC |= (1<< PC1);
if( gsCmd.ixCmdVal_1 )
{
PORTC |= (1<< PC1);
}
else
{
PORTC &= ~(1<< PC1);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("OUTP6") ) ) //PC2
{
DDRC |= (1<< PC2);
if( gsCmd.ixCmdVal_1 )
{
PORTC |= (1<< PC2);
}
else
{
PORTC &= ~(1<< PC2);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("OUTP7") ) ) //PC3
{
DDRC |= (1<< PC3);
if( gsCmd.ixCmdVal_1 )
{
PORTC |= (1<< PC3);
}
else
{
PORTC &= ~(1<< PC3);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("OUTP8") ) ) //PC4
{
DDRC |= (1<< PC4);
if( gsCmd.ixCmdVal_1 )
{
PORTC |= (1<< PC4);
}
else
{
PORTC &= ~(1<< PC4);
};
return;
};
// ------------------------------------------
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("INP3") ) ) //PD5
{
if( TCCR1B )
{
READ_FRQ_Stop();
};
DDRD &= ~(1<<PD5);
PORTD &= ~(1<<PD5);
if( PIND & (1<<PD5) )
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("INP1") ) ) //PB1
{
T1_STOP_CTC();
DDRB &= ~(1<<PB1);
PORTB &= ~(1<<PB1);
if( PINB & (1<<PB1) )
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("INP2") ) ) //PB3
{
if( TCCR2 ) {T2_STOPPWM();};
DDRB &= ~(1<<PB3);
PORTB &= ~(1<<PB3);
if( PINB & (1<<PB3) )
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("INP3") ) ) //PD5
{
if( TCCR1B )
{
READ_FRQ_Stop();
};
DDRD &= ~(1<<PD5);
PORTD &= ~(1<<PD5);
if( PIND & (1<<PD5) )
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("INP4") ) ) //PC0
{
DDRC &= ~(1<<PC0);
PORTC &= ~(1<<PC0);
if( PINC & (1<<PC0) )
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("INP5") ) ) //PC1
{
DDRC &= ~(1<<PC1);
PORTC &= ~(1<<PC1);
if( PINC & (1<<PC1) )
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("INP6") ) ) //PC2
{
DDRC &= ~(1<<PC2);
PORTC &= ~(1<<PC2);
if( PINC & (1<<PC2) )
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("INP7") ) ) //PC3
{
DDRC &= ~(1<<PC3);
PORTC &= ~(1<<PC3);
if( PINC & (1<<PC3) )
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("INP8") ) ) //PC4
{
DDRC &= ~(1<<PC4);
PORTC &= ~(1<<PC4);
if( PINC & (1<<PC4) )
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("ADCP4") ) )
{
PrintULongCR( ADC_AT8_10Bit( 0 ) ); //Nur 6 Eingänge
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("ADCP5") ) )
{
PrintULongCR( ADC_AT8_10Bit( 1 ) ); //Nur 6 Eingänge
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("ADCP6") ) )
{
PrintULongCR( ADC_AT8_10Bit( 2 ) ); //Nur 6 Eingänge
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("ADCP7") ) )
{
PrintULongCR( ADC_AT8_10Bit( 3 ) ); //Nur 6 Eingänge
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("ADCP8") ) )
{
PrintULongCR( ADC_AT8_10Bit( 4 ) ); //Nur 6 Eingänge
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("ADC") ) )
{
PrintULongCR( ADC_AT8_10Bit( (uint8_t)gsCmd.ixCmdVal_1 % 6 ) ); //Nur 6 Eingänge
return;
};
// ---------------------------------
/*
// INPUTS
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("IN-BITPB") ) ) //Format SETBITPx,Bitrnr,[0,1]
{
DDRB &= ~(1<<gsCmd.ixCmdVal_1);
PORTB &= ~(1<<gsCmd.ixCmdVal_1);
if(PINB & (1<<gsCmd.ixCmdVal_1))
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
// INPUTS
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("IN-BITPC") ) ) //Format SETBITPx,Bitrnr,[0,1]
{
DDRC &= ~(1<<gsCmd.ixCmdVal_1);
PORTC &= ~(1<<gsCmd.ixCmdVal_1);
if(PINC & (1<<gsCmd.ixCmdVal_1))
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
// INPUTS
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("IN-BITPD") ) ) //Format SETBITPx,Bitrnr,[0,1]
{
DDRD &= ~(1<<gsCmd.ixCmdVal_1);
PORTD &= ~(1<<gsCmd.ixCmdVal_1);
if(PIND & (1<<gsCmd.ixCmdVal_1))
{
uart_putc('1');
}
else
{
uart_putc('0');
};
PrintCR();
return;
};
// INPUT PORT
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("IN_PORTB") ) )
{
DDRB = 0;
PORTB = 0;
PrintULongCR( PINB );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("IN_PORTC") ) )
{
DDRC = 0;
PORTC = 0;
PrintULongCR( PINC );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("IN_PORTD") ) )
{
DDRC &= 0x3;
PORTC &= 0x3;
PrintULongCR( PIND );
return;
};
// SET BITS
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SETBITPB") ) )
{
DDRB |= (1<<gsCmd.ixCmdVal_1);
if( gsCmd.ixCmdVal_2 )
{
PORTB |= (1<<gsCmd.ixCmdVal_1);
}
else
{
PORTB &= ~(1<<gsCmd.ixCmdVal_1);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SETBITPC") ) ) //Format SETBITPx,Bitnr,[0,1]
{
DDRC |= (1<<gsCmd.ixCmdVal_1);
if( gsCmd.ixCmdVal_2 )
{
PORTC |= (1<<gsCmd.ixCmdVal_1);
}
else
{
PORTC &= ~(1<<gsCmd.ixCmdVal_1);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SETBITPD") ) ) //Format SETBITPx,Bitnr, [0,1]
{
DDRD |= (1<<gsCmd.ixCmdVal_1);
if( gsCmd.ixCmdVal_2 )
{
PORTD |= (1<<gsCmd.ixCmdVal_1);
}
else
{
PORTD &= ~(1<<gsCmd.ixCmdVal_1);
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SETPB") ) )
{
DDRB = 0xFF;
PORTB= (uint8_t)gsCmd.ixCmdVal_1;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SETPC") ) )
{
DDRC = 0xFF;
PORTC = (uint8_t)gsCmd.ixCmdVal_1;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SETPD") ) )
{
DDRD = 0xFF;
PORTD= (uint8_t)gsCmd.ixCmdVal_1;
return;
};
*/
// -----------------------------------------------------------
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PWM_T1A") ) )
{
OCR1A = (uint16_t)gsCmd.ixCmdVal_1;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PWM_T1B") ) )
{
OCR1B = (uint16_t)gsCmd.ixCmdVal_1;
return;
};
// ---------------------------------------------------
// ------------------------------------
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GTCNT0") ) )
{
PrintULongCR(TCNT0);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GTCCR0") ) )
{
PrintULongCR(TCCR0);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GTCNT1") ) )
{
PrintULongCR(TCNT1);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GTCCR1A") ) )
{
PrintULongCR(TCCR1A);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GTCCR1B") ) )
{
PrintULongCR(TCCR1B);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GOCR1A") ) )
{
PrintULongCR(OCR1A);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GOCR1B") ) )
{
PrintULongCR(OCR1B);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GTCNT2") ) )
{
PrintULongCR(TCNT2);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GOC2") ) )
{
PrintULongCR(OCR2);
return;
};
// -------------------------------------------------------------------
// ---------------------------------------------------
gu8Status = TOGGLE_FLAG; // |STATUS_TRAFFIC_FLAG;
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("LEDON") ) )
{
gu8Status |= TOGGLE_FLAG;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("LEDOFF") ) )
{
gu8Status &= ~TOGGLE_FLAG;
TOGGLE_LED_OFF();
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("LED") ) )
{
if((uint8_t)gsCmd.ixCmdVal_1)
{
gu8Status |= TOGGLE_FLAG;
}
else
{
gu8Status &= ~TOGGLE_FLAG;
TOGGLE_LED_OFF();
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("TALKON") ) )
{
gu8Status |= STATUS_TRAFFIC_FLAG;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("TALKOFF") ) )
{
gu8Status &= ~STATUS_TRAFFIC_FLAG;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("TALK") ) )
{
if((uint8_t)gsCmd.ixCmdVal_1)
{
gu8Status |= STATUS_TRAFFIC_FLAG;
}
else
{
gu8Status &= ~STATUS_TRAFFIC_FLAG;
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PING") ) )
{
Print_PStrCR( PSTR("Pong") );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("Device") ) )
{
Print_PStrCR( PSTR( AUTOR ) );
Print_PStrCR( PSTR( DATUM ) );
Print_PStrCR( PSTR(HARDWARE ) );
Print_PStrCR( PSTR( SHOW_BAUDRATE ) );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("TT") ) )
{
PrintLongCR( gu32_Ticks );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("RR") ) )
{
gu32_Ticks = 0; //Reset TickCounter
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("BAUD") ) )
{
uart_init( UART_BAUD_SELECT((uint16_t)gsCmd.ixCmdVal_1, F_CPU) );
ResetRxBuff();
return;
};
};
#endif
// **********************************
int main(void)
// **********************************
{
uint32_t u32MCULast= 0;
cli();//The global interrupt flag is maintained in the I bit of the status register (SREG).
//INIT HARDWARE
//USing of PORTOUTS 1=OUT, 0=IN
DDRB = 0;
DDRC = 0;
DDRD = UART_RXTX_LEVEL; //TX
PORTD = UART_RXTX_PULL;
//ADCSR |= (1<<ADC); //ADC OFF
//INIT_OC2DIR(); //| (1<<OC1A) | (1<<OC1B)
//INIT_PWM_T1_DIR();
//SFIOR = (1<<PUD); //Pullup Disable
//Pointer and Strings init
wdt_enable(WDTO_1S); //WDTO_500MS
wdt_reset(); //WATCHDOG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Initialize UART library, pass baudrate and avr cpu clock
// with the macro UART_BAUD_SELECT()
//#ifdef UART_IS_USED
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU) );
ResetRxBuff();
sei();
Print_PStrCR( PSTR(HARDWARE) );
Print_PStrCR( PSTR(SOFTWARE) );
Print_PStrCR( PSTR(AUTOR) );
Print_PStrCR( PSTR(DATUM) );
uart_puts_p( PSTR("UART-Baud="));
Print_PStrCR( PSTR(SHOW_BAUDRATE) );
//#endif
OCR1A = PWM_T1_MITTE;
OCR1B = PWM_T1_MITTE;
OCR2 = OCR2_MITTE;
Start_TICK_T0(); //8 Bit Timer 2 = MS Tick Counter
gu32_Ticks = 0;
gu8Status = TOGGLE_FLAG; // |STATUS_TRAFFIC_FLAG;
// ************ MAIN LOOP FOR EVER *********************
// TOGGLE
for (;;) /* loop forever */ //Aber schnell > 200.000 mal/Sekunde
{
sei();
wdt_reset(); //WATCHDOG!
//Hier kann was gemacht werden jede 1 Sekunde
u32MCULast++;
if( gu8Status & TICK_EVENT )
{
gu8Status &= ~TICK_EVENT;
if( gu8Status & TOGGLE_FLAG )
{
INIT_TOGGLE();
TOGGLE_LED();
};
if(gu8Status & FRQ_MEASURE_READY_FLAG)
{
PrintULongCR( (uint32_t)gufT1_MeasureFRQ );
gu8Status &= ~FRQ_MEASURE_READY_FLAG;
};
//PrintLongCR( gu32_Ticks );
if( gu8Status & STATUS_TRAFFIC_FLAG )
{
uart_puts_p( PSTR("MCU L/S=") );
PrintULongCR( u32MCULast );
u32MCULast = 0;
/*
CRLF();
ULongToNumStr( TCNT1 );
CRLF();
uart_puts_p( PSTR(", ") );
ULongToNumStr( gu32_Ticks );
uart_puts( gcaNumStr );
uart_puts_p( PSTR(", ") );
PrintLongCR( OCR1A );
*/
//PrintStrCR( ByteToBin (TIMSK) );
};
}; // Tickcounter
if( gu8Status & ORDER_EVENT)
{
CheckOrder( gcaRxStr );//gcaRxStr = accumulated str
ResetRxBuff();
};
}; //main loop Ende
};
// ******************* MAIN END ********************************************
main.h
#ifndef MAIN_HEADER //Prevents multiple includes
#define MAIN_HEADER
#define UART_BAUD_RATE 9600
//#define UART_BAUD_RATE 57600U
// #define UART_BAUD_RATE 19200U
#define TIMER_TICK_USED
#define DISABLE_ALL_PULLUP() (SFIOR |= _BV(PUD));
#define ENABLE_ALLUP_SCL() (SFIOR &= ~(_BV(PUD)));
#define WDTO_2S 7 //WatchDog
//========================================================================
//TIMERS
//TIMER2 = is 61 miliseconds Timer ~approx.
// 16MhZ / 1024 / 256 = 61,03515625 Hz
// T= 1/f = 0.016384 ms / Interrupt
//Aufzaehlbezeichner
#define RX_BITNR PD0 //0
#define TX_BITNR PD1 //1
#define UART_RXTX_PULL 0x03
#define UART_RXTX_LEVEL 0x02
extern volatile uint32_t gu32_Ticks; // T2 timeCounter, only NN_Counter for Keypressings
extern void CheckOrder(char *pcStrOrder); //von gcaRxStr
#ifdef TIMER_TICK_USED
void StartTickTimer(void); //0.1 Seconds interrupt
#endif
#define OC1A_PIN PB1
#define OC1B_PIN PB2
#define OC2_PIN PB3
#define ADC0_PIN PC0
#define ADC1_PIN PC1
#define ADC2_PIN PC2
#define ADC3_PIN PC3
#define ADC4_PIN PC4
#define T1_PIN PD5
#define AIN5_PIN PD6
#define AIN1_PIN PD7
#define T1_DDRX DDRB
#define T1_PORT PORTB
#define INIT_OC1A_PIN() (T1_DDRX |= (1<< OC1A_PIN))
#define INIT_OC1B_PIN() (T1_DDRX |= (1<< OC1B_PIN))
#define SET_T1A_HIGH() (T1_DDRX |= (1<< OC1A_PIN) )
#define SET_T1A_LOW() (T1_DDRX &= ~(1<< OC1A_PIN))
#define CLR_T1_OC1A_PIN() (T1_DDRX &= ~(1<< OC1A_PIN))
#define CLR_T1_OC1B_PIN() (T1_DDRX &= ~(1<< OC1B_PIN))
#define OC2DDRX DDRB
#define OC2PORT PORTB
#define INIT_OC2DIR() ( OC2DDRX |= (1<<OC2_PIN) )
#define SET_OC2_HIGH() ( OC2PORT |= (1<<OC2_PIN) )
#define SET_OC2_LOW() ( OC2PORT &=~(1<<OC2_PIN) )
#define TICK_1000MS 3906 //31250 //122.0703125 8MHz
//#define TICK_1000MS 31250U //122.0703125 8MHz
//#define TICKTIME_FLOAT 3906.25 //31250
//#define FRQ_FLOAT_FAKTOR 0.256 //( 1000.0 / 31250 );
//#define TICK_50MS 1562 // nur ~ungef
#define TICK_25MS 98 //781 // nur ~ungef
//#define TICK_25MS 781U // nur ~ungef
#define PWM_T1_1MS 16000U
#define PWM_T1_MITTE 24000U
#define OCR2_MITTE 127
#define PWM_2MS 32000U
#define INIT_TOGGLE() (DDRB |= (1<< PB2)) // TOGGLE
#define TOGGLE_LED() (PORTB ^= (1<< PB2))
#define TOGGLE_LED_OFF() (PORTB &= ~(1<< PB2))
#define TICK_EVENT 0x01
#define ORDER_EVENT 0x02
#define STATUS_TRAFFIC_FLAG 0x04
#define TOGGLE_FLAG 0x08
#define FRQ_MEASURE_ACTIVE_FLAG 0x20
#define FRQ_MEASURE_READY_FLAG 0x40
//volatile uint8_t gu8Status;
extern volatile uint8_t gu8Status;
#endif //MAIN_HEADER
TxtFun.c
#include <ctype.h>
#include <inttypes.h>
#include <avr\io.h>
#include <avr\pgmspace.h> // <--#include <progmem.h>
#include <string.h>
//#include <math.h>
#include <stdlib.h>
#include "main.h"
#include "uart328.h"
#include "TxtFunc.h"
#ifdef UART_USE_ENABLED
// GLOBALE VARIABLEN
char* gpcRxPars;
char gcaRxStr[RX_STRMAX + 1]; //+1 for the 0
char gcaNumStr[NUMMAX + 1]; //+1 for the 0
char gcaStr[STRMAX + 1]; //+1 for the 0
COMMAND_TYPE gsCmd;
//Funktionen Definition
// *******************************************************************
void UART_TXRX_Check(void)
/*
* Get received character from ringbuffer
* uart_getc() returns in the lower byte the received character and
* in the higher byte (bitmask) the last receive error
* UART_NO_DATA is returned when no data is available.
*/
// *******************************************************************
{
uint16_t uiRxUart;
if( gu8Status & ORDER_EVENT )
{
return;
};
uiRxUart = uart_getc();//!FETCH ALLWAYS BYTE FROM RX RINGBUFF INTERRUPT!
if ( !(uiRxUart & UART_NO_DATA) ) //0x0100
{
// * new data available from UART
// * check for Frame or Overrun error
#ifdef USE_ERROR_MSG
if ( uiRxUart & (UART_FRAME_ERROR | UART_OVERRUN_ERROR | UART_BUFFER_OVERFLOW) )
{
ResetRxBuff();
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU) );// !! Init UART interface
// Framing Error detected, i.e no stop bit detected
Print_PStrCR( PSTR("UartErr") );
};
#endif
//NOW SELCT ACTION FROM ORDER
//Check CR
uiRxUart &= 0xFF;
if( (uiRxUart < 13) || (uiRxUart > 122) ){return;};
if(gpcRxPars < (gcaRxStr + RX_STRMAX)) //ENDANSCHLAG ERREICHT ?
{
if(uiRxUart == 13)
{
gu8Status |= ORDER_EVENT;
}
else
{
// Accumulate String only to gcaRxStr with uiAAA Parser
*gpcRxPars++ = uiRxUart;//Append rxByte
*gpcRxPars = 0; //ZERO carry
};//switch
}// if (pcRxPars < (gcaRxStr + RXSTRMAX))
else // To much data Rx, than clear simple all
{
//overflow of RX clears all
ResetRxBuff(); // Clear Rx Parspointer in Buff an terminate RxStr with 0
};//if(gpcRxPars < (gcaRxStr + RXSTRMAX))
// ENDE DER RX EMPFANGSAUSWERTUNG
};
};
// *******************************************************************
void ResetRxBuff(void)
// *******************************************************************
{
gpcRxPars = gcaRxStr; // Set parse pointer back;
*gpcRxPars = 0; //clear Rx
//uart_flush();
gu8Status &= ~ORDER_EVENT;
};
// *******************************************************************
void TokensRXStr(char *pcStrOrder) //von gcaRxStr
// *******************************************************************
{ //INPUT ERWARTET INDER FOR "BEFEHL,WERT" BSP: "SFR,1000"
//uint16_t uiCnt =0;
char caDelimiter[]=",";
char * pStrTok; // für strtok_r
char * pucCh = &pcStrOrder[ strlen(pcStrOrder) ]; // Stelle POINTER auf \0 Ende // kein unsigned char*
if( (pStrTok = strtok_r( pcStrOrder, caDelimiter , &pucCh)) != NULL) // Trenne 1.Token in Command
{
strcpy(gsCmd.ucaCmd, pStrTok);
}
else
{
*gsCmd.ucaCmd = 0;
};
gsCmd.ucaCmd[ COMAMNDSIZEMAX ] = 0; //Sicherheitsterminierung COMAMNDSIZEMAX=10
//für 2 fVal Variablen nach dem Kommando
//gsCmd.ixCmdVal_1 = gsCmd.ixCmdVal_2 = 0;
//gsCmd.CmdVal_1 = gsCmd.ixCmdVal_2 = 0;
if( (pStrTok = strtok_r( NULL, caDelimiter, &pucCh)) != NULL)
{
gsCmd.ixCmdVal_1 = atol(pStrTok);// Und dann TO Float
};
if( (pStrTok = strtok_r( NULL, caDelimiter, &pucCh)) != NULL)
{
// gsCmd.ixCmdVal_2 = atof(pStrTok);// Und dann TO Float
gsCmd.ixCmdVal_2 = atol(pStrTok);// Und dann TO Float
};
};
#define FLOAT_PRAEDIGITS_MAX 6 // DIgits nach //dtostrf(fVal,NUMMAX, DIGITS_MAX, gcaNumStr);
#define FLOAT_DIGITS_MAX 3 // DIgits nach //dtostrf(fVal,NUMMAX, DIGITS_MAX, gcaNumStr);
// *******************************************************************
void PrintCR(void)
// *******************************************************************
{
uart_putc( 13 );
};
// ****************
void CRLF(void)
// ****************
{
uart_putc(13);
uart_putc(10);
};
// *******************************************************************
void PrintStrCR(const char* pStr)
// *******************************************************************
{
uart_puts(pStr);
PrintCR();
};
// *******************************************************************
void Print_PStrCR(PGM_P pmStr)
// *******************************************************************
{
uart_puts_p(pmStr);
PrintCR();
};
// **********************************************
void FloatToNumStr(double fVal)
// *************
{
dtostrf(fVal, FLOAT_PRAEDIGITS_MAX, FLOAT_DIGITS_MAX, gcaNumStr ); //[-]d.ddd
};
// **********************************************
void LongToNumStr(int32_t lVal)
// **********************************************
{
ltoa(lVal, gcaNumStr, 10 );
};
// **********************************************
void ULongToNumStr(uint32_t ulVal)
// **********************************************
{
ultoa(ulVal, gcaNumStr, 10 );
};
// *******************************************************************
void PrintLongCR(int32_t lVal)
// *******************************************************************
{
LongToNumStr(lVal); PrintStrCR(gcaNumStr);
};
// *******************************************************************
void PrintULongCR(uint32_t ulVal)
// *******************************************************************
{
ULongToNumStr(ulVal); PrintStrCR(gcaNumStr);
};
// *******************************************************************
void PrintFloatCR(double fVal)
// *******************************************************************
{
FloatToNumStr(fVal); PrintStrCR(gcaNumStr);
};
#endif //UART_USE_ENABLED
txtFunc.h
#ifndef TXTFUNC_HEADER
#define TXTFUNC_HEADER
#define UART_USE_ENABLED
#ifdef UART_USE_ENABLED
#define STRMAX 64
#define NUMMAX 32
#define RX_STRMAX 32
#define COMAMNDSIZEMAX 32
#define DELIMITER ','
#define DELIMITERSTR ","
#define ASC_CR 13
#define ASC_LF 10
// TYPEN DEKLARATION
typedef struct
{
char ucaCmd[COMAMNDSIZEMAX +1];
int32_t ixCmdVal_1;
int32_t ixCmdVal_2;
//uint8_t ucCmdID;
}COMMAND_TYPE;
// GLOBALE VARIABLEN
// const char MCA_DELIMITER_MSG[] PROGMEM = ",";
extern char* gpcRxPars;
extern char gcaRxStr[RX_STRMAX + 1]; //+1 for the 0
extern char gcaNumStr[NUMMAX + 1]; //+1 for the 0
extern char gcaStr[STRMAX + 1]; //+1 for the 0
extern COMMAND_TYPE gsCmd;
// PROTOTYPEN
//Funktions Deklaration
extern void ResetRxBuff(void);
extern void UART_TXRX_Check(void);
extern void TokensRXStr(char *pcStrOrder); //von gcaRxStr
extern void CRLF(void);
extern void PrintCR(void);
extern void PrintStrCR(const char * pStr);
extern void Print_PStrCR(PGM_P pmStr);
extern void CheckOrder(char * pcStr);
extern void LongToNumStr(int32_t lVal);
extern void ULongToNumStr(uint32_t ulVal);
extern void PrintLongCR(int32_t lVal);
extern void PrintULongCR(uint32_t ulVal);
extern void FloatToNumStr(double fVal);
#endif //UART_USE_ENABLED
#endif // TXTFUNC_HEADER
uart328.c
// Christof Ermer 2.2.2015 MODIFIZIERT PGM_P Pointer bei uart_puts_p
//SREG = u8Sreg; 5.2016
/*************************************************************************
Title: Interrupt UART library with receive/transmit circular buffers
Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
File: $Id: uart.c,v 1.6.2.1 2007/07/01 11:14:38 peter Exp $
Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher
Hardware: any AVR with built-in UART,
License: GNU General Public License
DESCRIPTION:
An interrupt is generated when the UART has finished transmitting or
receiving a byte. The interrupt handling routines use circular buffers
for buffering received and transmitted data.
The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define
the buffer size in bytes. Note that these variables must be a
power of 2.
USAGE:
Refere to the header file uart.h for a description of the routines.
See also example test_uart.c.
NOTES:
Based on Atmel Application Note AVR306
LICENSE:
Copyright (C) 2006 Peter Fleury
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*************************************************************************/
/************************************************************************
uart_available, uart_flush, uart1_available, and uart1_flush functions
were adapted from the Arduino HardwareSerial.h library by Tim Sharpe on
11 Jan 2009. The license info for HardwareSerial.h is as follows:
HardwareSerial.cpp - Hardware serial library for Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
************************************************************************/
/************************************************************************
Changelog for modifications made by Tim Sharpe, starting with the current
library version on his Web site as of 05/01/2009.
Date Description
=========================================================================
05/11/2009 Changed all existing UARTx_RECEIVE_INTERRUPT and UARTx_TRANSMIT_INTERRUPT
macros to use the "_vect" format introduced in AVR-Libc
v1.4.0. Had to split the 3290 and 6490 out of their existing
macro due to an inconsistency in the UART0_RECEIVE_INTERRUPT
vector name (seems like a typo: USART_RX_vect for the 3290/6490
vice USART0_RX_vect for the others in the macro).
Verified all existing macro register names against the device
header files in AVR-Libc v1.6.6 to catch any inconsistencies.
05/12/2009 Added support for 48P, 88P, 168P, and 328P by adding them to the
existing 48/88/168 macro.
Added Arduino-style available() and flush() functions for both
supported
UARTs. Really wanted to keep them out of the library, so
that it would be as close as possible to Peter Fleury's original
library, but has scoping issues accessing internal variables from
another program. Go C!
05/13/2009 Changed Interrupt Service Routine label from the old "SIGNAL" to
the "ISR" format introduced in AVR-Libc v1.4.0.
************************************************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "uart328.h"
/*
* constants and macros
*/
/* size of RX/TX buffers */
#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1)
#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1)
#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
#error RX buffer size is not a power of 2
#endif
#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )
#error TX buffer size is not a power of 2
#endif
#if defined(__AVR_AT90S2313__) \
|| defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \
|| defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \
|| defined(__AVR_ATmega103__)
/* old AVR classic or ATmega103 with one UART */
#define AT90_UART
#define UART0_RECEIVE_INTERRUPT UART_RX_vect
#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect
#define UART0_STATUS USR
#define UART0_CONTROL UCR
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__)
/* old AVR classic with one UART */
#define AT90_UART
#define UART0_RECEIVE_INTERRUPT UART_RX_vect
#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \
|| defined(__AVR_ATmega323__)
/* ATmega with one USART */
#define ATMEGA_USART
#define UART0_RECEIVE_INTERRUPT USART_RXC_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#elif defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__)
/* ATmega with one USART */
#define ATMEGA_USART
#define UART0_RECEIVE_INTERRUPT USART_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#elif defined(__AVR_ATmega163__)
/* ATmega163 with one UART */
#define ATMEGA_UART
#define UART0_RECEIVE_INTERRUPT UART_RX_vect
#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#elif defined(__AVR_ATmega162__)
/* ATmega with two USART */
#define ATMEGA_USART0
#define ATMEGA_USART1
#define UART0_RECEIVE_INTERRUPT USART0_RXC_vect
#define UART1_RECEIVE_INTERRUPT USART1_RXC_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART1_STATUS UCSR1A
#define UART1_CONTROL UCSR1B
#define UART1_DATA UDR1
#define UART1_UDRIE UDRIE1
#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
/* ATmega with two USART */
#define ATMEGA_USART0
#define ATMEGA_USART1
#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
#define UART1_RECEIVE_INTERRUPT USART1_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART1_STATUS UCSR1A
#define UART1_CONTROL UCSR1B
#define UART1_DATA UDR1
#define UART1_UDRIE UDRIE1
#elif defined(__AVR_ATmega161__)
/* ATmega with UART */
#error "AVR ATmega161 currently not supported by this libaray !"
#elif defined(__AVR_ATmega169__)
/* ATmega with one USART */
#define ATMEGA_USART
#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#elif defined(__AVR_ATmega48__) ||defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega48P__) ||defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || \
defined(__AVR_ATmega328P__)
/* TLS-Added 48P/88P/168P/328P */
/* ATmega with one USART */
#define ATMEGA_USART0
#define UART0_RECEIVE_INTERRUPT USART_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#elif defined(__AVR_ATtiny2313__)
#define ATMEGA_USART
#define UART0_RECEIVE_INTERRUPT USART_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#elif defined(__AVR_ATmega329__) ||\
defined(__AVR_ATmega649__) ||\
defined(__AVR_ATmega325__) ||defined(__AVR_ATmega3250__) ||\
defined(__AVR_ATmega645__) ||defined(__AVR_ATmega6450__)
/* ATmega with one USART */
#define ATMEGA_USART0
#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#elif defined(__AVR_ATmega3290__) ||\
defined(__AVR_ATmega6490__) ||
/* TLS-Separated these two from the previous group because of inconsistency in the USART_RX */
/* ATmega with one USART */
#define ATMEGA_USART0
#define UART0_RECEIVE_INTERRUPT USART_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega640__)
/* ATmega with two USART */
#define ATMEGA_USART0
#define ATMEGA_USART1
#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
#define UART1_RECEIVE_INTERRUPT USART0_UDRE_vect
#define UART0_TRANSMIT_INTERRUPT USART1_RX_vect
#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART1_STATUS UCSR1A
#define UART1_CONTROL UCSR1B
#define UART1_DATA UDR1
#define UART1_UDRIE UDRIE1
#elif defined(__AVR_ATmega644__)
/* ATmega with one USART */
#define ATMEGA_USART0
#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__)
/* ATmega with two USART */
#define ATMEGA_USART0
#define ATMEGA_USART1
#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
#define UART1_RECEIVE_INTERRUPT USART0_UDRE_vect
#define UART0_TRANSMIT_INTERRUPT USART1_RX_vect
#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART1_STATUS UCSR1A
#define UART1_CONTROL UCSR1B
#define UART1_DATA UDR1
#define UART1_UDRIE UDRIE1
#else
#error "no UART definition for MCU available"
#endif
/*
* module global variables
*/
static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
static volatile unsigned char UART_TxHead;
static volatile unsigned char UART_TxTail;
static volatile unsigned char UART_RxHead;
static volatile unsigned char UART_RxTail;
static volatile unsigned char UART_LastRxError;
#if defined( ATMEGA_USART1 )
static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE];
static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE];
static volatile unsigned char UART1_TxHead;
static volatile unsigned char UART1_TxTail;
static volatile unsigned char UART1_RxHead;
static volatile unsigned char UART1_RxTail;
static volatile unsigned char UART1_LastRxError;
#endif
ISR(UART0_RECEIVE_INTERRUPT)
/*************************************************************************
Function: UART Receive Complete interrupt
Purpose: called when the UART has received a character
**************************************************************************/
{
uint8_t u8Sreg = SREG;
unsigned char tmphead;
unsigned char data;
unsigned char usr;
unsigned char lastRxError;
/* read UART status register and UART data register */
usr = UART0_STATUS;
data = UART0_DATA;
/* */
#if defined( AT90_UART )
lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
#elif defined( ATMEGA_USART )
lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
#elif defined( ATMEGA_USART0 )
lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) );
#elif defined ( ATMEGA_UART )
lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
#endif
/* calculate buffer index */
tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;
if ( tmphead == UART_RxTail ) {
/* error: receive buffer overflow */
lastRxError = UART_BUFFER_OVERFLOW >> 8;
}else{
/* store new index */
UART_RxHead = tmphead;
/* store received data in buffer */
UART_RxBuf[tmphead] = data;
}
UART_LastRxError = lastRxError;
SREG = u8Sreg;
}
ISR(UART0_TRANSMIT_INTERRUPT)
/*************************************************************************
Function: UART Data Register Empty interrupt
Purpose: called when the UART is ready to transmit the next byte
**************************************************************************/
{
uint8_t u8Sreg = SREG;
unsigned char tmptail;
if ( UART_TxHead != UART_TxTail) {
/* calculate and store new buffer index */
tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
UART_TxTail = tmptail;
/* get one byte from buffer and write it to UART */
UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */
}else{
/* tx buffer empty, disable UDRE interrupt */
UART0_CONTROL &= ~_BV(UART0_UDRIE);
}
SREG = u8Sreg;
}
/*************************************************************************
Function: uart_init()
Purpose: initialize UART and set baudrate
Input: baudrate using macro UART_BAUD_SELECT()
Returns: none
**************************************************************************/
void uart_init(unsigned int baudrate)
{
UART_TxHead = 0;
UART_TxTail = 0;
UART_RxHead = 0;
UART_RxTail = 0;
#if defined( AT90_UART )
/* set baud rate */
UBRR = (unsigned char)baudrate;
/* enable UART receiver and transmmitter and receive complete interrupt */
UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN);
#elif defined (ATMEGA_USART)
/* Set baud rate */
if ( baudrate & 0x8000 )
{
UART0_STATUS = (1<<U2X); //Enable 2x speed
baudrate &= ~0x8000;
}
UBRRH = (unsigned char)(baudrate>>8);
UBRRL = (unsigned char) baudrate;
/* Enable USART receiver and transmitter and receive complete interrupt */
UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
/* Set frame format: asynchronous, 8data, no parity, 1stop bit */
#ifdef URSEL
UCSRC = (1<<URSEL)|(3<<UCSZ0);
#else
UCSRC = (3<<UCSZ0);
#endif
#elif defined (ATMEGA_USART0 )
/* Set baud rate */
if ( baudrate & 0x8000 )
{
UART0_STATUS = (1<<U2X0); //Enable 2x speed
baudrate &= ~0x8000;
}
UBRR0H = (unsigned char)(baudrate>>8);
UBRR0L = (unsigned char) baudrate;
/* Enable USART receiver and transmitter and receive complete interrupt */
UART0_CONTROL = _BV(RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
/* Set frame format: asynchronous, 8data, no parity, 1stop bit */
#ifdef URSEL0
UCSR0C = (1<<URSEL0)|(3<<UCSZ00);
#else
UCSR0C = (3<<UCSZ00);
#endif
#elif defined ( ATMEGA_UART )
/* set baud rate */
if ( baudrate & 0x8000 )
{
UART0_STATUS = (1<<U2X); //Enable 2x speed
baudrate &= ~0x8000;
}
UBRRHI = (unsigned char)(baudrate>>8);
UBRR = (unsigned char) baudrate;
/* Enable UART receiver and transmitter and receive complete interrupt */
UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
#endif
}/* uart_init */
/*************************************************************************
Function: uart_getc()
Purpose: return byte from ringbuffer
Returns: lower byte: received byte from ringbuffer
higher byte: last receive error
**************************************************************************/
unsigned int uart_getc(void)
{
unsigned char tmptail;
unsigned char data;
if ( UART_RxHead == UART_RxTail ) {
return UART_NO_DATA; /* no data available */
}
/* calculate /store buffer index */
tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
UART_RxTail = tmptail;
/* get data from receive buffer */
data = UART_RxBuf[tmptail];
return (UART_LastRxError << 8) + data;
}/* uart_getc */
/*************************************************************************
Function: uart_putc()
Purpose: write byte to ringbuffer for transmitting via UART
Input: byte to be transmitted
Returns: none
**************************************************************************/
void uart_putc(unsigned char data)
{
unsigned char tmphead;
tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
while ( tmphead == UART_TxTail ){
;/* wait for free space in buffer */
}
UART_TxBuf[tmphead] = data;
UART_TxHead = tmphead;
/* enable UDRE interrupt */
UART0_CONTROL |= _BV(UART0_UDRIE);
}/* uart_putc */
/*************************************************************************
Function: uart_puts()
Purpose: transmit string to UART
Input: string to be transmitted
Returns: none
**************************************************************************/
void uart_puts(const char *s )
{
while (*s)
uart_putc(*s++);
}/* uart_puts */
/*************************************************************************
Function: uart_puts_p()
Purpose: transmit string from program memory to UART
Input: program memory string to be transmitted
Returns: none
**************************************************************************/
//void uart_puts_p(const char *progmem_s )
void uart_puts_p(PGM_P progmem_s )
{
register char c;
while ( (c = pgm_read_byte(progmem_s++)) )
uart_putc(c);
}/* uart_puts_p */
/*************************************************************************
Function: uart_available()
Purpose: Determine the number of bytes waiting in the receive buffer
Input: None
Returns: Integer number of bytes in the receive buffer
**************************************************************************/
int uart_available(void)
{
return (UART_RX_BUFFER_MASK + UART_RxHead - UART_RxTail) % UART_RX_BUFFER_MASK;
}/* uart_available */
/*************************************************************************
Function: uart_flush()
Purpose: Flush bytes waiting the receive buffer. Acutally ignores them.
Input: None
Returns: None
**************************************************************************/
void uart_flush(void)
{
UART_RxHead = UART_RxTail;
}/* uart_flush */
/*
* these functions are only for ATmegas with two USART
*/
#if defined( ATMEGA_USART1 )
SIGNAL(UART1_RECEIVE_INTERRUPT)
/*************************************************************************
Function: UART1 Receive Complete interrupt
Purpose: called when the UART1 has received a character
**************************************************************************/
{
unsigned char tmphead;
unsigned char data;
unsigned char usr;
unsigned char lastRxError;
/* read UART status register and UART data register */
usr = UART1_STATUS;
data = UART1_DATA;
/* */
lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) );
/* calculate buffer index */
tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK;
if ( tmphead == UART1_RxTail ) {
/* error: receive buffer overflow */
lastRxError = UART_BUFFER_OVERFLOW >> 8;
}else{
/* store new index */
UART1_RxHead = tmphead;
/* store received data in buffer */
UART1_RxBuf[tmphead] = data;
}
UART1_LastRxError = lastRxError;
}
SIGNAL(UART1_TRANSMIT_INTERRUPT)
/*************************************************************************
Function: UART1 Data Register Empty interrupt
Purpose: called when the UART1 is ready to transmit the next byte
**************************************************************************/
{
unsigned char tmptail;
if ( UART1_TxHead != UART1_TxTail) {
/* calculate and store new buffer index */
tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK;
UART1_TxTail = tmptail;
/* get one byte from buffer and write it to UART */
UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */
}else{
/* tx buffer empty, disable UDRE interrupt */
UART1_CONTROL &= ~_BV(UART1_UDRIE);
}
}
/*************************************************************************
Function: uart1_init()
Purpose: initialize UART1 and set baudrate
Input: baudrate using macro UART_BAUD_SELECT()
Returns: none
**************************************************************************/
void uart1_init(unsigned int baudrate)
{
UART1_TxHead = 0;
UART1_TxTail = 0;
UART1_RxHead = 0;
UART1_RxTail = 0;
/* Set baud rate */
if ( baudrate & 0x8000 )
{
UART1_STATUS = (1<<U2X1); //Enable 2x speed
baudrate &= ~0x8000;
}
UBRR1H = (unsigned char)(baudrate>>8);
UBRR1L = (unsigned char) baudrate;
/* Enable USART receiver and transmitter and receive complete interrupt */
UART1_CONTROL = _BV(RXCIE1)|(1<<RXEN1)|(1<<TXEN1);
/* Set frame format: asynchronous, 8data, no parity, 1stop bit */
#ifdef URSEL1
UCSR1C = (1<<URSEL1)|(3<<UCSZ10);
#else
UCSR1C = (3<<UCSZ10);
#endif
}/* uart_init */
/*************************************************************************
Function: uart1_getc()
Purpose: return byte from ringbuffer
Returns: lower byte: received byte from ringbuffer
higher byte: last receive error
**************************************************************************/
unsigned int uart1_getc(void)
{
unsigned char tmptail;
unsigned char data;
if ( UART1_RxHead == UART1_RxTail ) {
return UART_NO_DATA; /* no data available */
}
/* calculate /store buffer index */
tmptail = (UART1_RxTail + 1) & UART_RX_BUFFER_MASK;
UART1_RxTail = tmptail;
/* get data from receive buffer */
data = UART1_RxBuf[tmptail];
return (UART1_LastRxError << 8) + data;
}/* uart1_getc */
/*************************************************************************
Function: uart1_putc()
Purpose: write byte to ringbuffer for transmitting via UART
Input: byte to be transmitted
Returns: none
**************************************************************************/
void uart1_putc(unsigned char data)
{
unsigned char tmphead;
tmphead = (UART1_TxHead + 1) & UART_TX_BUFFER_MASK;
while ( tmphead == UART1_TxTail ){
;/* wait for free space in buffer */
}
UART1_TxBuf[tmphead] = data;
UART1_TxHead = tmphead;
/* enable UDRE interrupt */
UART1_CONTROL |= _BV(UART1_UDRIE);
}/* uart1_putc */
/*************************************************************************
Function: uart1_puts()
Purpose: transmit string to UART1
Input: string to be transmitted
Returns: none
**************************************************************************/
void uart1_puts(const char *s )
{
while (*s)
uart1_putc(*s++);
}/* uart1_puts */
/*************************************************************************
Function: uart1_puts_p()
Purpose: transmit string from program memory to UART1
Input: program memory string to be transmitted
Returns: none
**************************************************************************/
void uart1_puts_p(const char *progmem_s )
{
register char c;
while ( (c = pgm_read_byte(progmem_s++)) )
uart1_putc(c);
}/* uart1_puts_p */
/*************************************************************************
Function: uart1_available()
Purpose: Determine the number of bytes waiting in the receive buffer
Input: None
Returns: Integer number of bytes in the receive buffer
**************************************************************************/
int uart1_available(void)
{
return (UART_RX_BUFFER_MASK + UART1_RxHead - UART1_RxTail) % UART_RX_BUFFER_MASK;
}/* uart1_available */
/*************************************************************************
Function: uart1_flush()
Purpose: Flush bytes waiting the receive buffer. Acutally ignores them.
Input: None
Returns: None
**************************************************************************/
void uart1_flush(void)
{
UART1_RxHead = UART1_RxTail;
}/* uart1_flush */
#endif
uart328.h
#ifndef UART_H
#define UART_H
/************************************************************************
Title: Interrupt UART library with receive/transmit circular buffers
Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
File: $Id: uart.h,v 1.8.2.1 2007/07/01 11:14:38 peter Exp $
Software: AVR-GCC 4.1, AVR Libc 1.4
Hardware: any AVR with built-in UART, tested on AT90S8515 & ATmega8 at 4 Mhz
License: GNU General Public License
Usage: see Doxygen manual
LICENSE:
Copyright (C) 2006 Peter Fleury
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
************************************************************************/
/************************************************************************
uart_available, uart_flush, uart1_available, and uart1_flush functions
were adapted from the Arduino HardwareSerial.h library by Tim Sharpe on
11 Jan 2009. The license info for HardwareSerial.h is as follows:
HardwareSerial.h - Hardware serial library for Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
************************************************************************/
/************************************************************************
Changelog for modifications made by Tim Sharpe, starting with the current
library version on his Web site as of 05/01/2009.
Date Description
=========================================================================
05/12/2009 Added Arduino-style available() and flush() functions for both
supported
UARTs. Really wanted to keep them out of the library, so
that it would be as close as possible to Peter Fleury's original
library, but has scoping issues accessing internal variables from
another program. Go C!
************************************************************************/
/**
* @defgroup pfleury_uart UART Library
* @code #include <uart.h> @endcode
*
* @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers.
*
* This library can be used to transmit and receive data through the built in UART.
*
* An interrupt is generated when the UART has finished transmitting or
* receiving a byte. The interrupt handling routines use circular buffers
* for buffering received and transmitted data.
*
* The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define
* the size of the circular buffers in bytes. Note that these constants must be a power of 2.
* You may need to adapt this constants to your target and your application by adding
* CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_RX_BUFFER_SIZE=nn to your Makefile.
*
* @note Based on Atmel Application Note AVR306
* @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury
*/
/**@{*/
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
#endif
/*
** constants and macros
*/
/** @brief UART Baudrate Expression
* @param xtalcpu system clock in Mhz, e.g.
4000000L for 4Mhz
* @param baudrate baudrate in bps, e.g. 1200, 2400, 9600
*/
#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1)
/** @brief UART Baudrate Expression for ATmega double speed mode
* @param xtalcpu system clock in Mhz, e.g.
4000000L for
4Mhz
* @param baudrate baudrate in bps, e.g. 1200, 2400, 9600
*/
#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/((baudRate)*8l)-1)|0x8000)
/** Size of the circular receive buffer, must be power of 2 */
#ifndef UART_RX_BUFFER_SIZE
#define UART_RX_BUFFER_SIZE 128
#endif
/** Size of the circular transmit buffer, must be power of 2 */
#ifndef UART_TX_BUFFER_SIZE
#define UART_TX_BUFFER_SIZE 128
#endif
/* test if the size of the circular buffers fits into SRAM */
#if ( (UART_RX_BUFFER_SIZE+UART_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) )
#error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM"
#endif
/*
** high byte error return code of uart_getc()
*/
#define UART_FRAME_ERROR
0x0800
/* Framing Error by UART */
#define UART_OVERRUN_ERROR
0x0400
/* Overrun condition by UART */
#define UART_BUFFER_OVERFLOW
0x0200
/* receive ringbuffer overflow */
#define
UART_NO_DATA
0x0100
/* no receive data available */
/*
** function prototypes
*/
/**
@brief Initialize UART and set baudrate
@param baudrate Specify baudrate using macro UART_BAUD_SELECT()
@return none
*/
extern void uart_init(unsigned int baudrate);
/**
* @brief Get received byte from ringbuffer
*
* Returns in the lower byte the received character and in the
* higher byte the last receive error.
* UART_NO_DATA is returned when no data is available.
*
* @param void
* @return lower byte: received byte from ringbuffer
* @return higher byte: last receive status
* - \b 0 successfully received data from UART
* -
\b
UART_NO_DATA
* <br>no receive data available
* - \b UART_BUFFER_OVERFLOW
* <br>Receive ringbuffer overflow.
*
We are not reading the receive buffer fast enough,
*
one or more received character have been dropped
* - \b UART_OVERRUN_ERROR
* <br>Overrun condition by UART.
*
A character already present in the UART UDR register was
*
not read by the interrupt handler before the next character arrived,
*
one or more received characters have been dropped.
* - \b UART_FRAME_ERROR
* <br>Framing Error by UART
*/
extern unsigned int uart_getc(void);
/**
* @brief Put byte to ringbuffer for transmitting via UART
* @param data byte to be transmitted
* @return none
*/
extern void uart_putc(unsigned char data);
/**
* @brief Put string to ringbuffer for transmitting via UART
*
* The string is buffered by the uart library in a circular buffer
* and one character at a time is transmitted to the UART using interrupts.
* Blocks if it can not write the whole string into the circular buffer.
*
* @param s string to be transmitted
* @return none
*/
extern void uart_puts(const char *s );
/**
* @brief Put string from program memory to ringbuffer for transmitting via UART.
*
* The string is buffered by the uart library in a circular buffer
* and one character at a time is transmitted to the UART using interrupts.
* Blocks if it can not write the whole string into the circular buffer.
*
* @param s program memory string to be transmitted
* @return none
* @see uart_puts_P
*/
//extern void uart_puts_p(const char *s );
extern void uart_puts_p(PGM_P s );
/**
* @brief Macro to automatically put a string constant into program memory
*/
#define uart_puts_P(__s) uart_puts_p(PSTR(__s))
/**
* @brief Return number of bytes waiting in the receive buffer
* @param none
* @return bytes waiting in the receive buffer
*/
extern int uart_available(void);
/**
* @brief Flush bytes waiting in receive buffer
* @param none
* @return none
*/
extern void uart_flush(void);
/** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */
extern void uart1_init(unsigned int baudrate);
/** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */
extern unsigned int uart1_getc(void);
/** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */
extern void uart1_putc(unsigned char data);
/** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */
extern void uart1_puts(const char *s );
/** @brief Put string from program memory to ringbuffer for
transmitting via USART1 (only available on selected ATmega) @see
uart_puts_p */
extern void uart1_puts_p(const char *s );
/** @brief Macro to automatically put a string constant into program memory */
#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s))
/** @brief Return number of bytes waiting in the receive buffer */
extern int uart1_available(void);
/** @brief Flush bytes waiting in receive buffer */
extern void uart1_flush(void);
/**@}*/
#endif // UART_H