|
|
View previous topic :: View next topic |
Author |
Message |
coderchick
Joined: 12 Jun 2008 Posts: 25
|
I/O and ADC issues w/16F887 using Device editor |
Posted: Thu Oct 30, 2008 1:16 pm |
|
|
Hi all!
I have an older version of the PCWH compiler (3.245) and attempted to use the Device editor to setup use for the 16F887 with the modified *.h file listed at the end of this message. Everything seemed to be fine, my code compiled and seemed to run with no apparent issues. However, after hooking it up to the debugger and an o-scope, I found that my I/O pins are not functioning correctly. They are neither high nor low, but kinda float somewhere in the middle, and when I try to drive them high or low, nothing happens. My ADC pin seems to be acting the same way, and not reading in the appropriate values.
I've checked my circuit, and there doesn't appear to be any shorts anywhere that may be causing this, and I have a full 5V power supply hooked up to it. So, I don't think it's my circuit that is causing the problems.
Following is the first section of my main code, the fuses that I have set for it, and a small list from the Device editor on how I've set up the A/D converter section. Can anyone check this out for me and see if I've missed something?
Device Editor A/D Converter section
Code: |
A/D Converter
ADC Channels 14
Go/Done Bit ADCON0:1
Clock Select C1:6, C0:6-7
Result Format C1:7
Channel LSB Bit 2
Pins Select C1:0-5_ABE
ADC Regs 1F, 0, 9F, 9E, 1E
ADC Bits 10
Continuous Loop False
|
partial main loop
Code: |
void main()
{
signed int16 new_value = 100; //placeholder for contrast
int16 current_contrast;
signed int16 adjust; //adjustment of brightness
signed int16 current_brightness;
setup_adc_ports(AN0|VSS_VDD); //set up ADC port RA0
setup_adc(ADC_CLOCK_INTERNAL); //acquisition time for analog pins
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);//~65.5 ms
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); //~524 ms
setup_timer_2(T2_DIV_BY_4,60,1); //used for PWM routine
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_EXT);
ext_int_edge( H_TO_L );
enable_interrupts(GLOBAL);
output_high(VIDEO_ENABLE);
|
header and fuses setup
Code: |
#include <16F887.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES LVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
/****PIN DEFINITIONS****/
#define ADC PIN_A0
#define VIDEO_ENABLE PIN_A4
#define STATUS PIN_A5
#define LEAK_DETECT PIN_B0 //external interrupt
#define GRN_LED PIN_B1
#define RED_LED PIN_B2
#define CONTRAST_UP PIN_B4
#define CONTRAST_DWN PIN_B5
#define BUZZ1 PIN_C1
#define BUZZ2 PIN_C2
#define TX PIN_C6 //for RS232 communication?
#define RX PIN_C7 //for RS232 communication?
#define FULL_LED PIN_D0
#define LOW_LED PIN_D1
#define MID_LED PIN_D2
#define BAT_IR_OUT PIN_E0
|
16F887.h
Code: |
//////// Standard Header file for the PIC16F887 device ////////////////
#device PIC16F887
#nolist
//////// Program memory: 8192x14 Data RAM: 271 Stack: 8
//////// I/O: 36 Analog Pins: 14
//////// Data EEPROM: 256
//////// C Scratch area: 77 ID Location: 2000
//////// Fuses: LP,XT,HS,EC_IO,INTRC_IO,INTRC,RC_IO,RC,NOWDT,WDT,NOPWRT,PWRT
//////// Fuses: NOMCLR,MCLR,NOCP,CP,NOCPD,CPD,NOBROWNOUT,BROWNOUT
//////// Fuses: BROWNOUT_NOSL,BROWNOUT_SW,NOIESO,IESO,NOFCMEN,FCMEN,NOLVP
//////// Fuses: LVP,NODEBUG,DEBUG,BOR4VBROWNOUT_SL,BOR2V,WRT2,WRT1,WRT0
//////// Fuses: NOWRT
////////
////////////////////////////////////////////////////////////////// I/O
// Discrete I/O Functions: SET_TRIS_x(), OUTPUT_x(), INPUT_x(),
// PORT_x_PULLUPS(), INPUT(),
// OUTPUT_LOW(), OUTPUT_HIGH(),
// OUTPUT_FLOAT(), OUTPUT_BIT()
// Constants used to identify pins in the above are:
#define PIN_A0 40
#define PIN_A1 41
#define PIN_A2 42
#define PIN_A3 43
#define PIN_A4 44
#define PIN_A5 45
#define PIN_A6 46
#define PIN_A7 47
#define PIN_B0 48
#define PIN_B1 49
#define PIN_B2 50
#define PIN_B3 51
#define PIN_B4 52
#define PIN_B5 53
#define PIN_B6 54
#define PIN_B7 55
#define PIN_C0 56
#define PIN_C1 57
#define PIN_C2 58
#define PIN_C3 59
#define PIN_C4 60
#define PIN_C5 61
#define PIN_C6 62
#define PIN_C7 63
#define PIN_D0 64
#define PIN_D1 65
#define PIN_D2 66
#define PIN_D3 67
#define PIN_D4 68
#define PIN_D5 69
#define PIN_D6 70
#define PIN_D7 71
#define PIN_E0 72
#define PIN_E1 73
#define PIN_E2 74
#define PIN_E3 75
////////////////////////////////////////////////////////////////// Useful defines
#define FALSE 0
#define TRUE 1
#define BYTE int
#define BOOLEAN short int
#define getc getch
#define fgetc getch
#define getchar getch
#define putc putchar
#define fputc putchar
#define fgets gets
#define fputs puts
////////////////////////////////////////////////////////////////// Control
// Control Functions: RESET_CPU(), SLEEP(), RESTART_CAUSE()
// Constants returned from RESTART_CAUSE() are:
#define WDT_FROM_SLEEP 3
#define WDT_TIMEOUT 11
#define MCLR_FROM_SLEEP 19
#define MCLR_FROM_RUN 27
#define NORMAL_POWER_UP 24
#define BROWNOUT_RESTART 26
////////////////////////////////////////////////////////////////// Timer 0
// Timer 0 (AKA RTCC)Functions: SETUP_COUNTERS() or SETUP_TIMER_0(),
// SET_TIMER0() or SET_RTCC(),
// GET_TIMER0() or GET_RTCC()
// Constants used for SETUP_TIMER_0() are:
#define RTCC_INTERNAL 0
#define RTCC_EXT_L_TO_H 32
#define RTCC_EXT_H_TO_L 48
#define RTCC_DIV_1 8
#define RTCC_DIV_2 0
#define RTCC_DIV_4 1
#define RTCC_DIV_8 2
#define RTCC_DIV_16 3
#define RTCC_DIV_32 4
#define RTCC_DIV_64 5
#define RTCC_DIV_128 6
#define RTCC_DIV_256 7
#define RTCC_8_BIT 0
// Constants used for SETUP_COUNTERS() are the above
// constants for the 1st param and the following for
// the 2nd param:
////////////////////////////////////////////////////////////////// WDT
// Watch Dog Timer Functions: SETUP_WDT() or SETUP_COUNTERS() (see above)
// RESTART_WDT()
//
#define WDT_ON 1
#define WDT_OFF 0
#define WDT_DIV_32 1
#define WDT_DIV_64 3
#define WDT_DIV_128 5
#define WDT_DIV_256 7
#define WDT_DIV_512 9
#define WDT_DIV_1024 11
#define WDT_DIV_2048 13
#define WDT_DIV_4096 15
#define WDT_DIV_8192 17
#define WDT_DIV_16394 19
#define WDT_DIV_32768 21
#define WDT_DIV_65536 23
////////////////////////////////////////////////////////////////// Timer 1
// Timer 1 Functions: SETUP_TIMER_1, GET_TIMER1, SET_TIMER1
// Constants used for SETUP_TIMER_1() are:
// (or (via |) together constants from each group)
#define T1_DISABLED 0
#define T1_INTERNAL 0x85
#define T1_EXTERNAL 0x87
#define T1_EXTERNAL_SYNC 0x83
#define T1_CLK_OUT 8
#define T1_DIV_BY_1 0
#define T1_DIV_BY_2 0x10
#define T1_DIV_BY_4 0x20
#define T1_DIV_BY_8 0x30
////////////////////////////////////////////////////////////////// Timer 2
// Timer 2 Functions: SETUP_TIMER_2, GET_TIMER2, SET_TIMER2
// Constants used for SETUP_TIMER_2() are:
#define T2_DISABLED 0
#define T2_DIV_BY_1 4
#define T2_DIV_BY_4 5
#define T2_DIV_BY_16 6
////////////////////////////////////////////////////////////////// CCP
// CCP Functions: SETUP_CCPx, SET_PWMx_DUTY
// CCP Variables: CCP_x, CCP_x_LOW, CCP_x_HIGH
// Constants used for SETUP_CCPx() are:
#define CCP_OFF 0
#define CCP_CAPTURE_FE 4
#define CCP_CAPTURE_RE 5
#define CCP_CAPTURE_DIV_4 6
#define CCP_CAPTURE_DIV_16 7
#define CCP_COMPARE_SET_ON_MATCH 8
#define CCP_COMPARE_CLR_ON_MATCH 9
#define CCP_COMPARE_INT 0xA
#define CCP_COMPARE_RESET_TIMER 0xB
#define CCP_PWM 0xC
#define CCP_PWM_PLUS_1 0x1c
#define CCP_PWM_PLUS_2 0x2c
#define CCP_PWM_PLUS_3 0x3c
long CCP_1;
#byte CCP_1 = 0x15
#byte CCP_1_LOW= 0x15
#byte CCP_1_HIGH= 0x16
// The following should be used with the ECCP unit only (or these in)
#define CCP_PWM_H_H 0x0c
#define CCP_PWM_H_L 0x0d
#define CCP_PWM_L_H 0x0e
#define CCP_PWM_L_L 0x0f
#define CCP_PWM_FULL_BRIDGE 0x40
#define CCP_PWM_FULL_BRIDGE_REV 0xC0
#define CCP_PWM_HALF_BRIDGE 0x80
#define CCP_SHUTDOWN_ON_COMP1 0x100000
#define CCP_SHUTDOWN_ON_COMP2 0x200000
#define CCP_SHUTDOWN_ON_COMP 0x300000
#define CCP_SHUTDOWN_ON_INT0 0x400000
#define CCP_SHUTDOWN_ON_COMP1_INT0 0x500000
#define CCP_SHUTDOWN_ON_COMP2_INT0 0x600000
#define CCP_SHUTDOWN_ON_COMP_INT0 0x700000
#define CCP_SHUTDOWN_AC_L 0x000000
#define CCP_SHUTDOWN_AC_H 0x040000
#define CCP_SHUTDOWN_AC_F 0x080000
#define CCP_SHUTDOWN_BD_L 0x000000
#define CCP_SHUTDOWN_BD_H 0x010000
#define CCP_SHUTDOWN_BD_F 0x020000
#define CCP_SHUTDOWN_RESTART 0x80000000
#define CCP_DELAY 0x1000000 // Multiply this by the delay count
long CCP_2;
#byte CCP_2 = 0x1B
#byte CCP_2_LOW= 0x1B
#byte CCP_2_HIGH= 0x1C
////////////////////////////////////////////////////////////////// SPI
// SPI Functions: SETUP_SPI, SPI_WRITE, SPI_READ, SPI_DATA_IN
// Constants used in SETUP_SPI() are:
#define SPI_MASTER 0x20
#define SPI_SLAVE 0x24
#define SPI_L_TO_H 0
#define SPI_H_TO_L 0x10
#define SPI_CLK_DIV_4 0
#define SPI_CLK_DIV_16 1
#define SPI_CLK_DIV_64 2
#define SPI_CLK_T2 3
#define SPI_SS_DISABLED 1
#define SPI_SAMPLE_AT_END 0x8000
#define SPI_XMIT_L_TO_H 0x4000
////////////////////////////////////////////////////////////////// UART
// Constants used in setup_uart() are:
// FALSE - Turn UART off
// TRUE - Turn UART on
#define UART_ADDRESS 2
#define UART_DATA 4
#define UART_AUTODETECT 8
#define UART_AUTODETECT_NOWAIT 9
#define UART_WAKEUP_ON_RDA 10
////////////////////////////////////////////////////////////////// COMP
// Comparator Variables: C1OUT, C2OUT
// Constants used in setup_comparator() are:
#define A0_A3_A1_A2 0xfff04
#define A0_A2_A1_A2 0x7ff03
#define NC_NC_A1_A2 0x6ff05
#define NC_NC_NC_NC 0x0ff07
#define A0_VR_A1_VR 0x3ff02
#define A3_VR_A2_VR 0xcff0A
#define A0_A2_A1_A2_OUT_ON_A3_A4 0x7e706
#define A3_A2_A1_A2 0xeff09
#bit C1OUT = 0x1f.6
#bit C2OUT = 0x1f.7
////////////////////////////////////////////////////////////////// ADC
// ADC Functions: SETUP_ADC(), SETUP_ADC_PORTS() (aka SETUP_PORT_A),
// SET_ADC_CHANNEL(), READ_ADC()
// Constants used for SETUP_ADC() are:
#define ADC_OFF 0 // ADC Off
#define ADC_CLOCK_DIV_2 0x100
#define ADC_CLOCK_DIV_8 0x40
#define ADC_CLOCK_DIV_32 0x80
#define ADC_CLOCK_INTERNAL 0xc0 // Internal 2-6us
// Constants used in SETUP_ADC_PORTS() are:
//#define sAN0 1 //| A0
//#define sAN1 2 //| A1
//#define sAN2 4 //| A2
//#define sAN3 8 //| A3
//#define sAN4 16 //| B0
//#define sAN5 32 //| B1
//#define sAN6 64 //| B2
//#define sAN7 128 //| B3
#define AN0 1 //| A0
#define AN1 2 //| A1
#define AN2 4 //| A2
#define AN3 8 //| A3
#define AN4 16 //| B0
#define AN5 32 //| B1
#define AN6 64 //| B2
#define AN7 128 //| B3
#define NO_ANALOGS 0 // None
#define ALL_ANALOG 255 // A0 A1 A2 A3 B0 B1 B2 B3
// The following may be OR'ed in with the above using |
#define VSS_VDD 0x0000 // Range 0-Vdd
#define VSS_VREF 0x1000 // Range 0-Vref1
#define VSS_VR 0x2000 // Range 0-Vr
#define VSS_VDAC 0x3000 // Range 0-Vdac
// Constants used in READ_ADC() are:
#define ADC_START_AND_READ 7 // This is the default if nothing is specified
#define ADC_START_ONLY 1
#define ADC_READ_ONLY 6
////////////////////////////////////////////////////////////////// INT
// Interrupt Functions: ENABLE_INTERRUPTS(), DISABLE_INTERRUPTS(),
// EXT_INT_EDGE()
//
// Constants used in EXT_INT_EDGE() are:
#define L_TO_H 0x40
#define H_TO_L 0
// Constants used in ENABLE/DISABLE_INTERRUPTS() are:
#define GLOBAL 0x0BC0
#define INT_RTCC 0x0B20
#define INT_RB 0xFF0B08
#define INT_EXT 0x0B10
#define INT_AD 0x8C40
#define INT_TBE 0x8C10
#define INT_RDA 0x8C20
#define INT_TIMER1 0x8C01
#define INT_TIMER2 0x8C02
#define INT_CCP1 0x8C04
#define INT_CCP2 0x8D01
#define INT_SSP 0x8C08
#define INT_BUSCOL 0x8D08
#define INT_EEPROM 0x8D10
#define INT_TIMER0 0x0B20
#define INT_OSC_FAIL 0x8D80
#define INT_COMP 0x8D20
#define INT_COMP2 0x8D40
#list
|
_________________ KMoe
~We the willing, led by the unknowing, are doing the impossible for the ungrateful. We have done so much, for so long, with so little. We are now qualified to do anything with nothing -M. Theresa |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 30, 2008 1:23 pm |
|
|
Quote: |
I found that my I/O pins are not functioning correctly. They are neither
high nor low, but kinda float somewhere in the middle
#FUSES LVP |
That fuse is probably the reason. Set it to NOLVP. Do that in all your
programs.
Also make sure you have a pull-up resistor on the MCLR pin.
Use 10K for the ICD2, or 47K for the ICD-U40. |
|
|
coderchick
Joined: 12 Jun 2008 Posts: 25
|
|
Posted: Thu Oct 30, 2008 1:45 pm |
|
|
Quote: | That fuse is probably the reason. Set it to NOLVP. Do that in all your
programs. |
I've changed the fuse to NOLVP and the I/O pins are still funky
Quote: | Also make sure you have a pull-up resistor on the MCLR pin.
Use 10K for the ICD2, or 47K for the ICD-U40. |
I have two 24K resistors in series for my ICD-U40 instead of one 47k, would that really cause that much of a difference?[/quote] _________________ KMoe
~We the willing, led by the unknowing, are doing the impossible for the ungrateful. We have done so much, for so long, with so little. We are now qualified to do anything with nothing -M. Theresa |
|
|
ECACE
Joined: 24 Jul 2006 Posts: 94
|
|
Posted: Thu Oct 30, 2008 1:55 pm |
|
|
I would suggest you start with a very simple LED blink program, just to remove all possibliity of it being your code.
I'm not sure what will happen if you create your own file for a processor that came out that much later than your complier.
Someone with more experience in that arena will hopefully speak up. _________________ A HW Engineer 'trying' to do SW !!! Run!!! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
coderchick
Joined: 12 Jun 2008 Posts: 25
|
|
Posted: Thu Oct 30, 2008 4:33 pm |
|
|
ok, so the snippet of code PCM suggested worked, the little LED flashed, yippee! Jubilation! After that I was hopeful and changed it to only turn on the LED when the button on B4 is pressed (see below)
Code: | void main()
{
while(1)
{
if (input(PIN_B4) == 0)
{
output_high(PIN_B0);
//delay_ms(500);
}
else
{
output_low(PIN_B0);
//delay_ms(500);
}
}
} |
However, when I ran the debugger, it turned the LED on right away and no amount of button pressing changed it. The button is very simple, one end is connected to ground and the other to B4, when the button is pressed, it connects the two lines. Yet, the pin constantly reads 0 or 0.134, either way it's still 0 and the LED turns on, which shouldn't be happening because the button isn't pushed. I've checked with a multimeter and there is no shorting within the button, so what could be causing the pin to read low?? _________________ KMoe
~We the willing, led by the unknowing, are doing the impossible for the ungrateful. We have done so much, for so long, with so little. We are now qualified to do anything with nothing -M. Theresa |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 30, 2008 5:05 pm |
|
|
You need a pull-up resistor on the input pin. The pull-up maintains a high
logic level on that pin when the button is not pressed. Either add an
external pullup (10K) or enable the built-in Port B pull-ups.
See the CCS manual for the function to do that. |
|
|
coderchick
Joined: 12 Jun 2008 Posts: 25
|
|
Posted: Thu Oct 30, 2008 5:08 pm |
|
|
hm, will all my input pins need pull-up resistors? _________________ KMoe
~We the willing, led by the unknowing, are doing the impossible for the ungrateful. We have done so much, for so long, with so little. We are now qualified to do anything with nothing -M. Theresa |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 30, 2008 5:15 pm |
|
|
Any pin that has a switch or a button on it will need one. |
|
|
coderchick
Joined: 12 Jun 2008 Posts: 25
|
|
Posted: Thu Oct 30, 2008 5:47 pm |
|
|
alright, that makes sense, but things are still not working. Through the multimeter, I can see the voltage go from 5.08 to 0.00 when the button is pressed, but according to the debugger, that pin on the port never changes. _________________ KMoe
~We the willing, led by the unknowing, are doing the impossible for the ungrateful. We have done so much, for so long, with so little. We are now qualified to do anything with nothing -M. Theresa |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 30, 2008 6:45 pm |
|
|
Because you added this PIC to the compiler, there may be a problem
in the device data. Compile the program below and look at the end of
the .LST file. Post the fuse settings. It should look like this:
Quote: | Configuration Fuses:
Word 1: 2FE4 INTRC_IO NOWDT PUT MCLR NOPROTECT NOCPD BROWNOUT IESO FCMEN NOLVP NODEBUG
Word 2: 3FFF NOWRT BORV40 |
Code: | #include <16F887.h>
#fuses INTRC_IO, NOWDT, PUT, BROWNOUT, MCLR, NOLVP
#use delay(clock=4000000)
//===============================
void main()
{
port_b_pullups(TRUE);
while(1)
{
if(input(PIN_B4) == 0)
output_high(PIN_B0);
else
output_low(PIN_B0);
}
} |
|
|
|
coderchick
Joined: 12 Jun 2008 Posts: 25
|
|
Posted: Fri Oct 31, 2008 2:15 pm |
|
|
Quote: |
Code:
#include <16F887.h>
#fuses INTRC_IO, NOWDT, PUT, BROWNOUT, MCLR, NOLVP
#use delay(clock=4000000)
//===============================
void main()
{
port_b_pullups(TRUE);
while(1)
{
if(input(PIN_B4) == 0)
output_high(PIN_B0);
else
output_low(PIN_B0);
}
} |
Right off the bat, my compiler was giving me an error stating that MCLR and INTRC_IO are unknown keywords. I assume that's a bad thing. I commented that part out to look like below:
Code: | #include <16F887.h>
#fuses /*INTRC_IO,*/ NOWDT, PUT, BROWNOUT, /*MCLR,*/ NOLVP
#use delay(clock=4000000)
//===============================
void main()
{
port_b_pullups(TRUE);
while(1)
{
if(input(PIN_B4) == 0)
output_high(PIN_B0);
else
output_low(PIN_B0);
}
} |
and this is what the list file showed for the fuses:
Quote: | Configuration Fuses:
Word 1: 3F73 RC NOWDT PUT NODEBUG NOPROTECT BROWNOUT NOLVP NOCPD NOWRT |
but again, because it did not understand INRC_IO or MCLR, I would assume something is wrong...? _________________ KMoe
~We the willing, led by the unknowing, are doing the impossible for the ungrateful. We have done so much, for so long, with so little. We are now qualified to do anything with nothing -M. Theresa |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 31, 2008 2:30 pm |
|
|
If you are adding a new PIC with the Device Editor, I think you must
add the appropriate fuses and their Masks and Values.
This is shown in the upper right corner of this screenshot:
http://www.ccsinfo.com/images/content/device_editor.gif
I suspect that a lot of your problems are caused by incomplete
or incorrect entries in the Device Data for the 16F887 -- especially
in the fuses section. Every fuse in that section should be carefully
checked against the Config Bits section of the 16F887 data sheet. |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri Oct 31, 2008 2:35 pm |
|
|
Would it be inappropriate to show the fuses??
I just finished doing this same thing for this same chip.
But I had version 4.x to copy from. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 31, 2008 2:39 pm |
|
|
Are you asking if it's OK to post them ? Should be. The data comes
from the 16F887 data sheet. It's not proprietary to CCS. |
|
|
|
|
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
|