Paso 3: El código
/***
ASIGNACIONES DE PINES EN EL ATMEGA48
PC6 (PCINT14/RESET)
PC5 (ADC5/SCL/PCINT13) / / entrada de reloj I2C
PC4 (ADC4/SDA/PCINT12) / / entrada de datos I2C
Receptor de IR (ADC3/PCINT11) //Sensor 4 PC3
PC2 (ADC2/PCINT10) //Sensor 3 receptor de infrarrojos
Receptor de IR (ADC1/PCINT9) //Sensor 2 PC1
Receptor IR de pc0 //Sensor (ADC0/PCINT8) 1
PB7 (XTAL2/PCINT7/TOSC2) //IR 4 gatillo
PB6 (XTAL1/PCINT6/TOSC1) //IR 3 gatillo
PB5 (SCK/PCINT5) //IR 2 gatillo
PB4 (MISO/PCINT4) //IR 1 gatillo
PB3 (MOSI/OC2A/PCINT3) //PWM 3
PB2 (OC1B/SS/PCINT2)
PB1 (OC1A/PCINT1)
PB0 (PCINT0/CLKO/ICP1)
PD0 (PCINT16/RXD)
PD1 (PCINT17/TXD)
PD2 (INT0/PCINT18)
PD3 (PCINT19/OC2B/INT1) //PWM 4
PD4 (PCINT20/XCK/T0)
PD5 (PCINT21/OC0B/T1) //PWM 2
PD6 (OC0A/PCINT22/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 //PORTD 6 PWM1 PWM perno asignaciones
PWM2 #define //PORTD 5
PWM3 #define //PORTB 3
#define PWM4 //PORTD 3
#define F_CPU 8000000UL
#include
#include
#include
#include
/ *** Función declaraciones *** /
int ADC_read(void);
void A2D_Channel_Select (unsigned canal char);
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);Todos, menos uno, de estas variables se declara volátil porque básicamente todo el trabajo se realiza en
rutinas de servicio de interrupción
/ *** Declaración de Variable global *** / buffer de unsigned char = 8; int Main SEI(); PORTD | = (1 << PWM1); parpadea para indicar el fin de la calibración Init_Timer0(); Init_I2C_Slave_Rx(); while(1) }
volátil char Sensor_Values_Updated = 0;
volátil char Timer1_Overflow = 0;
canal de volátiles char sin signo = 0;
volátil int Amb_Sensor_1 = 0, Amb_Sensor_2 = 0, Amb_Sensor_3 = 0, Amb_Sensor_4 = 0;
int volátil Sensor_1 = 0, Sensor_2 = 0, Sensor_3 = 0, Sensor_4 = 0;
volátil int Initial_1 = 0, Initial_2 = 0, Initial_3 = 0, Initial_4 = 0;
volátil int New_PWM1 = 0, New_PWM2 = 0, New_PWM3 = 0, New_PWM4 = 0;
volátil int Old_PWM1 = 0, Old_PWM2 = 0, Old_PWM3 = 0, Old_PWM4 = 0;
{
DDRB = 0XFF;
Asegúrese de emisores de infrarrojos están apagados y 3 PWM
PORTB & = ~ ((1 << 7) | () 1 << 6) | (1 << 5) | (1 << 4) | (1 << 3));
DDR = 0 X 00; hacer entradas de Puerto C
DDRD = 0XFF;
PORTD = 0 X 00; Configure todas PORT D baja. asegura
Init_ADC();
Calibrate_Sensors();
_delay_ms(600);
PORTD & = ~ (1 << PWM1);
Init_Timer2();
{
¿algo?
//. . .
}
Con el reloj en aproximadamente de 8MHz y temporizador 1 contar hasta 65535. El temporizador se desbordará aproximadamente 122 veces por segundo. Este ISR va a disparar y la variable de desbordamiento del temporizador aumentará y entonces la función SWITCH/CASE elegirá el siguiente píxel a prueba
ISR(TIMER1_OVF_vect)
{
Timer1_Overflow ++; variable de desbordamiento de contador de tiempo de incremento
Switch(Timer1_Overflow)
{
caso 1:
A2D_Channel_Select(0); Seleccione canal ADC 0
Amb_Sensor_1 = ADC_read(); tomar la lectura del sensor de ambiente IR
IR_1_ON; encender LED IR 1, PORTB | = (1 << 4)
Delay(); retardo para el receptor de IR resolver
Sensor_1 = ADC_read(); tomar ADC activa lectura del receptor IR
IR_1_OFF; Apague el LED 1 de IR
New_PWM1 = (Sensor_1 - Amb_Sensor_1) - Initial_1; lecturas de la condición
Si (New_PWM1 < = 0) {New_PWM1 = 0;} evitar los números negativos
simple-filtro de paso bajo, (87.5% * edad) + (12.5% * nueva) . Solo toma el valor anterior y pesos más que el valor mayor. Tiene el mismo efecto de ralentizar el cambio, que es crucial en el suministro de líquidos cambios en brillo
New_PWM1 = ((7*Old_PWM1) >> 3) + (New_PWM1 >> 3);
Si (OCR0A > = 1) {DDRD | = (1 << PWM1);}
Else {DDRD & = ~ (1 << PWM1);} Apagar LED totalmente//artificially aumentar el valor del sensor de lectura, no es totalmente necesario, pero hace que el sensor se parecen más sensiblespor ser más brillante cuanto antes
New_PWM1 << = 2;
if(New_PWM1 > 255) {New_PWM1 = 255;}
OCR0A = New_PWM1;
New_PWM1 >> = 2;
El debajo de código que es enteramente comentada es un algoritmo de brillo diferente. Es un algoritmo de activación que se decoloran los LED cuando algo viene dentro de un umbral. Y los LEDs se desvanecen lentamente cuando el objeto está fuera de la distancia del umbral. Esto es útil porque la operación podría ser más fiable y descolorarse hacia fuera tiempo puede ajustarse para ser muy largo o tiempo que desee. No lo he probado este código así que no estoy seguro si funcionará 100%
/ *** //Trigger secuencia if(OCR0A < 255)
if(New_PWM1 > Initial_1)
{
DDRD | = (1 << PWM1);
{
OCR0A += (255 - OCR0A) >> 2;
OCR0A ++;
}
Si (New_PWM1 < (Initial_1 + 8))
{
Initial_1 = ((7*Initial_1) >> 3) + (New_PWM1 >> 3);
}
}
otro if(New_PWM1 < Initial_1)
{
if(OCR0A > 0)
{
OCR0A-= (OCR0A >> 4) + 1;
OCR0A--;
}
else if (OCR0A < = 0)
{
DDRD & = ~ (1 << PWM1);
}
}
*****/
Old_PWM1 = New_PWM1;
rotura;
caso 2:
A2D_Channel_Select(1); Seleccione canal ADC 1
Amb_Sensor_2 = ADC_read();
IR_2_ON; encender LED IR 2, PORTB | = (1 << 5)
Delay(); retardo para el receptor de IR resolver
Sensor_2 = ADC_read(); tomar lectura de ADC
IR_2_OFF; apaga LED 2 de IR
New_PWM2 = (Sensor_2 - Amb_Sensor_2) - Initial_2;
if(New_PWM2 < 0) {New_PWM2 = 0;}
New_PWM2 = ((7*Old_PWM2) >> 3) + (New_PWM2 >> 3);
Si (OCR0B > = 1) {DDRD | = (1 << PWM2);}
Else {DDRD & = ~ (1 << PWM2);}
New_PWM2 << = 2;
if(New_PWM2 > 255) {New_PWM2 = 255;}
OCR0B = New_PWM2;
New_PWM2 >> = 2;
/*
if(New_PWM2 > Initial_2)
{
DDRD | = (1 << PWM2);
if(OCR0B < 255)
{
OCR0B += (255 - OCR0B) >> 2;
OCR0B ++;
}
Si (New_PWM2 < (Initial_2 + 8))
{
Initial_2 = ((7*Initial_2) >> 3) + (New_PWM2 >> 3);
}
}
otro if(New_PWM2 < Initial_2)
{
if(OCR0B > 0)
{
OCR0B-= (OCR0B >> 4) + 1;
OCR0B--;
}
else if (OCR0B < = 0)
{
DDRD & = ~ (1 << PWM2);
}
}
*/
Old_PWM2 = New_PWM2;
rotura;
caso 3:
A2D_Channel_Select(2); seleccionar el canal ADC 2
Amb_Sensor_3 = ADC_read();
IR_3_ON; encender LED IR 3, PORTB | = (1 << 6)
Delay(); retardo para el receptor de IR resolver
Sensor_3 = ADC_read(); tomar lectura de ADC
IR_3_OFF; Apagar IR 3 LED
New_PWM3 = (Sensor_3 - Amb_Sensor_3) - Initial_3;
if(New_PWM3 < 0) {New_PWM3 = 0;}
New_PWM3 = ((7*Old_PWM3) >> 3) + (New_PWM3 >> 3);
Si (OCR2A > = 1) {DDRB | = (1 << PWM3);}
Else {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 ++;
}
Si (New_PWM3 < (Initial_3 + 8))
{
Initial_3 = ((7*Initial_3) >> 3) + (New_PWM3 >> 3);
}
}
otro if(New_PWM3 < Initial_3)
{
if(OCR2A > 0)
{
OCR2A-= (OCR2A >> 4) + 1;
OCR2A--;
}
else if (OCR2A < = 0)
{
DDRB & = ~ (1 << PWM3);
}
}
*/
Old_PWM3 = New_PWM3;
rotura;
caso 4:
A2D_Channel_Select(3); Seleccione canal ADC 3
Amb_Sensor_4 = ADC_read();
IR_4_ON; encender LED IR 4, PORTB | = (1 << 7)
Delay(); retardo para el receptor de IR resolver
Sensor_4 = ADC_read(); tomar lectura de ADC
IR_4_OFF; Apagar 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);
Si (OCR2B > = 1) {DDRD | = (1 << PWM4);}
Else {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 ++;
}
Si (New_PWM4 < (Initial_4 + 8))
{
Initial_4 = ((7*Initial_4) >> 3) + (New_PWM4 >> 3);
}
}
otro if(New_PWM1 < Initial_4)
{
if(OCR2B > 0)
{
OCR2B-= (OCR2B >> 4) + 1;
OCR2B--;
}
else if (OCR2B < = 0)
{
DDRD & = ~ (1 << PWM4);
}
}
*/
Old_PWM4 = New_PWM4;
Timer1_Overflow = 0; RESET
Sensor_Values_Updated = 1; listos nuevos valores
rotura;
} //end interruptor
} //end ISR
Esto es algo que voy a probar y averiguar después. Es código elemental no probado que podría me permite utilizar la interfaz de dos hilos (I2C) así que varios controladores y comunicarse entre sí o tener un maestro y un montón de esclavos.
/****
ISR(TWI_vect) //to incluyen más adelante cuando me sale esto averiguado
{
Switch(TWSR)
{
caso TW_SR_SLA_ACK: //0x60 //Own dirección Rx
Byte_Number == 1;
rotura;
caso TW_SR_DATA_ACK: / / 0 x 80, datos en TWDR
Switch(Byte_Number)
{
caso 1:
Reg_Addr = TWDR;
Byte_Number ++;
rotura;
caso 2:
Reg_Val = TWDR;
Byte_Number = 0; restablecer, a menos que vienen bytes más
rotura;
caso Max_Bytes_Expected:
Reg_Val = TWDR;
Byte_Number = 0; restablecer, a menos que vienen bytes más
rotura;
}
rotura;
caso TW_SR_GCALL_DATA_ACK: / / 0x90
if(Byte_Number == 1)
{
Reg_Addr = TWDR;
Byte_Number ++;
}
otro if(Byte_Number == 2)
{
Reg_Val = TWDR;
Byte_Number = 0; restablecer, a menos que vienen bytes más
}
rotura;
} //end interruptor
} //end ISR
void Init_I2C_Slave_Rx(void)
{
Establecer la dirección del dispositivo en TWAR
TWAR = 10; tal vez hacer esto como argumento a esta función
TWCR | = ((1 << TWEA) | () 1 << TWEN));
TWCR & = ~ ((1 << TWSTA) | () 1 << TWSTO));
}
****/
void Calibrate_Sensors(void) //establish sensor ambiental inicial los valores
{
char q = 0;
Init_Timer1();
para (q = 0; q < 32; q ++) //should tomar un second-ish
{
ciclo de Sensor de hacerse esperar, entonces se reúnen valores de sensores
while(Sensor_Values_Updated == 0) {}
Initial_1 += (Sensor_1 - Amb_Sensor_1); diferencia inicial
Initial_2 += (Sensor_2 - Amb_Sensor_2);
Initial_3 += (Sensor_3 - Amb_Sensor_3);
Initial_4 += (Sensor_4 - Amb_Sensor_4);
Sensor_Values_Updated = 0; RESET
} //end para
//Condition valores de los sensores de ambiente inicial, además de un buffer void Init_ADC(void) void Init_Timer0(void) //PWM para sensores 1 y 2 int ADC_read(void) / *** Seleccione canal ADC antes de llamar a esta función *** /
Initial_1 = (Initial_1 >> 5) + buffer;
Initial_2 = (Initial_2 >> 5) + buffer;
Initial_3 = (Initial_3 >> 5) + buffer;
Initial_4 = (Initial_4 >> 5) + buffer;
}
{
ADMUX | = 1 << REFS0; AVCC con condensador externo al pin AREF
ADMUX | = (1 <
}
{
Rápido PWM, no invertir, WGM02-WGM00 == 011, ninguna interrupción desbordamiento
TCCR0A | = ((1 << COM0A1) | () 1 << COM0B1) | (1 << WGM01) | (1 << WGM00));
TCCR0B | = (1 << CS00); iniciar el reloj, sin prescaler
}
void Init_Timer1(void)
{
no PWM, habilitar interrupción de desbordamiento,
TOP == 0xFFFF == 65536 ciclos == desbordamiento aproximadamente 122 interrupciones/seg.
TCCR1B | = (1 << CS10);
TIMSK1 | = (1 << TOIE1);
}
void Init_Timer2(void) //PWM para los sensores 3 y 4
{
Rápido PWM, no invertir, WGM22-WGM20 == 011, ninguna interrupción desbordamiento
TCCR2A | = ((1 << COM2A1) | () 1 << COM2B1) | (1 << WGM21) | (1 << WGM20));
TCCR2B | = (1 << CS20); iniciar el reloj, sin prescaler
}
{
int ADC_value = 0;
int ADCsample;
char i;
ADCSRA | = (1 < ADCSRA | = (1 < mientras que ((ADCSRA y ADSC)); Espere para que la conversión completa y olvidarse de ella
//this se hace no más de 64 veces más de largo y ADC1_value tendrán que ser más grande que un int sin signo!!!
para (i = 0; i < 64; i ++)
{
ADCSRA | = (1 < mientras que ((ADCSRA y ADSC)); esperar para que la conversión hasta el final
//Change de ADCL de precisión de 10 bits y quitar el ajuste de la desviación a la izquierda poco
ADCsample = ADCH;
ADCsample += (ADCH << 8); Dejó pasar los dos bits superiores 8 lugares
ADC_value += ADCsample; Añadir a ADCsample a ADC_sensor
}
media de la muestra por derecho de cambio de 6 lugares, igual que dividir por 64
ADC_value = (ADC_value >> 6);
volver ADC_value;
ADCSRA & = ~(1<
void A2D_Channel_Select (canal de char sin signo)
{
interruptor (canal)
{
caso 0: //select A2D canal 0
ADMUX & = ~ ((1 << 3) | () 1 << 2) | (1 << 1) | (1 << 0));
rotura;
caso 1: //select A2D canal 1
ADMUX & = ~ ((1 << 3) | () 1 << 2) | (1 << 1));
ADMUX | = (1 << 0);
rotura;
caso 2: canal de //select A2D 2
ADMUX & = ~ ((1 << 3) | () 1 << 2) | (1 << 0));
ADMUX | = (1 << 1);
rotura;
caso 3: //select A2D canal 3
ADMUX & = ~ ((1 << 3) | () 1 << 2));
ADMUX | = ((1 << 1) | () 1 << 0));
rotura;
/ * No estoy utilizando estos para este proyecto
caso 4: canal de //select A2D 4
ADMUX & = ~ ((1 << 3) | () 1 << 1) | (1 << 0));
ADMUX | = (1 << 2);
rotura;
caso 5: //select A2D canal 5
ADMUX & = ~ ((1 << 3) | () 1 << 1));
ADMUX | = ((1 << 2) | () 1 << 0));
rotura;
*/
} //end interruptor
}
void Delay(void)
{
_delay_us(100);
}