Maker Pro
Maker Pro

help over microcontroller code

aditya bhandari

Jun 10, 2014
5
Joined
Jun 10, 2014
Messages
5
Hello,
i am facing problems understanding the following C code for microcontroller. Actually the task is to configure an external GSM modem via serial microcontroller port but i am not able to get the coding exactly. can someone please help me understand it. also it would be nice if some one can give me the assemble code for same.


void gsmcmdsend(unsigned char *cmd);

unsigned char gsm_cmd3[]="AT&W";
unsigned char gsm_cmd4[]="AT+CMGF";
void gsmcmdsend(unsigned char *cmd)
{
unsigned char i;
for(i=0;*cmd!='\0';i++)
{
SBUF=*cmd;
while(TI==0);
TI=0;
cmd++;
}
SBUF=0x0A;
while(TI==0);
TI=0;
SBUF=0x0D;
while(TI==0);
TI=0;
while(RI==0);
RI=0;
}

void main()
{
gsmcmdsend(gsm_cmd3);
gsmcmdsend(gsm_cmd4);
}
 

kpatz

Feb 24, 2014
334
Joined
Feb 24, 2014
Messages
334
Here's a commented version of the above program:

Code:
void gsmcmdsend(unsigned char *cmd);

unsigned char gsm_cmd3[]="AT&W";     // GSM modem commands
unsigned char gsm_cmd4[]="AT+CMGF";
void gsmcmdsend(unsigned char *cmd)
{
  unsigned char i;
  for(i=0;*cmd!='\0';i++)  // Loop through command one character at a time
  {
    SBUF=*cmd;              // Put character in UART output buffer (start transmit)
    while(TI==0);          // Loop until transmit complete
    TI=0;                  // Clear transmit flag
    cmd++;                  // Increment pointer to next character
  }
// This really should send 0D followed by 0A, it's backwards
  SBUF=0x0A;               // Send 0x0A (linefeed) to output buffer
  while(TI==0);              // Loop until transmit complete
  TI=0;                      // Clear transmit flag
  SBUF=0x0D;               // Send 0x0D (carriage return) to output buffer
  while(TI==0);              // Loop until transmit complete
  TI=0;                      // Clear transmit flag
  while(RI==0);            // Loop until receive complete
  RI=0;                    // clear receive flag
}

// This is executed first
void main()
{
  // Initialization of controller, peripherals needs to go here
  gsmcmdsend(gsm_cmd3);  // Send AT&W to GSM modem
  gsmcmdsend(gsm_cmd4);  // Send AT+CMGF to GSM modem
}

It has some flaws. main() needs to initialize things, such as peripherals (especially the UART used to send data to the modem), setting I/O pins to inputs or outputs, etc.

Also, 0D usually is sent ahead of 0A (carriage return/line feed, not the opposite).

At the end of gsmcmdsend(), there's a loop waiting for RI to be set. I don't know what micro is being used or how its UART works, but if data is being received, there is probably an RBUF register that needs to be read to prevent an overrun condition. Also, if the receiver is disabled, or the modem doesn't echo or respond, it's possible that RI will never get set, and your code will get stuck in a loop here.
 

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
Good analysis kpatz!

It's not usual to send the 0x0A at all; just the 0x0D is normally used on command strings. If the device has local echo enabled, it will echo a 0x0A along with the 0x0D, but modems do not normally expect to receive a 0x0A character.

Also it's normal to have a separate function to send a character out the UART, which is called as necessary by higher-level functions. This function normally checks for UART transmit ready first, then sends the character and returns.

Also, in the send-character loop, there is no need for the 'i' variable. The loop is normally written as a while() loop that just tests the character at the pointer for zero/non-zero.
 

kpatz

Feb 24, 2014
334
Joined
Feb 24, 2014
Messages
334
Also, in the send-character loop, there is no need for the 'i' variable. The loop is normally written as a while() loop that just tests the character at the pointer for zero/non-zero.
I was going to point that out, but I figured I'd leave it out for simplicity's sake for now. It could have been done with: "for(;*cmd!='\0';cmd++)" as well.

Also, depending on the micro, pointers may be less efficient than using arrays (lower-end PICs come to mind). Using "
for(i=0; cmd[ i ]; i++)" may be more efficient. (I added spaces around "i" so the brackets aren't interpreted as BB code)
 

KrisBlueNZ

Sadly passed away in 2015
Nov 28, 2011
8,393
Joined
Nov 28, 2011
Messages
8,393
He wasn't using an array. He was using a separate variable that would be incremented each time through the loop but never used!

I think the most efficient loop (including on baseline PICs) would be
Code:
byte c;
while ((c = *cmd++) != '\0')
  uart_tx(c);
 

kpatz

Feb 24, 2014
334
Joined
Feb 24, 2014
Messages
334
He wasn't using an array. He was using a separate variable that would be incremented each time through the loop but never used!
Strings are arrays of chars, so that's what I was referring to. But in the original code, i wasn't used for anything so initializing and incrementing it would have been a waste.

In XC8 for PIC at least, pointers add overhead since they could point to any number of things: variables in memory, registers, constants in flash ROM, data EEPROM, etc. The optimizer helps if you pay for it and make your pointer strongly typed enough (i.e. use a const char * to point to a const char array, for example).

Without optimization the array method is more efficient, at least that's what I've seen with the limited C work I've done on PICs, and since the free version of XC8 has optimization disabled.

I don't know what micro the OP is using. The optimization rules may be different on whatever it is (AVR perhaps?)
 

aditya bhandari

Jun 10, 2014
5
Joined
Jun 10, 2014
Messages
5
this is the entire program of my project. The project is SMS based homeautomation which activates or deactivates the home appliance connected to a relay when a particulat text is sent. also there is a LCD connected to see the process. I am getting all the portion of LCD interface but am unknown to the serial interface part. All i want to do is convert the code below to "assembly"

#include<reg51.h>
sbit rs=P3^7;
sbit rw=P3^6;
sbit e=P3^5;
sbit fan=P1^0;
sbit lgt=P1^1;
void gsmcmdsend(unsigned char *cmd);
void cmm(char value);
void dat(char value);
void compare();
unsigned char card_id[96];
unsigned char header[]="EFY";
unsigned char gsm_cmd3[]="AT&W";
unsigned char gsm_cmd4[]="AT+CMGF";
void gsmcmdsend(unsigned char *cmd)
{
unsigned char i;
for(i=0;*cmd!='\0';i++)
{
SBUF=*cmd;
while(TI==0);
TI=0;
cmd++;
}
SBUF=0x0A;
while(TI==0);
TI=0;
SBUF=0x0D;
while(TI==0);
TI=0;
while(RI==0);
RI=0;
}
void delay(int count) //Function to provide delay
{
int i,j;
for(i=0;i<count;i++)
for(j=0;j<1275;j++);
}
void cmm(char value)
{
P2 = value;
rs=0;
rw=0;
e=1;
delay(1);
e=0;
delay(1);
return;
}
void dat(char value)
{
P2 =value;
rs=1;
rw=0;
e=1;
delay(1);
e=0;
delay(1);
return;
}
void lcdin()
{ cmm(0x38);
cmm(0x0e);
cmm(0x01);
cmm(0x06);
cmm(0x85);
return;
}
void recieve() //Function to recieve data serialy from RS232
{
unsigned char k;
for(k=0;k<=87;k++)
{
while(RI==0);
card_id[k]=SBUF;
RI=0;
}
}
void main()
{
int l,i;
P1=0x00;
lcdin();
TMOD=0x20; //Enable Timer 1
TH1=0XFD;
SCON=0x50;
TR1=1;
gsmcmdsend(gsm_cmd3);
cmm(0x01);
gsmcmdsend(gsm_cmd4);
cmm(0x01);
cmm(0x85);
for(i=0;i<3;i++)
{dat(header);}
cmm(0xc0);
while(1)
{
recieve();
for(l=83;l<=87;l++)
{
dat(card_id[l]);
}
compare();
}
}
void compare()
{
if ((card_id[83]=='f')&&(card_id[84]=='a') && (card_id[85]=='n') && (card_id[86]=='o') && (card_id[87]=='n'))
fan=1;
else if((card_id[83]=='f')&&(card_id[84]=='a') && (card_id[85]=='n') && (card_id[86]=='o') && (card_id[87]=='f'))
fan=0;
else if((card_id[83]=='l')&&(card_id[84]=='g') && (card_id[85]=='t') && (card_id[86]=='o') && (card_id[87]=='n'))
lgt=1;
else if((card_id[83]=='l')&&(card_id[84]=='g') && (card_id[85]=='t') && (card_id[86]=='o') && (card_id[87]=='f'))
lgt=0;
}

end; //end of program
 

Harald Kapp

Moderator
Moderator
Nov 17, 2011
13,719
Joined
Nov 17, 2011
Messages
13,719
All i want to do is convert the code below to "assembly"

Run it through your compiler and tell the compiler to generate an assembly listing.
 
Top