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

software uart problem

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



Joined: 23 May 2007
Posts: 81

View user's profile Send private message

software uart problem
PostPosted: Mon May 31, 2010 11:37 am     Reply with quote

I can't see any signal on the sw uart tx pin with oscilloscope.

I'm using 2 software uarts and 1 hardware uart of 18f4520.

The hardware uart is used in the modbus.c

SW uart named UDBG does not sent fprintf routines which does not contain variables. only works like these fprintf(UDBG,"blabla %d",i);
fprintf(UDBG,"blabla"); does not work.

SW uart named ISO does not sent and receive nothing. I've tried to send a character in a infinity-loop and watch the pin with oscilloscope. No signal.

My code is:
Code:
#include <18F4520.h>
#device *=16
#device adc=10
#FUSES WDT128                  //Watch Dog Timer uses 1:128 Postscale
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES PROTECT                  //Code protected from reads
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV27                   //Brownout reset at 2.7V
#FUSES PUT                      //No Power Up Timer
#FUSES NOCPD                      //Data EEPROM Code Protected
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //No Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOIESO                   //Internal External Switch Over mode enabled
#FUSES NOFCMEN                  //Fail-safe clock monitor enabled
#FUSES NOPBADEN                 //PORTB pins are configured as analog input channels on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES EBTR                     //Memory protected from table reads
#FUSES EBTRB                    //Boot block protected from table reads
#FUSES CPB                      //Boot Block Code Protected
#FUSES LPT1OSC                  //Timer1 configured for low-power operation
#FUSES NOMCLR                   //Master Clear pin disabled
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(clock=32M,restart_wdt) // 4 x 8Mhz
#use rs232(baud=115200,parity=N,xmit=PIN_D0,rcv=PIN_D1,bits=8,stream=UDBG,FORCE_SW)       // Debug port (for now only TX)
#use rs232(baud=19200,parity=O,xmit=PIN_D2,rcv=PIN_D3,bits=8,stream=ISO,ERRORS,RESTART_WDT,TIMEOUT=30,FORCE_SW)

// Debug mode / Thru UDBG rs232 port
#define DEBUGMODE 1

#ifdef DEBUGMODE
   #define DBG(s)   fprintf(UDBG,s)
#else
   #define DBG(s)   {}
#endif
// ----------------------

#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
//#use fast_io(E) // 1wire sensor

#byte porta = getenv("SFR:PORTA")
#byte portb = getenv("SFR:PORTB")
#byte portc = getenv("SFR:PORTC")
#byte portd = getenv("SFR:PORTD")
#byte porte = getenv("SFR:PORTE")

#include "modbus.c"

void main()
{
   Set_tris_a(0b00001111);
   Set_tris_b(0b11111111);
   Set_tris_c(0b10000000); // uart
   Set_tris_d(0b00001010); // DBG uart, ISO uart
   Set_tris_e(0b00000000); // 1wire sensor
   port_b_pullups(TRUE);

   porta = 0;
   portb = 0;
   portc = 0;
   portd = 0;
   porte = 0;

   delay_ms(20);

   DBG("\f\nDebug mode enabled !\n");
 setup_adc_ports(AN0_TO_AN2|VSS_VREF);
   setup_adc(ADC_CLOCK_INTERNAL|ADC_TAD_MUL_8);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   setup_wdt(WDT_ON);
   setup_timer_0(RTCC_OFF);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_ccp1(CCP_OFF);
   setup_ccp2(CCP_OFF);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_TIMER1);

   porta = 0;
   portc = 0;
   portd = 0;
   porte = 0;

   DBG("Mcu inited\n");

   modbus_init();
   
   DBG("modbus inited\n");
   
   enable_interrupts(GLOBAL);

   for(;;)
   {
      restart_wdt();
      fprintf(ISO,"ping"); // send ping
   }//while
}


I couldn't find any solution on my own.
My CCS version is 4.107

Thanks in advance
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon May 31, 2010 12:46 pm     Reply with quote

I only see a few small issues, I don't think these cause your problem.

Code:
#device *=16
This line can be removed. It has no effect on a PIC18 which always uses 16 bit addressing.

Code:
 setup_spi(SPI_SS_DISABLED);
This is a bug in the CCS code wizard and sets an invalid hardware configuration. Change to:
Code:
 setup_spi(FALSE);


Code:
enable_interrupts(INT_TIMER1);
This could be a real problem. You don't have posted code for handling the Timer1 interrupt (Timer2 and Int_EXT are in the modbus.c).
tesla80



Joined: 23 May 2007
Posts: 81

View user's profile Send private message

PostPosted: Mon May 31, 2010 1:19 pm     Reply with quote

Hi, I'm adding other interrupt routines below.
I use timer0 in the Modbus because I use timer2 for pwm.
And Modbus works with hardware uart, without int_ext.
Code:

// Modbus timeout control
#define MODBUS_TO_PRELOAD  16200 // 104*9*60=1min*28 = ~28 minutes
int16 event_count_t = 0;
int16 modbus_timeout = MODBUS_TO_PRELOAD;
// ----------------------

#define BLINKPERIOD_PRELOAD 8 // ~500ms interval
int8 TimerBlink=0;

#int_TIMER1
void  TIMER1_isr(void) // enters here in every 104ms
{
   myaddr = portb;

   if(TimerBlink)
      TimerBlink--;
   else
   {
      TimerBlink=BLINKPERIOD_PRELOAD; // blink on every 5*104=520ms
      if(LedBlink)
         LedBlink=0;
      else
         LedBlink=1;
   }

//Modbus incoming data timeout | if in MODBUS_TO_PRELOAD minutes haven't received any valid data from modbus, reset the cpu
   if(event_count_t != event_count)
   {
      modbus_timeout = MODBUS_TO_PRELOAD;
      event_count_t = event_count;
   }
   else
      modbus_timeout--;
     
   if(!modbus_timeout)
   {
      DBG("Modbus timeout");
      reset_cpu();
   }
//----------------------------   
}


in modbus.c
Code:

#define USE_TIMER0   // Use TIMER0 instead of TIMER2

// Purpose:    Check if we have timed out waiting for a response
// Inputs:     None
// Outputs:    None
#ifdef USE_TIMER0
#int_timer0
#else
#int_timer2
#endif
void modbus_timeout_now(void)
{
   if((modbus_serial_state == MODBUS_GETDATA) && (modbus_serial_crc.d == 0x0000) && (!modbus_serial_new))
   {
      modbus_rx.len-=2;
      modbus_serial_new=TRUE;
   }
   else
   {
      modbus_serial_new=FALSE;
      reset_cpu();
   }
   
   modbus_serial_crc.d=0xFFFF;
   modbus_serial_state=MODBUS_GETADDY;
   modbus_enable_timeout(FALSE);
   
   if(modbus_kbhit()) // is there a new modbus message?
   {
      HandleModbus();
   }
}

.
.
.

// Purpose:   Interrupt service routine for handling incoming serial data
// Inputs:    None
// Outputs:   None
#if (MODBUS_SERIAL_INT_SOURCE==MODBUS_INT_RDA)
#int_rda
#elif (MODBUS_SERIAL_INT_SOURCE==MODBUS_INT_RDA2)
#int_rda2
#elif (MODBUS_SERIAL_INT_SOURCE==MODBUS_INT_EXT)
#int_ext
#else
#error Please define a correct interrupt source
#endif
void incomming_modbus_serial() {
   char c;

   c=fgetc(MODBUS_SERIAL);

   if (!modbus_serial_new)
   {
      if(modbus_serial_state == MODBUS_GETADDY)
      {
         modbus_serial_crc.d = 0xFFFF;
         modbus_rx.address = c;
         modbus_serial_state++;
         modbus_rx.len = 0;
         modbus_rx.error=0;
      }
      else if(modbus_serial_state == MODBUS_GETFUNC)
      {
         modbus_rx.func = c;
         modbus_serial_state++;
      }
      else if(modbus_serial_state == MODBUS_GETDATA)
      {
         if (modbus_rx.len>=MODBUS_SERIAL_RX_BUFFER_SIZE) {modbus_rx.len=MODBUS_SERIAL_RX_BUFFER_SIZE-1;}
         modbus_rx.data[modbus_rx.len]=c;
         modbus_rx.len++;
      }

      modbus_calc_crc(c);
      modbus_enable_timeout(TRUE);
   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon May 31, 2010 3:03 pm     Reply with quote

Quote:
#use rs232(baud=115200,parity=N,xmit=PIN_D0,rcv=PIN_D1,bits=8,stream=UDBG,FORCE_SW, DISABLE_INTS)
#use rs232(baud=19200,parity=O,xmit=PIN_D2,rcv=PIN_D3,bits=8,stream=ISO,ERRORS,RESTART_WDT,TIMEOUT=30,FORCE_SW,DISABLE_INTS)

You have interrupts running at the same time that you using the software
UARTs. This will disrupt the bit-timing of the software UARTs. To prevent
this from happening, add the DISABLE_INTS parameter to the #use rs232
statements as shown above in bold. This will disable Global interrupts
while each byte is transmitted by the software UARTs (or received).
This may fix your problem.

Also, you don't need to put in FORCE_SW on software i/o pins. The
compiler can only make a hardware UART if you specify the hardware
UART pins. On normal i/o pins, it must make a software UART.
Ttelmah



Joined: 11 Mar 2010
Posts: 19568

View user's profile Send private message

PostPosted: Tue Jun 01, 2010 2:16 am     Reply with quote

As another comment. Have you got the RX pin on the line for the Modbus receive, pulled up, or connected to a working receive circuit. It must be. If left floating, the MODBUS code, will continuously be receiving garbage characters, and calling the Modbus receive interrupt.
It is not clear from your code, that you have got the Modbus 'setup', before loading modbus.c
You should be defining:
1) Are you wanting a modbus slave, or a master?.
2) Your Modbus address.
3) What UART to use.

Best Wishes
tesla80



Joined: 23 May 2007
Posts: 81

View user's profile Send private message

PostPosted: Tue Jun 01, 2010 4:28 am     Reply with quote

Thanks for the answers.

@PCM programmer,
I've tried to add DISABLE_INTS but no change.

@Ttelmah, My Modbus code works, I use uart1 (HW) and there is no problem. I put cpu_reset() in mobdus_exception function and if it call the Modbus receive interrupt continuously I'll understand this.
The software uarts do not work properly. UDBG does not send some messages. ISO does not send nothing, I've seen, it's compiled and has assembly codes but nothing happens in the fprintf(ISO,...) function.
tesla80



Joined: 23 May 2007
Posts: 81

View user's profile Send private message

PostPosted: Tue Jun 01, 2010 10:28 am     Reply with quote

I success to send data from the ISO uart. but it sends some first strings wrong. When I send the same data about 5 times, it begins to send correct data.

For example:
Code:
fprintf(ISO,"ping\n"); // wrong
fprintf(ISO,"ping\n"); // wrong
fprintf(ISO,"ping\n"); // wrong
fprintf(ISO,"ping\n"); // wrong
fprintf(ISO,"ping\n"); // wrong
fprintf(ISO,"ping\n"); // not wrong!!
fprintf(ISO,"ping\n"); // not wrong!!
fprintf(ISO,"ping\n"); // not wrong!!
fprintf(ISO,"ping\n"); // not wrong!!
fprintf(ISO,"ping\n"); // not wrong!!
.
.
.


And I put another pic opposite to receive "ping"s. It uses this:
Code:
char string[10];
char _ping[4] = {'p','i','n','g'};

while(1){
  if(kbhit(ISO))
  {
     fgets(string,ISO);
     break;
  }
}

if(strcmp(string, _ping))
  led=1;
else
  led=0;

But the led never lights! :(

What can be the problem?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jun 01, 2010 10:47 am     Reply with quote

Quote:

char _ping[4] = {'p','i','n','g'};

strcmp() expects two strings, but _ping is not a string.
The _ping array is not long enough. It doesn't have room for the
string terminator char of 0x00. Also it's not initialized as a string.
Declare it like this:
Code:

char _ping[5] = "ping";

or
Code:
char _ping[] = "ping";


Quote:
if(strcmp(string, _ping))

2nd problem:
strcmp() does not return True or False. It returns 0x00 if the comparison
succeeds. This is in the documentation for strcmp(). It's essential to
read docs on all functions that are used.
tesla80



Joined: 23 May 2007
Posts: 81

View user's profile Send private message

PostPosted: Thu Jun 03, 2010 5:08 am     Reply with quote

Thank you PCM programmer, I made it without using rs232, because of disabling the interrupts.

I have another question;

In my fuse configurations ccs uses 4xpll to multiply 8Mhz internal clock.
And it's written "4 x 8Mhz" by the ccs pic wizard.
Quote:
#FUSES INTRC_IO
#use delay(clock=32M,restart_wdt) // 4 x 8Mhz


But my timer does not enter in interrupt routine in every 104ms
Quote:
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);

Which is configured by pic wizard too, there was written exactly 104ms.
What do you think about that?
tesla80



Joined: 23 May 2007
Posts: 81

View user's profile Send private message

PostPosted: Fri Jun 04, 2010 8:19 am     Reply with quote

any idea?
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Fri Jun 04, 2010 9:17 am     Reply with quote

Just a little note...

If you're not going to be receiving any data through your soft uart you don't need to define a rcv pin in your #use rs232() statement. That will save you a couple of pins for other use, if you need them.

Ronald
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 04, 2010 6:07 pm     Reply with quote

The program shown below will interrupt at a rate of 15.2 Hz.
The period is about 66 ms. The oscillator is running at 32 MHz.
The signal on Pin B0 is a square wave at 7.6 Hz.

The purpose of this program is to prove that the PIC is really
running at 32 MHz.

If this code doesn't work for you, then post your compiler version.
Code:

#include <18F4520.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=32M)

#int_timer1
void timer1_isr(void)
{
output_toggle(PIN_B0);
}

//======================================
void main(void)
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);

while(1);
}
asmboy



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

View user's profile Send private message AIM Address

just an observation
PostPosted: Fri Jun 04, 2010 7:13 pm     Reply with quote

Running TWO software UARTS - and one at 115200 no less makes me VERY anxious. are you expecting to do anything SAFE & USEFUL with the data ?

What happens when you are adding functionality - and say transmitting
a string of characters while some data is being async received on the 19200 stream?
Sooner or latter ( and i bet SOONER) you will be receiving gibberish and dropping chars on the 19.2 receive "soft" stream.
take it to the bank.

I personally would make the hardware design use port C6,7 pins HARDWARE UART for the 19200 - interrupt receive driven - and
do what U want 4 transmit only on the second stream.
use a buffered background INT handler for 19.2 while you are at it.

I have done JUST that sort of thing after learning the hard way
how risky & unreliable the code can become if the software uart
is present.
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