Infrared närheten Sensing soffbord modul & färgskiftande glödande kran (3 / 6 steg)
Steg 3: Koden
/***
STIFTTILLDELNINGAR PÅ ATMEGA48
PC6 (PCINT14/RESET)
PC5 (ADC5/SCL/PCINT13) / / I2C klocka-ingång
PC4 (ADC4/SDA/PCINT12) / / I2C Data ingång
PC3 (ADC3/PCINT11) //Sensor 4 IR-mottagare
PC2 (ADC2/PCINT10) //Sensor 3 IR-mottagare
PC1 (ADC1/PCINT9) //Sensor 2 IR-mottagare
PC0 (ADC0/PCINT8) //Sensor 1 IR-mottagare
PB7 (PCINT7/XTAL2/TOSC2) //IR 4 utlösa
PB6 (PCINT6/XTAL1/TOSC1) //IR 3 utlösa
Pb5 (SCK/PCINT5) //IR 2 utlösa
PB4 (MISO/PCINT4) //IR 1 utlösa
PB3 (MOSI/OC2A/PCINT3) //PWM 3
PB2 (SS/OC1B/PCINT2)
PB1 (OC1A/PCINT1)
PB0 (PCINT0/CLKO/ICP1)
PD0 (PCINT16/RXD)
PD1 (PCINT17/TXD)
PD2 (PCINT18/INT0)
PD3 (PCINT19/OC2B/INT1) //PWM 4
PD4 (PCINT20/XCK/T0)
PD5 (PCINT21/OC0B/T1) //PWM 2
PD6 (PCINT22/OC0A/AIN0) //PWM 1
PD7 (PCINT23/AIN1)
***/
#define IR_1_ON PORTB | = (1 << 4)
#define IR_2_ON PORTB | = (1 << 5)
#define IR_3_ON PORTB | = (1 << 6)
#define IR_4_ON PORTB | = (1 << 7)
#define IR_1_OFF PORTB & = ~ (1 << 4)
#define IR_2_OFF PORTB & = ~ (1 << 5)
#define IR_3_OFF PORTB & = ~ (1 << 6)
#define IR_4_OFF PORTB & = ~ (1 << 7)
#define PWM1 6 //PORTD PWM stift
#define PWM2 5 //PORTD
#define PWM3 3 //PORTB
#define PWM4 3 //PORTD
#define F_CPU 8000000UL
#include
#include
#include
#include
/ *** Funktion deklarationer *** /
int ADC_read(void);
void A2D_Channel_Select (unsigned char kanal);
void Init_ADC(void);
void Init_Timer0(void);
void Init_Timer1(void);
void Init_Timer2(void);
void Delay(void);
void Calibrate_Sensors(void);
void Init_I2C_Slave_Rx(void);Alla, utom en av dessa variabler deklareras flyktiga eftersom i princip allt arbete görs i
avbryta tjänsten rutiner
/ *** Global variabel deklarationer *** / unsigned char buffer = 8. int main(void) DDRD = 0XFF; Init_ADC(); SEI(); Calibrate_Sensors();
flyktiga char Sensor_Values_Updated = 0;
flyktiga char Timer1_Overflow = 0;
flyktiga unsigned char kanal = 0;
flyktiga int Amb_Sensor_1 = 0, Amb_Sensor_2 = 0, Amb_Sensor_3 = 0, Amb_Sensor_4 = 0;
flyktiga int Sensor_1 = 0, Sensor_2 = 0, Sensor_3 = 0, Sensor_4 = 0;
flyktiga int Initial_1 = 0, Initial_2 = 0, Initial_3 = 0, Initial_4 = 0;
flyktiga int New_PWM1 = 0, New_PWM2 = 0, New_PWM3 = 0, New_PWM4 = 0;
flyktiga int Old_PWM1 = 0, Old_PWM2 = 0, Old_PWM3 = 0, Old_PWM4 = 0;
{
DDRB = 0XFF;
Kontrollera att IR-sändare är avstängd, och PWM 3
PORTB & = ~ ((1 << 7) | () 1 << 6) | (1 << 5) | (1 << 4) | (1 << 3));
DDRC = 0X00; göra PORT C ingångar
PORTD = 0X00; alla PORT D lågt satt. säkerställer
PORTD | = (1 << PWM1); blinka för att indikera slutet av kalibrering
_delay_ms(600);
PORTD & = ~ (1 << PWM1);
Init_Timer0();
Init_Timer2();
Init_I2C_Slave_Rx();
While(1)
{
göra något?
//. . .
}
}
Switch(Timer1_Overflow) New_PWM1 = (Sensor_1 - Amb_Sensor_1) - Initial_1; tillstånd avläsningar om (OCR0A > = 1) {DDRD | = (1 << PWM1);}
Med klockan kör ungefär 8MHz och Timer 1 räknar upp till 65535. Timern kommer svämma över ungefär 122 gånger per sekund. Denna ISR kommer eld och ökar värdet för variabeln timer spill då funktionen SWITCH/CASE kommer att välja den nästa pixeln att testa
ISR(TIMER1_OVF_vect)
{
Timer1_Overflow ++; Increment timer overflow variabel
{
fall 1:
A2D_Channel_Select(0); ADC kanal 0
Amb_Sensor_1 = ADC_read(); ta omgivande IR sensor behandlingen
IR_1_ON; slå på IR-1 LED, PORTB | = (1 << 4)
Delay(); fördröjning för IR-mottagaren att bosätta sig
Sensor_1 = ADC_read(); ta aktiv ADC läsning av IR-mottagaren
IR_1_OFF; stänga av IR-1 LED
om (New_PWM1 < = 0) {New_PWM1 = 0;} //prevent negativa tal
enkel lågpassfilter, (87,5% * gamla) + (12,5% * New) . Det tar bara det gamla värdet och vikter det mer än äldre värdet. Har samma effekt på avmattning förändring, vilket är avgörande i att ge vätska förändringar i ljusstyrka
New_PWM1 = ((7*Old_PWM1) >> 3) + (New_PWM1 >> 3);
annat {DDRD & = ~ (1 << PWM1);} //turn av lysdioder helt
New_PWM1 << = 2;
IF(New_PWM1 > 255) {New_PWM1 = 255;}
OCR0A = New_PWM1;
New_PWM1 >> = 2;
Den nedan kod som är helt kommenteras ut är en annan ljusstyrka algoritm. Det är en utlösande algoritm som kommer att blekna lysdioderna på när något kommer inom en tröskel. Och lysdioderna kommer att tona ut långsamt när objektet är av tröskeln avståndet. Detta är användbart eftersom operationen kunde vara mer tillförlitliga och tona ut tid kan justeras för att vara mycket lång eller hur lång tid du vill ha den. Jag har inte testat denna kod så jag inte är säker på om det kommer att fungera 100%
/ *** //Trigger sekvens IF(OCR0A < 255) om (New_PWM1 < (Initial_1 + 8)) annat if(New_PWM1 < Initial_1) fall 2: New_PWM2 = (Sensor_2 - Amb_Sensor_2) - Initial_2; New_PWM2 = ((7*Old_PWM2) >> 3) + (New_PWM2 >> 3); New_PWM2 << = 2; IF(OCR0B < 255) om (New_PWM2 < (Initial_2 + 8)) annat if(New_PWM2 < Initial_2) fall 3: New_PWM3 = (Sensor_3 - Amb_Sensor_3) - Initial_3; New_PWM3 = ((7*Old_PWM3) >> 3) + (New_PWM3 >> 3);
IF(New_PWM1 > Initial_1)
{
DDRD | = (1 << PWM1);
{
OCR0A += (255 - OCR0A) >> 2;
OCR0A ++;
}
{
Initial_1 = ((7*Initial_1) >> 3) + (New_PWM1 >> 3);
}
}
{
IF(OCR0A > 0)
{
OCR0A-= (OCR0A >> 4) + 1;
OCR0A--;
}
annars om (OCR0A < = 0)
{
DDRD & = ~ (1 << PWM1);
}
}
*****/
Old_PWM1 = New_PWM1;
bryta;
A2D_Channel_Select(1); ADC kanal 1
Amb_Sensor_2 = ADC_read();
IR_2_ON; slå på IR-2 LED, PORTB | = (1 << 5)
Delay(); fördröjning för IR-mottagaren att bosätta sig
Sensor_2 = ADC_read(); ta ADC läsning
IR_2_OFF; stänga av IR-2 LED
IF(New_PWM2 < 0) {New_PWM2 = 0;}
om (OCR0B > = 1) {DDRD | = (1 << PWM2);}
annat {DDRD & = ~ (1 << PWM2);}
IF(New_PWM2 > 255) {New_PWM2 = 255;}
OCR0B = New_PWM2;
New_PWM2 >> = 2;
/*
IF(New_PWM2 > Initial_2)
{
DDRD | = (1 << PWM2);
{
OCR0B += (255 - OCR0B) >> 2;
OCR0B ++;
}
{
Initial_2 = ((7*Initial_2) >> 3) + (New_PWM2 >> 3);
}
}
{
IF(OCR0B > 0)
{
OCR0B-= (OCR0B >> 4) + 1;
OCR0B--;
}
annars om (OCR0B < = 0)
{
DDRD & = ~ (1 << PWM2);
}
}
*/
Old_PWM2 = New_PWM2;
bryta;
A2D_Channel_Select(2); ADC kanal 2
Amb_Sensor_3 = ADC_read();
IR_3_ON; slå på IR-3 LED, PORTB | = (1 << 6)
Delay(); fördröjning för IR-mottagaren att bosätta sig
Sensor_3 = ADC_read(); ta ADC läsning
IR_3_OFF; stänga av IR-3 LED
IF(New_PWM3 < 0) {New_PWM3 = 0;}
om (OCR2A > = 1) {DDRB | = (1 << PWM3);}
annat {DDRB & = ~ (1 << PWM3);}
New_PWM3 << = 2;
IF(New_PWM3 > 255) {New_PWM3 = 255;}
OCR2A = New_PWM3;
New_PWM3 >> = 2;
/*
IF(New_PWM3 > Initial_3)
{
DDRB | = (1 << PWM3);
IF(OCR2A < 255)
{
OCR2A += (255 - OCR2A) >> 2;
OCR2A ++;
}
om (New_PWM3 < (Initial_3 + 8))
{
Initial_3 = ((7*Initial_3) >> 3) + (New_PWM3 >> 3);
}
}
annat if(New_PWM3 < Initial_3)
{
IF(OCR2A > 0)
{
OCR2A-= (OCR2A >> 4) + 1;
OCR2A--;
}
annars om (OCR2A < = 0)
{
DDRB & = ~ (1 << PWM3);
}
}
*/
Old_PWM3 = New_PWM3;
bryta;
fall 4:
A2D_Channel_Select(3); ADC kanal 3
Amb_Sensor_4 = ADC_read();
IR_4_ON; slå på IR-4 LED, PORTB | = (1 << 7)
Delay(); fördröjning för IR-mottagaren att bosätta sig
Sensor_4 = ADC_read(); ta ADC läsning
IR_4_OFF; stänga av IR-4 LED
New_PWM4 = (Sensor_4 - Amb_Sensor_4) - Initial_4;
IF(New_PWM4 < 0) {New_PWM4 = 0;}
New_PWM4 = ((7*Old_PWM4) >> 3) + (New_PWM4 >> 3);
om (OCR2B > = 1) {DDRD | = (1 << PWM4);}
annat {DDRD & = ~ (1 << PWM4);}
New_PWM4 << = 2;
IF(New_PWM4 > 255) {New_PWM4 = 255;}
OCR2B = New_PWM4;
New_PWM4 >> = 2;
/*
IF(New_PWM4 > Initial_4)
{
DDRD | = (1 << PWM4);
IF(OCR2B < 255)
{
OCR2B += (255 - OCR2B) >> 2;
OCR2B ++;
}
om (New_PWM4 < (Initial_4 + 8))
{
Initial_4 = ((7*Initial_4) >> 3) + (New_PWM4 >> 3);
}
}
annat if(New_PWM1 < Initial_4)
{
IF(OCR2B > 0)
{
OCR2B-= (OCR2B >> 4) + 1;
OCR2B--;
}
annars om (OCR2B < = 0)
{
DDRD & = ~ (1 << PWM4);
}
}
*/
Old_PWM4 = New_PWM4;
Timer1_Overflow = 0; återställa
Sensor_Values_Updated = 1; nya värden redo
bryta;
} //end switch
} //end ISR
Detta är något jag kommer att försöka lista senare. Det är otestade elementära kod som skulle tillåta mig att använda två tråd gränssnittet (I2C) så flera styrenheter och kommunicera med varandra eller har en master och en massa slavar. fall TW_SR_DATA_ACK: / / 0x80, data i TWDR fall 2: fall Max_Bytes_Expected: fall TW_SR_GCALL_DATA_ACK: / / 0x90 void Init_I2C_Slave_Rx(void) TWCR | = ((1 << TWEA) | () 1 << TWEN)); void Calibrate_Sensors(void) //establish inledande sensor för omgivande värden Init_Timer1(); för (q = 0; q < 32; q ++) //should ta en second-ish Initial_1 += (Sensor_1 - Amb_Sensor_1); inledande skillnaden Sensor_Values_Updated = 0; återställa void Init_ADC(void) void Init_Timer0(void) //PWM för sensorer 1 & 2 void Init_Timer1(void) void Init_Timer2(void) //PWM för sensorer 3 & 4
/****
ISR(TWI_vect) //to inkluderar senare när jag får detta räknat ut
{
Switch(TWSR)
{
fall TW_SR_SLA_ACK: //0x60 //Own adress Rx
Byte_Number == 1;
bryta;
Switch(Byte_Number)
{
fall 1:
Reg_Addr = TWDR;
Byte_Number ++;
bryta;
Reg_Val = TWDR;
Byte_Number = 0; återställa, om inte fler byte kommer
bryta;
Reg_Val = TWDR;
Byte_Number = 0; återställa, om inte fler byte kommer
bryta;
}
bryta;
IF(Byte_Number == 1)
{
Reg_Addr = TWDR;
Byte_Number ++;
}
annat if(Byte_Number == 2)
{
Reg_Val = TWDR;
Byte_Number = 0; återställa, om inte fler byte kommer
}
bryta;
} //end switch
} //end ISR
{
Ange enhetens adress i TWAR
TWAR = 10; kanske göra detta som ett argument till funktionen
TWCR & = ~ ((1 << TWSTA) | () 1 << TWSTO));
}
****/
{
char q = 0;
{
vänta på sensorn cykeln göras, då samlas sensorer värden
While(Sensor_Values_Updated == 0) {}
Initial_2 += (Sensor_2 - Amb_Sensor_2);
Initial_3 += (Sensor_3 - Amb_Sensor_3);
Initial_4 += (Sensor_4 - Amb_Sensor_4);
} //end för
Initial_1 = (Initial_1 >> 5) + buffert;
Initial_2 = (Initial_2 >> 5) + buffert;
Initial_3 = (Initial_3 >> 5) + buffert;
Initial_4 = (Initial_4 >> 5) + buffert;
}
{
ADMUX | = 1 << REFS0; AVCC med extern kondensator på AREF pin
ADMUX | = (1 <
}
{
Snabb PWM, icke-invertering, WGM02-WGM00 == 011, inget spill avbrott
TCCR0A | = ((1 << COM0A1) | () 1 << COM0B1) | (1 << WGM01) | (1 << WGM00));
TCCR0B | = (1 << CS00); Start klockan, ingen prescale
}
{
ingen PWM, aktivera overflow avbrott,
TOPPEN == 0xFFFF == 65536 cykler == ungefär 122 overflow avbrott per sekund
TCCR1B | = (1 << CS10);
TIMSK1 | = (1 << TOIE1);
}
{
Snabb PWM, icke-invertering, WGM22-WGM20 == 011, inget spill avbrott
TCCR2A | = ((1 << COM2A1) | () 1 << COM2B1) | (1 << WGM21) | (1 << WGM20));
TCCR2B | = (1 << CS20); Start klockan, ingen prescale
}
int ADC_read(void) / *** ADC kanal innan du anropar den här funktionen *** /
{
int ADC_value = 0;
int ADCsample;
röding i.
ADCSRA | = (1 < ADCSRA | = (1 < medan ((ADCSRA & ADSC)); //Wait för konvertering till komplett, och glömma det. återvända ADC_value; ADCSRA & = ~(1< Switch (kanal) fall 1: //select A2D kanal 1 fall 2: //select A2D kanal 2 fall 3: //select A2D kanal 3 fall 5: //select A2D kanal 5 void Delay(void)
//This görs mer än 64 gånger, längre och ADC1_value måste vara större än en unsigned int!
för (jag = 0; jag < 64; i ++)
{
ADCSRA | = (1 < medan ((ADCSRA & ADSC)); //wait för konvertering till slut
//change tillbaka till ADCL för 10 bitars precision, och ta bort vänster-SKIFT bitinställningen
ADCsample = ADCH;
ADCsample += (ADCH << 8); Vänster shift de översta två bitar 8 platserna
ADC_value += ADCsample; lägga till ADCsample till ADC_sensor
}
genomsnittsprov vid rätt skiftande 6 platser, samma som divideras med 64
ADC_value = (ADC_value >> 6);
void A2D_Channel_Select (unsigned char kanal)
{
{
fall 0: //select A2D kanal 0
ADMUX & = ~ ((1 << 3) | () 1 << 2) | (1 << 1) | (1 << 0));
bryta;
ADMUX & = ~ ((1 << 3) | () 1 << 2) | (1 << 1));
ADMUX | = (1 << 0);
bryta;
ADMUX & = ~ ((1 << 3) | () 1 << 2) | (1 << 0));
ADMUX | = (1 << 1);
bryta;
ADMUX & = ~ ((1 << 3) | () 1 << 2));
ADMUX | = ((1 << 1) | () 1 << 0));
bryta;
/ * jag använder inte dessa för detta projekt
fall 4: //select A2D channel 4
ADMUX & = ~ ((1 << 3) | () 1 << 1) | (1 << 0));
ADMUX | = (1 << 2);
bryta;
ADMUX & = ~ ((1 << 3) | () 1 << 1));
ADMUX | = ((1 << 2) | () 1 << 0));
bryta;
*/
} //end switch
}
{
_delay_us(100);
}