Libstock
It is currently 23 Nov 2014 05:25

All times are UTC + 1 hour




Post new topic Reply to topic  [ 15 posts ] 
Author Message
PostPosted: 24 Nov 2010 11:55 
Offline

Joined: 24 Nov 2010 11:46
Posts: 9
Hello all.
I'm an student from Denmark with a lot of experience with microcontrollers, microprocessors and FPGAs.
Currently I'm making a project in school where we have to use the PIC16F684, and I have to connect it to the Parallax RFID Reader.
As the PIC16F684 doesn't have any hardware UART, I have to use the software UART library in mikroC.

I've changed the device in the Soft UART Example to 16F684 and programmed the chip. In the terminal on my computer I can see the letters from small z to capital A (as supposed). Then the error LED turns on: error=1, but unfortunately when I write something to the chip, I isn't returned, as it should.

Any idea why it can send (TX) but doesn't recieve (RX)?
I'm using the internal 8MHz oscillator, and this is my configuration:
OSCCON = 0b01110101;  // 16F684
TRISC = 0;
error = Soft_UART_Init(&PORTC, 4, 5, 2400, 0); // Initialize Soft UART at 2400 bps


Best Regards
Thomas Jespersen


Top
 Profile  
 
PostPosted: 26 Nov 2010 15:39 
Offline
User avatar

Joined: 11 Jun 2010 09:22
Posts: 433
Hello tkj,

Since you didn't post your code and due to simptoms described, I can only suggest that you didn't disable comparators, which are located on PortC and disable A/D Convertor just in case.

Add next lines into main program or in initialization subrutine:
  ANSEL = 0x00;
  CMCON0 = 0x07;

Best regards

_________________
Ranko Rankovic
mikroElektronika [Support Department]


Top
 Profile  
 
PostPosted: 26 Nov 2010 16:46 
Offline

Joined: 24 Nov 2010 11:46
Posts: 9
Hi.
That kind of fixed the problem, but it's not functionel.
This is the code:
char i, error, byte_read;                 // Auxiliary variables

void main(){
     OSCCON = 0b01110101;  // 16F684
     ANSEL = 0x00;
     CMCON0 = 0x07;

     TRISA = 0b00001000;
     TRISC = 0;
     PORTC.b2 = 0; // Enable the RFID Reader

  error = Soft_UART_Init(&PORTC, 0, 1, 2400, 0); // Initialize Soft UART at 2400 bps
  if (error > 0) {
    PORTA.b0 = 1;                        // Signalize Init error
    while(1) ;                            // Stop program
  }
  Delay_ms(100);

  for (i = 'z'; i >= 'A'; i--) {          // Send bytes from 'z' downto 'A'
    Soft_UART_Write(i);
    Delay_ms(100);
  }

  while(1) {                              // Endless loop
    byte_read = Soft_UART_Read(&error);   // Read byte, then test error flag
    if (error == 1)                            // If error was detected
        PORTA.b0 = 1;                        // Signalize Init error
    else if (error == 255)
         PORTA.b1 = 1;
    else
      Soft_UART_Write(byte_read);         // If error was not detected, return byte read
    }
}


The project settings is set to internal clock and 8MHz. In the computer I recieve the characters from z to A fine, and if I write a single character, I get it back correctly.
But if I write more than 1 character, I get some strange feedbacks, but there is some kind of pattern in what I recieve. I only recieve every second letter - fx:
Quote:
Write: Thomas Jespersen
Recieve: Toa epre
Write: abcdef
Recieve: ace
Write: 123456
Recieve: 135


Why is this happening? In my project I have to store the characters I recieve in a buffer and then check for an RFID code in that buffer when 0x0D is recieved.
But I can't, as I can't recieve the RFID serial data stream correctly?

Best Regards
Thomas Jespersen


Top
 Profile  
 
PostPosted: 27 Nov 2010 10:16 
Offline

Joined: 05 Jul 2008 06:05
Posts: 608
Location: Thailand
Hi Thomas, this is a common problem with the Soft_Uart functions. When you use a PIC with a hardware Uart, incoming data is buffered in a small FIFO memory space and (within reason) you can read the data at any time. Unfortunately the Soft_Uart functions do not have a FIFO buffer and each incoming character is overwritten by the next one. Also there is no provision for Uart_Data_Ready so there is no indication when new data has arrived.

The solution is to either implement some form of hardware handshaking (which can be quite difficult) or make sure your software reads the data before the next character arrives, the problem with the second solution is that it is entirely possible to read the same data twice if your software is reading too quickly! In essence, you need to make sure your software starts reading the data as soon as it arrives and continues reading until the end of the data, in practice this is almost impossible without implementing some kind of interrupt because the read cycles are not synchronised to the incoming baud rate.

Personally, I would avoid using Soft_Uart for reading incoming data because it can be very error prone and (as you have seen) it is very easy to miss data if your program is busy with other tasks.


Top
 Profile  
 
PostPosted: 27 Nov 2010 23:21 
Offline

Joined: 25 Dec 2008 15:22
Posts: 2656
Location: Scotland
what about using RA2/INT as the RX pin.

enable INT with falling edge (Start bit detect) interrupt function and wrap your byte RX routine within the ISR.

This would give you the ability to place greater importance on the uart RX function.

It would be worth having a go at constructing your own software uart too, this way you will have control over which timer is used and sample rate/resolution.

_________________
Best Regards

Mince


Top
 Profile  
 
PostPosted: 28 Nov 2010 10:10 
Offline

Joined: 22 Apr 2005 17:40
Posts: 1927
Location: France 87
a major problem here is the soft_uart_write, this will take the full byte-time and during this time the soft_uart_receive is NOT receiving. Hardware Uart indeed would be the better option but you may try without the echo-back in the loop. Maybe there are silence's in the datastream that allow to tx without the risk of loosing incoming data. 2400 baud is so slow that you can build an interrupt driven softuart receiver, it is some effort but may work well if you have no alternative

_________________
Au royaume des aveugles, les borgnes sont rois.


Top
 Profile  
 
PostPosted: 28 Nov 2010 13:22 
Offline

Joined: 24 Nov 2010 11:46
Posts: 9
Dear all.
Thanks for your responses.
As everything looks now, it doesn't look to good. The problem is that the project isn't that long, so we are starting to get time constraints.
As for me I don't have the time to start making an interrupt based Serial reciever - so we have to think of what excists and what don't...

So are there made any interrupt based serial recievers which can easily be ported to mikroC?

Best Regards
Thomas Jespersen


Top
 Profile  
 
PostPosted: 29 Nov 2010 10:20 
Offline

Joined: 22 Apr 2005 17:40
Posts: 1927
Location: France 87
i once did this in Pascal, should not be too difficult to translate.


program irq_soft_uart;
{ irq-driven software uart with circular buffer

  this is special version for 12F683 , 8 mhz internal clock
 
  concept :
 
    detect startbit on int/ change portb interrupt;
    disable this interrupt
    enable timer interrupt
    wait half bit time
    sample 8 bits at bittime interval by timerinterrupt
    disable timer-interrupt
    store complete byte to circular buffer
    reenable change notification interrupt
 
  no risk of blocking or characters getting lost
  reception of 1 character consumes ~640 processor-cycles , at 8Mhz internal clock this is 320uS ,
  at lower baudrates significantly better then normal soft-uart which consumes all processor-time.
  in the given example i use 9600 baud , for lower baudrates prescaler and timer-values must be adjusted

  RX on GPIO.0 , TX on GPIO.2 in this example
  tested on EP3 , jumpered GPIO.0 ( PORTA.0) to PORTC.7 and GPIO.2(PORTA.2) to PORTC.6 in order to use max232
}




const halfbittime : byte = 255-(104-60); // might need tiny corrections
      fullbittime : byte = 255-(208-28);
      astate      : byte = 1;
      rxbufsize   : byte = 12;

var k,
    bit           : byte;
    rxbyte,
    RXhead,
    RXtail,
    irqstate      : byte;

    Rxbuf         : array[0..rxbufsize+1] of byte;
    RXbufempty,
    RXbfull       : boolean ;
    chars,
    value         : byte;
    counter : word;
   
procedure interrupt;

begin
  case irqstate of
  2 : begin // we get here for all 8 databits
        if intcon.t0if = 1 then
        begin
          tmr0:= fullbittime;
          if gpio.0 = astate then setbit(rxbyte,bit) else clearbit(rxbyte,bit);
          inc(bit); //
          if bit = 8 then // now we should have received a full byte
          begin
            inc(chars);
            // copy this byte to circular buffer
            Rxbuf[Rxtail] := rxbyte;
            Inc(Rxtail);
            If Rxtail > Rxbufsize Then Rxtail := 0;
            Rxbufempty := False;
            If Rxtail = Rxhead Then Rxbfull := True;

            clearbit(intcon,t0ie); //and reinitialize everything for next character
            clearbit(intcon,gpif);
            setbit(intcon,gpie);
            irqstate := 0;
          end;
          clearbit(intcon,t0if);
        end;
      end;
  0 : begin
        if intcon.gpif = 1 then
        begin
          tmr0 := halfbittime;
          //clearbit(intcon,t0if);
          if gpio.0 = 0  then
          begin
            // now startbit maybe is detected
            // rxbyte := 0; // this is the byte into which we will recieve the character
            //startfound := false;
            clearbit(intcon,gpie); // stop interrupting on portb-change now
            setbit(intcon,t0ie); // Respond to timer-interrupt from here
            irqstate := 1; // next fase
          end;
          clearbit(intcon,gpif); // should never happen
        end;
        clearbit(intcon,t0if);
      end;
  1 : begin  // we get here 1/2 bittime after detection of startbit
        if intcon.t0if = 1 then
        begin
          tmr0 := fullbittime;
          if gpio.0 = 0 then
          begin
            bit := 0;
            rxbyte := 0;
            irqstate := 2;
          end  else
          begin // if not stable startbit return to waitforstartbit
            clearbit(intcon,t0ie);
            clearbit(intcon,gpif);
            irqstate := 0;
            setbit(intcon,gpie);
          end;
          clearbit(intcon,t0if);
        end;
      end;
  end;
end;



function message_received : boolean;
begin
 if chars <> 0 then result := true else result := false;
end;

function testkey  : byte; // test byte in buffer , before using this first check with message_received if buffer not empty !
begin
  result := rxbuf[rxhead];
end;

Function Readkey :Byte; // Read A Byte From The Input-fifo
Var Rk : Byte;
Begin
  Rk := 0;
  If Rxbufempty = False Then
  Begin
    Rk := Rxbuf[Rxhead];
    Rxbuf[Rxhead] := 0; // Destructive Read
    Inc(Rxhead);
    dec(chars);
    If Rxhead >  Rxbufsize Then Rxhead := 0;
    If Rxhead = Rxtail Then Rxbufempty := True Else Rxbfull := False;
  End;
  Result := Rk;
End;

procedure reply;
var i : byte;
    tmp : byte;
begin
  tmp := readkey;
  soft_uart_write(tmp);
end;

procedure init_main;
begin
  rxhead := 0;
  rxtail := 0;
  // initialize global variables , peripherals, interrupts , timers etc.
  osccon := %01110000;  // internal osc , 8 mHz
  while osccon.hts = 0 do nop;  // wait until osc stable
  cmcon0 := 7;
  ansel  := 0;          // all digital inputs
  gpio  := 0;
  trisio  := %00001000;  // GPIO.3 =RX
  trisio  := %00000001;
  IOc := %00000001;
  option_reg := %10001000; // timer div 2 > 4800 baud
  intcon := 0;
  clearbit(intcon,gpif);
  setbit(intcon,gpie);  // enable interrupt on change portb
  bit := 0;
  irqstate := 0;
  chars := 0;
  setbit(intcon,gie);   // allow interrupts
  soft_uart_init(gpio,0,2,9600,0);

end;

begin
  init_main;
  trisio := 1;
  soft_uart_write(13);
  soft_uart_write(10);
  soft_uart_write('T');
  soft_uart_write('e');
  soft_uart_write('s');
  soft_uart_write('t');
  soft_uart_write(13);
  soft_uart_write(10);
 
  while true do
  begin
    clrwdt;
    if message_received then reply;
    inc(counter);
    case counter of
     3000 : gpio.1 := 0;
     30000 : begin
               gpio.1 := 1;
               counter := 0;
             end;
    end; // case
  end;
end.

_________________
Au royaume des aveugles, les borgnes sont rois.


Top
 Profile  
 
PostPosted: 29 Nov 2010 10:49 
Offline

Joined: 05 Jul 2008 06:05
Posts: 608
Location: Thailand
Hi Thomas, if this is an educational assignment you should ask your teacher if you can use a different PIC. Personally I would be asking why your teacher specified a device which is completely impractical for the assignment; part of your education should include the ability to choose the right device for the job! Hitting a nail with a screwdriver is bad engineering practice.

There are many PIC's which would make this project very simple, it is far better to use the right tools rather than trying to hack a solution using the wrong ones.


Top
 Profile  
 
PostPosted: 29 Nov 2010 11:10 
Offline

Joined: 24 Nov 2010 11:46
Posts: 9
Sobrietytest wrote:
Hi Thomas, if this is an educational assignment you should ask your teacher if you can use a different PIC. Personally I would be asking why your teacher specified a device which is completely impractical for the assignment; part of your education should include the ability to choose the right device for the job! Hitting a nail with a screwdriver is bad engineering practice.

There are many PIC's which would make this project very simple, it is far better to use the right tools rather than trying to hack a solution using the wrong ones.

I know there are many PIC's which would fit this project a lot better. On our education we have PIC16F628 fx, which would be a lot better suited, as it has Hardware UART.
The reason why are trying to use the PIC16F684, is that our education already have made a board/PCB for this PIC. I don't understand why they did chose this PIC, but the board is already made.
We can of course chose another PIC, but then we will have to make a board, and that might be the only possibility too!

Thanks for the pascal code, jpc. I will take a look on that, and see if we can translate it.

Thomas


Top
 Profile  
 
PostPosted: 29 Nov 2010 13:43 
Offline

Joined: 25 Dec 2008 15:22
Posts: 2656
Location: Scotland
Sobrietytest wrote:
Hi Thomas, if this is an educational assignment you should ask your teacher if you can use a different PIC. Personally I would be asking why your teacher specified a device which is completely impractical for the assignment; part of your education should include the ability to choose the right device for the job! Hitting a nail with a screwdriver is bad engineering practice.

There are many PIC's which would make this project very simple, it is far better to use the right tools rather than trying to hack a solution using the wrong ones.


If would assume it was to force the student to learn how to deal with serial data hence why i suggested doing their own software uart rather than using the mikroC provided library. It could also just be the only pic the teacher knows inside out.

_________________
Best Regards

Mince


Top
 Profile  
 
PostPosted: 29 Nov 2010 13:47 
Offline

Joined: 25 Dec 2008 15:22
Posts: 2656
Location: Scotland
how i use the hardware library with interrupts to ensure no data is missed

// UART buffer parameters & constants
unsigned const char strbuffer_size = 50;
unsigned char strbuffer[strbuffer_size];
volatile unsigned char strbuffPtr = 0;
volatile unsigned char DisplayBuffer = 0; // used to control displaying of values



void interrupt(void)
      {
        if(PIR1.RCIF)
          {

           strbuffer[strbuffPtr] = UART1_Read();

                if(strbuffer[strbuffPtr] == 0x0A)    // New line found -
                  {                                  // DisplayBuffer tells main loop to
                   DisplayBuffer = 1;                // show buffer values.
                   

                  }
                strbuffPtr++;
                if((strbuffPtr > STRBUFFER_SIZE - 1)||(DisplayBuffer))strbuffPtr = 0;

          } // exit uart interrupt

      }// exit global interrupt

_________________
Best Regards

Mince


Top
 Profile  
 
PostPosted: 29 Nov 2010 13:56 
Offline

Joined: 25 Dec 2008 15:22
Posts: 2656
Location: Scotland
now convert to use software library

// UART buffer parameters & constants
unsigned const char strbuffer_size = 50;
unsigned char strbuffer[strbuffer_size];
volatile unsigned char strbuffPtr = 0;
volatile unsigned char DisplayBuffer = 0; // used to control displaying of values



void interrupt(void)
      {
        if(Replace with RA2/INT flag)
          {

           strbuffer[strbuffPtr] = (REPLACE with software uart read command);

                if(strbuffer[strbuffPtr] == 0x0A)    // New line found -
                  {                                  // DisplayBuffer tells main loop to
                   DisplayBuffer = 1;                // show buffer values.
                  }
                strbuffPtr++;
                if((strbuffPtr > STRBUFFER_SIZE - 1)||(DisplayBuffer))strbuffPtr = 0;

          } // exit RA2 falling edge interrupt

      }// exit global interrupt


all you need do is use RA2 for software uart RX and setup as falling edge interrupt. TBH if you cant fill in the blanks then you shouldnt really be asking other people for solutions to your educational projects.

_________________
Best Regards

Mince


Top
 Profile  
 
PostPosted: 29 Nov 2010 14:26 
Offline

Joined: 22 Apr 2005 17:40
Posts: 1927
Location: France 87
mince-n-tatties, i am afraid it is not that easy, softuart will consume all time inside the interrupt again, to make this work well the bit-timing should be done by a timer, if this is well done you may have real full duplex from soft-uart.The solution i suggested ( sorry it is in Pascal) in fact generates 8 interrupts for 1 byte, in between the cpu is free to do something else. At 4800 baud i bit is ~200 uS , the interrupt will use less than half of this , running a TX in software based upon the same technique ( use of timer for bittiming) is no problem.
Here the soft-TX i used :

procedure my_soft_uart_write( pin ,k : byte);
begin
  tmr2 := 0;
  clearbit(pir1,tmr2if);
  clearbit(gpio,pin);               // startbit
  while pir1.tmr2if = 0 do nop;
  nop;
  clearbit(pir1,tmr2if);
  for bit := 0 to 7 do
  begin
     gpio.pin := k.0;
     k := k shr 1;
     while pir1.tmr2if = 0 do nop;
     clearbit(pir1,tmr2if);
  end;
  setbit(gpio,pin); // stopbit
  while pir1.tmr2if = 0 do nop;
  nop;
  clearbit(pir1,tmr2if);
  while pir1.tmr2if = 0 do nop;
end;


_________________
Au royaume des aveugles, les borgnes sont rois.


Top
 Profile  
 
PostPosted: 29 Nov 2010 14:54 
Offline

Joined: 24 Nov 2010 11:46
Posts: 9
I totally agree with you guys, that the Soft UART library is a time consuming function, which should be avoided.
Also I understand how the UART protocol works, and if I had the time I would make an interrupt based function myself.
We will try to port your Pascal code, and see if it works. Thanks again JPC.

Mince-n-Tatties: I can definitely fill in the blanks myself, the only problem is the deadline.
Take a look at my company's website and blog, to see some of the projects I've done: http://www.tkjelectronics.dk


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: Exabot [Bot], Google [Bot] and 4 guests


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 post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group