|
|
View previous topic :: View next topic |
Author |
Message |
tesla80
Joined: 23 May 2007 Posts: 81
|
software uart problem |
Posted: Mon May 31, 2010 11:37 am |
|
|
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
|
|
Posted: Mon May 31, 2010 12:46 pm |
|
|
I only see a few small issues, I don't think these cause your problem.
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: | 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
|
|
Posted: Mon May 31, 2010 1:19 pm |
|
|
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
|
|
Posted: Mon May 31, 2010 3:03 pm |
|
|
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: 19538
|
|
Posted: Tue Jun 01, 2010 2:16 am |
|
|
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
|
|
Posted: Tue Jun 01, 2010 4:28 am |
|
|
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
|
|
Posted: Tue Jun 01, 2010 10:28 am |
|
|
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
|
|
Posted: Tue Jun 01, 2010 10:47 am |
|
|
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
|
|
Posted: Thu Jun 03, 2010 5:08 am |
|
|
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
|
|
Posted: Fri Jun 04, 2010 8:19 am |
|
|
any idea? |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Fri Jun 04, 2010 9:17 am |
|
|
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
|
|
Posted: Fri Jun 04, 2010 6:07 pm |
|
|
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
|
just an observation |
Posted: Fri Jun 04, 2010 7:13 pm |
|
|
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. |
|
|
|
|
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
|