I am using PIC15F1516 microcontroller, and doing reverse engineering to understand the code without any documentation. I failed to understand use of timer and logic implemented in main.c
Timer0RegValue = 64536.0
Prescalar = 1
Delay = ( (65536-Timer0RegValue)*(Prescalar*4) ) / Fosc = 0.001 Sec
I can understand in the main function timer is updated with value of 1mSec, however, I could not get after how much time ProcessTenthSec() and ProcessTwelfthSec() will get executed?
void TMR1_Initialize(void)
{
//Set the Timer to the options selected in the GUI
//T1CKPS 1:1; T1OSCEN disabled; nT1SYNC synchronize; TMR1CS FOSC/4; TMR1ON disabled;
T1CON = 0x00;
//T1GSS T1G; TMR1GE disabled; T1GTM disabled; T1GPOL low; T1GGO_nDONE done; T1GSPM disabled;
T1GCON = 0x00;
//TMR1H 252;
TMR1H = 0xFC;
//TMR1L 24;
TMR1L = 0x18;
// Load the TMR value to reload variable
// 6396= 0xFC18
// Delay = ( (65536-Timer0RegValue)*(Prescalar*4) ) / Fosc;
// Delay = ( (65536-6396)*(1*4) ) / 500000;
// Delay =
timer1ReloadVal=(TMR1H << 8) | TMR1L;
// Clearing IF flag before enabling the interrupt.
PIR1bits.TMR1IF = 0;
// Enabling TMR1 interrupt.
//PIE1bits.TMR1IE = 1;
// Set Default Interrupt Handler
//TMR1_SetInterruptHandler(TMR1_DefaultInterruptHandler);
// Start TMR1
//TMR1_StartTimer();
}
#define TENTH_SEC_RELOAD 156
#define TWELFTH_SEC_RELOAD 130
void main(void)
{
// initialize the device
SYSTEM_Initialize();
// When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
// Use the following macros to:
// Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
INTERRUPT_PeripheralInterruptEnable();
byTenthSec = TENTH_SEC_RELOAD
byTwelfthSec = TWELFTH_SEC_RELOAD
while (1)
{
if(PIR1bits.TMR1IF)
{
T1CONbits.TMR1ON = 0;
//TMR1H 252;
TMR1H = 0xFC;
//TMR1L 24;
TMR1L = 0x18;
T1CONbits.TMR1ON = 1;
PIR1bits.TMR1IF = 0;
if(--byTenthSec == 0)
{
byTenthSec = TENTH_SEC_RELOAD;
ProcessTenthSec();
}
if(--byTwelfthSec == 0)
{
if(byTwelfthFix--)
{
byTwelfthSec = TWELFTH_SEC_RELOAD ;
}
else
{
byTwelfthFix = 3;
byTwelfthSec = TWELFTH_SEC_RELOAD + 1;
}
ProcessTwelfthSec();
}
}
//if an ADC conversion is in progress do a low priority task
if(uHiPriTasks.HighPriority)
{
if(uHiPriTasks.One)
Function1();
else if(uHiPriTasks.Two)
Function2();
else if(uHiPriTasks.Three)
Function3();
else if(uHiPriTasks.four)
Function4();
else if(uHiPriTasks.five)
Function4();
}
if(uWatchdog.byWatchdog == WDT_ALL_TASKS_COMPLETE)
{
//reset the watchdog task structure
uWatchdog.byWatchdog = 0;
//restart the watchdog timer
CLRWDT();
}
}
}
Related
I am facing a problem while implementing a timer based interrupt in mikroC for PIC.
I want to toggle a port pin for 8 times if there is a keypress at PORTC.F0 and there should be a delay of say 100ms between the toggles.
Normally this would be very easy using a delay function
for (i=0;i<=8;i++)
{
PORTB.F0=~PORTB.F0;
Delay_ms(100);
}
But during the period, any other keypresses are missed by the system. So I thought of implementing the solution using interrupts.
#define SW PORTC.F0
char ttime,i;
volatile flag;
void Inittimer()
{
T1CON = 0x01;
TMR1IF_bit = 0;
TMR1H = 0x06;
TMR1L = 0x00;
TMR1IE_bit = 1;
INTCON = 0xC0;
}
void Interrupt()
{
if (TMR1IF_bit)
{
TMR1IF_bit = 0;
TMR1H = 0x06;
TMR1L = 0x00;
ttime--;
if (ttime==0)
{
flag=1;
}
}
}
void main()
{
Inittimer1();
TRISB = 0;
TRISC.F0 = 1;
PORTB = 0x00;
while(1)
{
if (SW==0)
{
ttime=3;
}
if (flag==1)
{
for (i=0;i<=8;i++)
{
PORTB=~PORTB;
flag=0;
}
}
}
}
Nothing is working. Can somebody please help me to correct the code?
Well this doesn't look right:
if (flag==1)
{
for (i=0;i<=8;i++)
{
PORTB=~PORTB;
flag=0;
}
}
When you first see that flag is set, you immediately loop and toggle the output 8 times, without waiting for flag to turn back to 1. That's not right, it's overly simplified.
You need to look for the flag, then toggle the output and clear the flag, and wait for it to to get set again, maintaining the counter in parallel. The for loop is not the proper structure for this, since it will "lock out" the rest of the program and might cause keypresses to be missed.
When you initialize your timer:
void Inittimer()
{
T1CON = 0x01;
TMR1IF_bit = 0;
TMR1H = 0x06; // No prescaler? I doubt your clock speed is 40-some KHz!
TMR1L = 0x00;
TMR1IE_bit = 1;
INTCON = 0xC0;
}
Why don't you control the LED directly from the ISR ?
if (ttime)
PORTB.F0 = (--ttime & 1); // ttime is not decremented when led is not blinking.
else
PORTB.F0 = 0; // ensures the LED is off.
To start blinking 8 times:
if (SW==0)
{
PORTB.F0 = 1;
ttime = 16;
}
Note that with a 100ms clock interrupt, the first 'blink' of the LED may last up to 200ms... This is why many like to work with a faster timer interrupt (this has usually other uses as well), controlling the led would require adding a soft post-scaler
if (blinking)
{
if (--blinkTimer == 0)
{
blinkTimer = BLINK_DELAY; // whatever number it takes for 100ms.
PORTB.F0 = (--blinking & 1);
}
}
else
{
PORTB.F0 = 0
}
To start blinking:
if (SW==0)
{
blinking = (2 * BLINKS) - 1;
blinkTimer = BLINK_DELAY;
PORTB.F0 = 1;
}
This should get you a more even first blink.
I wrote a simple led blinking code with hardware interrupt 0 of 8051.
When button is pressed it goes into interrupt service routine (ISR). After executing it should come back in main function but it is not coming.
This is my c code. Any positive reply will be appreciated.
sbit LED = P1^0;
void delay(int ms)
{
int i;
for(i=0;i<ms;i++)
{
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x66;
TR0 = 1;
while(TF0==0);
TR0 = 0;
TF0 = 0;
}
}
void main(void)
{
P1 = 0x00;
/// P3 = 0x04;
IT0 = 1;
EX0 = 1;
EA = 1;
LED=1;
while(1)
{
LED=~LED;
delay(200);
}
return ;
}
void external0_isr() interrupt 0
{
EA=0;
LED =0 ;
delay(2000);
LED=1;
EX0=1;
EA=1;
return;
}
When you enter the button interrupt, you disable global interrupt EA=0;
That also disables the timer interrupt. Therefore, you program would hang at while(TF0==0) in your delay(2000) routine.
I'm able to receive with the following code, but unfortunately, nothing is sent back. What am I doing wrong?
#include <pic18f25k80.h>
#include "config.h"
#include <usart.h>
int i = 0;
unsigned char MessageBuffer[200];
void main() {
OSCCONbits.IRCF = 0b110; // 8MHz
TRISB6 = 0; // TX set as output
TRISB7 = 0; // RX set as output
// Clear TX interrupt
// Set RX interrupt
// 8-bit Asynch. mode
// BRGH = 1 = high baud mode
// 51 = ((8MHz/baud)/16)-1 with baud = 9600
Open2USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE
& USART_EIGHT_BIT & USART_BRGH_HIGH, 51 );
RC2IF = 0; // reset RX2 flag
RC2IP = 0; // not high priority
RC2IE = 1; // Eneble RX2 interrupt
INTCONbits.PEIE = 1; // enable peripheral interrupts
INTCONbits.GIE = 1; // enable interrupts
RCSTA2bits.SPEN = 1; // enable USART
while(1){
}
}
void interrupt ISR () {
if(PIR3bits.RC2IF == 1) {
if(i<200) { // buffer size
MessageBuffer[i] = Read2USART(); // read byte from RX reg
if (MessageBuffer[i] == 0x0D) { // check for return key
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i=0;
return;
}
i++;
RC2IF = 0; // clear RX flag
} else {
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i = 0;
return;
}
}
}
I'm transmitting the 0x41 hex code, I checked with the scope and see that is is being received. And according to the code I have, an echo of the received data should be sent back. When I check the TX pin, nothing is happening.
Add USART_CONT_RX to Open2USART to enable continuous receive.
Also, it's a good idea to do the minimum necessary in the interrupt service routine. Consider something like:
void interrupt ISR () {
char data;
if(PIR3bits.RC2IF == 1) {
data = Read2USART(); // always read byte from RX reg (clears RC2IF)
if(i<200) { // buffer size
MessageBuffer[i] = data; // read byte from RX reg
i++;
}
else{
// flag buffer full error
}
}
}
and doing the rest of what you are doing in the while(1) loop.
I've been doing a project about home automation in which I have to use timer interrupts with 8051 microcontroller. I've constructed the following code, however I couldn't manage to get interrupt working. It seems that the program does not go into timer ISR at all. I use a buton to simulate PIR input, therefore lampControl is triggered, no worries there. I use as a library.
Any ideas or help will be greately appreciated:
void timer0_isr(void) interrupt 1 //Timer 0 Interrupt
{
TH0 = 0xDC;
TL0 = 0x00;
TR0 = 1;
if (++lamp_interrupt_count == 6000)
{
sendCharacterShowAsHex(0x8F);
lamp_interrupt_count = 0;
TR0 = 0;
}
}
void main()
{
unsigned char chr;
IE = 0x93;
while(1)
{
serialInput();
if (getPIRInput() == 0x00)
{
lampControl(0x80);
}
....
....
....
}
void lampControl(unsigned char serial_data_in)
{
if (serial_data_in == 0x80)
{
sendCharacterShowAsHex(0x80);
//enable interrupts
IE = 0x93;
device_interrupt = 2; //Lamp
TMOD = 0x21; // Timer0 Gate=0, Mode 1, 16bit timer
TH0 = 0xDC;
TL0 = 0x00;
TR0 = 1;
}
else if(serial_data_in == 0x8F)
{
sendCharacterShowAsHex(0x8F);
}
}
You need to configure the timer and interrupts before you can use them.
In main() you need at least the following configuration bits set in order to be able to turn
the timer on with "TR0 = 1;" :
Set those bits first thing in main() and this should do the trick:
TMOD = 0x01; // 16-bit no auto reload
TH0 = 0xDC; //Set high and low bits to count 0xFFFF - 0xDC00 = 0x23FF counts
TL0 = 0x00;
ET0 = 1; // Enable timer0 interrupt
EA = 1; // Enable all interrupts
//TR0 = 1; //Enable Timer0 immediately
The rest of your code should run fine.
Note: you could change your interrupt function definition to:
"void timer0_isr(void) interrupt 1 using 1" to force it to use register bank 1 for the interrupt function operation.
I am trying to enable timer2 interrupt to use it for PWM purposes. In this case, I just turn on an LED and when timer 2 interrupt occurs I turn it off but the timer interrupt never occurs. Everything looks good to me so I don't understand why Timer2 is not firing up. I am using PIC18F87J11, here is the datasheet.
/*
File: main.c
Date: 2011-SEP-4
Target: PIC18F87J11
IDE: MPLAB 8.76
Compiler: C18 3.40
*/
#include <p18cxxx.h>
#include<usart.h>
#include <pwm.h>
#include <delays.h>
#pragma config FOSC = INTOSC, WDTEN = OFF, XINST = OFF
#pragma interrupt HighISR
void main(void) {
unsigned int i;
/* set FOSC clock to 8MHZ */
OSCCON = 0b01110000;
/* turn off 4x PLL */
OSCTUNE = 0x00;
/* make all ADC inputs digital I/O */
ANCON0 = 0xFF;
ANCON1 = 0xFF;
PR2 = 124; // Period
TMR2=0;
// 1/16 prescalar
T2CONbits.T2CKPS0 = 1;
T2CONbits.T2CKPS1 = 0;
PIE1bits.TMR2IE == 1; // Enables the TMR2 to PR2 match interrupt
// Enable Timer 2
T2CONbits.TMR2ON = 1;
INTCONbits.PEIE = 1; // Enable Perpherial Interrupt
INTCONbits.GIE = 1; // Enable Global Interrupt
TRISDbits.TRISD6 = 0; // Turn on LED
LATDbits.LATD6 = 1;
while (1);
}
#pragma code highVector=0x08
void HighVector(void) {
_asm goto HighISR _endasm
}
#pragma code /* return to default code section */
// Timer Interrupt
void HighISR(void) {
if (PIR1bits.TMR2IF == 1) {
LATDbits.LATD6 = 0; // Turn off LED to indicate it came thru
PIR1bits.TMR2IF = 0;
}
}
Thanks!
Found my mistake
PIE1bits.TMR2IE == 1;
It should be PIE1bits.TMR2IE = 1;