CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

set motor duty-cycle (+other parameters) via rs232 [solved]

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

set motor duty-cycle (+other parameters) via rs232 [solved]
PostPosted: Sat May 24, 2014 8:29 am     Reply with quote

I have an electronic board that controls in PWM a small DC motor. I want to implement a simple protocol to control the motor via hyper-terminal.

For example,
MF=100 would mean motor forward 100% duty cycle
MR=55 would mean motor reverse 55% duty cycle
DT=2 set a pause of 2s when reversing the motor
DT? return the current setting of DT
MC? return the motor current (from a shunt resistor on the board)

Every command from the pc is terminated with CR (carriage return), and the idea is to look for CR in order to identify the end of the command.

So, from the circular buffer, looking at CR I can extract an array of characters MF=100.
My idea is to combine the first 3 characters into a string ("MF=") and have a state machine with a
case: "MF="....
case: "MR="....
case: "DT="....
case: "DT?"....
case: "MC?"....

And combine the characters 4 to CR into another string, which will be convertet to int16 and used in the 'case:'.

Does is sounds like a good approach?


Last edited by webgiorgio on Fri May 30, 2014 7:23 am; edited 1 time in total
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Sat May 24, 2014 9:09 am     Reply with quote

Code:

MF=100 would mean motor forward 100% duty cycle
MR=55 would mean motor reverse 55% duty cycle
DT=2 set a pause of 2s when reversing the motor
DT? return the current setting of DT
MC? return the motor current (from a shunt resistor on the board)


quicker to parse is:
F100
R55
T2
?
C


that way the command field is always=1
and the <CR> delimits arguments/command where expected.
at least that's how i always do it
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat May 24, 2014 9:19 am     Reply with quote

Links to serial protocol command parser code:
http://www.ccsinfo.com/forum/viewtopic.php?t=39462&start=3
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

PostPosted: Sun May 25, 2014 11:45 am     Reply with quote

ok, thank you, I found some useful hints.
I have the rx_buffer functioning now. However I could not find how to test if the character I receive is a carriage return. I came up with this, seems working.

Code:
         while((data_in_buffer)){
            ch=buffer_getc();
            putc( ch );
            if(ch=='\r') printf("got a CR");
         }


I guess that == is doing a byte comparison. So it can only be used to compare characters (not strings, for which I should use the strcmp)
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

PostPosted: Thu May 29, 2014 4:59 am     Reply with quote

So, here is a working example that:
- receive the characters in the buffer
- strip down the command from the numeric value
- convert the ascii 'number' into a int16 number with atol().

Code:


#include <16F886.h>
#device ADC=10
//#device icd=TRUE
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOLVP
#use delay(clock=8M, restart_wdt)
#use rs232(baud=19200,xmit=PIN_C6,rcv=PIN_C7)
#include <input.c>
#INCLUDE <STDLIB.H>

signed int16 motor_reference;
char c;
char scmd[10], snum[10];
char str;
int16 value;
int1 data_ready, flag1, flag0;
int8 tim1, L;
int i;

#define leg2 PIN_B2 //input2 of L298
//#define gamba4 PIN_C1 (CCP1)//input4 of L298 PWM2
#define enable_motor PIN_B4//enable A of L298
#define buzer PIN_C4

#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE], cmd_string[BUFFER_SIZE], ch;
BYTE next_in = 0;
BYTE next_out = 0;

//BYTE received[BUFFER_SIZE];

//------------------------------------------------------------------------
void configure_pic(void){ //initialization
    SETUP_SPI(SPI_SS_DISABLED);
   //timer0
   setup_timer_0(RTCC_DIV_256);
   enable_interrupts(int_RTCC); //timer0
   //timer1
   setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 ); //gives around 4 Hz interrupt
   enable_interrupts(int_TIMER1);
   //setup ADC
   SETUP_ADC_PORTS(sAN0 | sAN1 |sAN2 | sAN4 | sAN13 | VSS_VDD );
   setup_adc( ADC_CLOCK_DIV_8 ); //
   //setup PWM
   SETUP_CCP1(CCP_PWM);   // Configure CCP1 as a PWM
   //
   enable_interrupts(INT_RDA);
   enable_interrupts(global);
}
//---------------------------------------------------------------------------
void init(void){
   output_bit(enable_motor,0); //motor off
   output_bit(leg2,0);
   motor_reference=0;
   printf("\n\n***** booting... ******\n\n");
   data_ready=0;
   tim1=0;
   flag1=0;
   flag0=0;
   strcpy(scmd, "");
   strcpy(cmd_string, "");
   printf("\n>");
}

#int_rda //------------------------------------------------------------------
void serial_isr() { //interrupt when something is in the USART hw buffer
   buffer[next_in]=getc(); //download the character from hw buffer
   if (buffer[next_in]=='\r') {
      data_ready=1; //set the flag to start empty the buffer
   }
   next_in=(next_in+1) % BUFFER_SIZE;
}

#define data_in_buffer (next_in!=next_out)
BYTE bgetc() { //-------------------------------------------------------
   BYTE c;
   while(!data_in_buffer) ; //while there is data in the buffer
   c=buffer[next_out];      //extract it
   next_out=(next_out+1) % BUFFER_SIZE; //point the next one
   return(c);               //give back the character of [next_out]
}


#int_TIMER0 //----------------------------------------------------------------
void TIMER0_isr(void){ // interrupt
   flag0=1;
}

#int_TIMER1 //----------------------------------------------------------------
void TIMER1_isr(void){ // 4Hz interrupt
   set_timer1(0x0BDC); //3036 in hex is 0BDC
   tim1++;
   flag1=1;
}

//----------------------------------------------------------------------------
void main() {
   configure_pic();
   init();
   while(1){
      //printf("ok");
      if (flag1) {
         output_toggle(buzer);
         flag1=0;
      }
      if (data_ready){ //read cmd_string and empty buffer
         data_ready=0;
         i=0;
         printf("\nBuffered data => ");
         //strcpy(cmd_string, ""); //empty the array. serve??
         while((data_in_buffer)){
            ch=bgetc();
            printf("|"); putc(ch); printf("|");
            if (ch=='\r') ch='\0'; //an array terminated with \0 is a string
            cmd_string[i]=ch;
            i++;
            }
         printf("\nCmd_string: %s", cmd_string);
         L=strlen(cmd_string);
         printf("\nLength: %u", L);
         if (L>3){
            strncpy(scmd, cmd_string, 3);
            scmd[3]='\0';
            printf("\nscmd: %s", scmd);
            strncpy(snum, &cmd_string[3], L-3);
            snum[L-3]= '\0'; //terminate the number with \0
            printf("\nsnum: %s", snum);
            printf("\nLength: %u", strlen(snum));
            value=atol(snum);
            printf("\nvalue x 2 : %Lu", value*2);
            printf("\n\n>");
            }
      }
      if (tim1>=40){
         tim1=0;
      }
     

   
   }
} //end main



And how it looks like in hyperterminal (> is in front of what I type).

Quote:
***** booting... ******


>MF=654
Buffered data => |M||F||=||6||5||4||
|
Cmd_string: MF=654
Length: 6
scmd: MF=
snum: 654
Length: 3
value x 2 : 1308

>MF=10
Buffered data => |M||F||=||1||0||
|
Cmd_string: MF=10
Length: 5
scmd: MF=
snum: 10
Length: 2
value x 2 : 20
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

PostPosted: Thu May 29, 2014 6:46 am     Reply with quote

I should now compare the command string (2 or 3 characters) to a constant string.
For example,
MS should turn on the motor at default speed
MX turn it of.

If I use
Code:
printf("%u",stricmp(scmd, "MS");

does not work, because the second argument should be a pointer to a string, not a string. I don't want to define a variable for each command... So, how do I compare a string to a constant string?

I see that the advice of asmboy of using only one letter is intelligent, because a if (scmd=="S") { } would be sufficient. But I want the commands to be 2 characters (easyer to read and remember).
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Thu May 29, 2014 8:28 am     Reply with quote

You only need one variable for the comparison string.
If (for instance), you have a constant array containing five comparison strings, you can code like:
Code:

const char messages[][5] = {"MA","MB","MC","MD","ME"};
char look_for[3];

int row;

for (row=0;row<5;row++)
{
    strcpy(look_for,messages[row]);
    if (stricmp(scmd,look_for)==0)
       break;
}
//here 'row' contains the message number that matched, or 5
//if nothing was found.


strcpy, is an overloaded function, that will accept constant strings, so they can be copied to RAM for use.

Best Wishes
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

PostPosted: Thu May 29, 2014 1:47 pm     Reply with quote

ok! Very Happy then I implemented a switch to perform the actions associated to each command.
Code:

void run2c(){ //interpret and execute 2 characters commands
   const char messages[][6] = {"MS","MG","ME","MO","MX","LD"};
   char look_for[3];
   int row;
   for (row=0;row<6;row++) {
       strcpy(look_for,messages[row]);
       if (stricmp(scmd,look_for)==0)
          break;
   }
   //here 'row' contains the message number that matched, or 5
   //if nothing was found.
   switch(row){
   case 0: printf("motor s\n");
      break;
   case 1: printf("motor g\n");
      break;
   case 2: printf("motor e\n");
      break;
   case 3: printf("motor o\n");
      break;
   case 4: printf("motor stop\n");
      break;
   case 5: printf("load default\n");
      break;
   default: printf("Error, not found\n");
   break;
   }
}


What if I want to save in ROM the value?
Like if I send LD=85 I want to save 85 (eighty five) in ROM so that it is used as default duty-cycle when I call ME without value.
Should I just use
Code:

#define rom_LD 0
write_eeprom(rom_LD, value);
duty=read_eeprom(rom_LD);


or: is it possible to declare a int8 (or int16) variable so that its value is always saved in rom instead of in ram? Question
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Thu May 29, 2014 2:53 pm     Reply with quote

Basically no.

There is a feature that allows this, which is addressmod. This though uses a _lot_ of code space, and while it was working a few dozen compiler versions ago, went wrong, and stopped working for a long time. Haven't checked if the new versions work, but it is only worth using, when dealing with dozens or hundreds of variables stored in perhaps an external memory.

Best Wishes
temtronic



Joined: 01 Jul 2010
Posts: 9247
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu May 29, 2014 4:59 pm     Reply with quote

'default' values like you're using could be stored in EEPROM, if your PIC has that .Just be aware that it has limited write cycles. Check the datasheet of your PIC as it varies from PIC to PIC.

Another option is IF you're using a RTC chip ,it will have a few bytes of battery protected RAM so as long as the RTC battery is good(5-8 years) data in it's RAM will be there!

Yet another option is to battery backup the PIC itself. Depending on design, a large capacity battery AND a supercap make it possible to keep the PIC alive 24/7.You do need some 'switching' to control peripherals but that's up to you.

hth
jay
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

PostPosted: Fri May 30, 2014 7:23 am     Reply with quote

ok, we can consider this program solved, thank you to all of you Smile
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group