NumberFive
06.01.2008, 12:48
Ich gebe zu so viel habe ich noch nicht in c für den AVR geschrieben.
Aber ich möchte hinterher nicht alles neu machen weil ich eine dumme gebaut habe.
Zu meiner Frage:
Zur Zeit arbeitet ich so das in den Interrupt Routinen nur das wichtigste gemacht wird und die eingleiche arbeit finden im Main statt.
Das mache ich so damit die Interrupts sich nicht gegenseitig unter Brechen.
Wenn ich mir jetzt andere Software so angucken gibt es welche die haben überhaupt kein Main (spich da steht nur wihle) und wieder ander arbeiten komplett ohen interupts bzw. mit nur sehr wenig.
/**************************************
mains.c
Autor: Numberfive
versuchen das ganze mal zu verstehen.
Alle die im Netzt beispiel code habe
sei an dieser stelle gedankt
man komme nie auf die Idee irgend wo
Interupts zu enablen wenn dafür keine
signal procedure hat dann springt
der avr wieder in die main routine
Danke an Picknick für das Seriale Protokoll
*************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
//#include <stdlib.h>
//#define F_CPU 16000000 // 16 MHz jetzt im Makefile
#define UART_BAUD_RATE 19200 // 19200 Baud
#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*16l)-1)
#define SCLOCK 16;
// _BV = BitValue
#define SETBIT(ADDRESS,BIT)(ADDRESS |=(1<<BIT))
#define CLEARBIT(ADDRESS,BIT)(ADDRESS &= ~(1<<BIT));
typedef unsigned char BYTE;
typedef unsigned short WORD;
//MN Funktions
void WDT_off(void);
void InitCom(void);
void InitTimer1(void);
void InitAD(void);
void SendAlive(void);
//RS232 Protokoll funktionen
#define CTL_M_MASK 0xF8
#define CTL_M_ADON 0x08
#define CTL_C_BASE 0xA8
#define CTL_C_STX CTL_C_BASE + 1
#define CTL_C_ETX CTL_C_BASE + 2
#define CTL_C_PFX CTL_C_BASE + 3
void TxSendStuffByte (BYTE bTxChar);
void TxSendFrameByte (BYTE bTxChar);
void TxStartFrame ( void );
void TxCloseFrame ( void );
void SendChar(BYTE Zeichen);
void SendADValue(BYTE nToClass,BYTE nToIdent,BYTE nPort);
// Public Vars
volatile BYTE IsHardBeat = 0;
volatile BYTE IsPCData = 0;
volatile BYTE HardBeatCount = 0;
volatile BYTE bTxBcc; // Checksum für BCC
volatile BYTE bSerialInBuffer[128];
volatile BYTE bBefehlbuffer[128];
volatile BYTE bInBufferPos = 0;
volatile BYTE waitforad = 1;
//Interupts
SIGNAL(SIG_OVERFLOW1)
{
IsHardBeat = 1;
TCNT1 = 49910;//Reload Timer
}
SIGNAL(SIG_UART_RECV)
{
BYTE Zeichen = UDR;
if(bInBufferPos == 0)
{
if(Zeichen == CTL_C_STX)
{
bSerialInBuffer[0] = CTL_C_STX;
bInBufferPos++;
}
}
else
{
if(Zeichen == CTL_C_ETX)
{
bSerialInBuffer[bInBufferPos] = CTL_C_ETX;
//Copy Buffer resetInbuffer
for(BYTE nSize=0;nSize<=bInBufferPos;nSize++)
{
bBefehlbuffer[nSize] = bSerialInBuffer[nSize];
}
bInBufferPos = 0;
IsPCData = 1;
}
else
{
bSerialInBuffer[bInBufferPos] = Zeichen;
bInBufferPos++;
if(bInBufferPos == 128)
{
//Übergelaufen
bInBufferPos = 0;
}
}
}
}
SIGNAL(SIG_UART_TRANS)
{
// nix machen aber sonst komme ich immer wider forne an
}
SIGNAL(SIG_UART_DATA)
{
// nix machen aber sonst komme ich immer wider forne an
}
SIGNAL(SIG_ADC)
{
//Mal sehen der ad wander ist fertig
waitforad = 0;
}
//Interupts ende
int main (void)
{
//hauptprg hier geht der controler immer als erstes hin
InitCom();
WDT_off();
InitAD();
SETBIT(DDRD,PD7); // Das ist der lautsprecher
bSerialInBuffer[0] = 0X00;
bSerialInBuffer[1] = 0X00;
bSerialInBuffer[2] = 0X00;
bSerialInBuffer[3] = 0X00;
bSerialInBuffer[4] = 0X00;
InitTimer1();//Timer 1 auf 1 sec
sei();//interupt enable
for(;;)
{
if(IsHardBeat == 1)
{
IsHardBeat = 0;
HardBeatCount++;
if(HardBeatCount == 5)
{
HardBeatCount=0;
SendAlive();
}
}
if(IsPCData == 1)
{
IsPCData = 0;
BYTE nPos = 1;
BYTE nCheckSum = 0;
// Das geht schief wenn das BCC maskiert ist
while(bBefehlbuffer[nPos+1] != CTL_C_ETX)
{
if(bBefehlbuffer[nPos] != CTL_C_PFX)
{
nCheckSum ^= bBefehlbuffer[nPos];
}
else
{
nPos++;
nCheckSum ^= bBefehlbuffer[nPos]-CTL_M_ADON;
}
nPos++;
}
if(nCheckSum == bBefehlbuffer[nPos])
{
//BCC OK
if(bBefehlbuffer[1] == 0x05)
{
//NXT Bekommen
if(bBefehlbuffer[5] == 0x00)
{
//Erste Gerät auf diesem Roboter ist ein ADWandler mit der Adresse 0x25
TxStartFrame();
TxSendFrameByte(0x09);
TxSendFrameByte(0x00);
TxSendFrameByte(0x25);
TxSendFrameByte(0x00);
TxSendFrameByte(0x01);
TxSendFrameByte(0x82);
TxSendFrameByte(0x00);
TxCloseFrame();
}
if(bBefehlbuffer[5] == 0x01)
{
//.. ist ein ADWandler mit der Adresse 0x29
TxStartFrame();
TxSendFrameByte(0x09);
TxSendFrameByte(0x00);
TxSendFrameByte(0x25);
TxSendFrameByte(0x01);
TxSendFrameByte(0x02);
TxSendFrameByte(0x82);
TxSendFrameByte(0x01);
TxCloseFrame();
}
if(bBefehlbuffer[5] == 0x02)
{
// Ich bin das Letzt und ein RN-Control
TxStartFrame();
TxSendFrameByte(0x09);
TxSendFrameByte(0x00);
TxSendFrameByte(0x2D);
TxSendFrameByte(0x00);
TxSendFrameByte(0xFF);
TxSendFrameByte(0x62);
TxSendFrameByte(0x00);
TxCloseFrame();
}
}
else if(bBefehlbuffer[1] == 0x25)
{
if(bBefehlbuffer[2] == 0x00)
{
SendADValue(bBefehlbuffer[3],bBefehlbuffer[4],0);
}
}
}
}
} //Ende MainLoop
}
void InitCom(void)
{
/* Set baud rate */
/* wenn wir in das h register schreiben wollen muß da ein 0 drin sein */
UCSRC = (0<<URSEL);
UBRRH = (UART_BAUD_SELECT>>8);
UBRRL = UART_BAUD_SELECT;
/* Enable receiver and transmitter und die Interupts*/
UCSRB = _BV(RXEN)|_BV(RXCIE);//|_BV(TXCIE);
/* Set frame format: 8data, 1stop bit */
UCSRC = (1<<URSEL)|(0<<USBS)|(0<<UCSZ2)|_BV(UCSZ1)|_BV(UCSZ0);
// Braucht man nicht aber das ist dir register umschaltung ob man
// das hight byte des UBRR sieht oder UCSRC
UCSRC != _BV(URSEL);
}
void WDT_off(void)
{
//WDR();
WDTCR |=(1<<WDTOE) | (1<<WDE);
WDTCR = 0x00;
}
void InitTimer1(void)
{
SETBIT(TCCR1B,CS10);
SETBIT(TCCR1B,CS11);
//SETBIT(TCCR1B,CS12);
//enable interrupt timer
SETBIT(TIMSK,TOIE1);
// 1 sec bei Teiler 1024
TCNT1 = 49910;
TCNT1 = 100;//<- Für SIM
}
void InitAD(void)
{
//Init ADwandler
ADCSRA = (1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
//CLEARBIT(ADCSRA,ADFR); // Kein Freilauf
CLEARBIT(ADMUX,REFS1);
SETBIT(ADMUX,REFS0); // externe vergleichs Quelle
SETBIT(ADCSRA,ADIE);
}
void SendAlive(void)
{
TxStartFrame();
TxSendFrameByte(0x01);
TxSendFrameByte(0x00);
TxSendFrameByte(0x00);
TxSendFrameByte(0x00);
TxCloseFrame();
}
void SendADValue(BYTE nToClass,BYTE nToIdent,BYTE nPort)
{
CLEARBIT(ADCSRA,ADEN); // aus schlaten damit ich den port wechseln kann
//ADMUX = nPort; geht nicht da sind noch 2 bit's
if(nPort == 0)
{
CLEARBIT(ADMUX,MUX4);
CLEARBIT(ADMUX,MUX3);
CLEARBIT(ADMUX,MUX2);
CLEARBIT(ADMUX,MUX1);
CLEARBIT(ADMUX,MUX0);
}
else if(nPort == 1)
{
CLEARBIT(ADMUX,MUX4);
CLEARBIT(ADMUX,MUX3);
CLEARBIT(ADMUX,MUX2);
CLEARBIT(ADMUX,MUX1);
SETBIT(ADMUX,MUX0);
}
// Bit invertieren messung starten
ADCSRA |=_BV(ADSC);
waitforad = 1;
// warten bis messung abgesclossen ist und wert gültig
while(waitforad != 0)
{
//warten auf den adwandler;
};
// den wert aus dem register holen
if(nPort == 0)
{
TxStartFrame();
TxSendFrameByte(nToClass);
TxSendFrameByte(nToIdent);
TxSendFrameByte(0x25);
TxSendFrameByte(0x00);
TxSendFrameByte(ADCL);
TxSendFrameByte(ADCH);
TxCloseFrame();
/*
pBuffer[0] = nToClass;
pBuffer[1] = nToIdent;
pBuffer[2] = 0x25;
pBuffer[3] = 0x00;
pBuffer[4] = LOBYTE(nValue);
pBuffer[5] = HIBYTE(nValue);*/
}
//Result = ADCH*256 + ADCL;
}
void SendChar(BYTE Zeichen)
{
SETBIT(UCSRB,TXEN);
//Warten bis schnittstelle bereit
loop_until_bit_is_set(UCSRA,UDRE);
// Zeichen ins register schreiben
UDR = Zeichen;
CLEARBIT(UCSRB,TXEN);
}
// --------------------------------------------------------------
void TxStartFrame ( void )
{
bTxBcc = 0;
SendChar ( CTL_C_STX );
}
// --------------------------------------------------------------
void TxCloseFrame ( void )
{
TxSendStuffByte ( bTxBcc );// auch das BCC mit ev. prefixed werden
SendChar ( CTL_C_ETX );
}
// --------------------------------------------------------------
void TxSendFrameByte (BYTE bTxChar)
{
bTxBcc ^= bTxChar;
TxSendStuffByte( bTxChar );
}
// --------------------------------------------------------------
void TxSendStuffByte (BYTE bTxChar)
{
if((bTxChar & CTL_M_MASK) == CTL_C_BASE)
{
SendChar( CTL_C_PFX );
SendChar( bTxChar + CTL_M_ADON );
}
else
{
SendChar( bTxChar );
}
}
Das ist das was ich gestern verbrochen habe. Im Simulator tut es.
Aber ich möchte hinterher nicht alles neu machen weil ich eine dumme gebaut habe.
Zu meiner Frage:
Zur Zeit arbeitet ich so das in den Interrupt Routinen nur das wichtigste gemacht wird und die eingleiche arbeit finden im Main statt.
Das mache ich so damit die Interrupts sich nicht gegenseitig unter Brechen.
Wenn ich mir jetzt andere Software so angucken gibt es welche die haben überhaupt kein Main (spich da steht nur wihle) und wieder ander arbeiten komplett ohen interupts bzw. mit nur sehr wenig.
/**************************************
mains.c
Autor: Numberfive
versuchen das ganze mal zu verstehen.
Alle die im Netzt beispiel code habe
sei an dieser stelle gedankt
man komme nie auf die Idee irgend wo
Interupts zu enablen wenn dafür keine
signal procedure hat dann springt
der avr wieder in die main routine
Danke an Picknick für das Seriale Protokoll
*************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
//#include <stdlib.h>
//#define F_CPU 16000000 // 16 MHz jetzt im Makefile
#define UART_BAUD_RATE 19200 // 19200 Baud
#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*16l)-1)
#define SCLOCK 16;
// _BV = BitValue
#define SETBIT(ADDRESS,BIT)(ADDRESS |=(1<<BIT))
#define CLEARBIT(ADDRESS,BIT)(ADDRESS &= ~(1<<BIT));
typedef unsigned char BYTE;
typedef unsigned short WORD;
//MN Funktions
void WDT_off(void);
void InitCom(void);
void InitTimer1(void);
void InitAD(void);
void SendAlive(void);
//RS232 Protokoll funktionen
#define CTL_M_MASK 0xF8
#define CTL_M_ADON 0x08
#define CTL_C_BASE 0xA8
#define CTL_C_STX CTL_C_BASE + 1
#define CTL_C_ETX CTL_C_BASE + 2
#define CTL_C_PFX CTL_C_BASE + 3
void TxSendStuffByte (BYTE bTxChar);
void TxSendFrameByte (BYTE bTxChar);
void TxStartFrame ( void );
void TxCloseFrame ( void );
void SendChar(BYTE Zeichen);
void SendADValue(BYTE nToClass,BYTE nToIdent,BYTE nPort);
// Public Vars
volatile BYTE IsHardBeat = 0;
volatile BYTE IsPCData = 0;
volatile BYTE HardBeatCount = 0;
volatile BYTE bTxBcc; // Checksum für BCC
volatile BYTE bSerialInBuffer[128];
volatile BYTE bBefehlbuffer[128];
volatile BYTE bInBufferPos = 0;
volatile BYTE waitforad = 1;
//Interupts
SIGNAL(SIG_OVERFLOW1)
{
IsHardBeat = 1;
TCNT1 = 49910;//Reload Timer
}
SIGNAL(SIG_UART_RECV)
{
BYTE Zeichen = UDR;
if(bInBufferPos == 0)
{
if(Zeichen == CTL_C_STX)
{
bSerialInBuffer[0] = CTL_C_STX;
bInBufferPos++;
}
}
else
{
if(Zeichen == CTL_C_ETX)
{
bSerialInBuffer[bInBufferPos] = CTL_C_ETX;
//Copy Buffer resetInbuffer
for(BYTE nSize=0;nSize<=bInBufferPos;nSize++)
{
bBefehlbuffer[nSize] = bSerialInBuffer[nSize];
}
bInBufferPos = 0;
IsPCData = 1;
}
else
{
bSerialInBuffer[bInBufferPos] = Zeichen;
bInBufferPos++;
if(bInBufferPos == 128)
{
//Übergelaufen
bInBufferPos = 0;
}
}
}
}
SIGNAL(SIG_UART_TRANS)
{
// nix machen aber sonst komme ich immer wider forne an
}
SIGNAL(SIG_UART_DATA)
{
// nix machen aber sonst komme ich immer wider forne an
}
SIGNAL(SIG_ADC)
{
//Mal sehen der ad wander ist fertig
waitforad = 0;
}
//Interupts ende
int main (void)
{
//hauptprg hier geht der controler immer als erstes hin
InitCom();
WDT_off();
InitAD();
SETBIT(DDRD,PD7); // Das ist der lautsprecher
bSerialInBuffer[0] = 0X00;
bSerialInBuffer[1] = 0X00;
bSerialInBuffer[2] = 0X00;
bSerialInBuffer[3] = 0X00;
bSerialInBuffer[4] = 0X00;
InitTimer1();//Timer 1 auf 1 sec
sei();//interupt enable
for(;;)
{
if(IsHardBeat == 1)
{
IsHardBeat = 0;
HardBeatCount++;
if(HardBeatCount == 5)
{
HardBeatCount=0;
SendAlive();
}
}
if(IsPCData == 1)
{
IsPCData = 0;
BYTE nPos = 1;
BYTE nCheckSum = 0;
// Das geht schief wenn das BCC maskiert ist
while(bBefehlbuffer[nPos+1] != CTL_C_ETX)
{
if(bBefehlbuffer[nPos] != CTL_C_PFX)
{
nCheckSum ^= bBefehlbuffer[nPos];
}
else
{
nPos++;
nCheckSum ^= bBefehlbuffer[nPos]-CTL_M_ADON;
}
nPos++;
}
if(nCheckSum == bBefehlbuffer[nPos])
{
//BCC OK
if(bBefehlbuffer[1] == 0x05)
{
//NXT Bekommen
if(bBefehlbuffer[5] == 0x00)
{
//Erste Gerät auf diesem Roboter ist ein ADWandler mit der Adresse 0x25
TxStartFrame();
TxSendFrameByte(0x09);
TxSendFrameByte(0x00);
TxSendFrameByte(0x25);
TxSendFrameByte(0x00);
TxSendFrameByte(0x01);
TxSendFrameByte(0x82);
TxSendFrameByte(0x00);
TxCloseFrame();
}
if(bBefehlbuffer[5] == 0x01)
{
//.. ist ein ADWandler mit der Adresse 0x29
TxStartFrame();
TxSendFrameByte(0x09);
TxSendFrameByte(0x00);
TxSendFrameByte(0x25);
TxSendFrameByte(0x01);
TxSendFrameByte(0x02);
TxSendFrameByte(0x82);
TxSendFrameByte(0x01);
TxCloseFrame();
}
if(bBefehlbuffer[5] == 0x02)
{
// Ich bin das Letzt und ein RN-Control
TxStartFrame();
TxSendFrameByte(0x09);
TxSendFrameByte(0x00);
TxSendFrameByte(0x2D);
TxSendFrameByte(0x00);
TxSendFrameByte(0xFF);
TxSendFrameByte(0x62);
TxSendFrameByte(0x00);
TxCloseFrame();
}
}
else if(bBefehlbuffer[1] == 0x25)
{
if(bBefehlbuffer[2] == 0x00)
{
SendADValue(bBefehlbuffer[3],bBefehlbuffer[4],0);
}
}
}
}
} //Ende MainLoop
}
void InitCom(void)
{
/* Set baud rate */
/* wenn wir in das h register schreiben wollen muß da ein 0 drin sein */
UCSRC = (0<<URSEL);
UBRRH = (UART_BAUD_SELECT>>8);
UBRRL = UART_BAUD_SELECT;
/* Enable receiver and transmitter und die Interupts*/
UCSRB = _BV(RXEN)|_BV(RXCIE);//|_BV(TXCIE);
/* Set frame format: 8data, 1stop bit */
UCSRC = (1<<URSEL)|(0<<USBS)|(0<<UCSZ2)|_BV(UCSZ1)|_BV(UCSZ0);
// Braucht man nicht aber das ist dir register umschaltung ob man
// das hight byte des UBRR sieht oder UCSRC
UCSRC != _BV(URSEL);
}
void WDT_off(void)
{
//WDR();
WDTCR |=(1<<WDTOE) | (1<<WDE);
WDTCR = 0x00;
}
void InitTimer1(void)
{
SETBIT(TCCR1B,CS10);
SETBIT(TCCR1B,CS11);
//SETBIT(TCCR1B,CS12);
//enable interrupt timer
SETBIT(TIMSK,TOIE1);
// 1 sec bei Teiler 1024
TCNT1 = 49910;
TCNT1 = 100;//<- Für SIM
}
void InitAD(void)
{
//Init ADwandler
ADCSRA = (1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
//CLEARBIT(ADCSRA,ADFR); // Kein Freilauf
CLEARBIT(ADMUX,REFS1);
SETBIT(ADMUX,REFS0); // externe vergleichs Quelle
SETBIT(ADCSRA,ADIE);
}
void SendAlive(void)
{
TxStartFrame();
TxSendFrameByte(0x01);
TxSendFrameByte(0x00);
TxSendFrameByte(0x00);
TxSendFrameByte(0x00);
TxCloseFrame();
}
void SendADValue(BYTE nToClass,BYTE nToIdent,BYTE nPort)
{
CLEARBIT(ADCSRA,ADEN); // aus schlaten damit ich den port wechseln kann
//ADMUX = nPort; geht nicht da sind noch 2 bit's
if(nPort == 0)
{
CLEARBIT(ADMUX,MUX4);
CLEARBIT(ADMUX,MUX3);
CLEARBIT(ADMUX,MUX2);
CLEARBIT(ADMUX,MUX1);
CLEARBIT(ADMUX,MUX0);
}
else if(nPort == 1)
{
CLEARBIT(ADMUX,MUX4);
CLEARBIT(ADMUX,MUX3);
CLEARBIT(ADMUX,MUX2);
CLEARBIT(ADMUX,MUX1);
SETBIT(ADMUX,MUX0);
}
// Bit invertieren messung starten
ADCSRA |=_BV(ADSC);
waitforad = 1;
// warten bis messung abgesclossen ist und wert gültig
while(waitforad != 0)
{
//warten auf den adwandler;
};
// den wert aus dem register holen
if(nPort == 0)
{
TxStartFrame();
TxSendFrameByte(nToClass);
TxSendFrameByte(nToIdent);
TxSendFrameByte(0x25);
TxSendFrameByte(0x00);
TxSendFrameByte(ADCL);
TxSendFrameByte(ADCH);
TxCloseFrame();
/*
pBuffer[0] = nToClass;
pBuffer[1] = nToIdent;
pBuffer[2] = 0x25;
pBuffer[3] = 0x00;
pBuffer[4] = LOBYTE(nValue);
pBuffer[5] = HIBYTE(nValue);*/
}
//Result = ADCH*256 + ADCL;
}
void SendChar(BYTE Zeichen)
{
SETBIT(UCSRB,TXEN);
//Warten bis schnittstelle bereit
loop_until_bit_is_set(UCSRA,UDRE);
// Zeichen ins register schreiben
UDR = Zeichen;
CLEARBIT(UCSRB,TXEN);
}
// --------------------------------------------------------------
void TxStartFrame ( void )
{
bTxBcc = 0;
SendChar ( CTL_C_STX );
}
// --------------------------------------------------------------
void TxCloseFrame ( void )
{
TxSendStuffByte ( bTxBcc );// auch das BCC mit ev. prefixed werden
SendChar ( CTL_C_ETX );
}
// --------------------------------------------------------------
void TxSendFrameByte (BYTE bTxChar)
{
bTxBcc ^= bTxChar;
TxSendStuffByte( bTxChar );
}
// --------------------------------------------------------------
void TxSendStuffByte (BYTE bTxChar)
{
if((bTxChar & CTL_M_MASK) == CTL_C_BASE)
{
SendChar( CTL_C_PFX );
SendChar( bTxChar + CTL_M_ADON );
}
else
{
SendChar( bTxChar );
}
}
Das ist das was ich gestern verbrochen habe. Im Simulator tut es.