|
|
View previous topic :: View next topic |
Author |
Message |
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
Help: Trouble storing settings in data eeprom with 18f26k22 |
Posted: Fri Aug 25, 2017 12:26 pm |
|
|
Hi:
I'm having trouble with something seemingly simple, but which has me scratching my head. I'm working on a serial comm device, which has 2 modes of operation and works at 1200, 2400 and 4800 bps. Both settings should be selectable by the user with pushbuttons, and their current state shown with LEDs. Also, these settings should be stored in eeprom, so they remain as default as the equipment is turned off and on again.
So far, i haven't been able to accomplish this with PIC 18f26k22. I can toggle both mode and speed, but the settings are not getting stored in eeprom. I stripped my code to the bare minimum and it still doesn't work! I'm using compiler v5.015 by the way. My code is as follows:
Code: |
#include <18f26k22.h>
#fuses HSH,NOWDT,NOPROTECT,PUT,NOPLLEN,NOCPD
#use delay(clock=20000000)
#use rs232(UART1, stream = TEST1, baud=1200, parity=N, bits=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use rs232(UART2, stream = TEST2, baud=1200, parity=N, bits=8, xmit=PIN_B6, rcv=PIN_B7, ERRORS)
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)
/////////////////
// Definitions //
/////////////////
#define nop delay_cycles(1)
#byte PORTB = 0x0F81
#define V_1200_1 output_high(PIN_C1)
#define V_1200_0 output_low(PIN_C1)
#define V_2400_1 output_high(PIN_C2)
#define V_2400_0 output_low(PIN_C2)
#define V_4800_1 output_high(PIN_C3)
#define V_4800_0 output_low(PIN_C3)
#define MODE_A_1 output_high(PIN_C4)
#define MODE_A_0 output_low(PIN_C4)
#define MODE_B_1 output_high(PIN_C5)
#define MODE_B_0 output_low(PIN_C5)
/////////////
// Globals //
/////////////
int speed_ctr = 0;
int mode = 0;
////////////////
// Interrupts //
////////////////
#INT_EXT
void speed_isr()
{
speed_ctr++;
if(speed_ctr>2)
speed_ctr = 0;
write_eeprom(0,speed_ctr);
switch(speed_ctr)
{
case 0:
{
set_uart_speed(1200,TEST1);
V_1200_1;
V_2400_0;
V_4800_0;
break;
}
case 1:
{
set_uart_speed(2400,TEST1);
V_1200_0;
V_2400_1;
V_4800_0;
break;
}
case 2:
{
set_uart_speed(4800,TEST1);
V_1200_0;
V_2400_0;
V_4800_1;
break;
}
}
delay_ms(250);
}
#INT_EXT1
void bypass_isr()
{
write_eeprom(1,mode);
if(!mode)
{
mode = 1;
MODE_B_1;
MODE_A_0;
}
else
{
mode = 0;
MODE_B_0;
MODE_A_1;
}
delay_ms(250);
}
//////////////////
// main routine //
//////////////////
void main()
{
//Set external interrupts edge
ext_int_edge(0,H_TO_L);
ext_int_edge(1,H_TO_L);
//Enable necessary interrupts
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT);
enable_interrupts(INT_EXT1);
// Determine initial settings of the device
speed_ctr = read_eeprom(0);
switch(speed_ctr)
{
case 0:
{
set_uart_speed(1200,TEST1);
V_1200_1;
V_2400_0;
V_4800_0;
break;
}
case 1:
{
set_uart_speed(2400,TEST1);
V_1200_0;
V_2400_1;
V_4800_0;
break;
}
case 2:
{
set_uart_speed(4800,TEST1);
V_1200_0;
V_2400_0;
V_4800_1;
break;
}
default:
{
speed_ctr = 0;
set_uart_speed(1200,TEST1);
V_1200_1;
V_2400_0;
V_4800_0;
break;
}
}
mode = read_eeprom(1);
if(mode)
{
MODE_B_1;
MODE_A_0;
}
else
{
MODE_B_0;
MODE_A_1;
}
//Infinite loop
while(1)
{
}
}
|
*INT0 -> changes uart speed -> indicates current speed with pins C1 (1200), C2 (2400) and C3 (4800) respectively.
*INT1 -> toggles mode of operation -> indicates with pins C4 and C5 respectively.
I used the same code with a PIC18F252, and it worked just fine, so I have no idea why this apparently simple code doesn't work.
I tested storing data in eeprom with another short program, and using the same fuses, and that worked just fine, so I'm even more lost here.
Any help will be very appreciated. Thanks in advance!
Best regards,
Fernando |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Aug 25, 2017 1:43 pm |
|
|
What external circuits do you have on pins B0 and B1 ? Do you have
pull-up resistors on these two pins ? These pins are used to receive the
external interrupts.
Also you claim this program ran fine on an 18F452. But the 18F452 has
only 1 hardware UART. The 18F26K22 has two hardware UARTS.
These are not similar PICs. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Fri Aug 25, 2017 2:52 pm |
|
|
couple big nonos....
1) having delays within any ISR. might be ok for a quick test but not in the real world.
2) writing to eeprom within any ISR. again, same reason
Jay |
|
|
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
|
Posted: Fri Aug 25, 2017 5:07 pm |
|
|
@PCM Programmer: Yes, i have 10 k pullups in both pins; i'm trying to port a working code running in a 18f252 to the 18f26k22, and the second usart will be used for management; i"m just discovering how different these pics are...
@temtronic: 1) how should i debounce my inputs more optimally? 2) should raise a flag and write the eeprom within the main loop?
Thanks both for your answers! Is there a chance my version of the compiler is acting up?
Best regards,
Fernando |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Sat Aug 26, 2017 5:28 am |
|
|
re : debounce
When using mechanical switches, you should have a scope to 'see' what is happening. It's a 'get what you pay for' product. The inexpensive ones will really bounce, pay $$ for hard gold plated contacts to minimize bounce. They all wear out, so read the spec for number of operations AND at what current level. Reducing the current will greatly extend the life BUT they need a certain amount to 'self clean'. Compromise, like life...switches involve compromise.
two options
1) hardware solutions include...
a) add a small cap across the switch. I use a .68mfd as I have 3500-4000 of them on a reel here.... you want a value that 'quenches' or 'absorbs' most of the spikey energy caused when the mechanical switch 'bounces'. This is easy to see on a scope.
b) add a schmitt buffer or opamp window comparator between switch and PIC. Both of these control what is a '1' and a '0'.But bigger part, more space, more cost.
c) use solid state switches. They give perfect '1's and '0's at a cost !
d) transistor buffer.Old school, they work great but does anyone use them anymore ??
all add cost,board space.and R&D time
2) software solutions
a) use a timer and poll the switches
b) use a counter, say 3 highs in a row = a 'one'
add add cost to code(R&D time) but NO hardware changes
There are dozens of methods and there was a recent( 1-2 weeks ago) thread about this. Try using the 'search' window here, put in 'debounce' and see what comes up. It's a very common topic, maybe a candidate for a 'sticky'?
I use a combination of both hardware and software. Kinda 'old school', like a reasonably good signal to go to the PIC, have software 'clean it up' before committing to next process.
One 'trick' in using mechanical switches is that you need to ensure no debounce but allow quick button presses.Another compromise. I use one of those 3by4 matrixmembrane 'domed' keypads for data entry and only use a 10ms software delay. It works fine, no errors. I can't type fast so speed isn't needed,reliabilty is.
Just some points to ponder...
Jay |
|
|
guy
Joined: 21 Oct 2005 Posts: 297
|
|
Posted: Sat Aug 26, 2017 7:43 am |
|
|
Hi fmartinezs. If I understand your problem, it seems the EEPROM doesn't store your info and so the UART settings are not set properly.
I suggest to divide this into two - first make sure the EEPROM settings are written and read back correctly. If so, check that the set_uart_speed works correctly by looking at the hardware registers. It doesn't always do what it's told...
Other coding remarks mentioned earlier also apply of course. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sat Aug 26, 2017 8:45 am |
|
|
Three things (comments inline for two):
Code: |
//Set external interrupts edge
ext_int_edge(0,H_TO_L);
ext_int_edge(1,H_TO_L);
//You should always clear interrupts after changing the active edge
//This can lead to them being incorrectly triggered
clear_interrupt(INT_EXT);
clear_interrupt(INT_EXT1);
speed_ctr = read_eeprom(0);
//realistically I'd have expected to read the value
//before starting the interrupt code. Otherwise if the interrupt does
//trigger before the read completes you have an indeterminate value
//in the variable....
//Enable necessary interrupts
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT);
enable_interrupts(INT_EXT1);
|
Then debounce is definitely a likely problem. Is the keypad an actual one you have tested with the older chip, or just 'the same type'?. Assume you are running at 5v?. Honestly, yes, far better to debounce, and only perform an actual write, once the value is what you want. The EEPROM write is typically slightly faster on the new chip. If might just be that this change is causing a problem... |
|
|
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
|
Posted: Sun Aug 27, 2017 6:11 am |
|
|
Thanks for your answers guys! I'll try your suggestions on Monday and let you know about the results.
Best regards,
Fernando |
|
|
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
|
Posted: Mon Aug 28, 2017 11:24 am |
|
|
Quick update:
It seems that with your help i managed to sort this problem out! Basically, i used temtronic's suggestion, of a counter that checks if the pin is still low after 3 timer interrupts; if so, i raise a flag and perform the write_eeprom routine within the while(TRUE).
I'll post the code later, as it may be useful for someone else.
Thanks for your help!
Best regards,
Fernando |
|
|
|
|
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
|