#include <avr/io.h>
#include <avr/interrupt.h>
#define BAUD 9600
#define F_CPU 16000000UL
#define MYUBRR F_CPU/16/BAUD-1
// def costanti per direzione
#define INPUT 0
#define OUTPUT 1
volatile uint16_t PWMparam[4][4]; // matrice per i parametri PWM
volatile uint16_t DOparam[4][2]; // matrice per i paramentri digital output
volatile float expMat[4][2]; // coefficenti per exp
volatile uint8_t* regPointVect[4]={&OCR0B,&OCR2A,&OCR2B,&OCR0A,}; // punt ai registri controllo PWM ad 8 bit per 4 uscite, essendo PWM 0 e 2 sono omogenei
volatile uint8_t pinsPWMVect[4]={5,11,3,6};// vettori con i pin dei PWM
volatile uint8_t pinsDOVect[4]={PC0,PC1,PC2,PC3};
volatile uint32_t aus ;
volatile uint32_t L;
volatile uint32_t S;
volatile uint32_t D;
volatile uint32_t F;
volatile uint32_t O;
volatile uint32_t T;
volatile uint16_t sumLSDF;
// PWM
//LG lag giorno: dopo quanto tempo inizia il giorno
//SG start giorno : durata dell'incremento di luminosità da 0 al massimo
// DG dwell giorno: durata alla massima luminosità
//FG fade giorno : durata del decremento di luminosità dal massimo a 0
// Giorno - rosso
// Tramonto - arancione
// costanti di tempo per crescita e decrescita esponenziali
#define expSG expMat[0][0]
#define expFG expMat[0][1]
#define expST expMat[1][0]
#define expFT expMat[1][1]
#define expSN expMat[2][0]
#define expFN expMat[2][1]
#define expSA expMat[3][0]
#define expFA expMat[3][1]
char stringS[4][20] = {
"\nora LG SG DG FG\n",
"\nora LT ST DT FT\n",
"\nora LN SN DN FN\n",
"\nora LA SA DA FA\n"
};
char stringD [4][20] ={
"\nora OG TG \n",
"\nora OT TT \n",
"\nora ON TN \n",
"\nora OA TA \n",
};
volatile uint32_t elapsedTime=0;
volatile uint32_t MAXD;
// variabili di stato
volatile bool updatePwmFlag = false;
//volatile uint8_t updateOutputFlag = 0;
void setup() {
// Configura Timer0 Fast PWM mode Pin 6 e Pin 5
TCCR0A = (1 << WGM00) | (1 << WGM01) | (1 << COM0A1) | (1 << COM0B1);
TCCR0B = (1 << CS01) | (1 << CS00); // Prescaler 64
// Configura Timer2 Fast PWM mode Pin 11 e Pin 3
TCCR2A = (1 << WGM20) | (1 << WGM21) | (1 << COM2A1) | (1 << COM2B1);
TCCR2B = (1 << CS22); // Prescaler 64
// Configura Timer1 per interrupt 0,1s
TCCR1A = 0; // CTC mode
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // Prescaler 64
//OCR1A = 15624;
OCR1A =24999; // (16MHz / (64 * 10Hz)) - 1
TIMSK1 = (1 << OCIE1A); // Interrupt enable Timer1 Compare A
// Inizializza output PWM
//DDRD |= (1 << DDD6) | (1 << DDD5); // Pin 6, Pin 5
// DDRB |= (1 << DDB3) | (1 << DDB2); // Pin 11, Pin 3
DDRD &= ~(1 << DDD3);
DDRD &= ~(1 << DDD5);
DDRD &= ~(1 << DDD6); //
DDRB &= ~(1 << DDB3);
// configura output digitali
DDRC |= (1 << DDC0); // PC0 (A0)
DDRC |= (1 << DDC1); // PC1 (A1)
DDRC |= (1 << DDC2); // PC2 (A2)
DDRC |= (1 << DDC3); // PC3 (A3)
// inizializza com seriale
SerialInit(MYUBRR);
sei();
/* per test veloci da abilitare e conf in alternativa al getInputValues() */
// inizia processo input----------------
/*
PWMparam[0][0]=10; PWMparam[0][1]=20;PWMparam[0][2]=40; PWMparam[0][3]=70;
PWMparam[1][0]=100; PWMparam[1][1]=160;PWMparam[1][2]=210; PWMparam[1][3]=240;
PWMparam[2][0]=250; PWMparam[2][1]=270;PWMparam[2][2]=310; PWMparam[2][3]=330;
PWMparam[3][0]=350; PWMparam[3][1]=410;PWMparam[3][2]=430; PWMparam[3][3]=500;
DOparam[0][0] = 40;
DOparam[0][1] = 100; //TG
DOparam[1][0] = 110; //OG
DOparam[1][1] = 90; //TG
DOparam[2][0] = 210; //OG
DOparam[2][1] = 90; //TG
DOparam[3][0] = 20; //OG
DOparam[3][1] = 80; //TG
*/
GetInputValues();
findMax();
elapsedTime=0;
}
// Timer1 interrupt eogni 0,1 sec
ISR(TIMER1_COMPA_vect) {
updatePwmFlag = true;
elapsedTime += 1; // conteggio in decimi quindi intero
}
void setPinMode(uint8_t pin, uint8_t direction) {
if (pin >= 0 && pin <= 7) {
// Pins 0-7 correspond to PORTD
if (direction == OUTPUT) {
DDRD |= (1 << pin); // Set the pin as output
} else {
DDRD &= ~(1 << pin); // Set the pin as input
}
}
else if (pin >= 8 && pin <= 13) {
// Pins 8-13 correspond to PORTB
uint8_t bit = pin - 8; // Adjust for PORTB
if (direction == OUTPUT) {
DDRB |= (1 << bit); // Set the pin as output
} else {
DDRB &= ~(1 << bit); // Set the pin as input
}
}
else if (pin >= A0 && pin <= A5) {
// Analog pins A0-A5 correspond to PORTC
uint8_t bit = pin - A0; // Adjust for PORTC
if (direction == OUTPUT) {
DDRC |= (1 << bit); // Set the pin as output
} else {
DDRC &= ~(1 << bit); // Set the pin as input
}
}
}
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
//---- LOOP principale : se interrupt ha settato flag esegue funzione di update e resetta la flag--------------//
void loop() {
if (updatePwmFlag) {
updatePWM_DO();
updatePwmFlag = false;
}
}
void updateDO(uint16_t O, uint16_t T, int pin_pos ){
if(elapsedTime > O & elapsedTime < O + T){
PORTC |= (1 << pin_pos); // Set PC0 (A0) HIGH
}
else
PORTC &= ~(1 << pin_pos);
}
void updateChannel(volatile uint8_t &ocr, uint8_t pin, uint8_t index) {
float xs;
if (elapsedTime < PWMparam[index][0]) {
// ocr = 0;
setPinMode(pin, INPUT);
} else if (elapsedTime < PWMparam[index][1]) {
setPinMode(pin, OUTPUT);
xs = 1.0 - (PWMparam[index][1]-(elapsedTime)/expMat[index][0])/ 16;
xs *= xs; xs *= xs; xs *= xs; xs *= xs;
ocr = (uint8_t)255*xs;
} else if (elapsedTime < PWMparam[index][2] ) {
ocr = 255;
} else if (elapsedTime < PWMparam[index][3]) {
xs=1-(( elapsedTime-(PWMparam[index][2]))/expMat[index][1])/16;
xs *= xs; xs *= xs; xs *= xs; xs *= xs;
ocr = (uint8_t)255*xs;
} else if (elapsedTime < MAXD) {
setPinMode(pin, INPUT);
}
else {
elapsedTime = 0; // Reset cycle
}
}
void updatePWM_DO() {
updateDO(OG,TG,PC0);
updateDO(OT,TT,PC1);
updateDO(ON,TN,PC2);
updateDO(OA,TA,PC3);
updateChannel(OCR0B,5, 0);
updateChannel(OCR2A,11, 1);
updateChannel(OCR2B,3, 2);
updateChannel(OCR0A,6, 3);
}
/*-----SERIALE------ ---*/
/*----------------------------*/
/* funzione di init seriale */
void SerialInit(unsigned int ubrr) {
// Setta baud rate
UBRR0H = (unsigned char)(ubrr >> 8);
UBRR0L = (unsigned char)ubrr;
// Enable ric e trasmissione
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
//formato frame : 8 bit dati, 1 stop
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
}
// funzione per mandare caratteri sulla seriale
void SerialWrite(char data) {
// attesa buffer trasmissione vuoto
while (!(UCSR0A & (1 << UDRE0)));
// metti dato in buffer
UDR0 = data;
}
// funzione per mandare stringhe sulla seriale
void SerialWriteString(const char* str) {
while (*str) {
SerialWrite(*str++);
}
}
// funzione per leggere un carattere da seriale
char SerialRead() {
// aspetta i dati da ricevere
while (!(UCSR0A & (1 << RXC0)));
// restituisce i dati ricevuti dal buffer
return UDR0;
}
// funzione per leggere unsigned integer 16 bit da seriale, cioè legge stringa e la converte
uint16_t ReadInteger() {
char buffer[6]; // Buffer input (5 cifre max + null per terminare)
int index = 0;
char c;
while (true) {
c = SerialRead();
if (c == '\n' || c == '\r') {
SerialWrite('\n');
break; // Break newline - carriage return
}
if (index < 5) { // Limite input 5 cifre
buffer[index++] = c;
SerialWrite(c); // Eco char su seriale
}
}
buffer[index] = '\0'; // Null- (termina stringa)
return StringToInteger(buffer)*10; // conversione ad intero poi moltiplicazione per 10 per passare ai decimi
// return StringToInteger(buffer);
}
/*-----------------------------------------------*/
/*------------------ CONVERSIONE ----------------- */
// funzione di conversione custom stringa ad unsigned integer 16 bit
uint16_t StringToInteger(const char* str) {
uint16_t result = 0;
while (*str) {
result = result * 10 + (*str - '0');
str++;
}
return result;
}
// funzione da intero a stringa
char* IntToStr(uint16_t num) {
static char str[6]; // Max 5 cifre + null
int i = 5;
str[i] = '\0';
do {
i--;
str[i] = (num % 10) + '0';
num /= 10;
} while (num > 0 && i > 0);
return &str[i];
}
/*------------------------------------------*/
/* ---------------INPUT --------------------*/
// funzione per input dati e validazione
void GetInputValues() {
sumLSDF =0; // inzializzato a 0 perchè è il primo set di param , quindi LG deve solo essere>0
int j,k;
for (j=0;j<=3;j++)
{
SerialWriteString("\n ogni valore < 1638 e prossimo valore maggiore di ");
SerialWriteString(IntToStr(sumLSDF/10));
SerialWriteString("\n");
SerialWriteString(stringS[j]);
while (true) {
PWMparam[j][0] = ReadInteger();
if (PWMparam[j][0]> sumLSDF & PWMparam[j][0]<16380 ) break;
SerialWriteString("\nnon valido\n");
}
for (k=1;k<=3;k++)
{
while (true) {
PWMparam[j][k]=ReadInteger();
if (PWMparam[j][k] <16380 ) { PWMparam[j][k]=PWMparam[j][k]+PWMparam[j][k-1];} break;
SerialWriteString("\nnon valido\n");
}
}
sumLSDF=(PWMparam[j][3]);
int p=1;
}
// divisione per 3 delle durate di salita e discesa equivale alla durata deltaT/LN(100/5)
// dal 100% al 5% del valore ( e viceversa)
for (j=0;j<=3;j++)
{
expMat[j][0]= (PWMparam[j][1]-PWMparam[j][0])/3; // equivalente apporx a dividere per 3 l'intervallo , rimanendo però intero, riporto prima in decmi
expMat[j][1]= (PWMparam[j][3]-PWMparam[j][1])/3;
}
// poi i parametri per gli output digitali
for (j=0;j<=3;j++){
SerialWriteString("\n ogni valore < 1638 ");
SerialWriteString(stringD[j]);
while (true) {
DOparam[j][0] = ReadInteger(); //OG
if (DOparam[j][0]<16380 ) break;
SerialWriteString("\nnon valido\n");
}
while (true) {
DOparam[j][1] = ReadInteger(); //TG
if (DOparam[j][1]<16380 ) break;
SerialWriteString("\nnon valido\n");
}
}
findMax();
}
void findMax() {
int aus1,j;
MAXD = PWMparam[3][3];
for (j=0;j<3;j++){
aus1=DOparam[j][0]+DOparam[j][1];
if (MAXD<aus1) MAXD=aus1;
}
}
/* -----------------------*/