[英]AVR, Using FIFO in interrupts
Greetings to all connoisseurs.向所有鉴赏家问好。 Good day.
再会。 I will try to program AVR ATMega328.
我将尝试对 AVR ATMega328 进行编程。 I use the following libraries: bme280 avr-st7735
我使用以下库: bme280 avr-st7735
Routine for Timer from here定时器例程从这里开始
I want every two seconds to get the BME280 data, and I want to use TIMER1 and overflow, see code.我想每两秒获取一次 BME280 数据,我想使用 TIMER1 并溢出,请参阅代码。 I read the sensor as an interrupt handler.
我将传感器读取为中断处理程序。 Use custom FIFO queue implementation.
使用自定义 FIFO 队列实现。 In the interrupt operation, the data is retrieved into the FIFO queue.
在中断操作中,数据被检索到 FIFO 队列中。 Finally, I will try to read FIFO in the main loop.
最后,我将尝试在主循环中读取 FIFO。
Code:代码:
main.cpp主程序
#include <stdio.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <util/delay.h>
extern "C" {
#include "spi.h"
#include "st7735.h"
#include "st7735_gfx.h"
#include "st7735_font.h"
#include "bme280/bme280.h"
#include <i2c/i2c_master.h>
#include "ftoa/ftoa.h"
}
#include <fifo.hpp>
#include "millis/millis.h"
#include "Utils/avr.hpp"
fifo_struct<float> fifo;
void showVisual()
{
// Just toggle led diode state
}
// global variable to count the number of overflows
volatile uint8_t tot_overflow;
// initialize timer, interrupt and variable
void timer1_init()
{
// set up timer with prescaler = 8
TCCR1B |= (1 << CS11);
// initialize counter
TCNT1 = 0;
// enable overflow interrupt
TIMSK1 |= (1 << TOIE1);
// initialize overflow counter variable
tot_overflow = 0;
}
// TIMER1 overflow interrupt service routine
// called whenever TCNT1 overflows
ISR(TIMER1_OVF_vect)
{
// keep a track of number of overflows
tot_overflow++;
// check for number of overflows here itself
// 61 overflows = 2 seconds delay (approx.)
if (tot_overflow >= 61) // NOTE: '>=' used instead of '=='
{
{
// Get data
float data = 5.5f; //bme280_readTemperature();
// Push to FIFO
fifo_push<float>(&fifo, data); // TODO: Not in the effect! Why?
}
showVisual(); // blink with led
// no timer reset required here as the timer
// is reset every time it overflows
tot_overflow = 0; // reset overflow counter
}
}
extern "C" int main(void)
{
// Init millis
clock_init();
// Init SPI and TFT
spi_init();
st7735_init();
st7735_set_orientation(ST7735_LANDSCAPE_INV);
st7735_fill_rect(0, 0, 128, 128, ST7735_COLOR_BLACK);
// Initialize PWM
// Fast PWM with MAX
TCCR0A |= (1 << WGM01) | (1 << WGM00);
// Mode output
// Noninvert for OC0A
TCCR0A |= (1 << COM0A1);
// Divider to 64
TCCR0B |= (1 << CS01) | (1 << CS00);
// Set pwm to 200/255
OCR0A = 200;
// Initialize I2C and BME280
i2c_init();
fifo = fifo_create<float>(5);
if (!bme_init())
{
// Error!!
}
// initialize timer
timer1_init();
// Enable global interrupts
sei();
wdt_enable(WDTO_2S);
while (1)
{
float val = fifo_pop<float>(&fifo);
uart_puts(val); // Printed 0.0
uart_puts(fifo_count<float>(&fifo)); // Allways print 0!
wdt_reset();
}
}
fifo.h先进先出
/**
* This file is a part of FIFO implementation in C/C++
*
* fifo.h
*
* Created on: 14. 1. 2020
* Author: Denis Colesnicov
* Licence: WTFPL
* Version: 4
*/
#ifndef FIFO_HPP_
#define FIFO_HPP_
#include <stdint.h>
/**
* Struktura udrzujici informace pro frontu
*/
template<typename T> struct fifo_struct
{
volatile uint8_t top; /*<! Ukazatel na vrchol zasobniku (na jakou pozici byl vlozen posledni prvek) */
volatile T *data; /*<! Pole s ulozenymi prvkz */
uint8_t size; /*<! Rezervovana velikost fronty */
};
/**
* Vytvori novou frontu
*
* @note Pro fifo_struct::data je pouzita f-ce calloc(...),
* musi se pouZit funkce free(..) pro uvolneni!
* @param _size Kolik ma obsahovat prvku
* @return Vraci frontu
*/
template<typename T> fifo_struct<T> fifo_create(uint8_t _size);
/**
* Kolik prvku je ve fronte
*
* @param _fifo Fronta
* @return Pocet prvku ve fronte
*/
template<typename T> uint8_t fifo_count(fifo_struct<T> *_fifo);
/**
* Pro kolik prvku je rezervovana fronta (maximalni pocet prvku ve fronte)
*
* @param _fifo Fronta
* @return Pocet rezervovanych "mist"
*/
template<typename T> uint8_t fifo_size(fifo_struct<T> *_fifo);
/**
* Odstrani z fronty vsechny ulozene prvky a vynuluje ji.
*
* @note Frontu jiz nadale nebude mozne pouzivat!
* @param _fifo Fronta
*/
template<typename T> void fifo_destroy(fifo_struct<T> *_fifo);
/**
* Vlozi prvek na konec fronty
*
* @param _fifo Fronta
* @param _data Data ke vlozeni
*/
template<typename T> void fifo_push(fifo_struct<T> *_fifo, T _data);
/**
* Vrati data ktera jsou na zacatku fronty.
*
* @note Data zustanou ve fronte (ne odstranuje ziskana data!)
* @param _fifo Fronta
* @return Data
*/
template<typename T> T fifo_first(fifo_struct<T> *_fifo);
/**
* Vrati data ktera jsou na konci fronty.
*
* @note Data zustanou ve fronte (ne odstranuje ziskana data!)
* @param _fifo Fronta
* @return Data
*/
template<typename T> T fifo_last(fifo_struct<T> *_fifo);
/**
* Zredukuje velikost fronty o zadany pocet pozic
* Posune obsah fronty do leva o zadany pocet pozic.
* Data ktera byla na zacatku fronty budou odstranene!
*
* @param _fifo Fronta
* @param _count Pocet pozic k posunu
*/
template<typename T> void fifo_reduce(fifo_struct<T> *_fifo, uint8_t _count);
/**
* Vrati data ze zacatku fronty.
*
* @note Tim dojde k odstraneni techto dat a zredukovani pole.
* @see fifo_reduce(...)
* @param _fifo Fronta
* @return Data
*/
template<typename T> T fifo_pop(fifo_struct<T> *_fifo);
/**
* Trida usnadnujici praci s FIFO frontou
*/
template<typename T>
class Fifo
{
public:
/**
* Vytvori novou frontu
*
* @param _size Kolik ma obsahovat prvku
*/
Fifo(uint8_t _size);
/**
* Odstrani z fronty vsechny ulozene prvky a vynuluje ji.
*
* @note Frontu jiz nadale nebude mozne pouzivat!
* @param _fifo Fronta
*/
~Fifo();
/**
* Vrati data ktera jsou na zacatku fronty.
*
* @note Data zustanou ve fronte (ne odstranuje ziskana data!)
* @param _fifo Fronta
* @return Data
*/
T first();
/**
* Vrati data ktera jsou na konci fronty.
*
* @note Data zustanou ve fronte (ne odstranuje ziskana data!)
* @param _fifo Fronta
* @return Data
*/
T last();
/**
* Kolik prvku je ve fronte
*
* @return Pocet prvku ve fronte
*/
uint8_t count();
/**
* Pro kolik prvku je rezervovana fronta (maximalni pocet prvku ve fronte)
*
* @return Pocet rezervovanych "mist"
*/
uint8_t size();
/**
* Vrati data ze zacatku fronty.
*
* @note Tim dojde k odstraneni techto dat a zredukovani pole.
* @see fifo_reduce(...)
* @return Data
*/
T pop();
/**
* Vlozi prvek na konec fronty
*
* @param _fifo Fronta
* @param _data Data ke vlozeni
*/
void push(T _data);
/**
* Zredukuje velikost fronty o zadany pocet pozic
* Posune obsah fronty do leva o zadany pocet pozic.
* Data ktera byla na zacatku fronty budou odstranene!
*
* @param _count Pocet pozic k posunu
*/
void reduce(uint8_t _count);
private:
fifo_struct<T> m_fifo; /*<! Fronta (FIFO) */
};
#include <stdlib.h>
template<typename T> fifo_struct<T> fifo_create(uint8_t _size)
{
fifo_struct<T> fifo;
fifo.top = 0;
fifo.size = _size;
fifo.data = (T*) calloc(_size, sizeof(T));
return fifo;
}
template<typename T> uint8_t fifo_count(fifo_struct<T> *_fifo)
{
return (uint8_t) _fifo->top;
}
template<typename T> uint8_t fifo_size(fifo_struct<T> *_fifo)
{
return (uint8_t) _fifo->size;
}
template<typename T> void fifo_destroy(fifo_struct<T> *_fifo)
{
_fifo->size = 0;
_fifo->top = 0;
free(_fifo->data);
}
template<typename T> void fifo_push(fifo_struct<T> *_fifo, T _data)
{
if (_fifo->size == _fifo->top)
{
fifo_reduce<T>(_fifo, 1);
}
_fifo->data[_fifo->top] = _data;
_fifo->top++;
}
template<typename T> T fifo_pop(fifo_struct<T> *_fifo)
{
if (_fifo->top == 0)
{
return (T) NULL;
}
T data = _fifo->data[0];
fifo_reduce<T>(_fifo, 1);
return data;
}
template<typename T> T fifo_first(fifo_struct<T> *_fifo)
{
if (_fifo->top == 0)
{
return (T) NULL;
}
return _fifo->data[0];
}
template<typename T> T fifo_last(fifo_struct<T> *_fifo)
{
if (_fifo->top == 0)
{
return (T) NULL;
}
return _fifo->data[_fifo->top - 1];
}
template<typename T> void fifo_reduce(fifo_struct<T> *_fifo, uint8_t _count)
{
for (uint8_t i = 0; i < _fifo->size; i++)
{
_fifo->data[i] = _fifo->data[_count + i];
}
_fifo->top -= _count;
}
template<typename T>
Fifo<T>::Fifo(uint8_t _size)
{
m_fifo = fifo_create<T>(_size);
}
template<typename T>
Fifo<T>::~Fifo()
{
fifo_destroy<T>(&m_fifo);
}
template<typename T>
T Fifo<T>::first()
{
fifo_first<T>(m_fifo);
}
template<typename T>
T Fifo<T>::last()
{
fifo_last<T>(m_fifo);
}
template<typename T>
uint8_t Fifo<T>::count()
{
return fifo_count<T>(m_fifo);
}
template<typename T>
uint8_t Fifo<T>::size()
{
return fifo_size<T>(m_fifo);
}
template<typename T>
T Fifo<T>::pop()
{
return fifo_pop<T>(&m_fifo);
}
template<typename T>
void Fifo<T>::push(T _data)
{
fifo_push<T>(&m_fifo, _data);
}
template<typename T>
void Fifo<T>::reduce(uint8_t _count)
{
fifo_reduce<T>(&m_fifo, _count);
}
#endif /* FIFO_HPP_ */
milli.h毫小时
/*
* Project: Lightweight millisecond tracking library
* Author: Zak Kemble, contact@zakkemble.net
* Copyright: (C) 2018 by Zak Kemble
* License: GNU GPL v3 (see License_GPL-3.0.txt) or MIT (see License_MIT.txt)
* Web: http://blog.zakkemble.net/millisecond-tracking-library-for-avr/
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <util/atomic.h>
#ifdef __cplusplus
}
#endif
#include "millis.h"
#define CLOCK_SCALE_MICROS 0
#define CLOCK_SCALE_MILLIS 1
#define CLOCK_SCALE CLOCK_SCALE_MICROS
#define MILLIS_TIMER0 0 /**< Use timer0. */
#define MILLIS_TIMER1 1 /**< Use timer1. */
#define MILLIS_TIMER2 2 /**< Use timer2. */
#define MILLIS_TIMER MILLIS_TIMER0 /**< Which timer to use. */
#define MICROSECONDS_PER_TIMER0_OVERFLOW 16384
#define MILLIS_INC 1024
#define FRACT_INC ((1024 % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)
#ifndef F_CPU
#error "F_CPU not defined!"
#endif
#if F_CPU < 256 || F_CPU >= 32640000
#error "Bad F_CPU setting (<256 or >=32640000)"
#endif
#ifndef MILLIS_TIMER
#error "Bad MILLIS_TIMER set"
#endif
// Decide what what prescaler and registers to use
#if MILLIS_TIMER == MILLIS_TIMER0
// Timer0
#if F_CPU > 16320000 // 16.32MHz - 65.28MHz
#define CLOCKSEL (_BV(CS20))
#define PRESCALER 256
#elif F_CPU > 2040000 // 2.04MHz - 16.32MHz
#define CLOCKSEL (_BV(CS01)|_BV(CS00))
#define PRESCALER 64
#elif F_CPU > 255 // 256Hz - 2.04MHz
#define CLOCKSEL (_BV(CS01))
#define PRESCALER 8
#endif
#define REG_TCCRA TCCR0A
#define REG_TCCRB TCCR0B
#define REG_TIMSK TIMSK0
#define REG_OCR OCR0A
#define BIT_WGM WGM01
#define BIT_OCIE OCIE0A
#ifdef TIMER0_COMPA_vect
#define ISR_VECT TIMER0_COMPA_vect
#else
#define ISR_VECT TIM0_COMPA_vect
#endif
#define pwr_enable() power_timer0_enable()
#define pwr_disable() power_timer0_disable()
#define SET_TCCRA() (REG_TCCRA |= _BV(BIT_WGM))
#define SET_TCCRB() (REG_TCCRB |= CLOCKSEL)
#elif MILLIS_TIMER == MILLIS_TIMER1
// Timer1
// 1KHz - 65.28MHz
#define CLOCKSEL (_BV(CS10))
#define PRESCALER 1
#define REG_TCCRA TCCR1A
#define REG_TCCRB TCCR1B
#define REG_TIMSK TIMSK1
#define REG_OCR OCR1A
#define BIT_WGM WGM12
#define BIT_OCIE OCIE1A
#ifdef TIMER1_COMPA_vect
#define ISR_VECT TIMER1_COMPA_vect
#else
#define ISR_VECT TIM1_COMPA_vect
#endif
#define pwr_enable() power_timer1_enable()
#define pwr_disable() power_timer1_disable()
#define SET_TCCRA() (REG_TCCRA |= 0)
#define SET_TCCRB() (REG_TCCRB |= _BV(BIT_WGM)|CLOCKSEL)
#elif MILLIS_TIMER == MILLIS_TIMER2
// Timer2
#if F_CPU > 16320000 // 16.32MHz - 32.64MHz
#define CLOCKSEL (_BV(CS22)|_BV(CS20))
#define PRESCALER 128
#elif F_CPU > 8160000 // 8.16MHz - 16.32MHz
#define CLOCKSEL (_BV(CS22))
#define PRESCALER 64
#elif F_CPU > 2040000 // 2.04MHz - 8.16MHz
#define CLOCKSEL (_BV(CS21)|_BV(CS20))
#define PRESCALER 32
#elif F_CPU > 255 // 256Hz - 2.04MHz
#define CLOCKSEL (_BV(CS21))
#define PRESCALER 8
#endif
#define REG_TCCRA TCCR2A
#define REG_TCCRB TCCR2B
#define REG_TIMSK TIMSK2
#define REG_OCR OCR2A
#define BIT_WGM WGM21
#define BIT_OCIE OCIE2A
#define ISR_VECT TIMER2_COMPA_vect
#define pwr_enable() power_timer2_enable()
#define pwr_disable() power_timer2_disable()
#define SET_TCCRA() (REG_TCCRA |= _BV(BIT_WGM))
#define SET_TCCRB() (REG_TCCRB |= CLOCKSEL)
#else
#error "Bad MILLIS_TIMER set"
#endif
static volatile millis_t timer_value;
// Initialise library
void clock_init()
{
// Timer settings
SET_TCCRA();
SET_TCCRB();
REG_TIMSK |= _BV(BIT_OCIE);
REG_OCR = ((F_CPU / PRESCALER) / 1000);
}
// Get current timer_value
millis_t clock_get()
{
millis_t ms;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
ms = timer_value;
}
return ms;
}
// Turn on timer and resume time keeping
void clock_resume()
{
pwr_enable();
REG_TIMSK |= _BV(BIT_OCIE);
}
// Pause time keeping and turn off timer to save power
void clock_pause()
{
REG_TIMSK &= ~_BV(BIT_OCIE);
pwr_disable();
}
// Reset microseconds count to 0
void clock_reset()
{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
timer_value = 0;
}
}
// Add time
void clock_add(millis_t ms)
{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
timer_value += ms;
}
}
// Subtract time
void clock_subtract(millis_t ms)
{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
timer_value -= ms;
}
}
ISR(ISR_VECT)
{
static unsigned char timer_fract = 0;
#if CLOCK_SCALE == CLOCK_SCALE_MICROS
timer_value += MILLIS_INC;
timer_fract += FRACT_INC;
if (timer_fract >= FRACT_MAX)
{
timer_fract -= FRACT_MAX;
timer_value += 1;
}
#else
timer_value += 1;
timer_fract += 3;
if (timer_fract >= 125)
{
timer_fract -= 125;
timer_value += 1;
}
#endif // CLOCK_SCALE
}
Problem: No data is stored in FIFO.问题:FIFO 中没有存储数据。 Do you see someone solving please ??
你看到有人解决了吗??
I changed my strategy.我改变了策略。 My code already works differently.
我的代码已经不同了。 But my FIFO implementation could be useful to someone...
但是我的 FIFO 实现可能对某人有用......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.