da ich mich wunderte, warum Bascom bei den paar Codezeilen 966 Byte verbraucht, habe ich den Bascom-Code mal 1:1 in Avr-gcc umgeschrieben:
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h> // wg. char-print
// interner RC-Oszillator
#define F_CPU 8.0E6
//'Timeraufruf alle 178µs (10 Samples = 1 Bit = 1,778ms)
#define INTERRUPT_PRELOADER 78
#define UART_BAUD_RATE 9600 // die gewünschte Baudrate
#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*16L)-1)
//UART -----------------------------------------------------------
char myCharBuffer[10];
char *myCharPtr;
void UART_init(void){
UBRRL |= (uint8_t) UART_BAUD_SELECT;
UCSRB = (1<<RXEN)|(1<<TXEN); //Sender & Empfänger aktivieren
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //Asynchron 8N1
}
void UART_transmit(uint8_t c){
while(!(UCSRA & (1<<UDRE)));
UDR = c;
}
void UART_transmit_string(uint8_t *string){
while(!(UCSRA & (1<<UDRE)));
while( *string){ UART_transmit (*string++); }
}
void UART_transmit_byte(uint8_t b){
myCharPtr = myCharBuffer;
myCharPtr = itoa( b,myCharPtr,10);
UART_transmit_string(myCharBuffer);
}
//Timing für 10 Samples Per Bit = 1,778ms
#define Samples_early 8 //Flanke Frühestens Nach 8 Samples
#define Samples_late 12 //Flanke Spätestens Nach 12 Samples
#define Samples_min 3 //Flanke Vor 3 Samples - > Paket Verwerfen
//Variablen der ISR
volatile uint8_t Sample; //eigentlich Bit
volatile uint8_t Ir_lastsample; //zuletzt gelesenes Sample
volatile uint8_t Ir_bittimer; //zählt die Aufrufe von Timer_IRQ
volatile uint16_t Ir_data_tmp; //Bitstream
volatile uint8_t Ir_bitcount; //Anzahl gelesener Bits
//Rückgabewerte der ISR
volatile uint8_t Address_rc5;
volatile uint8_t Command_rc5;
volatile uint8_t Rc5_flag; //eigentlich Bit
// Initialisierung der Hardware
void ioinit()
{
// Initialisiert Timer0
TCCR0 |= (1<<CS01); //Prescale=8
// TCNT0 = INTERRUPT_PRELOADER; //Counter
TIMSK |= (1<<TOIE0); //Timer Overflow Interrupt
}
// Das Hauptprogramm
int main()
{
// Peripherie initialisieren
ioinit();
UART_init();
//Pin für TSOP1736
DDRB &= ~(1<<DDB0); // Eingang eh vorhanden
// Interrupts aktivieren
sei();
// Eine Endlosschleife.
while (1)
{
if (Rc5_flag == 1)
{
Rc5_flag = 0;
UART_transmit_string("\r\ntoggle:");
UART_transmit_byte((Command_rc5 & (1<<7))>>7);
//clear the toggle bit
Command_rc5 &= 0b01111111;
UART_transmit_string(" Adresse:");
UART_transmit_byte(Address_rc5);
UART_transmit_string(" Code:");
UART_transmit_byte(Command_rc5);
}
}
}
// Die Interrupt Service Routine (ISR)
SIGNAL(SIG_OVERFLOW0)
{
TCNT0 = INTERRUPT_PRELOADER;
Sample = !(PINB & (1<<PINB0));
//'bittimer erhöhen (bleibt bei 255 stehen)
if (Ir_bittimer < 255) Ir_bittimer += 1;
//flankenwechsel erkennen
if (Ir_lastsample != Sample)
{
if (Ir_bittimer <= Samples_min)
{
//flanke kommt zu früh: paket verwerfen
Ir_bitcount = 0;
}
else
{
//nur Flankenwechsel in Bit-Mitte berücksichtigen
if (Ir_bittimer >= Samples_early)
{
if (Ir_bittimer <= Samples_late)
{
//Bit speichern
Ir_data_tmp = (Ir_data_tmp << 1);
Ir_data_tmp = Ir_data_tmp + Sample;
Ir_bitcount +=1;
}
else
{
//Flankenwechsel zu spät: Neuanfang mit gemessener Flanke
Ir_bitcount = 1;
Ir_data_tmp = Sample;
}
//bittimer zurücksetzen wenn Timer > Samples_early
Ir_bittimer = 0;
}
}
//Kontrolle des Startbits auf 1
if (Ir_bitcount == 1) Ir_bitcount = Ir_data_tmp & 1; //Bit 0
//Alle 14 Bits gelesen?
if (Ir_bitcount >= 14)
{
Command_rc5 = Ir_data_tmp & 0x3F ; //Bit 6 und 7 siehe unten
Ir_data_tmp = (Ir_data_tmp >> 6);
Address_rc5 = Ir_data_tmp & 0b00011111;
//For extended RC5 code, the extended bit is bit 6 of the command.
if ((Ir_data_tmp & (1<<6))==0) Command_rc5 |= (1<<6);
//The toggle bit is stored in bit 7 of the command
Command_rc5 |= ( (Ir_data_tmp & (1<<5)) <<2 );
//Paket erfolgreich gelesen
Rc5_flag=1;
//paket zurücksetzen
Ir_bitcount = 0;
}
}
//sample im samplepuffer ablegen
Ir_lastsample = Sample;
}
Trotz Compiler-Direktive "OPTIMIZE = -O2" beträgt die Codelänge in C erstaunliche 912Byte (gegenüber 966Byte in Bascom).
Fazit: Bascom macht hier keine schlechte Figur. Das Hauptproblem von Bascom ist das fehlende Registerrechnen. Ständig wird alles vom RAM hin- und hergeschaufelt. Da in GCC die Variablen für die ISR mit Volatile definiert werden müssen, kommt diese WINAVR-Optimierung nicht zum Zuge. (Volatile erfordert ca. 82 Byte zusätzlichen Code).
Markant ist in AVR-gcc die fehlende Push-Pop Orgie in der ISR:
Code:
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ISR SIG_OVERFLOW0 in AVR-GCC ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
ROM:00BD push r1
ROM:00BE push r0
ROM:00BF in r0, SREG
ROM:00C0 push r0
ROM:00C1 clr r1
ROM:00C2 push r18
ROM:00C3 push r24
ROM:00C4 push r25
...
ROM:016D pop r25
ROM:016E pop r24
ROM:016F pop r18
ROM:0170 pop r0
ROM:0171 out SREG, r0
ROM:0172 pop r0
ROM:0173 pop r1
ROM:0174 reti
bekanntlich langt hier Bascom ordentlich zu
Code:
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ISR Timer0 in Bascom ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
ROM:008F push r0
ROM:0090 push r1
ROM:0091 push r2
ROM:0092 push r3
ROM:0093 push r4
ROM:0094 push r5
ROM:0095 push r7
ROM:0096 push r10
ROM:0097 push r11
ROM:0098 push r16
ROM:0099 push r17
ROM:009A push r18
ROM:009B push r19
ROM:009C push r20
ROM:009D push r21
ROM:009E push r22
ROM:009F push r23
ROM:00A0 push r24
ROM:00A1 push r25
ROM:00A2 push r26
ROM:00A3 push r27
ROM:00A4 push r28
ROM:00A5 push r29
ROM:00A6 push r30
ROM:00A7 push r31
ROM:00A8 in r24, SREG
ROM:00A9 push r24
...
ROM:0154 pop r24
ROM:0155 out SREG, r24
ROM:0156 pop r31
ROM:0157 pop r30
ROM:0158 pop r29
ROM:0159 pop r28
ROM:015A pop r27
ROM:015B pop r26
ROM:015C pop r25
ROM:015D pop r24
ROM:015E pop r23
ROM:015F pop r22
ROM:0160 pop r21
ROM:0161 pop r20
ROM:0162 pop r19
ROM:0163 pop r18
ROM:0164 pop r17
ROM:0165 pop r16
ROM:0166 pop r11
ROM:0167 pop r10
ROM:0168 pop r7
ROM:0169 pop r5
ROM:016A pop r4
ROM:016B pop r3
ROM:016C pop r2
ROM:016D pop r1
ROM:016E pop r0
ROM:016F reti
Lesezeichen