View previous topic :: View next topic |
Author |
Message |
wehlers
Joined: 15 Dec 2016 Posts: 5
|
Baud rate wrong pic18f43k22 |
Posted: Fri Dec 16, 2016 1:21 pm |
|
|
I have a design using a PIC18F43K22. I have attached code below. Problem is two fold.
One program does not function unless #USE_DELAY is set at 64000000 and baud rate is 300 regardless of what I try. I have written specific parameters to the registers involved in USART per datasheet sheet but the only operation I get is the attached program. I believe this is operator error but I have been looking at the code to long and if it is obvious I don't see it.
Code: |
#include <18F43K22.h>
#use delay(clock=64000000)
#use rs232(uart1,baud=19200)
#use spi (MASTER, SPI2, MODE=1, BAUD = 100000, BITS=8)
#fuses NOWDT
#FUSES NOLVP
#include <uart1.h>
#include <ctype.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdlibm.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
/////////////////////////////////////////////////////////////////////////////////
// Global Variables
/////////////////////////////////////////////////////////////////////////////////
unsigned int new_relay_cmd_flag = 0;
unsigned int bytes_waiting = 0;
/////////////////////////////////////////////////////////////////////////////////
// RS232 data union
/////////////////////////////////////////////////////////////////////////////////
struct rs232bits
{
int1 dbit[40];
};
struct rs232byte
{
int8 dbyte[5];
};
union rs232bitsandbytes
{
struct rs232byte rxbyte;
struct rs232bits rxbit;
};
union rs232bitsandbytes rx_data;
/////////////////////////////////////////////////////////////////////////////////
//RS232 ISR
/////////////////////////////////////////////////////////////////////////////////
#INT_RDA
void RDA_isr(void)
{
new_relay_cmd_flag = 1;
clear_interrupt(INT_RDA);
}
/////////////////////////////////////////////////////////////////////////////////
// init_relays()
/////////////////////////////////////////////////////////////////////////////////
void init_relays()
{
unsigned int8 i;
for (i = 0; i <= 11; i++)
{
output_bit(PIN_D3,0);
delay_us(100);
spi_write2(i);
delay_us(100);
spi_write2(rx_data.rxbyte.dbyte[1]);
delay_us(100);
spi_write2(rx_data.rxbyte.dbyte[0]);
delay_us(100);
output_bit(PIN_D3,1);
delay_ms(10);
}
puts("*****************");
puts("Switch Ready");
puts("*****************");
}
/////////////////////////////////////////////////////////////////////////////////
// Main
/////////////////////////////////////////////////////////////////////////////////
void main()
{
unsigned int i = 0;
rx_data.rxbyte.dbyte[2] = 0x00;
rx_data.rxbyte.dbyte[1] = 0x0A;
rx_data.rxbyte.dbyte[0] = 0xAA;
init_relays();
clear_interrupt(INT_RDA);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
while(1)
{
if (new_relay_cmd_flag == 1)
{
for (i = 4; i == 0; i--)
{
rx_data.rxbyte.dbyte[i] = getc();
delay_us(100);
}
output_bit(PIN_D3,0);
delay_us(100);
spi_write2(rx_data.rxbyte.dbyte[2]);
delay_us(100);
spi_write2(rx_data.rxbyte.dbyte[1]);
delay_us(100);
spi_write2(rx_data.rxbyte.dbyte[0]);
delay_us(100);
output_bit(PIN_D3,1);
delay_us(100);
}
new_relay_cmd_flag = 0;
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Dec 16, 2016 1:51 pm |
|
|
You're missing the oscillator fuse. If you don't want to determine the fuse,
you can let the compiler do it for you. Change 'clock' to 'internal' as
shown below in bold:
Quote: | #use delay(internal=64000000) |
Also, in your #int_rda routine, you need to actually get the character
with a call to getc(). You don't need to clear the interrupt. The compiler
does this for you. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Fri Dec 16, 2016 1:58 pm |
|
|
also you need to add 'errors' to the #use RS232(..options...), keeps the UART from 'locking up'.... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Dec 16, 2016 2:34 pm |
|
|
Just to add one more bit the PCM_Programmers reply.
In the interrupt, the interrupt flag can't actually be cleared where you try to do it. Key is to understand that INT_RDA, will automatically set as long as there is a character not yet read. So because you don't read it in the interrupt, when you clear the flag, it'll set again on the very next instruction. Result the code can never actually get out of the interrupt handler.....
So once a character is received, the code will hang forever in the handler. |
|
|
wehlers
Joined: 15 Dec 2016 Posts: 5
|
|
Posted: Fri Dec 16, 2016 3:26 pm |
|
|
Thank you all for your fast response.
Unfortunately if I put anything in the program besides
#use delay(clock=64000000) program appears to lock up and the start sequence in init_relays() does not happen. It does not appear to matter what speed I put after "internal=" or when I use "clock=" the init relays() will only happen with #use delay(clock=64000000). And Baud rate is always 300. I am able to communicate with the LabView program using 300 so I can only assume 300 is valid. I can operate at 300, just it is not a valid condition for the software as written.
The clear interrupt was stupid on my part I was trying some things and hadn't removed it. My apologies for sending you on that side track.
As noted before I know I am missing something. I was hoping it was some dumb and obvious thing. |
|
|
wehlers
Joined: 15 Dec 2016 Posts: 5
|
|
Posted: Fri Dec 16, 2016 3:35 pm |
|
|
Just for grins I changed "#use rs232(uart1,baud=300,errors)". Comm speed out of the chip is 4.5 bps. Definetely a clock issue of some kind.
Thanks you again for your help and responses. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Dec 16, 2016 3:40 pm |
|
|
Post your compiler version.
1. Compile a test file, and look at the top of the .LST file, which will
be in your project folder. It will show the version. However, to get
the .LST file to be generated, the source file must compile with no errors.
2. Click on the Start button in Windows, then go to Programs, and then
find the entry for CCS, which will be called "PIC-C". Then click on the icon
for "Compiler Version". It will display a box which shows the compiler
version.
3. Open a Command Prompt window and go to c:\Program Files\Picc
(or wherever the compiler is installed on your PC) and run this command line:
|
|
|
wehlers
Joined: 15 Dec 2016 Posts: 5
|
|
Posted: Fri Dec 16, 2016 3:52 pm |
|
|
PCH 5.065 |
|
|
wehlers
Joined: 15 Dec 2016 Posts: 5
|
|
Posted: Fri Dec 16, 2016 3:56 pm |
|
|
Sorry using it with MPLAB 8.92 and Windows7 ultimate. Old lab rat computer but I do get the same on my year old windows 10 pro machine running MPLAB 8.92. Could it be a MPLAB issue and I need to move to MPLABx. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Dec 16, 2016 4:21 pm |
|
|
See if this program runs for you. I was able to make it work with an
18F46K22 (I don't have an 18F43K22, but it's the same PIC family).
I used MPLAB 8.92 and CCS vs. 5.065. I tested this with a PicDem2-Plus
board. It displays "Start: ", and then it echoes any keys that you type.
Make sure Local Echo is turned off on your terminal program. I used
TeraTerm for this test. I edited the PIC below to be the one you're using.
Also, I am compiling with MPLAB set for "Release" mode.
Code: |
#include <18F43K22.h>
#fuses NOWDT,PUT,BROWNOUT
#use delay(internal=64M)
#use rs232(baud=9600, UART1, ERRORS)
//======================================
void main(void)
{
char c;
delay_ms(5); // Allow time for the PLL to start-up
printf("\n\rStart: ");
while(TRUE)
{
c = getc();
putc(c);
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Sat Dec 17, 2016 3:36 am |
|
|
Realistically, the first thing you should do when you have any apparently 'clock' related problem, is step back to the old 'flash an led' test.
A literally sub ten line section of code, just setting up the oscillator and flashing an LED. So:
Code: |
#include <18F43K22.h>
#use delay(clock=16M)
void main(void)
{
while(TRUE)
{
output_toggle(PIN_A0);
delay_ms(1000);
}
}
|
Now if we build this, we can see straight away it runs wrong. The reason is simple. You are not selecting the internal oscillator, and it defaults to the external. This is not present, so it does a 'fail safe clock monitor' and switches to the internal oscillator at 1Mhz, and runs 16* slower than it should.
So we then use PCM_Programmer's basic fuse settings, and try:
Code: |
#include <18F43K22.h>
#fuses NOWDT,PUT,BROWNOUT,NOLVP //prefer to specify NOLVP
#use delay(internal=16M)
|
Low and behold it starts flashing at the right rate.
Basically the reason the code is not working, is that you are not setting up the oscillator. It goes to a default that is 1/64th of the specified clock value (if you specify 64MHz), so gives 320baud when you select 19200 (not actually 300, but nearly). |
|
|
|