Forum: Mikrocontroller und Digitale Elektronik printf bei Handy-SMS Code aus Artikel geht nicht?


von Y. T. (moritzz)


Lesenswert?

Hallo,
Ich bin gerade dabei, aus der Artikelsammlung das "mikrocontroller 
verschickt SMS an Siemens-Handy"-Projekt nachzubauen. Hab auch alles 
soweit, Handy geht, etc. jetzt schaue ich, dass ich den Code auf einen 
ATmega8 abgespeckt bekomme.

Leider geht die printf-Funktion nicht, der µC sendet dabei nix über das 
UART raus...Woran kann das liegen? Ich habe im Makefile schon 
printf-options auf "minimalistic" eingestellt. Warum geht diese 
printf-Variante nicht?

In meiner Hauptroutine steht jetzt zum Test:
1
uart_sends("hallo"); //das funktioniert
2
printf("at+cclk?\r\n"); //da kommt nix an
3
_delay_ms(2500);
4
sms_send("015781581259","Die Krümmung ist eine Größe der inneren Geometrie");
5
//da kommt auch nix an

Die wichtigsten Code-Schnipsel aus dem Artikel für die SMS-Funktionen 
lauten so:
1
void sms_init(void){
2
  // Initialisierung der seriellen Schnittstelle Asynchron
3
  uart_init();
4
  // öffnet Kanal für printf
5
  //stdout = &mystdout;
6
  fdevopen (uart_sendc, uart_receive);
7
8
  UCSRB &= ~(1 << RXCIE);    // UART Receive ISR ausstellen
9
10
  printf("ATE0\r\n");    // Echo off, reduce traffic
11
  _delay_ms(200);
12
  printf("AT+CPMS=\"ME\",\"MT\",\"MT\"\r\n");    // Speicher von gelesenen, geschriebenen und empfangenen SMS auf Telefonspeicher stellen
13
  _delay_ms(200);
14
  printf("AT+CNMI=1,1,0,0,1\r\n");        // new message indication --> "+CMTI:<mem>,<index>"
15
  _delay_ms(200);
16
17
  // Auslesen der ersten 5 Telefonnummern der SIM-Karte
18
  char telnr[SMS_TELNR_MAX_LEN+1];
19
  uint8_t i=0;
20
  int dummy;
21
  printf("AT+CPBS=\"SM\"\r\n");          // Telefonbuch auf SIM Karte umstellen
22
  _delay_ms(200);
23
  uart_clear();
24
  for (i=0;i<SMS_TELNR_LIST_MAX;i++) {
25
    uart_clear();
26
    printf("AT+CPBR=%i\r\n",i+1);
27
    gets(telnr);
28
    scanf("+CPBR: %i,\"%[^\"]",&dummy,telnr);
29
    _delay_ms(400);                // Rest der Antwort abwarten und verwerfen
30
    if (strlen(telnr)>3) {
31
      strcpy(sms_telnr_list[i].telnr,telnr);  // ausgelesene Telefonnummer in Struktur speichern  
32
    }
33
    else { strcpy(sms_telnr_list[i].telnr, "noNR");}
34
  }
35
  uart_clear();
36
  if (UART_ISR!=0) {UCSRB |= (1 << RXCIE);}    // UART Receive ISR wieder einstellen
37
}

und
1
void sms_send(char* zielnr, char* nachricht)
2
{
3
  uint8_t cnt_shiftzero=0;
4
  uint8_t cnt_nr=0;          // Zähler für Zielnummer, nach Umwandlung = Länge der Zielnummer
5
  uint8_t cnt_txt=0;          // Zähler für Nachricht, nach Umwandlung = Länge der Nachricht
6
  uint8_t shift=0;
7
  uint8_t i=0;
8
  char nachricht_neu[SMS_MESSAGE_MAX_LEN+1]={"\0"};
9
  char zielnr_neu[SMS_TELNR_MAX_LEN+1]={" "};
10
11
  UCSRB &= ~(1 << RXCIE);    // UART Receive ISR ausstellen
12
13
  // Nachricht umwandeln in PDU-Format
14
  while (nachricht[cnt_txt]!=0)
15
  {
16
    if (shift==7) {
17
      shift=0;
18
      cnt_txt++;
19
      cnt_shiftzero++;
20
    }
21
    else {                
22
      nachricht_neu[cnt_txt-cnt_shiftzero] = (((nachricht[cnt_txt]&0x7F)>>shift) | ((nachricht[cnt_txt+1])<<(7-shift)));
23
      shift++;
24
      cnt_txt++;
25
    }
26
  }
27
  nachricht_neu[cnt_txt-cnt_shiftzero]=nachricht[cnt_txt];  // '0' anfügen , Endestring
28
  
29
  // Zielnummer neu zusammensetzen
30
  // Bsp. 01 62 64 94 30 0 --> 10 26 46 49 03 F0
31
  // wenn 2 Bytes nicht voll ausgenutzt werden, 'F' einfügen
32
  while (zielnr[cnt_nr]!=0) {
33
    if (zielnr[cnt_nr+1]==0) {
34
      zielnr_neu[cnt_nr]='F';  
35
      zielnr_neu[cnt_nr+1]=zielnr[cnt_nr];
36
      cnt_nr++;
37
      cnt_nr++;
38
      zielnr_neu[cnt_nr]=zielnr[cnt_nr-1];  // '0' anfügen , Endestring
39
      break;
40
    }
41
    else {
42
      zielnr_neu[cnt_nr]=zielnr[cnt_nr+1];
43
      zielnr_neu[cnt_nr+1]=zielnr[cnt_nr];
44
      cnt_nr=cnt_nr+2;
45
    }
46
  }
47
48
  //Anzahl der Zeichen im PDU-String/2-->Hex Paare -2 (ersten 2 Hex Zeichen weglassen)
49
  //-->'Anzahl der Nachrichtenzeichen' + 'Anzahl der Nummern /2' (/2 da nur Hex Paare gezählt werden) + '7' (zusätzliche Header)
50
  if (zielnr_neu[cnt_nr-2]=='F') {
51
    printf("AT+CMGS=%i\r\n",cnt_txt-cnt_shiftzero+(cnt_nr/2)+7);
52
    cnt_nr--;    //Länge der Zielnummer -1, da 'F' angefügt
53
  }
54
  else {
55
    printf("AT+CMGS=%i\r\n",cnt_txt-cnt_shiftzero+(cnt_nr/2)+7);
56
  }
57
58
  //while(uart_receive()!=' ');    // auf antwort von Handy warten '> '
59
  _delay_ms(1000);
60
  printf("000100%02X81",cnt_nr);
61
  printf(zielnr_neu);
62
  printf("0000%02X",cnt_txt);
63
  for (i = 0;i<(cnt_txt-cnt_shiftzero);i++){
64
    printf("%02X", nachricht_neu[i]);
65
  };
66
  printf("%c",26);
67
  if (UART_ISR!=0) {UCSRB |= (1 << RXCIE);}    // UART Receive ISR wieder einstellen)
68
}

Danke!

von SMS (Gast)


Lesenswert?

M. G. schrieb:
> In meiner Hauptroutine steht jetzt zum Test:
> uart_sends("hallo"); //das funktioniert
> printf("at+cclk?\r\n"); //da kommt nix an
> _delay_ms(2500);
> sms_send("015781581259","Die Krümmung ist eine Größe der inneren Geometrie");
> //da kommt auch nix an

Kann ´ja auch nicht ohne vorher sms_init aufzurufen.

von SMS (Gast)


Lesenswert?

M. G. schrieb:
> Hab auch alles
> soweit, Handy geht, etc. jetzt schaue ich, dass ich den Code auf einen
> ATmega8 abgespeckt bekomme.

Das geht eher nicht, selbst wenn du alle lcd routinen etc. rausnimmst 
wird das kaum passen. Steht auch so im Artikel.

von Y. T. (moritzz)


Lesenswert?

Na, sms_init ist natürlich aufgerufen, und Platz ist auch genug auf dem 
µC (siehe unten), ich habe halt in der sms.c alle Funktionen 
rausgenommen ausser sms_send und sms_init. Ich will auch nur diese zwei 
Sachen erstmal machen!
Also die ganze Hauptroutine in main.c sieht halt so aus:
1
#include "main.h"
2
#include "uart.c"
3
#include "sms.c"
4
5
volatile uint8_t timer_flag;
6
7
int main(void) {
8
9
DDRD = (1<<PD1) | ( 1 << PD2 );
10
DDRB=0xFF;
11
PORTB=0;
12
13
  sei();
14
  sms_init();
15
  uart_clear();
16
17
uart_sends("hallo"); //geht
18
printf("at+cclk?\r\n"); //geht nicht
19
20
21
  
22
  
23
  
24
while(1) //Ende
25
{
26
PORTB = ( 1 << PB0 );
27
_delay_ms(250);
28
PORTB = ( 0 << PB0 );
29
_delay_ms(250);
30
}
31
}

Ach ja, und der AVR ist halt bis zum Rand gefüllt:
1
Program:    5112 bytes (62.4% Full)
2
(.text + .data + .bootloader)
3
4
Data:       1009 bytes (98.5% Full)
5
(.data + .bss + .noinit)

von SMS (Gast)


Lesenswert?

M. G. schrieb:
> #include "uart.c"
> #include "sms.c"

Das sollte eher *.h heißen.
Am original Code brauchst du sicher keine Fehler suchen, der 
funktioniert so wie er ist. Wurde schon dutzende Male erfolgreich 
verwendet. Wahrscheinlicher ist, dass du etwas auskommentiert hast, was 
du nicht hättest auskommentieren sollen (wie z.B. die header -Dateien)

von Stefan E. (sternst)


Lesenswert?

M. G. schrieb:
> Data:       1009 bytes (98.5% Full)
> (.data + .bss + .noinit)

Also praktisch Null Platz für den Stack. Das funktioniert so sicher 
nicht. Als erste Maßnahme solltest du mal die ganzen 
printf-Formatstrings ins Flash verbannen und entsprechend printf_P 
benutzen.

von Y. T. (moritzz)


Lesenswert?

Ah,
das klingt nach der Lösung...
Also du meinst, man definiert für die AT-Commandostrings 
Flash-Variablen?
etwa so:
1
char StringImFlash[] PROGMEM = "at+cclk?\r\n"; // im "Flash"
2
3
printf_P(StringImFlash);

oder etwa sowas wie
1
const char Ichbinimflash[] PROGMEM = "%s";
2
3
printf_P(Ichbinimflash); 
4
??????


(Kennt jemand eigentlich mal so eine Art Dokumentation zu diesen 
merkwürdigen printf-Funktionen? Ich weiß eigentlich gar nicht genau, was 
die machen...?!)

von Stefan E. (sternst)


Lesenswert?

M. G. schrieb:
> Also du meinst, man definiert für die AT-Commandostrings
> Flash-Variablen?
> etwa so:
1
char StringImFlash[] PROGMEM = "at+cclk?\r\n"; // im "Flash"
2
3
printf_P(StringImFlash);
>
> oder etwa sowas wie
1
const char Ichbinimflash[] PROGMEM = "%s";
2
3
printf_P(Ichbinimflash);
4
??????

Oder einfach so:
1
printf_P(PSTR("at+cclk?\r\n"));


> (Kennt jemand eigentlich mal so eine Art Dokumentation zu diesen
> merkwürdigen printf-Funktionen? Ich weiß eigentlich gar nicht genau, was
> die machen...?!)
http://www.nongnu.org/avr-libc/user-manual/

von Y. T. (moritzz)


Lesenswert?

Vielen Dank!
Das werd ich jetzt  erstmal probieren!!!
Dabei werd ich mir auch die Doku vorknüpfen!

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Was ich mich frage ist: Wozu benötigt man hier überhaupt printf? Nur für 
die Formatierte Ausgabe von ein paar Zahlen? Da könnte man durch eine 
eigene Routine sicherlich auch noch etwas Platz sparen.

von SMS (Gast)


Lesenswert?

Läubi .. schrieb:
> Was ich mich frage ist: Wozu benötigt man hier überhaupt printf? Nur für
> die Formatierte Ausgabe von ein paar Zahlen? Da könnte man durch eine
> eigene Routine sicherlich auch noch etwas Platz sparen.

Zitat aus Artikel:
"Die einzelnen Algorithmen sind dabei sehr einfach gehalten. Das 
bedeutet, dass es sicherlich sehr viel kürzere Varianten gibt, um z. B. 
einen Text in das PDU Format zu transformieren. Ich habe mich aber 
lieber auf mehr und damit für andere auch verständlicheren Code 
beschränkt. Das verbraucht zwar mehr Speicher, trägt aber meines 
Erachtens zum Verständnis bei."

Platz sparen war hier nicht der Ansporn, sondern vielmehr das 
Verständniß und printf kennt nun mal jeder. Der Anfänger muss siche eben 
nicht mit dem UART rumschlagen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

SMS schrieb:
> Platz sparen war hier nicht der Ansporn, sondern vielmehr
> das Verständniß
Schon klar nur der TE scheint ja
 a) Platz sparen zu wollen
 b) mit printf auf dem Kriegsfuß zu stehen ;)

von SMS (Gast)


Lesenswert?

Läubi .. schrieb:
> Schon klar nur der TE scheint ja
>  a) Platz sparen zu wollen
>  b) mit printf auf dem Kriegsfuß zu stehen ;)

Selten aber wahr^^

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.