Code:
/* T E S T P R O G R A M M (USART+EEPROM)
* ---------------------------------------
*
* Dieses Testprogramm (geschrieben für ATTiny2313) empfängt und sendet Zeichen über die
* RS232-Schnittstelle (UART/USART) und ermöglicht die folgenden Funktionen:
*
* SW0 (Taster 0, bei mir an PIND2): empfangene Zeichen im EEPROM speichern
*
* SW1 (Taster 1, bei mir an PIND3): gespeicherte Zeichen wieder auslesen und ans Terminal senden
*
* SW2 (Taster 2, bei mir an PIND4): Anzahl aktuell eingelesener Zeichen ans Terminal senden
*
* SW3 (Taster 3, bei mir an PIND5): freien Speicher (SRAM) ans Terminal senden
*
* Zum Testen dieses Programm benötigt man ein Terminal-Programm (ich nutze HTerm), mit dem man
* Daten zum AVR schicken und von ihm empfangen kann.
*
* Wenn das Terminal-Programm verbunden ist, sieht man, dass kontinuierlich ein Punkt ('.') gesendet
* wird. Dies ist als Lebenszeichen des AVR zu verstehen. Bricht der Datenstrom plötzlich ab, ist
* das Programm wahrscheinlich hängengeblieben (z.B. wegen Speicherüberlauf o.ä.).
*
* Da das SRAM in seiner Größe sehr beschränkt ist (beim ATTiny2313 nur 128 Bytes), habe ich eine
* maximale Größe für den empfangenen String festgelegt. Sie kann über IUSART_INP_MAX geändert werden.
*
* Das Beschreiben des EEPROM ist in der Hinsicht kritisch, als dass der Speicher nur
* ca. 100000 mal beschreibbar ist. Deshalb ist es nicht sinnvoll, jedesmal wieder ab
* Byte 0 zu schreiben. Deshalb habe ich die Funktionen eeprom_get_last_byte() und
* eeprom_get_first_written_byte() geschrieben. Mithilfe dieser Funktionen kann man so
* navigieren, dass das EEPROM kontinuierlich beschrieben wird, so dass alle Bytes
* gleichmäßig beansprucht werden und die Lebensdauer deutlich erhöht wird. Erreicht man
* das Ende des EEPROM (beim ATTiny2313 128 Bytes, änderbar über EEPROM_MAX_BYTE), so
* beginnt man wieder bei Byte 0, wobei ein String auch überlappen kann (z.B. ein
* 5-Zeichen-String in den Bytes 126, 127, 0, 1 und 2).
*
* Bei meinem Testboard (STK500) habe ich die Taster nicht nach Standardkonfiguration angeschlossen,
* wie oben an der Funktionsübersicht zu sehen ist (SW0 auf PIND2 statt PIND0 usw.). Wer ganz normal
* SW0 an PIND0 hat, muss lediglich diese wenigen Stellen im Code abändern.
*
* Beispiel:
* ---------
*
* if( !(PIND & (1<<PIND3)) && iUSART_inp>0 && cBoolSaved) { //SW1 gedrückt
* -
* ändern in
*
* if( !(PIND & (1<<PIND1)) && iUSART_inp>0 && cBoolSaved) { //SW1 gedrückt
* -
*
* Tipp: Wer HTerm benutzt, sollte in der oberen Ansicht (vom AVR gesendete Zeichen) nur die ASCII-
* Ausgabe zulassen (also Häkchen weg bei Hex, Dec und Bin). So behält man den Überblick.
*
*
* Wer (wie ich gerade) in die AVR-Programmierung einsteigt und an der Kommunikation zwischen AVR
* und PC sowie am Beschreiben des EEPROM interessiert ist, wird vielleicht (hoffentlich) mithilfe
* dieses Programms weiterkommen.
*
*
* Matthias Marschhausen (2007-07-20)
*
*/
#ifndef F_CPU
#define F_CPU 4000000
#endif
#ifndef UART_BAUD_RATE
#define UART_BAUD_RATE 9600
#endif
//
#define IUSART_INP_MAX 20 //maximale Anzahl an Zeichen, die vom AVR empfangen werden darf
#define EEPROM_MAX_BYTE 127 //letztes Byte des EEPROM (beim ATTiny2313 128 Byte großer Speicher)
//
extern unsigned char __heap_start;
//
#include <avr/io.h>
#include <stdlib.h>
#include <avr/eeprom.h>
#include <util/delay.h>
/*
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdint.h>
*/
//
//PROTOTYPEN
//----------
void USART_init(unsigned int baud);
void USART_transmit(unsigned char cData);
void USART_transmit_str(char *cStr);
void long_delay_ms( unsigned long ms );
void clearArray(char cArray[],int iMax);
void __attribute__ ((naked, section (".init8"))) __init8_mem (void);
uint8_t eeprom_get_next_byte(uint8_t iLastByte);
uint8_t eeprom_get_first_written_byte(uint8_t iLastByte,uint8_t iWrittenBytes);
//GLOBALE VARIABLEN
//-----------------
uint8_t i = 0;
uint8_t iEEPROM_lastByte = 0;
/***************/
int main(void) {
/***************/
char cUSART_inp[IUSART_INP_MAX]; //Array für das Zwischenspeichern von über USART empfangenen Zeichen
unsigned short iUSART_inp = 0; //Index für das Array cUSART_inp[], entspricht der Anzahl der empfangenen Zeichen
unsigned short iDot = 0; //zum ständigen Senden eines Punktes (als Lebenszeichen)
char cTmpZahl[5] = {0}; //Temp-Variable für Konvertierungen mit itoa()
unsigned char cBoolSaved = 0; //wurden die empfangenen Zeichen im EEPROM gespeichert?
//
DDRB = 0xff; //Port B Pins als Ausgänge definieren
PORTB = 0xff;
//DDRD = 0x00; //Port D Pins als Eingänge definieren. Wohl nicht notwendig, da die Bits standardmäßig sowieso 0 sind
//
USART_init(UART_BAUD_RATE); //USART initialisieren
//
for(;;) { //Endlosschleife (bei AVR-Programmierung gewollt/nötig)
if( ++iDot % 1000 == 0 ) { //alle 1000 Durchläufe einen Punkt ans Terminal senden
USART_transmit('.'); //Punkt senden
iDot = 0; //iTest natürlich zurücksetzen, um einen Überlauf zu verhindern
}
if( iUSART_inp > IUSART_INP_MAX ) { //string wäre zu lang, also alles zurücksetzen
USART_transmit_str(" WARNUNG: >"); //Warnung/Information ans
USART_transmit_str(itoa(IUSART_INP_MAX,cTmpZahl,10)); //Terminal senden
USART_transmit_str(" Zeichen - RESET "); //
clearArray(cUSART_inp,IUSART_INP_MAX); //Array zurücksetzen
iUSART_inp = 0; //Array-Index zurücksetzen
long_delay_ms(500); //kurze Pause...
}
//
if( UCSRA & (1<<RXC) ) { //Zeichen werden empfangen und im char-array gespeichert
//USART_transmit(UDR); //sendet jedes empfangene Zeichen direkt wieder and Terminal
//(kann zum grundsätzlichen Testen der Kommunikation aktiviert werden)
cUSART_inp[++iUSART_inp-1] = UDR; //empfangenes Zeichen im Array speichern
cBoolSaved = 0; //"gespeichert"-Status auf 0 (false) setzen
}
//
if( !(PIND & (1<<PIND2)) && iUSART_inp>0) { //SW0 gedrückt
for(i=0;i<iUSART_inp;i++) {
//char-array (cUSART_inp) in EEPROM speichern
eeprom_write_byte((uint8_t*)(unsigned int)eeprom_get_next_byte(iEEPROM_lastByte),cUSART_inp[i]);
}
//
clearArray(cUSART_inp,IUSART_INP_MAX); //Array zurücksetzen
//
USART_transmit_str(" SAVED "); //damit man was sieht...
cBoolSaved = 1; //"gespeichert"-Status auf 1 (true) setzen
long_delay_ms(500); //kurze Pause...
}
//
if( !(PIND & (1<<PIND3)) && iUSART_inp>0 && cBoolSaved) { //SW1 gedrückt
//
for(i=0;i<iUSART_inp;i++) {
//Inhalt des EEPROM rurück in das char-array schreiben
cUSART_inp[i] = eeprom_read_byte((uint8_t*)(unsigned int)eeprom_get_first_written_byte(iEEPROM_lastByte,iUSART_inp-1-i));
}
//
USART_transmit_str(cUSART_inp); //Array ans Terminal senden
//
iUSART_inp = 0; //Array-Index zurücksetzen
cBoolSaved = 0; //"gespeichert"-Status auf 0 (false) setzen
long_delay_ms(500); //kurze Pause...
}
if( !(PIND & (1<<PIND4)) ) { //SW2 gedrückt: iUSART_inp (Anzahl eingegebener Zeichen) ausgeben
USART_transmit_str(" Anzahl Zeichen: "); //ans Terminal
USART_transmit_str(itoa(iUSART_inp,cTmpZahl,10)); //senden
USART_transmit(32); //
long_delay_ms(500); //kurze Pause...
}
if( !(PIND & (1<<PIND5)) ) { //SW3 gedrückt: freien Speicher (SRAM) ermitteln
USART_transmit_str(" FREE MEM: "); //und ans Terminal senden
USART_transmit_str(itoa(SP - (uint16_t) &__heap_start,cTmpZahl,10));
USART_transmit_str(" Bytes ");
long_delay_ms(500); //kurze Pause...
}
}
//
return(0); //wird nie erreicht, da Endlosschleife...
}
/***************/
void long_delay_ms( volatile unsigned long ms ) {
/***************/
while( ms-- )
_delay_ms( 1 );
}
/***************/
void USART_init(unsigned int baud) { //nochmal genau ansehen und schöner formulieren!
/***************/
/*
UBRRH = (unsigned char)(baud>>8); //Baudrate setzen
UBRRL = (unsigned char)baud; //
//
UCSRB = (1<<RXEN)|(1<<TXEN); //Receiver und Transmitter aktivieren
//
UCSRC = (1<<USBS)|(3<<UCSZ0); //8 Datenbits, 2 Stopbits (?)
*/
UCSRA=0x00;
//UCSRB=0x08;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x17;
//
UCSRB = (1<<RXEN)|(1<<TXEN); //Receiver und Transmitter aktivieren
}
/***************/
void USART_transmit(unsigned char cData) { //sendet ein Zeichen ans Terminal
/***************/
while( !(UCSRA & (1<<UDRE)) ) {
;//warten, bis der transmit buffer leer ist, so dass wieder übertragen werden kann
}
UDR = cData;
}
/***************/
void USART_transmit_str(char *cStr) { //sendet einen String (char-Array) ans Terminal
/***************/
while(*cStr) {
USART_transmit(*cStr++);
}
}
/***************/
void clearArray(char cArray[],int iMax) { //ersetzt alle Werte in einem Array durch binäre Nullen ('\0')
/***************/
for(i=0;i<iMax;i++) {
cArray[i]='\0';
}
}
/***************/
uint8_t eeprom_get_next_byte(uint8_t iLastByte) {
/***************/
uint8_t iNextByte = iLastByte + 1;
//
if(iNextByte > EEPROM_MAX_BYTE) {
iNextByte = 0;
}
//
iEEPROM_lastByte = iNextByte;
return(iNextByte);
}
/***************/
uint8_t eeprom_get_first_written_byte(uint8_t iLastByte,uint8_t iWrittenBytes) {
/***************/
uint8_t iFirstByte;
if( iLastByte - iWrittenBytes < 0 ) {
iFirstByte = EEPROM_MAX_BYTE + iLastByte - iWrittenBytes;
} else {
iFirstByte = iLastByte - iWrittenBytes;
}
return(iFirstByte);
}
Danke nochmal an alle, die mir mit ihren Tipps geholfen haben!
Lesezeichen