EKG
(Schuljahr 2013) Im ersten Schuljahr der Techniker-Ausbildung entstand dieses EKG-Projekt im Rahmen zweier Module. Da in dem unten angehängten *.pdf alles genau beschrieben ist, verzichte ich hier weiter darauf einzugehen.
Es handelt sich um ein gemeinsames Projekt mit meinem Projektpartner: Steffen Sieberger (sieberger.steffen@gmail.com)
PC-Software (benötigt LabView-Runtime)
/*
* EKG.c
*
* Created: 12.11.2013 13:38:26
* Author: Simon Kappes, Steffen Sieberger
*/
//==============================Bibliotheken + CPU-Takt Definition==============================
#define F_CPU 3686400 //µC-Takt definiern
#include <avr\io.h> //Registernamen
#include <avr/interrupt.h> //Interrupts
#include <stdint.h> //Datentypen
//==============================Globale Vaiablen==============================
unsigned char UARTDatenEmpfangen = 1; //1 = String wurde vom PC komplett empfangen + 0 = Freigabe zum Empfang eines weiteren Strings
volatile uint8_t SteuerbitsSend = 0; //zu sendende Steuerbits
/* Bit0 (Betriebmodus)
0 = LiveView-Modus
1 = EEPROM-Modus
Bit1 (Watchdog)
Bit2 (Übertragung aus EEPROM)
0 = keine Übertragung
1 = Übertragung läuft*/
volatile uint8_t SteuerbitsEmpf = 0; //empfangene Steuerbits
/* Bit0 (Anforderung von Daten aus dem EEPROM)
0 = keine Daten angefordert
1 = Daten angefordert
Bit1 (Watchdog)
Bit2 (Alarm/Puls)
0 = nichts ausgeben
1 = Alarm/Puls*/
volatile uint8_t Messwert = 255; //Messwert
uint16_t Index = 0; //Index für EEPROM-Modus (Adressen)
//==============================Funktionen==============================
//UART
void sendeUART(char Daten) //Daten per UART senden
{
while (!(UCSRA & (1<<UDRE))); //Endlosschleife solange UDR nicht leer ist
UDR = Daten; //Daten zum Senden übergeben
}
void sende() //Strings an PC senden
{
SteuerbitsSend ^= (1<<1); //Watchdog-Bit toggeln
sendeUART(SteuerbitsSend);
sendeUART(Messwert);
sendeUART('\n'); //Endzeichen des Strings senden
UARTDatenEmpfangen = 0; //Freigabe für Empfang weiterer Strings
}
//EEPROM
void EEPROMschreiben(uint8_t Wert, uint16_t Stelle) //Daten ins EEPROM schreiben
{
while(EECR & (1<<1)); //Warte bis vorherige Schreibaktion abgeschlossen
EEAR = Stelle; //Adresse übergeben
EEDR = Wert; //zu schreibende Daten übergeben
EECR = 0x04; //EEPROM Write Enabled
EECR = 0x06; //EEPROM Write
}
uint8_t EEPROMlesen(uint16_t Stelle) //Daten vom EEPROM auslesen
{
uint8_t gelesen;
EEAR = Stelle; //Adresse an EEAR übergeben
EECR |= 0b00000001; //Leseaufforderung
while (EECR & (1<<0)); //warte auf Fertigmeldung
gelesen = EEDR; //Daten aus EEDR übernehmen
return gelesen;
}
//Sonstige
uint8_t AD_Wandlung() //Analog-Digital-Wandlung
{
uint16_t Wert = 0;
cli(); //globale Interrupts deaktivieren
ADMUX = 0b00000001; //Kanal 1 für ADC auswählen
ADMUX |= (1<<REFS0); //AVCC als Referenzspannung
ADMUX &= ~(1<<ADLAR); //Wandlungsergebnis rechtsbündig
ADCSRA = 0b11000101; //Frequenzvorteiler auf 32 setzen und ADC0 als Analogeingangsbit aktivieren
while(bit_is_set(ADCSRA,ADSC)); //auf Wandlungsende warten
Wert = (ADCW/4); //Wert übergeben und auf 8-Bit umrechnen
sei(); //globale Interrupts aktivieren
return Wert;
}
void Herzschlag(uint8_t Wert) //optischer Herzschlag
{
OCR1A = ((Wert-127)/6); //Anpassung der LED-Helligkeit und Ausgabe des Wertes
}
void Summer() //akustischer Herzschlag/Alarm
{
if (bit_is_clear (PINB, 4) && bit_is_set (SteuerbitsEmpf, 2)) //Wenn Summer eingeschaltet und Impuls kommt
{PORTC |= (1<<PC0);} //Summer ein
else {PORTC &= ~(1<<PC0);} //Summer aus
}
//==============================Interrupts==============================
ISR(USART_RXC_vect) //Daten über USART empfangen (als Interrupt um nicht währenddessen unterbrochen zu werden)
{
SteuerbitsEmpf = UDR; //Empfangene Daten übernehmen (UDR ist ein FIFO-Speicher)
UARTDatenEmpfangen = 1; //"Daten wurden empfangen" setzen
}
ISR(TIMER0_OVF_vect) //Messung im EEPROM-Modus
{
Messwert = AD_Wandlung();
Herzschlag(Messwert);
EEPROMschreiben(Messwert, Index);
PORTB ^= (1<<0); //EEPROM-LED toggeln
Index++;
if (Index>=512) //Wenn EEPROM voll beschrieben
{
TIMSK &= ~(1<<TOIE0); //Interrupts für Timer-Overflow deaktivieren
UCSRB |= (1 << RXCIE); //Interrupts für UART aktivieren
Index = 0; //Index zurücksetzen
}
TCNT0 = 183; //bei 183 mit Zählen beginnen (Overflow bei 0,02s. Entspricht 72 Takte bei 1024 als Vorteiler)
}
//==============================Programm==============================
int main(void)
{
//Datenrichtung einstellen------------------------------
/* PortB.0 => LED EEPROM-Modus
PortB.1 => LED Herzschlag
PortB.2 => LED LabView-Modus
PortB.3 <= Betriebswahl
PortB.4 <= Summer ein/aus
PortB.5 <= Messung starten (EEPROM)
PortC.0 => Summer
PortC.1 <= Messsignal*/
DDRD = 0b00000000; //PortD = Eingänge
DDRB = 0b00000111; //PortB = Pin0-2(Ausgänge) / Pin 3-7(Eingänge)
DDRC = 0b00000001; //PortC = Pin0 (Ausgang / Pin1-7(Eingänge)
PORTD = 0b11111111; //Pull-Ups aktivieren
PORTB = 0b11111000; //Pull-Ups aktivieren / Ausgänge ausschalten
PORTC = 0b11111110; //Pull-Ups aktivieren / Ausgänge ausschalten
//UART Einstellungen------------------------------
UBRRL = 23; //9600 Baud (siehe Baudratentabelle)
UCSRB = (1<<RXCIE) | (1<<RXEN) | (1<<TXEN); //Interrupts ein /Receiver ein /Transmitter ein
UCSRC = (1<<URSEL) | (1<<UCSZ0) | (1<<UCSZ1); //Register Select /Character Size (8Bit)
//Timer 1 (PWM für Herzschlag-LED)------------------------------
TCCR1A = (1<<COM1A1) | (1<<WGM10); //Fast PWM(8-bit), Compare Match Mode
TCCR1B = (1<<WGM12); //Fast PWM(8-bit)
OCR1A = 0; //PWM-Wert (0-255), 0 = aus, 1-255 = ein
TCCR1B = (1<<CS10) | (1<<CS11); //Vorteiler(Prescaler) auf 64
//Timer 0 (für Messwertermittlung im EEPROM-Modus)------------------------------
TCCR0 = (1<<CS00) | (1<<CS02); //Prescaler auf 1024
TCNT0 = 183; //bei 183 mit Zählen beginnen (Overflow bei 0,02s. Entspricht 72 Takte bei 1024 Vorteiler)
//Sonstiges------------------------------
sei(); //globale Interrupts aktivieren
//------------------------------Hauptprogramm------------------------------
while(1)
{
//EEPROM-Modus------------------------------
if (bit_is_clear (PINB, 3))
{
PORTB |= (1<<PB0); //Betriebsmodus-LED EEPROM ein
PORTB &= ~(1<<PB2); //Betriebsmodus-LED LabView aus
SteuerbitsSend |= (1<<0); //Betriebsmodus (EEPROM) zur Übermittlung an LabView setzen
//Anforderung von Daten aus dem EEPROM------------------------------
if (bit_is_set (SteuerbitsEmpf, 0) && (Index==0))
{
TIMSK &= ~(1<<TOIE0); //Interrupts für Timer-Overflow deaktivieren
SteuerbitsSend |= (1<<2); //Sende-Bit setzen
for (Index=0; Index<=511; Index++) //bis EEPROM komplett gesendet ist
{
Messwert = EEPROMlesen(Index);
sende();
}
SteuerbitsSend &= ~(1<<2); //Sende-Bit rücksetzen
sende();
while (bit_is_set (SteuerbitsEmpf, 0)); //warte auf Bestätigung das Daten empfangen wurden (um mehrmaliges senden zu verhindern)
Index = 0; //Index zurücksetzen
}
//Messung starten------------------------------
if (bit_is_clear (PINB, 5))
{
TIMSK |= (1<<TOIE0); //Interrupts für Timer-Overflow aktivieren
UCSRB &= ~(1<<RXCIE); //Interrupts für UART deaktivieren
while(bit_is_set(TIMSK,TOIE0)); //warte solange wie Timer-Interrupt aktiv ist
}
if(UARTDatenEmpfangen == 1) //Wenn String komplett Empfangen wurde
{sende();}
}
//LabView-Modus------------------------------
if (bit_is_set (PINB, 3))
{
PORTB |= (1<<PB2); //Betriebsmodus-LED LabView ein
PORTB &= ~(1<<PB0); //Betriebsmodus-LED EEPROM aus
SteuerbitsSend &= ~(1<<0); //Betriebsmodus (LabView) zur Übermittlung an LabView setzen
if(UARTDatenEmpfangen == 1) //Wenn String komplett Empfangen wurde
{
sende();
Messwert = AD_Wandlung();
Herzschlag(Messwert);
Summer();
}
}
}
}