#include <avr/io.h>
#include <avr/interrupt.h>
// Definizione dei comandi (pulsanti)
#define READ_ROM 0x33
#define READ_SCRATCHPAD 0xBE
// Pin utilizzato per il bus 1-Wire
#define ONEWIRE_PIN PD4
#define ONEWIRE_PORT PORTD
#define ONEWIRE_DDR DDRD
#define ONEWIRE_PIN_INPUT PIND
#define F_CPU 16000000UL // Frequenza di clock della CPU
#define TIMER_INTERVAL_MS 1 // Intervallo del timer in millisecondi
// Variabili globali per i comandi
volatile uint8_t command = 0;
volatile uint16_t timer_counter = 0;
bool rom_received = false;
void setup() {
DDRD &= ~((1<<PD2) | (1<<PD3)); // Imposta PD2 e PD3 come input (pulsanti)
PORTD |= (1<<PD2) | (1<<PD3); // Attiva pull-up interni per PD2 e PD3
ONEWIRE_DDR |= (1<<ONEWIRE_PIN); // Imposta il pin PD4 come output
ONEWIRE_PORT |= (1<<ONEWIRE_PIN); // Attiva pull-up interno per PD4
adc_init(); // Inizializza ADC (Analogic-to-Digital Converter)
EIMSK |= (1<<INT0) | (1<<INT1); // Abilita INT0 e INT1
EICRA |= (1<<ISC01) | (1<<ISC11); // Falling edge triggers
timer1_init(); // Inizializza Timer1
SREG |= (1 << 7); // Abilita gli interrupt globali
}
void loop() {
if (command == READ_ROM) {
command = 0;
uint8_t rom_code[8] = {0x28, 0xFF, 0x6C, 0x50, 0x91, 0x16, 0x04, 0x04};
uint8_t crc = crc8(rom_code, 7);
rom_code[7] = crc;
for (int8_t i = 7; i >= 0; i--) {
onewire_write_byte(rom_code[i]);
}
rom_received = true; // Imposta il flag a true dopo aver ricevuto il comando READ_ROM
} else if (command == READ_SCRATCHPAD && rom_received) {
command = 0;
volatile uint16_t scratchpad = 0;
uint16_t adc_value = adc_read(0); // Legge il valore del potenziometro
scratchpad = adc_value & 0x3FF; // Mantieni solo i 10 bit meno significativi
// Spezza il valore in due parti: 2 bit più significativi e 8 bit meno significativi
uint8_t msb = (scratchpad >> 8) & 0x03; // Ottieni i 2 bit più significativi
uint8_t lsb = scratchpad & 0xFF; // Ottieni gli 8 bit meno significativi
onewire_write_byte(lsb); // Invia gli 8 bit meno significativi
onewire_write_bits(msb, 2); // Invia i 2 bit più significativi
}
}
// ISR per i pulsanti
ISR(INT0_vect) {
command = READ_ROM;
}
ISR(INT1_vect) {
command = READ_SCRATCHPAD;
}
// ISR per il Timer1
ISR(TIMER1_COMPA_vect) {
timer_counter++;
}
// Funzione per inizializzare l'ADC
void adc_init() {
ADMUX = (1<<REFS0); // AVcc con condensatore su AREF
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1); // Abilita ADC e prescaler a 64
}
// Funzione per leggere il valore dall'ADC
uint16_t adc_read(uint8_t ch) {
ch &= 0b00001111; // Canale deve essere tra 0 e 8
ADMUX = (ADMUX & 0xF0) | ch; // Seleziona canale
ADCSRA |= (1<<ADSC); // Avvia conversione
while(ADCSRA & (1<<ADSC)); // Aspetta fine conversione
return (ADC);
}
void timer1_init() {
TCCR1A = 0; // Modalità normale
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // CTC mode, prescaler 64
OCR1A = (F_CPU / 64 / 1000) * TIMER_INTERVAL_MS - 1; // Imposta il valore di confronto per 1ms
TIMSK1 |= (1 << OCIE1A); // Abilita l'output compare interrupt per Timer1
}
void delay_ms(uint16_t ms) {
uint16_t start_time = timer_counter;
while ((timer_counter - start_time) < ms) {
// Attendi per il tempo dato in input
}
}
void onewire_write_byte(uint8_t byte) {
for (uint8_t i = 0; i < 8; i++) {
onewire_write_bit(byte & 0x01); // Trasmetti il bit meno significativo
byte >>= 1; // Shifta il byte per preparare il prossimo bit
}
}
void onewire_write_bits(uint8_t data, uint8_t num_bits) {
for (uint8_t i = 0; i < num_bits; i++) {
onewire_write_bit(data & 0x01); // Trasmetti il bit meno significativo
data >>= 1; // Shifta l'input a destra per preparare il prossimo bit
}
}
void onewire_write_bit(uint8_t bit) {
if (bit) {
// Scrittura di un bit '1'
ONEWIRE_DDR |= (1<<ONEWIRE_PIN); // Imposta il pin come output
ONEWIRE_PORT &= ~(1<<ONEWIRE_PIN); // Porta bassa
delay_ms(8); // Attendi 6 µs
ONEWIRE_PORT |= (1<<ONEWIRE_PIN); // Porta alta
delay_ms(56); // Attendi 64 µs
} else {
// Scrittura di un bit '0'
ONEWIRE_DDR |= (1<<ONEWIRE_PIN); // Imposta il pin come output
ONEWIRE_PORT &= ~(1<<ONEWIRE_PIN); // Porta bassa
delay_ms(60); // Attendi 60 µs
ONEWIRE_PORT |= (1<<ONEWIRE_PIN); // Porta alta
delay_ms(4); // Attendi 10 µs
}
}
// Funzione per calcolare CRC8
uint8_t crc8(const uint8_t *data, uint8_t len) {
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *data++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}