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.
Related
I'm testing some things on a Attiny85 and thought about the best way to handle the interrupt rutine. I know it is bad to have a lot of code in the interrupt handler, but I'm uncertain of any other ways to do this. I want my main program to sleep and wake on PCINT, the PCINT comes from multiple pins (rotary encoder A, b & switch and a receiving UART) so I was thinking just having a lot of code in the handler.
The code to determining which pin caused the interrupt, would look like this
#include <avr/io.h>
#include <stdint.h> // has to be added to use uint8_t
#include <avr/interrupt.h> // Needed to use interrupts
volatile uint8_t portbhistory = 0xFF; // default is high because the pull-up
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
/*main program loop here */
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
/* PCINT0 changed */
}
if(changedbits & (1 << PB1))
{
/* PCINT1 changed */
}
if(changedbits & (1 << PB2))
{
/* PCINT2 changed */
}
}
And then ofc inside each of the if-statements in the interrupt handler, there would be code handling something, like this code, turning on the Timer0
TCNT0 = 0; // Set counter to 0
OCR0A = SERIAL_BIT_TIME; // Call timer interrupt in middle of first bit
position = 0; // Reset position and data
TIMSK |= 1 << OCIE0A; // Enable interrupt for compare register A (timer interrupt)
TIFR |= 1 << OCF0A; // Clear timer interrupt flag to prevent it jumping directly there
PCMSK &= ~(1 << SERIAL_RECEIVE); // Disable pin change interrupt
or with the switch input, the code inside the if-statement would be
if (lightState)
{
dali.transmit(ADDRESS, OFF);
lightState = 0;
}
else
{
dali.transmit(ADDRESS, ON);
lightState = 1;
}
Would this be a dumb solution?
volatile uint8_t flag;
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
gotosleep();
do
{
switch(flag)
{
case 1:
dosomething1();
break;
case 2:
dosomething2();
break;
case 3:
dosomething3();
break;
}
cli();
flag = 0;
sei();
}while(flag);
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
flag = 1;
}
if(changedbits & (1 << PB1))
{
flag = 2;
}
if(changedbits & (1 << PB2))
{
flag = 3;
}
}
I'm trying to run two functions 'similtaniously' via interrupts:
1) Measure ADC via timing of timer 0 (100Hz) and show results on pin 0-5
2) Blink a led via timer 1 (10Hz) on pin 6.
Problem seems to be that the ISR of timer 1 blocks the function, so nothing else is executed. Here is the code:
(Please don't be offended by any styling mistakes, the code is under development)
#define F_CPU 16000000UL // 16MHz Clock speed
#include <avr/io.h>
#include <avr/interrupt.h>
void ADC_init(void);
void SetTimer0(void);
void SetTimer1(void);
int main(void)
{
DDRB |= (1<<DDB0) + (1<<DDB1) + (1<<DDB2) + (1<<DDB3) + (1<<DDB4) + (1<<DDB5) + (1<<DDB6);
PORTB = 0b00000000;
DDRB &= ~(1<<DDB7);
ADC_init();
SetTimer0();
SetTimer1();
while(1){
}
}
void ADC_init(void)
{
cli();
// Select Vref=AVcc
// and set left adjust result
// select pin ADC0 (PC0)
ADMUX |= (1<<REFS0)|(1<<ADLAR);
//and enable ADC
//enable ADC interupt
//enable autotriggering
//set prescaller to 128
ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
//set ADC trigger source - Timer0 compare match A
ADCSRB |= (1<<ADTS1)|(1<<ADTS0);
// StartADC
ADCSRA |= (1<<ADSC);
sei();
}
//initialize timer0 match A on 100hz
void SetTimer0(void)
{
cli();
TCCR0A = 0; // set entire TCCR0A register to 0
TCCR0B = 0; // same for TCCR0B
TCNT0 = 0; // initialize counter value to 0
// set compare match register for 100Hz increments
OCR0A = 155; // = 16000000 / (1024 * 100.16025641025641)-1
// toggle PD6/OC0A pin on compare match
TCCR0A |=(1<<COM0A0)|(1<<WGM01);
//Set CTC mode
TCCR0B |= (1 << WGM01);
// Set CS02, CS01 and CS00 bits for 1024 prescaler
TCCR0B |= (1 << CS02) | (0 << CS01) | (1 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
sei();
}
//initialize timer1 10hz
void SetTimer1(void){
cli();
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// set compare match register for 10 Hz increments
OCR1A = 24999; // = 16000000 / (64 * 10) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 64 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();
}
// ADC done interrupt
ISR(ADC_vect)
{
// Clear timer compare match flag
TIFR0=(1<<OCF0A);
// save ADC measurement
uint16_t val = ADC;
// show ADC results
if (val < 100)
{ PORTB = 0b00000000; }
else if (val < 300)
{ PORTB = 0b00000001; }
else if (val < 550)
{ PORTB = 0b00000011; }
else if (val < 850)
{ PORTB = 0b00000111; }
else if (val < 1020)
{ PORTB = 0b00001111; }
else
{ PORTB = 0b00011111; }
}
ISR(TIMER1_COMPA_vect)
{
//PORTB ^= PINB5;
static uint16_t on = 0;
if (on == 1){
PORTB = 0b00100000;
on = 0;
}
else {
PORTB = 0b00000000;
on = 1;
}
}
When the SetTimer1() function is disabled the DCA runs as expected. So individually are are both ISR's working fine, but together not. Could someone help me solve this problem?
You have output compare interrupt enabled fro Timer0:
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
but no ISR handler for that interrupt.
The default __bad_interrupt handler just performs jump to zero interrupt vector, i.e. restarts the program.
That means if you have an interrupt enabled there should be an ISR for that interrupt.
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)
{
}
}
I am trying to build a drum machine using an Atmega644. The drum machine will have 16 LED's which will show which 16th of the beat it is at. The user should be able to set the BPM and therefore the updating of the LED will be different for different BPM.
I have a 16 MHz Crystal set at XTAL1 and XTAL2. I used a FUSE calculator to write the FUSE bits to a "Full Swing Oscillator" and remove the internal clock divide 8. I then set up the TIMER0 to perform this task
#define F_CPU 16000000UL // 1MHz internal clock
unsigned int tempo = 250; // Default BPM of 120.
volatile unsigned int seq_timer = 0;
//set-up timer for 0.5 ms update
TIMSK0 = (1<<OCIE0A);
TCCR0A = (1 << WGM01) |(1<<WGM00);
TCCR0B = (0 << WGM02) | (0<< CS02) | (1 << CS01) | (1 << CS00); //divide by 64
OCR0A = 125;
ISR (TIMER0_COMPA_vect) {
if (seq_timer>0) {seq_timer--;}
}
//Update which 16th note we are at.
void step(void){
update_led();
step_number = step_number < 15 ? step_number +1 : 0;
}
//Shift the LED such that the LED corresponding to step_number is lit up.
void update_led(void) {
for (int j = 16; j>=0; j--)
{
if ((((1 << step_number))>>j) & 0x01) {
PORTD |= (1 << PD5); //Serial Input
}
else {
PORTD &= ~(1 << PD5);
}
PORTD |= (1 << PD4); //Read clock
PORTD &= ~(1<< PD4);
}
PORTD |= (1 << PD3); //Shift clock
_delay_ms(40);
PORTD &= ~(1 << PD3);
}
while (1)
{
if ((seq_timer == 0)) {
seq_timer = tempo;
step();
}
Step functions calls a "update_led()" function which light up the LED corresponding to the step_number. This should according to my calculations occur (16e6 / (64*250*125)) = 8 updates/sec. But instead it does 4 updates/sec.
Am I missing something crucial?
I am using an Atmega328p-pu. I am trying to use the timer 1 for both a 16 bit PWM as well as using the overflow inturrupt to increment a timer. My code is below, I also set the F_CPU to 8000000UL in the make file.
I would like the to have a variable that counts up for a defined amount of time and then resets and continues. so far I would expect it to count up for 7.5 seconds. I believe I should have a clock frequency of 8 MHz, then with fast PWM with a 1 prescaler and ICR1 at 5000 I would expect the inturrupt to happen at 1600 Hz. Then I let it count up for 12000 counts. I would expect this to take 7.5 seconds. but I've measured it at around 57 seconds. I'm not sure what I'm missing, maybe something in the setting of the registers, but I'm not sure where. thanks for your help,
here is what I think is most important,
// values for timer1
// WGM 13 12 11 10 is
// fast PWM 1 1 1 0
TCCR1A |= (1 << 7); // output on A pin (COM1A1)
TCCR1A |= (1 << 1); // WGM 11
TCCR1A &= ~(1 << 0); // WGM 10
TCCR1B |= (1 << 4); // WGM 13
TCCR1B |= (1 << 3); // WGM 12
//for prescaler of 1 set CS12 CS11 CS10
0 0 1
TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
TCCR1B |= (1 << 0); // set prescaler to 1x CS10
TIMSK1 = 0; // enable output compare A inturrupt
TIMSK1 |= (1 << 0); // Set the Overflow inturrupt
TCNT1 = 0; // set the counter to zero on startup
ICR1 = 5000; //Set the top of the counter
OCR1A = 0; //set the duty cycle
....
ISR(TIMER1_OVF_vect){
longTimer++;
....
if (longTimer >= 12000){
longTimer = 0;
and here is the entire code
/* Light Control */
// ------- Preamble -------- //
#include <avr/io.h> /* Defines pins, ports, etc */
#include <avr/interrupt.h>
// Global variables
volatile uint8_t tick = 0;
volatile uint8_t fastTimer = 0;
volatile uint16_t longTimer = 0;
volatile uint16_t fader = 0;
volatile uint16_t dayBrightness = 0;
volatile uint8_t nightBrightness = 0;
uint8_t Day = 0;
void init(void) {
// values for push button inturrupt
EIMSK = (1 << 0);
EICRA = (1 << 1) & (1 << 0);
// values for timer1
// WGM 13 12 11 10 is
// fast PWM 1 1 1 0
TCCR1A |= (1 << 7); // output on A pin (COM1A1)
TCCR1A |= (1 << 1); // WGM 11
TCCR1A &= ~(1 << 0); // WGM 10
TCCR1B |= (1 << 4); // WGM 13
TCCR1B |= (1 << 3); // WGM 12
//for prescaler of 1 set CS12 CS11 CS10
0 0 1
TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
TCCR1B |= (1 << 0); // set prescaler to 1x CS10
TIMSK1 = 0; // enable output compare A inturrupt
TIMSK1 |= (1 << 0); // Set the Overflow inturrupt
TCNT1 = 0; // set the counter to zero on startup
ICR1 = 5000; //Set the top of the counter
OCR1A = 0; //set the duty cycle
sei();
// values for IO
DDRB |= 0b00000011; /* Data Direction Register B: writing a one to the bit enables output. */
DDRD = 0x00; /* zero sets all as input */
PORTD = 0xff; /* set all inputs as pull ups */
}
ISR(INT0_vect){
//longTimer = 0;
}
ISR(TIMER1_OVF_vect){
longTimer++;
if(Day){
fader++;
}
else{
if(fader > 0){
fader--;
}
}
}
int main(void) {
init();
// ------ Event loop ------ //
while (1) {
if(Day) {
if (fader >= 5000){
OCR1A = 5000;
}
else {
OCR1A = fader;
}
}
else {
OCR1A = fader;
}
if (longTimer >= 12000){
longTimer = 0;
if(Day){
fader = 5000;
}
else{
fader = 0;
}
tick = 1;
}
if (tick == 1){
Day ^= 1;
tick = 0;
}
} /* End event loop */
return 0; /* This line is never reached */
}
Whenever I'm using the internal oscillator and things are running either way (8x) faster, or way (8x) slower, I check the CKDIV8 bit setting. Almost always that's the culprit.
If using an external oscillator or clock, weird timings are often from not switching the the external clock in the fuse settings, or from having F_CPU set differently from actual frequency.
Also, off-topic a bit, but code such as this is redundant:
TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
Those bits are zeroes by default so no reason to clear them unless it's just for clarity as you're learning.