afhoke
Newbie level 2
- Joined
- Apr 24, 2013
- Messages
- 2
- Helped
- 0
- Reputation
- 0
- Reaction score
- 0
- Trophy points
- 1,281
- Activity points
- 1,296
Hello,
I'm using an AT89C51RC2. I'm using one of the PCA modules a timer, and the timer fires an interrupt when it matches the value in a compare register. The ISR works the first few times and then is mysteriously disabled: the IEN0 byte changes from 0xC0 to 0x40. I'm pretty sure IEN0 can't be changed by hardware, but I can't figure out which part of my code is changing it, after it is first initialized. The program continues to run with no other known errors, but the ISR stops running once IEN0 has changed.
Is it possible that simply reading IEN0 in order to printf it could change its value? I don't know how else it could be getting changed. Any help would be much appreciated.
Andy
Here is my code:
I'm using an AT89C51RC2. I'm using one of the PCA modules a timer, and the timer fires an interrupt when it matches the value in a compare register. The ISR works the first few times and then is mysteriously disabled: the IEN0 byte changes from 0xC0 to 0x40. I'm pretty sure IEN0 can't be changed by hardware, but I can't figure out which part of my code is changing it, after it is first initialized. The program continues to run with no other known errors, but the ISR stops running once IEN0 has changed.
Is it possible that simply reading IEN0 in order to printf it could change its value? I don't know how else it could be getting changed. Any help would be much appreciated.
Andy
Here is my code:
Code:
#include <at89c51ed2.h> //also includes 8052.h and 8051.h
#include <mcs51reg.h>
//#include <8052.h> // also included in at89c51ed2.h
#include <stdio.h>
#include "ADCdrive.h"
// Global functions. See function definitions for descriptions.
void putchar (char c);
char getchar ();
char getputchar ();
void getstr(char s[SIZE], int length);
void serialinit();
// Timer 0 functions
void init_t0();
void start_t0();
unsigned long int read_t0();
// PWM functions
void init_pwms();
void start_pwms();
void set_pwms(unsigned char duty256);
void stop_pwms();
void init_TPCA();
// Global variables
volatile unsigned char r, col; // current column and row of LCD cursor
//volatile unsigned char overflows;
volatile unsigned char cnt;
const unsigned char ccap_array[256] = {0,3,5,8,11,13,16,19,21,24,27,29,32,35,37,40,42,45,48,50,53,55,58,61,63,
66,68,71,73,76,78,81,83,86,88,90,93,95,98,100,102,105,107,109,112,114,116,118,121,123,125,127,129,
132,134,136,138,140,142,144,146,148,150,152,154,155,157,159,161,163,164,166,168,170,171,173,174,
176,178,179,181,182,184,185,186,188,189,190,192,193,194,195,196,197,199,200,201,202,203,204,205,
205,206,207,208,209,209,210,211,211,212,213,213,214,214,214,215,215,216,216,216,216,217,217,217,
217,217,217,217,217,217,217,217,217,217,216,216,216,216,215,215,214,214,214,213,213,212,211,211,
210,209,209,208,207,206,205,205,204,203,202,201,200,199,197,196,195,194,193,192,190,189,188,186,
185,184,182,181,179,178,176,174,173,171,170,168,166,164,163,161,159,157,155,154,152,150,148,146,
144,142,140,138,136,134,132,129,127,125,123,121,118,116,114,112,109,107,105,102,100,98,95,93,90,
88,86,83,81,78,76,73,71,68,66,63,61,58,55,53,50,48,45,42,40,37,35,32,29,27,24,21,19,16,13,11,8,5,3
};
// All processor XRAM should be enabled before the call to main().
// This can be done in a user supplied _sdcc_external_startup() function.
// See section 3.11.1 of sdccman.pdf for SDCC revision 2.6.0.
_sdcc_external_startup()
{
AUXR |= 0x0C; // enable all 1k of internal XRAM (see p25 of manual)
}
void main()
{
char adcin, vpos = 2;
int vdig;
long unsigned int halfper;
P3_2 = 0; // used for debugging
serialinit();
// initialization functions
SPIinit(); // initialize SPI peripheral to talk to MAX1112 ADC
//init_t0(); // initialize timer 0
//init_pwms(); // initialize PWMS
init_TPCA(); // initialize PCA timer (fires interrupt each PWM period to update duty cycle)
start_pwms();
while(1)
{
adcin = ADCread();
vdig = (int)adcin; // convert ADC value from twos complement to signed integer
// Check voltage polarity
if (adcin>0)
{
if (!vpos) // last value was negative
{
start_t0(); // time positive half-cycle
}
vpos = 1;
}
else
{
if (vpos == 1) // last value was positive
{
printf("CMOD %x, IE %x, IEN0 %x, CCAPM2 %x, CCAP2L %x, CCAP2H %x, CCON %x, cnt %x \n\r", CMOD, IE, IEN0, CCAPM2, CCAP2L, CCAP2H, CCON, cnt);
halfper = read_t0(); // half of period in us
printf("halfper = %lu us\n\r", halfper);
}
vpos = 0;
}
getchar();
}
}
// Send a character to terminal emulator
void putchar (char c)
{
//while (!TI); // compare asm code generated for these three lines
//while (TI == 0);
while ((SCON & 0x02) == 0); // wait for TX ready, spin on TI
SBUF = c; // load serial port with transmit value
TI = 0; // clear TI flag
}
// Retrieve a character from terminal emulator
char getchar ()
{
//while (!RI); // compare asm code generated for these three lines
//while ((SCON & 0x01) == 0); // wait for character to be received, spin on RI
while (RI == 0);
RI = 0; // clear RI flag
return SBUF; // return character from SBUF
}
// Retrieve a character from terminal emulator and echo it.
char getputchar ()
{
char cc;
//while (!RI); // compare asm code generated for these three lines
//while ((SCON & 0x01) == 0); // wait for character to be received, spin on RI
while (RI == 0);
RI = 0; // clear RI flag
cc = SBUF;
putchar(cc); // echo character
return cc; // return character from SBUF
}
// Get a string and echo it to terminal emulator
//void getstr (char s[SIZE], int length)
void getstr (char s[], int length)
{
int i = 0;
do
{
s[i] = getchar();
putchar(s[i]);
i++;
//printf("(int)s[i-1] = %d ", (int)s[i-1]);
}while (i <= SIZE && (int)s[i-1] > 31 && i <= length);
s[i-1] = '\0';
}
// Serial port initialization code found at https://sites.google.com/site/controlandelectronics/serial-port-uart-using-8051
void serialinit()
{
TMOD = 0x20;
SCON = 0x50;
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
TI = 1;
}
// Initialize Timer 0
void init_t0()
{
IE |= 0x82; // enable global interrupts and T0 interrupt
TMOD |= 0x01; // set timer 0 to 16 bit mode
}
void start_t0()
{
//overflows = 0; // initialize timer overflow counter
TL0 = 0;
TH0 = 0;
TCON |= 0x10; // start timer zero (set TCON.4 to 1)
//printf("\n\rStarting timer 0. TCON = %d. overflows = %ld. TL0 = %d. TH0 = %d.\n\r", TCON, overflows, TL0, TH0);
}
// Stops T0 and returns the total time since it was started in microseconds (including any past overflows.)
long unsigned int read_t0()
{
unsigned long int t, t2ns, t2us;
//float t2f;
//printf("Size of int is %d. Size of long is %d. Size of unsigned long is %d.\n\r", (char)sizeof(int), (char)sizeof(long), (char)sizeof(unsigned long));
//TCON &= 0x0EF; // stop timer 0 (set TCON.4 to 0)
//printf("TL0 = %d. TH0 = %d. TCON = %d. overflows = %ld.\n\r", TL0, TH0, TCON, overflows);
t = (unsigned long int)TL0 + (unsigned long int)256*(unsigned long int)TH0; // calculate T0 value
//printf("Timer 0 value is %ld.\n\r", t);
/* Timer calculation:
Counter speed = 11.0592 MHz / 12 = 921600 Hz
Total time = t/921600 s
= 10000*t/9216 us
*/
t2us = 10000*t/9216; // time in ms
//t2us = t2ns/100; // time in milliseconds
return t2us;
}
// T0 Interrupt service routine
void isr_one(void) __interrupt (1)
{
//overflows++; // increment number of overflows
//printf("ISR 1; Overflows: %d.\n\r", overflows);
}
// Send pulse width modified square waves to two output pins
void start_pwms()
{
CCAP0H = 0x0F3; // Set PWM0 duty cycle to 5% (0.95*256 = 0xF3)
CCAP1H = 0x66; // Set PWM1 duty cycle to 60% (0.4*256 = 0x66)
CCAPM0 |= 0x42; // Put PCA 0 in PWM mode (8 bit) (output: P1.3)
CCAPM1 |= 0x42; // Put PCA 1 in PWM mode (8 bit) (output: P1.4)
}
// Send PWM square waves with specified duty cycle to two output pins
// PCA 1 has complement of PCA 0 duty cycle
// duty cycle = duty256/256
void set_pwms(unsigned char duty256) __critical
{
CCAP0H = duty256; // Set PWM0 duty cycle to specified value (duty cycle = duty256/256)
CCAP1H = 0xFF - duty256; // Set PWM1 duty cycle to 1-(PWM0 duty)
}
// Stop sending PWM signals to outputt pins
void stop_pwms()
{
printf("\n\rStopping both PWMs.\n\r");
CCAPM0 &= 0x0BD; // Remove PCA 0 from PWM mode (8 bit) (output: P1.3)
CCAPM1 &= 0x0BD; // Remove PCA 1 from PWM mode (8 bit) (output: P1.4)
printf("\n\rEnter next command.\n\r");
}
// Initialize PWMs
void init_pwms ()
{
CMOD &= 0x0f9; // Set PCAs to run at 1/6 of peripheral clock (datasheet p33) (measured f_PWM = 3597 Hz) ; can also be set to T0 overflow frequency
CCON |= 0x40; // Enable PCAs (programmable counter arrays)
}
// Initialize PCA timer (PCA = programmable counter array)
void init_TPCA () __critical
{
CMOD &= 0x0f9; // Set PCAs to run at 1/6 of peripheral clock (datasheet p33) (measured f_PWM = 3597 Hz) ; can also be set to T0 overflow frequency
CMOD |= 0x01; // Enable PCA timer overflow interrupt
//IE |= 0xC0; // Enable PCA interrupt, and enable interrupts globally
IEN0 |= 0xC0; // Enable PCA interrupt, and enable interrupts globally
CCAPM2 = 0x09; // Put PCA module 2 in timer mode with interrupt enabled (table 25 on p37) (ECOM2 bit is set automatically when CCAP2H is set, below)
CCAP2L = 0xff; // Low byte of counter compare register
CCAP2H = 0x01; // High byte of counter compare register. Setting this also sets CCAPM2.6 = ECOM2. See Fig. 14 on p40.
//CCAPM2 |= 0x40; // Set ECOM2
CCON |= 0x40; // Enable PCAs
printf("CMOD %x, IE %x, IEN0 %x, CCAPM2 %x, CCAP2L %x, CCAP2H %x, CCON %x \n\r", CMOD, IE, IEN0, CCAPM2, CCAP2L, CCAP2H, CCON);
}
// PCA Interrupt service routine
void isr_six(void) __interrupt (6)
{
P3_2 = 1;
CCON &= 0xFB; // Clear PCA 2 interrupt flag
P3_2 = 0;
CCAP2H++; // Increment high byte of compare register so interrupt will occur every 256 timer counts
P3_2 = 1;
cnt++;
P3_2 = 0;
set_pwms(ccap_array[cnt]);
P3_2 = 1;
P3_2 = 0;
}