Add GPS/PARSE to 8xSERVO-MOTOR CODE in Oshonsoft

OK, here's the relevant bits in C,
main code,
Code:
void main(void){
    OSCCON=0b01110000;      //8MHz
    PLLEN=1;                //x4=32MHz
    TRISA=255;
    TRISB=255;
    done=true;
    T1CON=0b00100000;       //timer 1 pre=4 = clocks at 2MHz
    TMR1ON=1;               //start timer 1CCP2CON=%1010
    TRISC=0;                //make it output
    LATC=2;
    //while(1);
    fifoStart=0;            //initialize the fifo
    fifoEnd=0;
    CCP2CON=0b1010;         //generate interrupt only
    CCPR2=TMR1+100;
    putFifo(0xff);
    CCP2IE=1;
    PEIE=1;
    GIE=1;
    while(1){
        if(serialCount>=9600){  //approximately do this once per second
            serialCount=0;      //reset the count
            putMessage("Mike Was Ere!!!!!");
            putFifo(13);        //send CR
            putFifo(10);        //and Lf
        }
    }
}
I didn't know how to put a message in Osh so straight lined it.
The putMessage routine,
Code:
void putMessage(const char* mess){
    while(*mess)
        putFifo(*mess++);
}
The fifo routines,
Code:
void putFifo(uint8_t dat){
    while(((fifoEnd-fifoStart)&(FIFO_LEN-1))==(FIFO_LEN-1));
    fifo[fifoEnd]=dat;
    fifoEnd=(fifoEnd+1)&(FIFO_LEN-1);
}

uint8_t getFifo(void){
    uint8_t retVal;
    retVal=fifo[fifoStart];
    fifoStart=(fifoStart+1)&(FIFO_LEN-1); 
    return(retVal);
}

uint8_t getFifoLen(void){
    return((fifoEnd-fifoStart)&(FIFO_LEN-1));
}
And, finally, the ISR,
Code:
void __interrupt() inter(void){
    if(CCP2IF){
        serialCount++;
        LATC1=PORTCbits.RC1;       //ensure latch reflects current output
        if(done){
            bitCount=0;
            if(getFifoLen()){
                TXbyte=getFifo();
                CCP2CON=0b1001;     //go low next interrupt = start bit
                done=false;
                prev=0;
            }
        }else{
            //we're sending a byte
            if(bitCount<9){
                if((TXbyte&1)==prev){
                    //just need interrupt
                    CCP2CON=0b1010;
                }else{
                    //need to flip bit
                    if(prev){
                        //we need a zero next
                        prev=0;
                        CCP2CON=0b1001;
                    }else{
                        //we need a one next
                        prev=1;
                        CCP2CON=0b1000;
                    }
                }
                TXbyte>>=1;
            }else{
                //doing the stop bits
                if(bitCount<10){
                    if(prev){
                        //just need interrupt
                        CCP2CON=0b1010;
                    }else{
                        //we need a one next = stop bit
                        prev=1;
                        CCP2CON=0b1000;
                    }
                    
                }else{
                    done=true;
                }
            } 
        }
        bitCount=bitCount+1;
        CCPR2+=2000000L/9600L;
        CCP2IF=0;
    }
}

Hope this helps.

Mike.
 
Here is what I see on my scope,

The yellow line is the output - the red is just used as a trigger.
The data starts with an "M" which is 01001101 in binary,
What you see above is a start bit (0) followed by the LSB (1),bit 1 (0) bits 2&3 (both 1) etc.
Note the two stop bits at the end of division 3.

It's backwards because the Least Significant Bit is sent first.

I've connected the output to an Arduino Nano (pin 10) and used the following code to display it,
Code:
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

void setup() {
  Serial.begin(115200);
  // set the data rate for the SoftwareSerial port
  mySerial.begin(9600);
}

void loop() {
  if (mySerial.available()) {
    Serial.write(mySerial.read());
  }
}

This is what I see,

Hopefully you can get something working now.

Mike.
 
I've found a difference between the C and Basic code.
The variable ccpDone if not set to true.
It needs to be added before interrupts are enabled,
I.E.
Code:
fifoStart=0
fifoEnd=0
ccpDone=true            'added
INTCON.PEIE = 1
INTCON.GIE = 1

Mike.
 
Hi M,
Sorry!
I didn't get a notification that you had posted more messages.

I'll review them, and if I can't see the C-Osh differences, I can get a mate of mine to check a bit later. (he's busy)

If you can send the hex file/s I may be able to load C onto the PIC?
Thanks C.
 
Hi M,
I'll keep trying to get this CODE working, but I don't see [ccpDone] in the #164 CODE. (I do find reading a bit difficult though)

EDIT: I've found [ccpDone] in another program! I'm not sure quite what's happening.
C.
 
Here's a new verision with,
clock for 164 on C2
data for 164 on C0
Serial out (software) on C1
Serial in (hardware) on C7.

If you connect C1 to C7 then the string sent ($test stringW) should end up in buff.
I've tried to seperate it into various logical sections but may have messed it up.
Code:
'18F4431 32MHz XTL REMOTE_SLAVE 164 160223 2330

Define CONFIG1L = 0x00
Define CONFIG1H = 0x06    '8mHz XTL x4 =32mHz
Define CONFIG2L = 0x0c
Define CONFIG2H = 0x20
Define CONFIG3L = 0x04
Define CONFIG3H = 0x80
Define CONFIG4L = 0x80    'Set for HVP
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

Define CLOCK_FREQUENCY = 32
Define SINGLE_DECIMAL_PLACES = 2
Define STRING_MAX_LENGTH = 20

Define SIMULATION_WAITMS_VALUE = 1    'Comment in for SIM out for PIC

Dim wordTemp As Word
Dim servoCount As Byte
Dim i As Word
Dim servoPos(8) As Word
Dim servoDir(8) As Byte
Dim frame As Word
Dim buff(80) As Byte
Dim strCount As Byte
Dim rec As Byte
Dim isDone As Bit
Dim cnt As Byte
dim fifo(16) as byte
dim fifoStart as byte
dim fifoEnd as byte
Dim ccpDone As Bit
Dim previous as Bit
Dim TXbyte as byte
Dim bitCount as byte
Dim ms as long
Dim tick as long

Dim str as string


OSCCON = %01110000        '& h70
gosub initIO
gosub initServos
gosub initSerial
gosub initTMR1
gosun initTMR2
tick=0
ms=0
INTCON=0xc0                        'only PEIE and GIE set
pause(2)                            'let serial flush and get stable
str="$test stringW"
for i=0 to len(str)-1
    call putFifo(str(i))
next i
While 1
    'adjust servo positions here
    INTCON.GIE=0                            'disable interrupts so ms can't change
    if (ms-tick)>50 then
        tick=ms
        For i = 0 To 7
            INTCON.GIE = 0
            If servoDir(i) = 1 Then
                servoPos(i)=servoPos(i)+40    'add 1/50th to the servo position
            Else
                servoPos(i)=servoPos(i)-40    'subtract it
            Endif
            If servoPos < 2000 Then        'have we gone past the end?
                servoPos(i) = 2000            'yes so make it the end stop
                servoDir(i) = 1                    'and turn it around
            Endif
            If servoPos(i)>4000 Then    'same for other end
                servoPos(i) = 4000
                servoDir(i) = 0
            Endif
            INTCON.GIE = 1
        Next i
    endif
    INTCON.GIE=1
    If isDone then
        'put a break here and see what's in buff.
        'deal with the received sentence here
        'This code can be any length but ideally less than 20mS
        isDone=0
    Endif
    'other code here.
Wend
End                                                                                          

proc putFifo(dat as byte)
    while ((fifoEnd-fifoStart) AND 0x0f)=0x0f
    wend 
    fifo(fifoEnd)=dat                                    'add data to queue
    fifoEnd=(fifoEnd+1) AND 0x0f                    'and increment pointer
End Proc 

function getFifo() as byte                            'note, doesn't test if fifo is empty
    getFifo=fifo(fifoStart)                            'so always call getFifoLen first
    fifoStart=(fifoStart+1) AND 0x0f
End Function                                                                                  

function getFifoLen() as byte
    getFifoLen=(fifoEnd-fifoStart) AND 0x0f
End Function

initSerial:
    'setup USART for 9600 baud receive
    RCSTA = %10010000
    TXSTA.BRGH = 1
    SPBRG = 207
    PIR1.RCIF = 0
    BAUDCON.BRG16 = 1
    PIE1.RCIE = 1
    PIE1.RCIE = 1
    strCount = 0
    isDone = 0
    ccpDone = 1
return

initServos:
    LATC.0 = 0                        'ensure data is low
    LATC.2 = 0                        'and clock
    For i = 0 To 7
        LATC.2 = 1                    'send positive clock edge
        servoPos(i) = i * 250 + 2000    '1ms(2000) to 1.875(1 7/8ths - 3750)ms in 1/8th mS steps
        LATC.2 = 0                    'send negative edge
        servoDir(i) = i And 1    '<<<<<<<added
    Next i
    servoCount = 8                    'cause it to reset
    CCP1CON = %1000                'will go high on interrupt - will start a 0.5mS pulse
    frame = 1000                    'start everything in 4000 cycles
return

initTMR1:
    T1CON = %00100000            'prescaler = 4
    T1CON.0 = 1                        'start timer
return

initTMR2:
    'setup 1mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
    T2CON = %01001110                        '& h4e
    PR2 = 49                                        'This is timer 2 period register. I.E. reset after 50 clocks (0 to 49 = 50 counts)
    PIE1.TMR2IE = 1                             'timer 2 interrupts enable
return

initIO:
    TRISA = %11000000            '7=OSC, 6=OSC,
    TRISC = %11111000            '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA 1=Serial out
    TRISC = %11111010            'CCP0 (RC2) & RC0 output
return

On High Interrupt            'go via location 0x0008
Save System
    if PIR2.CCP2IF Then
        serialCount=serialCount+1
        wordTemp.LB=CCPR2L                    'ensure next interrupt is
        wordTemp.HB=CCPR2H                    'in 208*4=832 instruction cycles
        wordTemp=wordTemp+208                '208 is 2,000,000/9600 = 104uS or the time for 1 bit at 9600 baud
        CCPR2H=wordTemp.HB                    'it's really important that the high byte gets written first
        CCPR2L=wordTemp.LB                    'write it back
        LATC.1=PORTC.1                            'ensure latch is same as current CCP output
        if ccpDone then                        'are we idle
            bitCount=0                            'yes so reset things
            length=getFifoLen()                'is anything in the fifo?
            if length>0 then                    'yes so start a new transmision
                TXbyte=getFifo()                'get byte to transmit
                CCP2CON=%1001                    'pin high and low on next interrupt = start bit
                ccpDone=false                    'tell everything we're no londer idle
                previous=0                        'set previous equal to start bit
            Endif
        else
            'we're sending a byte
            if bitCount<9 then                'have we done a complete byte
                if TXbyte.0=previous then    'no so send next bit,
                    'just need the interrupt as next bit is same as previous bit
                    CCP2CON=%1010
                else
                    'we need to flip the bit
                    if previous Then            'did we previously send a one?
                        'we need a zero next
                        previous=0                'we're sending a zero next
                        CCP2CON=%1001            'will go to zero next match
                    else
                        'we need a one next
                        previous=1                'we're sending a one next
                        CCP2CON=%1000            'will go to zero next match
                    endif
                endif
                TXbyte=shiftRight(TXbyte,1)'shift next bit to zero position
            else
                'doing the stop bits
                if bitCount<10 then
                    if previous then
                        CCP2CON=%1010        'just need interrupt
                    else
                        previous=1
                        CCP2CON=%1000        'go high next interrupt
                    endif
                else
                    ccpDone=true            'stop bits will still be generated - this happens at bitCount=10
                 Endif                            'and output will stay high until next byte
            Endif
        Endif
        bitCount=bitCount+1                'this will get reset if idle
        PIR2.CCP2IF=0
    Endif
    If PIR1.TMR2IF Then                    'Is it a timer 2 interrupt
        Cnt = Cnt + 1                        'Increment count
        ms=ms+1                                'increment milliSecond
        If Cnt >= 5 Then                    'Has 5mS passed without a byte being received
            isDone=0
            strCount=0
            cnt=0
        Endif
        PIR1.TMR2IF = 0
    Endif
    If PIR1.CCP1IF Then                'has CCP1 triggered?
        wordTemp.HB = CCPR1H        'get value of CCPR1 into wordTemp
        wordTemp.LB = CCPR1L
        If CCP1CON = 0x08 Then    'have we started the 1000 cycle pulse
            CCP1CON = 0x09                'yes so end the pulse after 0.5mS
            wordTemp = wordTemp + 1000    'adding 1000 will make pulse 0.5mS long
        Else
            LATC.0 = 0                        'clear the data pin
            CCP1CON = 0x08                'No so output the timed gap
            If servoCount < 8 Then
                'still doing the servos so add remainder of time
                wordTemp = wordTemp + servoPos(servoCount)
                wordTemp = wordTemp - 1000    'knock of the 1000 (0.5mS) already elapsed
                frame = frame - servoPos(servoCount)
                servoCount = servoCount + 1
            Else
                'done all the servos so just the frame gap to do
                wordTemp = wordTemp + frame
                frame = 39000                '40,000(20mS) minus time of positive pulse(0.5mS)
                servoCount = 0            'start all over again
                LATC.0 = 1                    'will become first pulse
            Endif
        Endif
        CCPR1H = wordTemp.HB    'put value back into CCPR1
        CCPR1L = wordTemp.LB
        PIR1.CCP1IF = 0                'clear interrupt flag
    Endif
    If PIR1.RCIF Then
        cnt=0                                    'stop any timeout happening
        rec = RCREG                        'get the received character
        If RCSTA.OERR Or RCSTA.FERR Then    'neither of these should ever occur.
            RCSTA.CREN = 0            'this is kinda wishful thinking
            while PIR1.RCIF            'if any bytes in the buffer
                rec = RCREG                'throw them away
            wend
            RCSTA.CREN = 1            'as any data received is corrupt
            strCount = 0                'however, reset everything
            isDone = 0                    'and hope for the best
        Else                                    'no errors so use the data
            'the following is waiting for a "$" sign
            If strCount=0 Then    'are we already receiving
                'waiting for $        'no so wait
                If rec = "$" Then    'for $ to appear
                    buff(strCount)=rec'start receiving
                    strCount = 1        'must have been zero previously
                Endif
            Endif
            'the following gets executed if we've allready got a "$" sign
            'but not got a "W" yet.
            If isDone=0 And strCount<>0 Then
                if strCount<80 then                'only store it if there's room in the buffer
                    buff(strCount)=rec            'no so carry on storing
                    strCount = strCount + 1    'this may cause strCount to get to 80 = buffer full
                Endif
                If rec = "W" Then                    'have we got the "endOfString" character
                    isDone = 1                            'yes, so set done true
                Endif
            Endif
            If isDone=0 AND strCount>79 Then 
                'buffer has overflown
                strCount = 0
            Endif
        Endif
    Endif    'end RS232 if
Resume

I've had to guess at a lot of the syntax so it maybe completely wrong.


Mike.
 

Attachments

  • All.txt
    8.8 KB · Views: 219
Last edited:
Here's the serial only code,
Code:
'18F4431 32MHz XTL REMOTE_SLAVE 164 160223 2330

Define CONFIG1L = 0x00
Define CONFIG1H = 0x06    '8mHz XTL x4 =32mHz
Define CONFIG2L = 0x0c
Define CONFIG2H = 0x20
Define CONFIG3L = 0x04
Define CONFIG3H = 0x80
Define CONFIG4L = 0x80    'Set for HVP
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

Define CLOCK_FREQUENCY = 32
Define SINGLE_DECIMAL_PLACES = 2
Define STRING_MAX_LENGTH = 20


Dim wordTemp As Word
Dim i As Word
dim fifo(16) as byte
dim fifoStart as byte
dim fifoEnd as byte
Dim ccpDone As Bit
Dim previous as Bit
Dim TXbyte as byte
Dim bitCount as byte
dim serialCount as word
Dim length as Byte

OSCCON = %01110000        '& h70
TRISA = %11000000            '7=OSC, 6=OSC,
TRISC = %11111000            '6=1-slave4431_cs, 2=74HC164 CLK, 0=74HC164 DATA 1=serial out
LATC.1=1                        'serial idle
T1CON = %00100000            'prescaler = 4
T1CON.0 = 1                    'start timer
CCP2CON=%1010                'interrupt only
PIE2.CCP2IE = 1            'CCP2 interrupts enable
fifoStart=0
fifoEnd=0
ccpDone=1
INTCON.PEIE = 1
INTCON.GIE = 1
serialCount=0
pause(2)
call putFifo(0xff)                'send a dummy byte to get in sync
While 1
    if serialCount>=9600 then        'do this every second
        serialCount=0                    'clear the count
        call putFifo(77)                        'send the string as seperate bytes
        call putFifo(105)
        call putFifo(107)
        call putFifo(101)
        call putFifo(32)
        call putFifo(87)
        call putFifo(97)
        call putFifo(115)
        call putFifo(32)
        call putFifo(69)
        call putFifo(114)
        call putFifo(101)
        call putFifo(33)
        call putFifo(33)
        call putFifo(13)
        call putFifo(10)
    Endif
Wend
End   

proc putFifo(dat as byte)
    while ((fifoEnd-fifoStart) AND 0x0f)=0x0f
    wend   
    fifo(fifoEnd)=dat                                    'add data to queue
    fifoEnd=(fifoEnd+1) AND 0x0f                    'and increment pointer
End Proc   

function getFifo() as byte                            'note, doesn't test if fifo is empty
    getFifo=fifo(fifoStart)                            'so always call getFifoLen first
    fifoStart=(fifoStart+1) AND 0x0f
End Function                                                                                    

function getFifoLen() as byte
    getFifoLen=(fifoEnd-fifoStart) AND 0x0f
End Function

On High Interrupt            'go via location 0x0008
Save System
    if PIR2.CCP2IF Then
        serialCount=serialCount+1
        wordTemp.LB=CCPR2L                    'ensure next interrupt is
        wordTemp.HB=CCPR2H                    'in 208*4=832 instruction cycles
        wordTemp=wordTemp+208                '208 is 2,000,000/9600 = 104uS or the time for 1 bit at 9600 baud
        CCPR2H=wordTemp.HB                    'it's really important that the high byte gets written first
        CCPR2L=wordTemp.LB                    'write it back
        LATC.1=PORTC.1                            'ensure latch is same as current CCP output
        if ccpDone then
            bitCount=0
            length=getFifoLen()
            if length>0 then
                TXbyte=getFifo()
                CCP2CON=%1001                    'pin high and low on next interrupt = start bit
                ccpDone=false
                previous=0
            Endif
        else
            'we're sending a byte
            if bitCount<9 then
                if TXbyte.1=previous then
                    'just need the interrupt
                    CCP2CON=%1010
                else
                    'we need to flip the bit
                    if previous Then
                        'we need a zero next
                        previous=0
                        CCP2CON=%1001
                    else
                        'we need a one next
                        previous=1
                        CCP2CON=%1000
                    endif
                endif
                TXbyte=shiftRight(TXbyte,1)
            else
                'doing the stop bits
                if bitCount<10 then
                    if previous then
                        CCP2CON=%1010        'just need interrupt
                    else
                        previous=1
                        CCP2CON=%1000        'go high next interrupt
                    endif
                else
                    ccpDone=true            'stop bits will still be generated - this happens at bitCount=10
                 Endif                            'and output will stay high until next byte
            Endif
        Endif
        bitCount=bitCount+1
        PIR2.CCP2IF=0
    Endif
Resume

Mike.
 

Attachments

  • soft UART only.txt
    3.6 KB · Views: 219
Last edited:
Note, in the All.txt the while loop is now free running - it was only running 50 times per second(20mS). The change servo position is (accidentally) running every 50mS due to my incompetence.
If you change line 65 from if (ms-tick)>50 then to if (ms-tick)>20 then
Is should run at the proper speed again.

Mike.
 
Hi M,
I'm trying UART first.

I changed [ pause(2) ] to [ waitms 2 ] and it compiles.

Running in OSH SIM:
The FIFO(X) buffer doesn't fill only FIF(0) with 255.

On another computer the FIFO(X) buffer did fill, but then it stopped. Could this be timing or something?

EDIT: There's a fault on the SERVO connected PCB, which I have to fix.
I tried the ALL CODE. I changed a few minor lines, so it compiles, and this CODE fills the FIFO() buffer with [ "$test srtingw" ] ok.
C
 
Last edited:
The string should go into the fifo buffer, then it should be removed by the ISR, sent out of RC1 and (if C1 is connected to C7) into the hardware receive to finally end up in buff. You can tell if the fifo is being emptied as fifoStart will increase.

Note, the code,
Code:
str="$test stringW"
for i=0 to len(str)-1
    call putFifo(str(i))
next i
Is instead of the straight lined code,
Code:
        call putFifo(77)
        call putFifo(105)
        call putFifo(107)
        call putFifo(101)
        call putFifo(32)
        call putFifo(87)
        call putFifo(97)
        call putFifo(115)
        call putFifo(32)
        call putFifo(69)
        call putFifo(114)
        call putFifo(101)
        call putFifo(33)
        call putFifo(33)
        call putFifo(13)
        call putFifo(10)

Mike.
 
In either of the above codes, TRISC=%11111000 is included (it needs changing in All.txt from %11111010) so C7 should be input. How can it be high (on)?

Mike.
 
Hi m,
Hi M,
Is this about the UART or ALL CODE? It looks like it's for the ALL CODE,!
EDIT: I tried the above instructions on the ALL CODE, but it didn't work.

I'll have to fix the SERVO wired PCB.

C
 
Last edited:
It's about All.txt. The soft serial code just outputs on C1 and can be tested separately. Do you have a spare chip and someway to read serial to see if it works?

I'm using an 18F2620 (with C) and an Arduino to receive the code and I can get it to go around and endup in buff.

Mike.
 
Gonna try again to make a post but things keep getting messed up.

In both the above codes, TRISC=%11111000 is present so RC7 should always be an input. How can RC7 be high(on)?

Mike.
 
Hi M,
The PCB wired for SERVO, has 2xPICs, the one for SERVOs in this case is 18F4431.
The PICs are surface mount, and I had to solder thin wires onto C1 and I think C2 for the SERVO tests.
This PCB need fixing, which I'll do tomorrow.

I have been using the OSH SIM, in the last few tests.
C
 
Hi M,
While I get the PCB working again, could you clarify how to setup the OSH SIM to output the FIFO buffer please?
In the SIM RC7 switches on, and stays on.
C
 

Attachments

  • Show.jpg
    111.1 KB · Views: 181
In either of the above codes, TRISC=%11111000 is included (it needs changing in All.txt from %11111010) so C7 should be input. How can it be high (on)?

Mike.
Hi M,
Both of those settings were there together, maybe this caused a problem, I've now changed it to %11111010 only.
C
 
Hi,
I have new boards arrived from china, with RC0 and RC2 connected to a 'shift register' for later
The components need to be stuck on though.

At the moment I'm working with adapted PCBs (As mentioned I have to fix the test board with the 'shift register' attached.)

It's not easy to solder wires between pins, see attched:

If I can get the OSH SIM to output from RC7 into the SW interface, that would be fine for now, at the moment it's staying on.
C
 

Attachments

  • REMOTE .JPG
    1.5 MB · Views: 192
Cookies are required to use this site. You must accept them to continue using the site. Learn more…