|
|
View previous topic :: View next topic |
Author |
Message |
Chipunused Guest
|
Internal write_eeprom Question !!! |
Posted: Tue Feb 28, 2006 2:53 pm |
|
|
Hello,
Anytime external interrupt occur, i receive the same value at the same address. Idealy, i would like to increment to new address with new value anytime i interrupt occur. (100 Max)
what am i doing wrong? Can you please give me some advises.
- thank you
TP
Code: |
//////////////////////////////////////////////////////////////////////////
#include <16F877A.h>
#device ADC=10
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stddef.h>
#rom 0x2100={0x00}
//#rom 0x2100={0x55, 0xAA, 0x01, 0x23, 0x45, 0x67, 0x89}
#fuses HS,NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock=8000000)
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12
#include <input.c>
#define EEPROM_SIZE 256
float adresult =0;
int8 address,energyresult;
#int_rda
void rs232_irs()
{
char statusw,add;
statusw = getc();
if (statusw == 'R')
{
printf("\r\n\nEEPROM:\r\n");
printf( "rda Read %X", read_eeprom(address) );
printf("\n\r");
}
else{
break; //for now
}
}
#int_ext
void external_isr()
{
output_high(PIN_B1); //turn on relay
delay_ms( 20 ); //delay 20ms
adresult = read_adc(); //read ADC and save in adresult
output_low(PIN_B1); //turn off relay
delay_ms(10); //10ms delay for settling time
energyresult = ((adresult*.02928267) - (.8048504)-4); // Y=mX + B
energyresult++; //
write_data = write_eeprom(address,energyresult);
printf("Read: %X\n\r",read_eeprom(address));
printf("\n\r");
}
void init()
{
enable_interrupts(global);
enable_interrupts(int_rda); //turn on rs232 receive interrupt
ext_int_edge(L_TO_H); //rising edge interrupt on portb0
enable_interrupts(int_ext); // enable portb0 interrupt
setup_adc_ports( AN0_AN1_VSS_VREF ); //an0 is analog input RA3 is reference voltage
setup_adc(ADC_CLOCK_INTERNAL); //use internal rc clock for a/d converter
output_low(PIN_B1); //
set_adc_channel(0); // read channel AN0
delay_us(10); //settling time delay
}
void main()
{
init(); // initialize values
while(1){}; //do nothing loop wait for interrupt
}
|
I use this simple test from PC_Programmer, it works fine for hardcode values.
Code: |
#rom 0x2100={0x55, 0xAA, 0x01, 0x23, 0x45, 0x67, 0x89}
#fuses HS,NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock=8000000)
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12
#int_ext
void external_isr()
{
char value, addr;
output_high(PIN_B1); //turn on relay
delay_ms( 20 ); //delay 20ms
adresult = read_adc(); //read ADC and save in adresult
output_low(PIN_B1); //turn off relay
delay_ms(10); //10ms delay for settling time
for(addr = 0; addr < 9; addr++)
{
value = read_eeprom(addr);
printf("erop: %X\n\r", value);
}
printf("\n\r");
}
|
|
|
|
Ttelmah Guest
|
|
Posted: Tue Feb 28, 2006 4:08 pm |
|
|
The maths for 'energy result', will give -ve results for any incoming value below 164. Since energy result is only an int8, and not signed, this will result in silly values.
The actual code is really bad (sorry, but it has to be said). There is no point at all really in using an interrupt anywhere here, since as written, the code prevents them from working. Basically, if the 'R' character arrives on the RS232, the serial will be disabled for about 8mSec, leading to overflows if anything else is typed. Address is not initialised/changed anywhere, so what is the point of using a variable?. The 'edge' interrupt, will kill serial input for probably about 100 character times, again killing the reason to use interrupts. As a minor comment, don't use ADC_CLOCK_INTERNAL, above a 4mHz processor clock if you want accuracy.
Best Wishes |
|
|
Chipunused Guest
|
|
Posted: Tue Feb 28, 2006 7:34 pm |
|
|
Thank you for your comment, as a newbie @ programming, I learn alot from reading examples from this forum. Give me time, sure i will get better.
As far as increment write_eeprom (address, value). I can't find any example. if you see it somewhere please post me a link. All i would like to learn is how to use ext interrupt, Convert ADC, write_eeprom (from 0 to address 127 then wrap arround), read_eeprom (when receive a char).
once again, thank you for all your advises
TP |
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 01, 2006 7:57 am |
|
|
This is only part of the code (you will need to sort out the initalisation, the artithmetic, etc., as well as checking the actual functionality - the code has not been checked at all), but gives an idea of how I'd possibly appoach the problem.
Code: |
int8 address=0,last_address=0;
int8 sbuff[8];
int8 inp_loc=0,out_loc=0;
int8 tbuff[32];
int8 tinp_loc=0;tout_loc=0;
/*Note that neither the receive or transmit handlers have any checking for
overflow.
Hopefully the buffers are large enough to avoid this, but it may need to be
considered/added, depending on what else is done in the code. */
//Receive character and add it to the input buffer
#int_rda
void rs232_receive_isr(void) {
sbuff[inp_loc]=getc();
inp_loc = (inp_loc+1)&7;
}
//Check if a character is present in the input buffer
#define sbuff_kbhit() (inp_loc!=out_loc)
//Get a character from the input buffer
int8 sbuff_getc(void) {
int8 temp;
while (!sbuff_kbhit()) ;
temp=out_loc;
outloc = (out_loc+1)&7;
return (sbuff[temp]);
}
//Check if a character is waiting in the output buffer
#define tbuff_data_waiting() (tinp_loc!=tout_loc)
//Handle character transmission
#int_tbe
void rs232_transmit_isr(void) {
/* If characters are waiting in the buffer, the next one is transferred
to the UART
otherwise the interrupt is disabled, waiting for the next transmission. */
if tbuff_data_waiting() {
putc(tbuff[tout_loc]);
tout_loc=(tout_loc+1)&31;
}
else
DISABLE_INTERRUPTS(INT_TBE);
}
void rs_putc(int8 val) {
/*Routine to send a character to the interrupt driven transmit handler
*/
disable_interrupts(INT_TBE);
tbuff[tinp_loc]=val;
tinp_loc = (tinp_loc+1)&31;
enable_interrupts(INT_TBE);
}
void main(void) {
int8 temp;
int1 old_input;
int16 adresult;
//Note don't bother to enable external interrupt in init, also
//don't enable the
//int_tbe. The code handles this automatically, when data is printed.
init();
old_input=input(PIN_B0);
//Loop checking if the input pin is active, or a character is received
while (true) {
if (sbuff_kbhit()) {
//Here a serial character has been received
temp=sbuff_getc();
if (temp=='R' || temp=='r') {
//Retrieve fom the _last_ written address
printf(rs_putc,"\r\n\nEEPROM Read: %2X\n\r",read_eeprom(last_address));
}
}
if (old_input!=input(PIN_B0)) {
//Here the input pin has changed
if (old_input==0) {
//Here there is a rising edge
output_high(PIN_B1); //Turn on relay
delay_ms(20);
adresult=read_adc();
output_low(PIN_B1); //Turn off relay
last_address=address;
//Now the arithmetic should provide the required settling time
//At this point, you need to sort out the arithmetic.
//With the current code, for an adc value of '0', the code will give
//0 - 4.8048504 = -4
//For a value of 100, this will give
//2.928267 - 4.8048504 = -1
//While for a maximum input of 1023, it'll give
//29.95617141 - 4.8048508 = 25
//A maximum reading of just 25, when trimmed to an integer....
//Do your maths here, and write the value to the EEPROM
//Then if required, print the result (to rs_putc).
old_input=1;
//Now move so that the _next_ write, will be to the next address
//in the EEPROM
address = (address+1) % 100;
}
else old_input=0;
}
}
}
|
Note that the response to the input pin is not interrupt based. There is no advantage to interrupt response here - an interrupt will take at least 30 instruction times to respond, and will result in other interrupt events being stopped while the code handles this, which as it has long delays, is 'non desirable.
Note also, you should add 'errors' to your RS232 initalisation.
Best Wishes |
|
|
Chipunused Guest
|
|
Posted: Fri Mar 03, 2006 12:51 pm |
|
|
Thank you Ttelmah. You are going really far to help other
TP |
|
|
Chipunused Guest
|
16F877A ADC what could be wrong? |
Posted: Wed Mar 08, 2006 7:09 pm |
|
|
What can be wrong? using PCW 3.236, MPLAP7.30
Input to pin B1 is a ramp up from 600mV for 2mS. Increase Input from 0.6V to 1V. ADC --> output won't change.
Code: | ADRESH = 0x03
ADRESL = 0xFF. |
And Result is alway 1D
including is my code, can someone take a look please.
Thank you for your time.
TP
Code: | #include <16F876A.H>
#device adc=10
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 8000000)
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
void main()
{
int16 result;
// set_tris_a(0xFF);
enable_interrupts(global);
ext_int_edge(L_TO_H);
enable_interrupts(int_ext);
setup_adc_ports(AN0_AN1_VSS_VREF); //an0 is analog input RA3 is reference voltage
// setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_16); //use internal rc clock for a/d converter
set_adc_channel(0); // read channel AN0
while(1)
{
output_high(PIN_B1); // Cap on
delay_ms(20);
result = read_adc();
printf("\r\nResult: %2X\n\r", result);
output_low(PIN_B1); // Cap off
delay_ms(500);
}
} |
|
|
|
Ttelmah Guest
|
|
Posted: Thu Mar 09, 2006 3:50 am |
|
|
Obvious first comment. Are you using RA3 as a reference or not?
You have two setup_adc_ports lines. The second will override the first, and neither uses RA3 as a reference, mentioned in the comment.
The 'A' chips, have a comparator module as well as the ADC connected to the analog inputs. Try turning this off (setup_comparators(NC_NC_NC_NC)). There is a nasty habit on some compiler versions, of leaving this enabled...
I'd suspect that possibly it is the two setup lines causing an unexpected configuration, and the chip is not actually seeing a reference voltage (from either Vdd, or RA3), hence is always returning 1023 (which is what you will get when the signal is at or above the reference voltage).
Alternatively, the input is at a different voltage to what you expect. Can you check with a scope, what voltage is actually on the input?.
Best Wishes |
|
|
Chipunused Guest
|
|
Posted: Thu Mar 09, 2006 2:45 pm |
|
|
Using MPLAP ICE 2000 with PCM16XK1 moudule for 16F877. ADC result as expected. when i use PCM16XV0 moudle for 16F877A. (Vref is 4.096V)(Comparators off). Result from ACD alway the same number, it doens't matter what input range. (PIN_A0 is connected to Follower Buffer). Could it be impedance?
Thank you
TP |
|
|
Ttelmah Guest
|
|
Posted: Thu Mar 09, 2006 3:42 pm |
|
|
What sort of 'follower buffer'?. Op-amp as a voltage follower?. Emitter follower?. etc. etc..
How is Vref fed?. What is the voltage at the chip?.
What is your actual line for setup_adc_ports?.
Using the simulator, check that the registers for the ADC are correctly configured. There have been problems at times in the past, with the compiler accessing the wrong registers on particular chips. I don't remember this applying to 3.236, but it might be..
Best Wishes |
|
|
Chipunused Guest
|
|
Posted: Fri Mar 10, 2006 8:59 am |
|
|
I use Op-amp as a voltage follower for PIN_A0.
Vref is fed by Volt Ref MCP1541.
For ports setup i use:
setup_adc_ports(AN0_AN1_VSS_VREF); and also try (ALL_ANALOG);
setup_comparators(NC_NC_NC_NC);
Registers for ADC are correctly configured.
Thanks,
TP |
|
|
Ttelmah Guest
|
|
Posted: Sat Mar 11, 2006 9:45 am |
|
|
If the reference voltage is actually at the Vref pin, has it's required decoupling capacitor, and the voltage on the analog input is at a sensible value, the code ought to work.
Best Wishes |
|
|
|
|
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
|