![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
set motor duty-cycle (+other parameters) via rs232 [solved] |
Posted: Sat May 24, 2014 8:29 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat May 24, 2014 9:09 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Sun May 25, 2014 11:45 am |
|
|
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) |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Thu May 29, 2014 4:59 am |
|
|
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
|
|
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Thu May 29, 2014 6:46 am |
|
|
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). |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Thu May 29, 2014 8:28 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Thu May 29, 2014 1:47 pm |
|
|
ok! 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](images/smiles/icon_question.gif) |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Thu May 29, 2014 2:53 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9174 Location: Greensville,Ontario
|
|
Posted: Thu May 29, 2014 4:59 pm |
|
|
'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 |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Fri May 30, 2014 7:23 am |
|
|
ok, we can consider this program solved, thank you to all of you ![Smile](images/smiles/icon_smile.gif) |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|