Is this SPI and frequency counter program implemented correctly? - c

I am setting up a frequency counter on the PIC18F4585, which sends the frequency out via 8bit SPI.
I'm setting up a frequency counter in my PICF4584 that will calculate the frequency of a square wave going into timer/counter1, samples for 8ms timed by timer/counter0, and then sent to another MCU via SPI. I don't have the SPI input pin SDI connected because I won't send any data back, but for some reason I am not outputting data. I learned MCU's through the AVR line so the way PIC does things is a little different to me and I think I might have missed something basic.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <xc.h>
volatile int count;
void timer0_init() //for sampling period 64 prescaler# 8MHz -> 1000 ticks per 8ms
{
T0CON |= (1<<7); //Timer1 on
T0CON |= (1<<2) | (1<<0); //64 prescaler
TMR0 = 64535; //interrupt initiated on overflow, 1000 ticks until overflow
}
void timer1_init() //for frequency counting
{
T1CON |= (1<<7); //16 bit operation
T1CON |= (1<<1); //Timer1 clock source external RC0/T1OSO/T13CKI on rising edge
T1CON |= (1<<0); //Enables Timer1
T1CON |= (1<<6); //Device clock source is derived from Timer1 oscillator
}
void SPI_init()
{
//TRIS 0 is default output, TRIS 1 is input
TRISC &= ~(1<<3);
TRISC &= ~(1<<5);
TRISA |= (1<<5);
PORTA |= (1<<5);
SSPSTAT |= (1<<7); //Input data sampled at end of output time
SSPSTAT |= (1<<6); //Clock: transmit occurs on active to idle
SSPCON1 |= (1<<5); //SCK, SDO, SDI, and SS are serial port pins
SSPCON1 |= (1<<0); //Fosc/16
}
void interrupt_init()
{
INTCON |= (1<<7); //global interrupt enable
INTCON |= (1<<7); //Enables high priority interrupts
INTCON |= (1<<5); //enables Timer0 overflow
}
void __interrupt () ISR(void)
{
count = TMR1;
count = (count)/.008;
/*SPI TRANSMIT*/
PORTA &= ~(1<<5); //Slave Select goes low
SSPBUF = count;
PORTA |= (1<<5);
/*RESET TIMERS AND INTERRUPTS*/
TMR1 = 0;
TMR0 = 64343;
INTCON &= ~(1<<2);
}
int main() {
interrupt_init();
timer0_init();
timer1_init();
SPI_init();
while(1)
{
}
}

Related

blinking a led using timer 1 overflow interrupt in atmega328p

I'm trying to blink a led using ISR for 3seconds, here atmega328p is used. I'm trying to create a 1second delay in isr using TIMER1(16 BIT) and then loop that for 3seconds. LED is connected to PD7, I don't know why it is not blinking, can anyone point out the mistake. I'm using simulIDE, here is the circuit,timer_circuit
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define SET_BIT(PORT,BIT) PORT |= (1<<BIT)
#define CLR_BIT(PORT,BIT) PORT &= ~(1<<BIT)
unsigned int count = 0;
void timer()
{
TCCR1A = 0x00; // Normal mode of operation
TCNT1 = 0xC2F8; // decimal value is 49912
TCCR1B |= ((1 << CS10) | (1 << CS12));
TCCR1B &= ~(1 << CS11); //1024 prescaler
sei(); // Global interrupt
}
int main(void)
{
SET_BIT(DDRD,PD7);
timer();
while(1)
{
TIMSK1 |= TOIE1;
if(count>=3)
{
SET_BIT(PORTD,PD7);
count=0;
}
}
;
return 0;
}
ISR(TIMER1_OVF_vect)
{
count++;
}
This code never turn off the LED ... once the bit is set your code never clear it ... try to toggle the bit instead of set it
#define toggle_BIT(PORT,BIT) PORT ^= (1<<BIT) //this will flip the bit
...
if(count>=3)
{
toggle_BIT(PORTD,PD7);
count=0;
TCNT1 = 0xC2F8; // reset counter
}
update
use volatile access modifier before count variable to tell the compiler that you will Chang it from ISR to make sure that count variable will not delete in optimization
when you set TCCR1B you have to set other bits to zero to operate in normal mode
Recalculate value TCNT1 for 8 MHz which is internal default frequency
full code
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define toggle_BIT(PORT,BIT) PORT ^= (1<<BIT) //this will flip the bit
#define SET_BIT(PORT,BIT) PORT |= (1<<BIT)
#define CLR_BIT(PORT,BIT) PORT &= ~(1<<BIT)
volatile unsigned int count = 0;
void timer()
{
TCCR1A = 0x00; // Normal mode of operation
TCNT1 = 64754; // over flow after 1 sec calculated at 8 MHZ
TCCR1B = ((1 << CS10) | (1 << CS12)); //1024 prescaler
TIMSK1 |= 1<<TOIE1; // Enable timer1 overflow interrupt
sei(); // Global interrupt
}
int main(void)
{
SET_BIT(DDRD,PD7);
timer();
while(1)
{
if(count>=3)
{
toggle_BIT(PORTD,PD7);
count=0;
}
}
return 0;
}
ISR(TIMER1_OVF_vect)
{
count++;
TCNT1 = 64754; // reset to over flow after 1 sec calculated at 8 MHZ
}

ATmega32u4 Timer 3 overflow not functioning

I've run into an issue using an ATmega32u4, where I am successfully able to use timer 1 overflows, but when I try to repurpose the code for timer 3, it doesn't function.
The following code turns an LED (on pin b7) on and off when timer 1 (16 bit) overflows. It works.
#include <avr/io.h>
#include <avr/interrupt.h>
int main (void) {
DDRB |= (1<<7);; //PortB Output
PORTB = 0x00; //PortB All LEDs off
TCCR1B |= (1<<CS10) | (1<<CS12); //Set Prescaler to 1024
TIMSK1 |= (1<<TOIE1); //Enable Timer Overflowinterrupt
sei(); //Enable Interrupts
while(1);
return 0;
}
ISR(TIMER1_OVF_vect)
{
PORTB ^= (1<<7); //toggle LED
}
This next code is intended to perform the same functionality using timer 3, but doesn't work.
#include <avr/io.h>
#include <avr/interrupt.h>
int main (void) {
DDRB |= (1<<7);; //PortB Output
PORTB = 0x00;
TCCR3B |= (1<<CS30) | (1<<CS32); //Set prescaler to 1024
TIMSK3 |= (1<<TOIE3); //Enable Timer Overflowinterrupt
sei(); //Enable Interrupts
while(1);
return 0;
}
ISR(TIMER3_OVF_vect)
{
PORTB ^= (1<<7);
}
This final code block was used to test that timer 3's count value was increasing (no interrupts involved), which it is. (I'm using a different LED in this test)
#include <avr/io.h>
int main()
{
// Prescaler of 1024
TCCR3B |= (1<<CS32)|(1<<CS30);
// Initialize Counter
TCNT3 = 0;
// Initialize LED
DDRE |= (1 << 6); // LED0
// Infinite Loop
while (1)
{
// Flash every 0.016 secs
// COUNTER = 0.016 / (PRE SCALER / CPU FREQ)
// 250
if( TCNT3 >= 250 )
{
// Toggle LED
PORTE ^= (1 << 6); // If output use PORT, If input use PIN
TCNT3 = 0;
}
}
return 0;
}
From this, I'm assuming that I'm doing something wrong when calling the interrupt, I'm just not sure what
I am not sure if you are using LilyPad or Leonardo.
I am assuming from the code above that it's LilyPad. Change the TCCR3B to 256 and see if it corrects the problem for you.
TCCR3B = 0x0C; // prescaler = 256

Setting a flag does not work in my timer Interrupt (while the Interrupt is working)

I used to write my codes in ICCAVR and I had no problem there, but not for some reason I should migrate to AtmelStudio.
in the following code, the LED is flashing in the interrupt, but when I only set a flag in the interrupt and want to flash the LED in polling (using the flag) it wouldn't work:
#include<avr/io.h>
#include<avr/interrupt.h>
#define LED PA1
ISR (TIMER1_OVF_vect) // Timer1 ISR
{
//PORTA ^= (1 << LED);
TCNT1 = 63974; // for 1 sec at 16 MHz
PORTA ^= (1 << LED);
}
int main()
{
DDRA = (0x01 << LED); //Configure the PORTD4 as output
TCNT1 = 63974; // for 1 sec at 16 MHz
TCCR1A = 0x00;
TCCR1B = (1<<CS10) | (1<<CS12);; // Timer mode with 1024 prescler
TIMSK = (1 << TOIE1) ; // Enable timer1 overflow interrupt(TOIE1)
sei(); // Enable global interrupts by setting global interrupt enable bit in SREG
while(1)
{
}
}
while this change would make it not to flash:
#include<avr/io.h>
#include<avr/interrupt.h>
#define LED PA1
unsigned int counter=0;
unsigned char flag=0;
ISR (TIMER1_OVF_vect) // Timer1 ISR
{
//PORTA ^= (1 << LED);
TCNT1 = 63974; // for 1 sec at 16 MHz
counter++;
if(counter>=10)
{
flag=1;
counter=0;
}
}
int main()
{
DDRA = (0x01 << LED); //Configure the PORTD4 as output
TCNT1 = 63974; // for 1 sec at 16 MHz
TCCR1A = 0x00;
TCCR1B = (1<<CS10) | (1<<CS12);; // Timer mode with 1024 prescler
TIMSK = (1 << TOIE1) ; // Enable timer1 overflow interrupt(TOIE1)
sei(); // Enable global interrupts by setting global interrupt enable bit in SREG
while(1)
{
if(flag)
{
flag=0;
PORTA ^= (1 << LED);
}
}
}
could anyone please help me?
Compiler saw that flag set to 0 at start of program and can't know that the variable can be changed by interrupt handler (the code never called directly in program).
So it optimized out flag check in while loop.
Use volatile qualifier for variables that accessed from different code streams (main code and interrupt handler, different threads in multi-threaded environment).
volatile unsigned char flag = 0;

distance measuring from ultrasonic sensor, variable overflow

Hy, I have ultrasonic sensor measuring distance and no mather which type is my variable "range" (uint8_t, uint16_t, 32, 64)I always get overflow, and than sensor starts from 0 again..Is there a way that I can limit "range" variable or I must limit that on harder way with pulsewidth... Thanks
SENSOR_DDR |= (1<<TRIGGER_PIN);
SENSOR_DDR &= ~(1<<ECHO_PIN) & ~(1<<PB3) & ~(1<<PB2) & ~(1<<PB1) & ~(1<<PB0);
DDRD = DDRD | _BV(4);
PORTD = PORTD | _BV(4);
ENGINE_DDR = 0xff;
ENGINE_PORT = 0;
lcd_init(LCD_DISP_ON);
lcd_clrscr();
lcd_puts("Something wrong...");
while(1)
{
PORTB |= (1<<PB4); //Send Trigger
_delay_us(10);
PORTB &= ~(1<<PB4); //Send trigger
timer0counter=0;
TCNT0=0; //Clear timer
while(bit_is_clear(PINB,5)); //Wait for rising edge
TCCR0 |= (1<<CS02); //Select prescalar 256
TIMSK |= (1<<TOIE0) | (1<<TOIE2); //Enable timer0 overflow interrupt
lcd_clrscr();
while(bit_is_set(PINB,5) && timer0counter<9) //wait for falling edge of echo
{
_delay_us(5);
}
TCCR0 &= ~(1<<CS02); //Stop timer
TIMSK &= ~(1<<TOIE0);
if(bit_is_set(PINB,5))
{
lcd_puts("No OBSTACLE");
}
else
{
range=(256*timer0counter+TCNT0)*32*0.017; //range conversion
lcd_clrscr();
lcd_puts("Distance:");
lcd_puts(itoa(range,buffer,10));
lcd_puts_P("cm");
}
if(range<15){
...
ISR(TIMER0_OVF_vect)
{
TIMSK &= ~(1<<TOIE0);
TCNT0=0;
timer0counter++;
TIMSK |= (1<<TOIE0);
if(timer0counter>8)
{
TCCR0 &= ~(1<<CS02);
TIMSK &= ~(1<<TOIE0);
}
The calculation
256*timer0counter+TCNT0
saves temporary value in 'default' size int, which on AVR is 16b. so, every time timer0counter is higher than 256 it will overflow regardless of the final type of the variable.
instead of doing
range=(256*timer0counter+TCNT0)*32*0.017;
try going with:
double range_real = 256.0 * (double)timer0counter + (double)TCNT0 * 32.0 * 0.017;
range = (int) range_real;
Being explicit about types can really save your skin.

How can I use ADXL345 in timer interrupt with Arduino mega

I want to use ADXL345 in timer interrupt with Arduino mega.
But it can't not work.
Here is my code :
#include <Wire.h>
#define Register_ID 0
#define Register_2D 0x2D
#define Register_X0 0x32
#define Register_X1 0x33
#define Register_Y0 0x34
#define Register_Y1 0x35
#define Register_Z0 0x36
#define Register_Z1 0x37
int ADXAddress = 0xA7>>1;
int reading = 0;
int val = 0;
int X0,X1,X_out;
int Y0,Y1,Y_out;
int Z1,Z0,Z_out;
double Xg,Yg,Zg;
unsigned long t1, t2;
void setup()
{
Serial.begin(9600);
Wire.begin(); //初始化I2C
delay(100);
Wire.beginTransmission(ADXAddress);
Wire.write(Register_2D);
Wire.write(8);
Wire.endTransmission();
delay(500);
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 2500; // compare match register //250 = 1ms//500=2ms
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS10) + (1 << CS11); // 64 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}
void loop()
{
Serial.println(Z_out);
delay(500);
}
ISR(TIMER1_COMPA_vect){
Wire.beginTransmission(ADXAddress);
Wire.write(Register_Z0);
Wire.write(Register_Z1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress,2);
if(Wire.available()<=2);
{
Z0 = Wire.read();
Z1 = Wire.read();
Z1 = Z1<<8;
Z_out = Z0+Z1;
}
}
ISR() function executes every 1 millisecond, but the codes in ISR() only take 650 microseconds.
I don't know why it couldn't work.
If I do all things in the loop(), it can work normally.
Can any one help me?
Thanks in advance,
You shouldn'y handle I2C communications in the ISR. Try using the timer interrupt to change the value of a flag. Check that flag in the main loop and read the value.
You cannot use the Wire library inside an ISR, as interrupts have been disabled. The Wire library uses interrupts.

Resources