Forum: Compiler & IDEs Problem beim senden mit printf


von Phil (Gast)


Lesenswert?

Hallo!

Bin gerade dabei mittels Tasterdruck eine SMS zu versenden.
Beim ersten Tasterdruck funktioniert alles besten, doch beim zweiten mal 
kommt das Unterprogramm zum Versenden der SMS immer nur bis zum printf 
Befehl. Dieser wird nicht mehr über die serielle Schnittstelle 
rausgeschrieben.

Um das ganze zu initialisieren benutze ich:
fdevopen (uart_putchar, uart_getchar);

und:
1
//############################################################################
2
//Routine für die Serielle Ausgabe
3
int uart_putchar (char c){
4
  if (c == '\n')
5
    uart_putchar('\r');
6
  //Warten solange bis Zeichen gesendet wurde
7
  while(!(UCSRA & (1<<UDRE)));
8
  //Ausgabe des Zeichens
9
  UDR = c;
10
  return (0);
11
};
12
//############################################################################
13
//Routine für die Serielle Ausgabe
14
int uart_getchar (void){
15
  while(!(UCSRA & (1<<RXC)));
16
  return(UDR);
17
};

Beim compilieren bekomme ich dises Warning:
../handy.c:50: warning: passing argument 1 of 'fdevopen' from 
incompatible pointer type

Habt ihr vielleicht einen Verdacht warum das printf nicht rausgeht über 
die schnittstelle?

Ich kann natürlich auch den ganzen Code senden.

Vielen Dank,
philip

: Verschoben durch Moderator
von Grrrr (Gast)


Lesenswert?

Die Rekursion in uart_putchar geht natürlich schief.

Besser:
1
int uart_putchar (char c){
2
  if (c == '\n')
3
    c = '\r';
4
  //Warten solange bis Zeichen gesendet wurde
5
  while(!(UCSRA & (1<<UDRE)));
6
  //Ausgabe des Zeichens
7
  UDR = c;
8
  return (0);
9
};

von Grrrr (Gast)


Lesenswert?

Phil schrieb:
> Beim compilieren bekomme ich dises Warning:
> ../handy.c:50: warning: passing argument 1 of 'fdevopen' from
> incompatible pointer type

Kompletten Code zeigen.

von Karl H. (kbuchegg)


Lesenswert?

Grrrr schrieb:
> Die Rekursion in uart_putchar geht natürlich schief.

Nö.
Warum sollte die schief gehen (ausser durch einen knapp bemessenen 
Stack)

> Besser:
>
1
> int uart_putchar (char c){
2
>   if (c == '\n')
3
>     c = '\r';
4
>   //Warten solange bis Zeichen gesendet wurde
5
>   while(!(UCSRA & (1<<UDRE)));
6
>   //Ausgabe des Zeichens
7
>   UDR = c;
8
>   return (0);
9
> };
10
>

Das macht was anderes.

Die Idee im Original ist es, einem \n ein \r voranzustellen. Dein Code 
ersetzt ein \n durch ein \r

von Grrrr (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Die Idee im Original ist es, einem \n ein \r voranzustellen.

Na gut. ;-)

von Phil (Gast)


Angehängte Dateien:

Lesenswert?

anbei der code

von Grrrr (Gast)


Lesenswert?

Phil schrieb:
> anbei der code

Ich habe mich falsch ausgedrückt.
Reduziere den Code bitte soweit, das der Fehler gerade noch auftritt, 
das Ganze aber kompilierbar ist.
Dann brauchen wir nicht so viel lesen, was garnichts mit dem Problem zu 
tun hat.

von Phil (Gast)


Lesenswert?

ok alles klar!

wird ein bisschen dauern...
melde mich wieder mit dem code...

danke einmal

von Remote O. (remote1)


Lesenswert?

Grrrr schrieb:
> int uart_putchar (char c){

Da muss noch ein dummy mit rein
1
int putchar(char c, FILE *dummy){

Kann dir natürlich nicht sagen, ob es nun daran liegt. Hab nur eben mal 
schnell drüber geschaut.

von Remote O. (remote1)


Lesenswert?

Du solltest auch einmal dein gesamtes Konzept überdenken. Da sind einige 
Stolperfallen mit drin. Z.B.  schreibt man in die ISR keine while 
Schleifen. Dein strcmp beim auslesen des Inhaltes einer SMS ist auch 
fragwürdig. Was ist wenn jemand EIN schreibt oder ein Leerzeichen 
anfügt? Das auslesen der SMS zyklisch zu machen ist auch völlig 
überflüssig ( es sei denn ich hab mich verguckt). Beim Eingang einer SMS 
bekommst du über die serielle Schnittstelle ein +CMTI Kommando zurück 
mit dem entsprechenden Index wo die neue SMS gespeichert ist. Da braucht 
man nichts pollen. Lediglich den UART Puffer auf z.B.
if ( strstr((char*)uart_string,"+CMTI:") ){
überprüfen und wenn das schon mal geklappt hat, den Index der SMS 
auslesen mit sscanf((char*)uart_string,"+CMTI: \"ME\",%i",&sms_index); 
und die entsprechende SMS abrufen.

Das sind nur ein paar Kleinigkeiten, aber genau an so einer wirst du 
hängen. Ist alles ein wenig unübersichtlich. Schalte dir doch einfach 
mal ein paar LEDs an bestimmten Codeabschnitten ein. Ich tippe mal, dass 
du irgendwo in einer Endlosschleife kommst und es nicht an dem printf 
scheitert. Oder du hast irgend ein Flag nicht zurückgesetzt.

Evtl. hilft dir auch mein Code 
(http://www.mikrocontroller.net/articles/Versenden_von_SMS_mittels_Mobiltelefon).

Da reagiere ich auch auf bestimmte Textinhalte einer SMS und führe dann 
eine bestimmte Funktion aus (Wie z.B. die Heizung einschalten). Ist nur 
ein wenig universeller (zumindest denke ich das^^)

von Phil (Gast)


Lesenswert?

du hast absolut recht - es ist ein wenig unübersichtlich!

Ich bekomme aber kein BEfehle auf die RS232 bei empfangener SMS.

Muss ich das beim Handy extra einschalten.
Ich hab auch noch das Echo vom Handy an - das könnte auch ein Problem 
sein.

von Remote O. (remote1)


Lesenswert?

Schau dir mal in meinem Artikel die sms.c an. Da findest du eine 
sms_init() in welcher die UART Schnittstelle initialisiert wird, das 
Echo ausgeschaltet wird, der Speicherplatz eingehender SMS auf den 
internen Speicher des Handys gesetzt wird und das new message indication 
eingestellt wird. Probier das einfach mal aus und schau dann nach, ob 
wirklich keine Indikation kommt. Der Befehl war glaube ich AT+CNMI... 
für die new message indikation.

Die Unübersichtlichkeit bekommst du dchon weg, wenn du alles was 
zusammengehört in einzelne *.c Dateien auslagerst. Also deine State 
Machine z.B. mit in die handy.c Die ganzen UART Funktionen in eine extra 
UART.c and so on...

Pass auch auf deine globalen Variablen auf. Da fehlt bestimmt auch 
irgenwo ein volatile.

von Phil (Gast)


Lesenswert?

wie hast du den code in einen Atmega gebracht?

Ich habe schon den Code für den Temp Sensor rausgenommen,
Data ist aber immer noch 106,6 % voll !!

von Phil (Gast)


Lesenswert?

ATMEGA8, wollte ich vorher schreiben

von Remote O. (remote1)


Lesenswert?

Auszug aus dem Artikel:
Die aktuelle Software passt nicht mehr in einen ATmega8. Ich arbeite 
aktuell mit einem ATmega32. Mit ein paar Anpassungen sollte es aber 
problemlos möglich sein, den Code in der Größe stark zu reduzieren. So 
können z.B. die Bibliotheken zur Ansteuerung des Temperatursensors 
entfallen (twi.c, twi.h, ds75lv.c und ds75lv.h).

Hast du die Optimierungen eingeschaltet?
Du kannst auch Funktionen, welche du nicht benötigst rausschmeissen. 
Evtl. brauchst du z.B. nicht die Funktion zum Anzeigen von Nachrichten 
auf dem Display (sms_diaplay_text) etc...

von Remote O. (remote1)


Lesenswert?

Remote One schrieb:
> Ich habe schon den Code für den Temp Sensor rausgenommen,
> Data ist aber immer noch 106,6 % voll !!

Data sind Variablen etc. du kannst ja den SMS Puffer Speicher von 450 
Zeichen reduzieren. Also einfach in der uart.h das define uart_maxstrlen 
von auf z.b 50 reduzieren. Das bedeutet aber auch, dass du nicht mehr 
SMS mit 160 Zeichen empfangen kannst. Die 450 kommt Zustande, da ja 
neben den einzelnen Zeichen der Nachricht noch der PDU Header dazukommt 
(also TelNr, Zeitstempel etc.). Zudem wird jedes Zeichen der Nachricht 
ja im PDU Format als Hex String übermittelt. Also ist im schlimmsten 
Fall jedes einzelne Nachrichtenzeichen 2 Byte groß. Jeder konstante 
String nimmt natürlich auch Speicher im Data Bereich weg. Also jeden 
printf("at-....");

Ich schau mal was in den nächsten Tagen noch reduzieren kann.

von Phil (Gast)


Lesenswert?

oh man, schaffs es mittlerweile nicht mehr bei jedem Anruf einen Pin zu 
toggln!
1
if ( strstr((char*)uart_string,p_sms_telnr_tmp) ){
2
      UCSRB &= ~(1 << RXCIE);    // uart RX ISR deaktivieren
3
      uart_clear();
4
      uart_sends("AT+CHUP\r\n");  //Auflegen
5
      anz_klingeln=0;
6
      _delay_ms(100);  // auf Antwort von AT+CHUP warten
7
      uart_clear();
8
      if (Heizung==0)
9
        {
10
          Heizung=1;
11
        }
12
      else
13
        {
14
          Heizung=0;
15
        }
16
17
      // UART RX ISR aktivieren  
18
      if (UART_ISR!=0) { UCSRB |= (1 << RXCIE); }
19
      uart_str_complete=0;
20
      return SMS_RETRIEVE_TELNR;
21
    }
gehört doch in diesen Abschnitt odeR?

von Remote O. (remote1)


Lesenswert?

Hattest du nicht bei einem Text von "Ein" in der SMS die Heizung 
eingeschaltet??

Dann ist es doch einfacher, diesen Bereich in der sms.c anzupassen:
1
const SMS_CMD_LIST_T sms_cmd_list[] = {
2
  {"set",sms_cmdset},
3
  {"test",sms_cmdtest}
4
};
Also statt "set" nimmst du "Ein" und gibst dann noch die Funktion an, 
welche ausgeführt werden soll.

OK, du hast es aber erst einmal versucht, mit einem Anruf.

In der sms.c brauchst du dazu eigentlich gar nichts ändern. Schau dir 
doch einfach mal die main loop an, dort wird zyklisch sms_state_machine 
ausgeführt. Der Rückgabewert ist aus dem enum:
1
typedef enum {
2
  SMS_OK,      /**< OK von Mobiltelefon empfangen */
3
  SMS_ERROR,    /**< ERROR von Mobiltelefon empgangen */
4
  SMS_MSG_DECODE,    /**< Textnachricht eingegangen, decodiert und in \ref SMS_DECODE_DATA_T Struktur gespeichert */
5
  SMS_INCOMING_RING,  /**< eingehender Anruf */
6
  SMS_CANCEL_RING,  /**< eingehender Anruf wurde abgewiesen */
7
  SMS_REQUEST_TELNR,  /**< Telefonnummer des eingehenden Anruft wurde abgefragt */
8
  SMS_RETRIEVE_TELNR,  /**< Anrufer wurde abgewiesen, Telefonnummer ermittelt und korrekt mit \ref SMS_TELNR verglichen */
9
  SMS_IDLE    /**< empfangene Zeichenkette wurde nicht in sms_state_machine "gefunden" (kein Eintrag) */
10
} SMS_MSG;
Das heisst, du kannst in der main loop von der sms_state_machine den 
Rückgabewert vergleichen mit SMS_RETRIEVE_TELNR.
1
uint8_t flag;
2
flag=sms_state_machine()
3
if (flag==SMS_RETRIEVE_TELNR){
4
//mach irgend was
5
}
Wenn das zutrifft, hast DU angerufen (insofern du in der sms.h deine 
Telefonnummer eingetragen hast, also SMS_TELNR). Das ist denke ich das 
einfachste. Das ganze Projekt ist ja extra so angelegt, dass du 
möglichst wenig am code ändern musst. Also entweder mit den 
Aufzählungstypen arbeiten (enum SMS_MSG) oder eben das mit den 
Textnachrichten-Phrasing.

Schau dir in Verbindung mit dem Detektieren des Anrufes auch einmal an, 
was dein Handy sendet bei einem Anruf. Ich vergleiche mit "Ring". Manche 
Mobiltelefone senden aber auch etwas anderes. Also erst einmal mit hterm 
überprüfen und evtl. anpassen.

(Für weitere Fragen bin ich morgen wieder erreichbar^^. Muss jetzt 
langsam Schluss machen.)

von Remote O. (remote1)


Lesenswert?

Phil schrieb:
> Ich habe schon den Code für den Temp Sensor rausgenommen,
> Data ist aber immer noch 106,6 % voll !!

Remote One schrieb:
> Data sind Variablen etc. du kannst ja den SMS Puffer Speicher von 450
> Zeichen reduzieren. Also einfach in der uart.h das define uart_maxstrlen
> von auf z.b 50 reduzieren.

Das mit den 50 war etwas zu voreilig. Ich habe mir mal eben den Header 
vom PDU String angeschaut. Der ist im schlimmsten Fall 60Byte groß. Das 
heisst, wenn du für uart_maxstrlen 290 eingibst sollte es auch 
problemlos in die Data Sektion des ATmega8 passen (habe bei dem Test die 
Lib zum Temp Sensor noch mit drin gehabt, also kann es auch höher als 
290 sein). Bei einem eingestellten Wert von 290 solltest du noch 
Textnachrichten mit ca. 130 Zeichen empfangen können.

von Phil (Gast)


Angehängte Dateien:

Lesenswert?

Erst einmal möcht ich mich bei dir bedanken, dass du dich um mein 
Problem so annimst!

Ich sag dir einmal was mein Programm können sollte:

- Bei Anruf soll die Heizung umgeschaltet werden und eine SMS mit dem 
aktuellen Status der Heizung zurück gesendet werden.

- wenn eine SMS mit dem Text "Ein" ankommt soll eingeschaltet werden.
- wenn eine SMS mit dem Text "Aus" ankommt soll ausgeschaltet werden.
- wenn eine SMS mit dem Text "Status" ankommt soll der aktuelle Status 
per SMS zurück gesendet werden.

So, bin jetzt beim ersten Problem:
Bei Anruf umschalten: Habe ich so gelöst wie du gestern gesagt hast.
Funktioniert auch nur kommt am Handy dann ein komisches Symbol, das 
Handy lasst sich auch nicht mehr normal bedienen bzw. ausschalten.
Das Symbol findest du im Anhang.
Das Handy lässt sich weiter hin mit den AT Befehlen steuern, also
soweit kein Problem - wahrscheinlich aber trotz dem nicht erwünscht.

Vielleicht könnten wir auch per Email weiter kommunizieren...

von Phil W. (wurglitsphil)


Lesenswert?

Phil schrieb:
> Funktioniert auch nur kommt am Handy dann ein komisches Symbol, das
> Handy lasst sich auch nicht mehr normal bedienen bzw. ausschalten.

Das Problem hat sich mit einem anderen Handy erledigt...
Weiß jetzt nicht was der Fehler war.

Werd jetzt das Thema mit den SMS versuchen zu lösen, bei Problemen melde 
ich mich wieder...

von Remote O. (remote1)


Lesenswert?

Schön dass sich alles von alleine regelt ;)
Ich hab den Artikel zum Versenden von SMS auf deine Anfragen auch noch 
einmal ergänzt. Da kannst ja auch noch mal rein schauen. Auch wenn sich 
das mit dem "Symbol" erledigt hat, so sieht es für mich so aus, als 
würde das Handy erkennen, dass das Datenkabel dran ist und in einen 
"Kommunikationsmodus" umschalten. Das kann man bestimmt in den 
Einstellungen abschalten. Die zwei Symbole sehen ja schon wie 2 Handys 
aus und die Pfeile symbolisieren den Datenaustausch. Das würde auch 
erklären, warum die AT Kommandos noch klappen.

von Phil W. (wurglitsphil)


Lesenswert?

Remote One schrieb:
> Das kann man bestimmt in den
> Einstellungen abschalten

ok, das werde ich versuchen und sag dir dann bescheid!

Bin nun beim Versenden der SMS:

in der Main schleife läuft nun:
1
flag=sms_state_machine();
2
  if (flag==SMS_RETRIEVE_TELNR){
3
    if(Heizung==0)
4
    {
5
      Heizung=1;
6
      sms_send(SMS_TELNR,"Heizung Ein");
7
    }
8
    else
9
    {
10
      Heizung=0;
11
      sms_send(SMS_TELNR,"Heizung Aus");
12
    }
13
  }

der MC sendet aber nichts über die Schnittstelle raus, nicht einmal das 
"AT+CMGS=xx" geht raus.

was hab ich falsch gemacht :-) ?

von Remote O. (remote1)


Lesenswert?

Ich habs auch gerade mal über hterm getestet (Handyakku ist gerade 
leer^^) und da geht alles problemlos raus.
Kannst du das Problem weiter eingrenzen?
Also falls du ein Display hast ein paar Zwischenausgaben machen oder 
LEDs toggeln. Ich weiss ja icht in wie fern du was am code geändert 
hast. Aber in der Funktion sms_send wird ja lediglich über printf der 
PDU string raus geschrieben.
Wird denn der eingehende Anruf korrekt detektiert?

In der sms_send sind zwei while Schleifen vor der Ausgabe von AT+CMGS. 
Evtl hängst du da fest.
Ist die Telefonnummer auch ein String? Also sind im Makro die "..." mit 
dabei.

von Phil W. (wurglitsphil)


Lesenswert?

1
UCSRB &= ~(1 << RXCIE);    // UART Receive ISR ausstellen
2
printf("AT\r\n");
3
_delay_ms(200);
4
// Nachricht umwandeln in PDU-Format
5
while (nachricht[cnt_txt]!=0)
6
{

ich hab jetzt vor der ersten while schleife ein "AT" eingefügt und das 
delay, jetzt funktioniert das SMS senden.
Versteh aber eigentlich nicht was das bringen soll...

Remote One schrieb:
> Ist die Telefonnummer auch ein String? Also sind im Makro die "..." mit
> dabei.

das stimmt, der Anruf wird ja auch richtig erkannt.

von Remote O. (remote1)


Lesenswert?

Das wird einfach nur das delay sein. Das hab ich auch schon 
festgestellt, dass die Mobiltelefone mitunter etwas Zeit zum Überlegen 
brauchen ;)

Phil Wurglits schrieb:
> das stimmt, der Anruf wird ja auch richtig erkannt.

Stimmt^^

von Phil W. (wurglitsphil)


Lesenswert?

Jetzt möchte ich noch im Hauptprogramm den Text der Empfangengen 
Nachricht auswerten.
Kannst du mir das bitte kurz zeigen bzw. hast du auch gleich eine gute 
Seite da besser in die C-Programmierung reinzuschnuppern???

von Remote O. (remote1)


Lesenswert?

Das Auswerten von Textnachrichten wird automatisch in der 
sms_state_machine gemacht. Das heißt, wenn über die serielle 
Schnittstelle erkannt wird, dass einen Textnachricht eingeht, wird der 
Index ermittelt und diese ausgelesen. Das Ergebnis, also der PDU String, 
wird decodiert und in der globalen Variable sms_dec_data der 
Datenstruktur SMS_DECODE_DATA_T abgelegt. Automatisch wird ebenfalls der 
decodierte Text nach den von dir festgelegten Schlüsselwörtern 
durchsucht und die entsprechend hinterlegte Funktion über den 
Funktionspointer aufgerufen. Du brauchst also nur, wie im Artikel 
beschrieben, in der sms.c das Konstrukt
1
const SMS_CMD_LIST_T sms_cmd_list[] = {
2
  {"set",sms_cmdset},
3
  {"test",sms_cmdtest}
4
};
anpassen. Also der erste Parameter ist der String auf den reagiert 
werden soll. Dabei ist zu beachten, dass es nur Kleinbuchstaben sind, da 
ich den Text immer in Kleinbuchstaben wandle und dann erst vergleiche. 
Die Funktion, also hier z.B. sms_cmdset muss nach folgendem Schema 
aufgebaut sein:
1
uint8_t funktionsname(uint8_t dat){
2
...
3
}
Ich habe das so gestaltet, da ich es noch realisieren möchte, dass auch 
Parameter an die Funktion übergeben werden. Also, dass man z.B. 
Heizung#1 schreibt und die Heizung eingeschaltet wird bzw. bei Heizung#0 
wird eben ausgeschaltet. Da würde ich dann nur nach Heizung suchen und 
die nachfolgende Zahl als Parameter der Funktion übergeben. Das ist 
zumindest geplant^^

von Phil W. (wurglitsphil)


Lesenswert?

ok, das Problem ist nur dass ich den beiliegenden Code auskommentiert 
habe, sonst würde der Code nicht in den ATMEGA passten.
Es hilft auch nichts wenn ich den Code auskommentiere um einen Text auf 
das Display zu schreiben.
Die Empfangslänge für den ankommenden String beträgt 200 Zeichen.
Sonst kann ich meiner Meinung nach nichts mehr auskommentieren, da ich 
die anderen Funktionen benötige.

hättest du vielleicht sonst noch eine Idee oder muss ich auf einen 
größeren Controller ausweichen?
Ist halt mühsam weil die Platine und der Aufbau schon fix fertig ist!
1
// sortieren der Befehlsliste (Voraussetzung für bsearch)
2
      char *tmp;
3
      qsort(&sms_cmd_list, (sizeof(sms_cmd_list)/sizeof(SMS_CMD_LIST_T)), sizeof(SMS_CMD_LIST_T), (int(*)(const void*,const void*))strcmp);
4
      ptr_nachricht = strtok_r(nachricht,SMS_DELIMITER,&tmp);  // ersten Befehl extrahieren
5
      while (ptr_nachricht!=NULL){
6
        // Befehle entsprechend Liste ausführen
7
        // nach www.wachtler.de/informatik_2/node58.html
8
        strcpy(keyItem.cmd,ptr_nachricht);  // gefundenes Kommando übergeben
9
            SMS_CMD_LIST_T* spItem = (SMS_CMD_LIST_T*)bsearch (&keyItem, sms_cmd_list, (sizeof(sms_cmd_list)/sizeof(SMS_CMD_LIST_T)), sizeof(SMS_CMD_LIST_T), (int(*)(const void*,const void*)) strcmp);
10
            if (spItem != NULL) { spItem->fp(0); }
11
        ptr_nachricht = strtok_r(NULL,SMS_DELIMITER,&tmp);  // neues Kommando suchen (falls mehrerer vorhanden sind)
12
      }

von Remote O. (remote1)


Lesenswert?

Na ja, sms_time könntest du noch auskommentieren. Also 
auskommentieren/löschen von:
* sms_time
* sms_display_text
* twi.c
* twi.h
* ds75lv.c
* ds75lv.h
* uart_maxstrlen verringern (für Data Bereich)

von Phil W. (wurglitsphil)


Lesenswert?

Remote One schrieb:
> Na ja, sms_time könntest du noch auskommentieren

Sorry, hab ich vergessen zu sagen.
Habe sms_time auch schon draußen,
die Librarys fürs LCD und den Temp Sensor auch schon draußn.
Ich glaub dann bleibt leider nichts mehr übrig :-(

von Remote O. (remote1)


Lesenswert?

Ansonsten wäre evtl. der ATmega328P was für dich. Der hat 32kb, hat aber 
auch 23 Pins. Also gleiche Größe. Ich weiß nur nicht in wie weit der 
jetzt pinkompatibel zum Atmega8 ist.

Schau mal hier nach:
http://www.atmel.com/dyn/products/param_table.asp?family_id=607&OrderBy=part_no&Direction=ASC

EDIT: Hab gerade nachgeschaut, ist pinkompatibel
EDIT2: hier gibt's den relativ günstig:
http://shop.myavr.de/index.php?404;http://www.myavr.de:80/shop/article.php?artDataID=167
EDIT3: wenn du 1€ sparen möchtest geht bestimmt auch der ATmega168

von Phil W. (wurglitsphil)


Lesenswert?

er ist pinkompatibel!

Ok, dann werd ich mir das Ding mal besorgen!

Vielen Dank für deine tolle Hilfe...

von Phil W. (wurglitsphil)


Lesenswert?

Hallo!

Hab mir nun den ATMEGA328 angeschafft und auch schon das erste Problem.
Immer wenn das Handy etwas über den UART zum AVR sendet startet dieser 
neu.

Was kann den das für ein Problem sein.
Ich habe alle Register auf den ATMEGA328 angepasst, sonst sollte sich im 
Code ja nichts verändern oder?

von Remote O. (remote1)


Lesenswert?

Das kann alles und auch nichts sein. Teste am Besten alles step by step 
durch. D.h. erst einmal mit hterm prüfen ob du eine vernünftige 
Kommunikation mit dem Mobiltelefon zu Stande bekommst. Dann bei dem 
neuen µC lediglich die UART Schnittstelle überprüfen. D.h. auch wieder 
mit hterm --> also hterm + µC.
Dann kannst du erst das Mobiltelefon anschließen und weiter testen.

Hast du die Fuses des neuen µC richtig gesetzt? OK das wird du 
spätestens beim Test hterm + µC sehen. Also immer schön Schritt für 
Schritt vorgehen und nicht zu viel auf einmal ändern um korrekt 
Rückschlüsse zu ziehen.

Hast du was an der Beschaltung geändert, also hast du alle 
Abblockkondensatoren dran?

von Phil W. (wurglitsphil)


Lesenswert?

Hallo,

hab das Problem behoben...
Die Interruptroutine muss man folgendermaßen aufrufen ISR(USART_RX_vect)

was anderes,
Ich habe im Hautpprogramm eine Variable die Heizung heißt!
Wenn ich nun "ein" als SMS bekomme soll diese Variable auf 1 gesetzt 
werden.

Ich habe nun im main.c folgenden Code
1
uint8_t sms_cmdein(uint8_t dat)
2
{
3
  Heizung=1;
4
  return 0;
5
}

und in sms.c
1
const SMS_CMD_LIST_T sms_cmd_list[] = {
2
  {"ein",sms_cmdein},
3
  {"aus",sms_cmdaus}
4
}

die SMS wird nachher auch gelöscht!

muss ich den Code den ich im main.c habe im sms.c schreiben?
Wenn ja, wie kann ich dann meine Variable ansprechen.

Ein bisschen dumm erklärt, ich hoffe du weißt was ich meine!

von sebastians (Gast)


Lesenswert?

In einem Header, den du in beiden Dateien mit #include einbindest:

extern uint8_t sms_cmdein(uint8_t dat);

von Remote O. (remote1)


Lesenswert?

Phil Wurglits schrieb:
> Ein bisschen dumm erklärt, ich hoffe du weißt was ich meine!

Richtig verstanden hab ich nicht^^

Phil Wurglits schrieb:
> Ich habe nun im main.c folgenden Code
<uint8_t sms_cmdein(uint8_t dat)
> {
>   Heizung=1;
>   return 0;
> }
>
> und in sms.cconst SMS_CMD_LIST_T sms_cmd_list[] = {
>   {"ein",sms_cmdein},
>   {"aus",sms_cmdaus}
> }

Aber da fehlt noch der Eintrag in sms.h. Also du musst den Prototyp in 
sms.h anlegen, damit sms.c auch was damit anfangen kann. Also einfach 
den folgenden Eintrag durch deine Funktionsprototypen ersetzen (ist in 
sms.h ganz unten zu finden)
1
extern uint8_t sms_cmdset(uint8_t dat);

Da müsste eigentlich auch eine Fehler oder ein Warning kommen, wenn du 
das nicht gemacht hast. Aber evtl. hab ich dich nur falsch verstanden.

von Phil W. (wurglitsphil)


Lesenswert?

okela, habe jetzt alles hinbekommen, dank deiner Hilfe - vielen dank!

Nun noch eine Frage!
Die Software funktioniert ja nur mit einer Nummer die fix programmiert 
ist.

Wäre es nicht möglich beim Einschalten die ersten 5 Nummern im 
Telefonbuch auszulesen und diese für Anrufe oder SMS freigeben?

lg, philip

von Remote O. (remote1)


Lesenswert?

Phil Wurglits schrieb:
> Wäre es nicht möglich beim Einschalten die ersten 5 Nummern im
> Telefonbuch auszulesen und diese für Anrufe oder SMS freigeben?

Ja, möglich ist alles...
Ich schau mir das mal an. Hab in letzter Zeit aber mehr mit meiner 
Masterarbeit zu tun. Ich such auf jeden Fall mal den AT-Befehl zum 
auslesen der Nummern raus. Sollen die Nummern vom Mobiltelefon oder von 
der SIM kommen?
Na ja, da kann ich auch wieder einen Schalter aller #define... machen.

von Phil W. (wurglitsphil)


Lesenswert?

Ich habe das mit den Nummern in meinen alten Programm so gelöst, dass 
ich die ersten 5 Nummern von der Sim Karte abfrage und diese dann für 
Anruf und SMS freigebe.
Nur schaffe ich es nicht, dass ich meinen alten Code in dein Projekt 
einbaue, so dass es funktioniet - da hab ich wohl zu wenig Wissen in C !

Ich kann dir gerne meine Lösung in meinem alten Projekt am Abend posten.
Ist für dich dann sicher einfach, das ganze zu implementieren.

von Remote O. (remote1)


Lesenswert?

Phil Wurglits schrieb:
> Ich habe das mit den Nummern in meinen alten Programm so gelöst, dass
> ich die ersten 5 Nummern von der Sim Karte abfrage und diese dann für
> Anruf und SMS freigebe.

Das sollte mit at+cpbs und at+cpbr eigentlich nicht so schwer sein. Ich 
muss ja nur ein Array für die 5 Telefonnummern anlegen und die ersten 5 
Einträge da rein packen. Das bekomm ich schon hin^^
Der Vergleich müsste natürlich angepasst werden. Das klappt schon...

von Phil W. (wurglitsphil)


Lesenswert?

ich möchte ja nicht unhöfflich sein :-), aber bis wann wirst du den Code 
fertig haben ?

von Remote O. (remote1)


Lesenswert?

Sende mal an dein Mobiltelefon AT+CPBS="SM" <cr><lf>
und danach AT+CPBR=1 <cr><lf>
Poste dann mal die exakte Antwort am besten als hex und ASCII Werte.

Ich hab grad mal ein paar Stunden Zeit, aber kein Mobiltelefon zur Hand. 
Ich weiß nicht, ob vor der Antwort von CPBR noch ein \n\r kommt und wo 
evtl Leerzeichen sind.

Ansonsten kann ich mich da nicht vor Donnerstag ran setzten.

von Phil W. (wurglitsphil)


Lesenswert?

Auf den Befehl AT+CPBR=1 <cr><lf> kommt

+CPBR: 1,"+43664xxxxxxx",145,"Phil"

OK

von Remote O. (remote1)


Lesenswert?

Das Wichtigste hast du vergessen, welche Steuerzeichen werden gesendet? 
Das OK ist z. B. meist doppelt und dreifach mit Steuerzeichen 
"eingepackt".

von Remote O. (remote1)


Lesenswert?

Eigentlich hab ichs, aber es gibt noch ein paar kleine Probleme. Wenn 
ich die Antwort von AT+CPBR einlese mit:
1
char telnr[25];
2
char tmp[SMS_TELNR_MAX_LEN+1];
3
uint8_t i=0;
4
int dummy;
5
...
6
scanf("+CPBR: %i,\"%s\",%i,\"%s\"\r\n",&dummy,telnr,&dummy,tmp);
 Dann erhalte ich nach Ausgabe von telnr auf dem Display
1
+43664xxxxxxx",145,"Phil"
anstatt
1
+43664xxxxxxx
Keine Ahnung woran das liegt. Da muss ich noch mal testen, oder hat 
jemand eine Idee?!?!

von Klaus W. (mfgkw)


Lesenswert?

%s liest immer bis zu einem white space, also bis Leerzeichen,
Zeilenvorschub, Tab etc..

Eine feinere Steuerung geht mit %[...] bzw. %[^...].

Wenn du das Lesen also bei einem Gänsefüßchen abbrechen willst,
müsstest du %[^"] im Formatstring haben, was dann im Quelltext
als %[^\"] zu schreiben wäre.

von Remote O. (remote1)


Lesenswert?

Verdammt, hast Recht (Brett vorm Kopf^^)
Da ich die Länge der Telefonnummer nicht kenne bleibt mir wohl nichts 
anderes übrig, als auf das " nach der Telefonnummer zu parsen und mit \0 
zu ersetzen.

von Remote O. (remote1)


Lesenswert?

Klaus Wachtler schrieb:
> Wenn du das Lesen also bei einem Gänsefüßchen abbrechen willst,
> müsstest du %[^"] im Formatstring haben, was dann im Quelltext
> als %[^\"] zu schreiben wäre.

Cool, das war neu für mich. Steht nicht einmal in meinem C Buch. Hab 
schon nach so etwas gesucht ;)
Werde es gleich mal probieren

von Klaus W. (mfgkw)


Lesenswert?

wieso mit \0 ersetzen?
1
scanf("+CPBR: %i,\"%[^\"]\",%i,\"%s\"\r\n",&dummy,telnr,&dummy,tmp);
sollte das schaffen.
Den Dummy-Wert kannst du dir übrigens sparen mit:
1
scanf("+CPBR: %*i,\"%[^\"]\",%*i,\"%s\"\r\n",telnr,tmp);

von Klaus W. (mfgkw)


Lesenswert?


von Klaus W. (mfgkw)


Lesenswert?

PS: scanf() liefert übrigens auch einen Wert zurück, den man gerne
nutzen darf um die Konversion zu kontrollieren...

von Remote O. (remote1)


Lesenswert?

Klaus Wachtler schrieb:
> wieso mit \0 ersetzen?scanf("+CPBR: 
%i,\"%[^\"]\",%i,\"%s\"\r\n",&dummy,telnr,&dummy,tmp);
> sollte das schaffen.
> Den Dummy-Wert kannst du dir übrigens sparen mit:scanf("+CPBR: 
%*i,\"%[^\"]\",%*i,\"%s\"\r\n",telnr,tmp);

Ja thx, ich hatte deinen Beitrag zu spät gelesen. Ich habs jetzt so:
1
scanf("+CPBR: %i,\"%[^\"]",&dummy,telnr);
damit fällt dann auch das lästige tmp raus (frisst eh nur Speicher)

Klaus Wachtler schrieb:
> http://www.wachtler.de/ck/19_4_Liste_Funktionen.ht...

Ja, da sollte man(n) dann doch mal öfters nachschauen. Hab die zwar in 
den Favoriten, schau aber meist dann doch ins C Buch^^

Nochmal thx, wieder was gelernt

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:
> wieso mit \0 ersetzen?
>
1
> scanf("+CPBR: %i,\"%[^\"]\",%i,\"%s\"\r\n",&dummy,telnr,&dummy,tmp);
2
>
> sollte das schaffen.

Nichts gegen diese "neuen" Regular Expressions im Formatstring.

Aber:
Es ist IMHO unklug, von der Eingabe nicht alles zu lesen. Mit sowas 
kommt man ganz schnell in Teufels Küche bei nachfolgenden 
Leseversuchen, weil man nie weiß was und wieviel noch im Input-Buffer 
wartet. Besonders dann, wenn es beim scanf-Parsen zu Fehlern kommt, 
sitzt man da ganz schnell in der Bredoullie.

Die Empfehlung von früher
  zuerst eine komplette Zeile in einen programminternen Buffer lesen
  von dort weg mit einem sscanf (oder sonst irgendwie anders) parsen.
hat auch heute noch ihre Berechtigung.

Edit: vergiss das mit dem 'nicht alles lesen' wieder. Hab zu spät 
gesehen, dass ja ohnehin bis zum \n gelesen wird. Nichtsdestotrotz 
bleibt noch das unangenehme Behandeln von Fehlersituationen, die einem 
mit scanf den ganzen Tag versauen können.

: Wiederhergestellt durch User
von Klaus W. (mfgkw)


Lesenswert?

Daher mein vorsichtiger Ratschlag mit dem Rückgabewert.

Prinzipiell gebe ich dir aber sicher recht.
Wenn man eine definitiv in Zeilen organisierte Eingabe erwartet,
ist es sinnvoll die auch so zu verarbeiten.

Ob man dafür je nach Rechner reichlich Puffer spendieren will,
hängt natürlich von den Umständen ab.
Auf einem PC ist das gar kein Thema, aber da würde ich mir
sowas gar nicht mehr in C antun, sondern C++ nehmen.
Auf einem MC dagegen will man vielleicht nicht immer
dafür Speicher veplempern. scanf() ist jetzt auch nicht
gerade ein Sparmodell, aber wenn man es an einer Stelle schon
braucht, kann man die Funktionalität auch gleich ausreizen,
anstatt sich an jeder Stelle selbst etwas zu bauen.

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:

> braucht, kann man die Funktionalität auch gleich ausreizen,
> anstatt sich an jeder Stelle selbst etwas zu bauen.

Schon klar.

Ich denke, dir ist es in deinen Sturm und Drang Lehrjahren auch nicht 
anders gegangen als mir und so ziemlich jedem anderen C-Novizen. Man ist 
begeistert von den Möglichkeiten, die einem der Format-String von scanf 
so bietet und baut hoffnungsfroh seine ersten Programme mit scanf. 
Funktioniert auch alles super, bis man das erste mal nicht selbst an der 
Eingabe sitzt. Plötzlich krankt es hinten und vorne und nichts geht 
mehr. (Die Erklärung: Als Entwickler tendiert man dazu, Eingaben die 
nicht erlaubt sind auch nicht zu machen. Lieschen Müller ist das aber 
egal, die tippt frei von der Leber weg). Dann fängt man an, mit dem 
Returnwert von scanf zu arbeiten und irgendwie den Input Stream wieder 
in einen vernünftigen Zustand zu bringen etc. Nach langen, mühevollen, 
frustrierenden Versuchen kommt jeder irgendwann zum Schluss, dass es so 
nicht wirklich brauchbar geht. Solange der Input machinengeneriert ist 
und man nicht unbedingt mit Fehlern im Datenformat rechnen muss, gehts 
ja noch. Aber ein scanf direkt auf die Benutzereingabe ist ganz schnell 
eine 'Nightmare die sich gewaschen hat'.

Wollte das nur loswerden. Nicht weil ich vor den Möglichkeiten des 
Formatstrings nichts halte (ganz im Gegenteil), sondern weil scanf 
oftmals nicht die Lösung darstellt, sondern der Weg oft genug über 
sscanf führt.

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.