/***************************************************** This program was produced by the CodeWizardAVR V1.24.7e Standard Automatic Program Generator © Copyright 1998-2005 Pavel Haiduc, HP InfoTech s.r.l. http://www.hpinfotech.com e-mail:office@hpinfotech.com Project : 3D LANC Master Version : 0.91 Date : 1.1.2006 Author : Damir Vrancic Company : J. Stefan Institute Comments: Chip type : ATmega8 Program type : Application Clock frequency : 16,000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 256 Copyright (C) Damir Vrancic This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *****************************************************/ #include #include #include #include #include #include #define ADC_VREF_TYPE 0x20 // External voltage reference, Right justified (8-bit resolution) #pragma regalloc- register unsigned char LANC_Left_Byte @4; // Read byte from left LANC source or remote (first two bytes) register unsigned char LANC_Left_Byte_Valid @5; // Write byte to left LANC source register unsigned char LancL_State @6; // State (byte counter) of the left LANC source register unsigned char LancR_State @7; // State (byte counter) of the right LANC source register unsigned char BitCounterL @8; // Bit counter within received (transmitted) left byte (2*bits) register unsigned char BitCounterR @9; // Bit counter within received (transmitted) right byte (2*bits) register unsigned char LANC_Right_Byte @12; // Read the 3rd byte from right LANC source register unsigned char LANC_Right_Byte_Valid @10; // Write byte to right LANC source register unsigned char LANC_Remote_Out @11; // Byte sent to LANC remote #pragma regalloc+ flash unsigned int Soft_Version=91; // Software version flash unsigned char RS232_TimeOut_Max=3; // Max time between receiving complete RS232 command from PC (between 2..3*32ms) flash unsigned char Menu_Shift_Time=6; // Time required that page key becomes shift key flash char Message1[]="S[äs] "; // R[us] flash char Message2[]="S[/s] "; // L[us] eeprom unsigned int E2_Initialisation=0xFF; // E2PROM is programmed the first time (copy some initial values to E2PROM) eeprom unsigned int E2_Table[96]; // Various data stored (E2_Cam_Addr/Page/Data, Power-on times, User-defined commands, etc.) eeprom unsigned char LANC_Command_Wide=0x37; // LANC code for slow wide speed for camcorders (first byte is fixed to 0x28) eeprom unsigned char LANC_Command_Tele=0x35; // LANC code for slow tele speed for camcorders (first byte is fixed to 0x28) unsigned int CamL_Timer; // Current value of timer1 for left LANC source unsigned int CamR_Timer; // Current value of timer1 for right LANC source unsigned char DataBytes[9]; // Data received/transmitted from/to LANC unsigned char LANC_Byte0_L; // Valid byte 0 to left LANC unsigned char LANC_Byte1_L; // Valid byte 1 to left LANC unsigned char LANC_Byte2_L; // Valid byte 2 to left LANC unsigned char LANC_Byte0_R; // Valid byte 0 to right LANC unsigned char LANC_Byte1_R; // Valid byte 1 to right LANC unsigned char LANC_Byte2_R; // Valid byte 2 to right LANC unsigned int CaptureL_Time; // Time capture at start of first left LANC signal unsigned int CaptureR_Time; // Time capture at start of first right LANC signal unsigned int CaptureL_Time_Old; // Time capture at start of previous first left LANC signal unsigned int CaptureR_Time_Old; // Time capture at start of previous first right LANC signal unsigned int CaptureL_Time_Mean; // Mean value between actual and previous value of first left LANC signal unsigned int CaptureR_Time_Mean; // Mean value between actual and previous value of first right LANC signal unsigned int CaptureL_Time_Mean_Old; // Old mean value between actual and previous value of first left LANC signal unsigned int CaptureR_Time_Mean_Old; // Old mean value between actual and previous value of first right LANC signal unsigned int PeriodL; // Period of left LANC signal signed int LANC_Sync; // Synchronization between two lanc signals in us unsigned char Time_PowerOn; // Timer 1 (number of overflows of Timer1) - used for internal timings (LCD display) unsigned char Time_HMI; // Timer 2 (number of overflows of Timer1) - used for internal timings (keyboard) unsigned char Time_Startup; // Timer from startup unsigned int TempTimer; unsigned char Counter0Byte3; // Counter of empty 3rd bytes (if empty for more than 21 bytes -> photo mode) unsigned char CounterCatch3; // Counter of 3rd byte codes equal to CatchByte3 (in photo mode) unsigned char CatchByte3=0x47; // Codes are 0x47 or 0x57 (in photo mode) unsigned char CounterCatch3R; // Counter of 3rd byte codes equal to CatchByte3R (in photo mode) of the right LANC unsigned char CatchByte3R=0x47; // Codes are 0x47 or 0x57 (in photo mode) of the right LANC unsigned int DeltaL, DeltaR, DeltaLR; signed int Integral_Term; unsigned char Initial_Integral; // Initial value of data at required page/address for changing oscillator frequency unsigned char Controller_Output; // Controller output signal unsigned char RS232_Counter; // Counter of received rs232 bytes (command and special instructions) unsigned char Command_Repetition_Counter; // Number of repeated instructions sent to LANC - working counter unsigned char RS232_XOR; // Checksum of received command bytes unsigned char RS232_Bytes[9]; // Received bytes from RS232 unsigned char RS232_Command_Type; // 0=ordinary command, 1=goto page/address, 2=get page/addr DATA unsigned char RS232_TimeOut; // Elapsed time from the first received RS232 byte from PC unsigned char RS232_High; // Temporary storage for higher byte unsigned char Command0; // First command unsigned char Command1; // Second command unsigned char Command_Status; // Status byte (DataBytes[6]) after executing command unsigned char Command_Page; // Page byte (DataBytes[5]) after executing command unsigned char Command_Addr; // Address byte (DataBytes[7]) after executing command unsigned char Command_Data; // Data byte (DataBytes[8]) after executing command unsigned char RS232_Final_Page; // Goal page received by RS232 unsigned char RS232_Final_Addr; // Goal address received by RS232 unsigned char RS232_PA_Data; // Goal data in particular page/address received by RS232 unsigned char Final_Page; // Goal page unsigned char Final_Addr; // Goal address unsigned char Command_Ammount; // The closest distance (ammount of) between source and destination page/address unsigned char Keyboard_Command; // Stores keyboard status - temporary (codes of pressed key(s)) unsigned char Keyboard_Final; // Stores final keyboard status (codes of pressed key(s)) unsigned char Keyboard_Old; // Stores old keyboard status (codes of pressed key(s)) unsigned char Page_Address_State; // Current state of function Goto_Page_Addr unsigned char Closed_Loop_State; // Current state of function Active_Control unsigned char Command_Priority; // Priority of current command; 0-no command, 1-keyboard, 2-remote, 3-rs232, 4-e.g. closed-loop unsigned char Menu_Page; // Current menu page (keyboard functions) unsigned char Closed_Loop_Toggle; // Indicates whether the function switches on or off the camcorder/camera unsigned char Menu_Shift_Counter; // The variable measures the time of pressed MENU key in order to become SHIFT key :-) unsigned char Display_Toggle; // Toggles between displaying sync in us or recommanded shutter speed 1/s // Note that recommended shutter speed is 10 times slower than sync speed!!! unsigned char E2_Cam_Page; // Initial page for adjusting oscillator frequency (depends on camcorder's model) unsigned char E2_Cam_Addr; // Initial address for adjusting oscillator frequency (depends on camcorder's model) unsigned char E2_Cam_Data; // Initial data at page/addr for adjusting oscillator frequency unsigned int Period_PowOnL1=3392; // Lower part of power-on impulse length (100ms) for camcorder unsigned int Period_PowOnH1=3; // Higher part of power-on impulse length (Length=65536*Period_PowOnH1 + Period_PowOnL1) for camcorder unsigned int Period_PowOnO1; // Lower part of power-on impulse length (100ms) for camcorder unsigned int Period_PowOnL2=3392; // Lower part of power-on impulse length (100ms) for photo cam unsigned int Period_PowOnH2=3; // Higher part of power-on impulse length (Length=65536*Period_PowOnH1 + Period_PowOnL1) for photo cam unsigned int Period_PowOnO2; // Time offset of power-on impulse (positive: right lanc power-on impulse starts later) for photo cam unsigned int User_Command1_Cam; // First user-defined command (Command0/Command1) for camcorder unsigned int User_Command2_Cam; // Second user-defined command (Command0/Command1) for camcorder unsigned int User_Command3_Cam; // Third user-defined command (Command0/Command1) for camcorder unsigned int User_Command4_Cam; // Fourth user-defined command (Command0/Command1) for camcorder unsigned int User_Command1_Pho=0x0E00; // First user-defined command (Command0/Command1) for photo camera unsigned int User_Command2_Pho=0x0E00; // Second user-defined command (Command0/Command1) for photo camera unsigned int User_Command3_Pho=0x0E00; // Third user-defined command (Command0/Command1) for photo camera unsigned int User_Command4_Pho=0x0E00; // Fourth user-defined command (Command0/Command1) for photo camera signed int Proportional_Factor=8; // Proportional band factor for the closed-loop control signed int Integral_Factor=512; // Integral time factor for the closed-loop control unsigned char Power_Off_Delay=24; // Time delay between power-off and power-on (24*32ms) unsigned int Sum_Voltage1; // Sum of measured voltage1 unsigned char Counter_Voltage1; // Number of summed voltages (Voltage1) unsigned char Voltage1; // Filtered voltage1 unsigned char Blinking_Flag; // Used for blinking of display //unsigned char Open_Loop_Flag; // when set, the closed-loop control goes into open-loop one (camcorder modifications disabled) unsigned char Closed_Loop_Flag; // when 1, closed-loop control is enabled, if 2 open-loop is initiated bit Valid_CaptureL; // Becomes true if all 8 bytes from the left LANC are received on time bit Valid_CaptureR; // Becomes true if all 8 bytes from the right LANC are received on time bit Counter_OverflowL; // Becomes true if counter overflows from the left LANC bit Counter_OverflowR; // Becomes true if counter overflows from the right LANC bit FirstFlag; // If 1, first start bit of the first left LANC byte is received (calculation of synchronisation) bit LastFlag; // If 1, last bit of the last left LANC byte is received bit RS232_New; // will be set to 1 when new character will be received bit Command_Execution_Flag; // when set, the LANC command is being executed //bit Closed_Loop_Flag; // when set, closed-loop control is enabled bit Photo_Flag; // 0=camcorder, 1=photo camera bit Page_Address_Found; // Indicator if page/address is found after executing function Goto_Page_Addr bit Data_Modified; // Indicator if data is modified as desired (value becomes 1) bit Shut_Off_Toggle; // Indicates whether the function switches on or off the camcorder/camera bit Pre_Trigger_Toggle; // Indicates if pre-trigger is selected by the keyboard (signal remains after de-pressing the key) bit Keyboard_Processed_Flag; // Indicates whether keyboard is active and processed bit Menu_Shift_Flag; // Indicates if SHIFT is valid #define LANC_Rem_Read PINC.4 // LANC frame signal for lanc remote controller (read) #define LANC_Rem_DirR DDRC.4 // LANC frame output direction (reading) #define LANC_Rem_Write PORTB.1 // LANC frame signal for lanc remote controller (write) #define LANC_Rem_Dir DDRB.1 // LANC frame output direction (writing) #define LANC_L_Read PIND.2 // LANC device read signal (Left) #define LANC_R_Read PIND.3 // LANC device read signal (Right) #define LANC_L_Direction DDRD.2 // LANC device direction signal (Left) = reading #define LANC_R_Direction DDRD.3 // LANC device direction signal (Right) = reading #define LANC_L_Out PORTB.2 // LANC left out signal #define LANC_L_OutD DDRB.2 // LANC left out signal direction (writing) #define LANC_R_Out PORTC.3 // LANC right out signal #define LANC_R_OutD DDRC.3 // LANC right out signal direction (writing) #define switch_1_Read PIND.4 // First switch (read) (default = up or Tele) #define switch_1_Write PORTD.4 // First switch (write) (default = up or Tele) #define switch_1_Direction DDRD.4 // First switch (direction) (default = up or Tele) #define switch_2_Read PIND.5 // Second switch (read) (default = up or Tele) #define switch_2_Write PORTD.5 // Second switch (write) (default = up or Tele) #define switch_2_Direction DDRD.5 // Second switch (direction) (default = up or Tele) #define switch_3_Read PIND.6 // Third switch (read) (default = up or Tele) #define switch_3_Write PORTD.6 // Third switch (write) (default = up or Tele) #define switch_3_Direction DDRD.6 // Third switch (direction) (default = up or Tele) #define switch_4_Read PIND.7 // Fourth switch (read) (default = up or Tele) #define switch_4_Write PORTD.7 // Fourth switch (write) (default = up or Tele) #define switch_4_Direction DDRD.7 // Fourth switch (direction) (default = up or Tele) #asm .equ __PORTB_asm=0x18 .equ __PORTC_asm=0x15 .equ __PORTD_asm=0x12 .equ __DDRB_asm=0x17 .equ __DDRC_asm=0x14 .equ __DDRD_asm=0x11 .equ __PINB_asm=0x16 .equ __PINC_asm=0x13 .equ __PIND_asm=0x10 #endasm void delay_time (unsigned char Delay1) { unsigned char i; unsigned int j; for (i=Delay1;i>0;i--) { for (j=0;j<65535;j++) { }; }; } unsigned char read_adc(unsigned char adc_input) { ADMUX=adc_input|ADC_VREF_TYPE; ADCSRA|=0x40; // Start the AD conversion while ((ADCSRA & 0x10)==0); // Wait for the AD conversion to complete ADCSRA|=0x10; return ADCH; } void write_LCD_int (unsigned int IntNumber, unsigned char SignChar) { char chr01[6]; itoa(IntNumber,chr01); if (SignChar == 1) { lcd_gotoxy(6,1); lcd_putchar(0x2D); // minus sign! } else { lcd_gotoxy(7,1); } lcd_putchar(chr01[0]); if (IntNumber >= 10) { lcd_putchar(chr01[1]); } if (IntNumber >= 100) { lcd_putchar(chr01[2]); } if (IntNumber >= 1000) { lcd_putchar(chr01[3]); } if (IntNumber >= 10000) { lcd_putchar(chr01[4]); } } void Battery_Low (void) { lcd_gotoxy(0,0); lcd_putsf(" Battery low! "); #asm ("cli") // Disable all interrupts sleep_enable(); // Go into power-down mode powerdown(); } void Power_On_Procedure (void) { unsigned int Pulse_TimeL, Pulse_OffsetU; signed int Pulse_Offset; unsigned char Pulse_TimeH; Shut_Off_Toggle = 0; // Reset shut_off toggle GICR = (GICR & 0x3F); // Switch off external interrupts 0 and 1 TIMSK = (TIMSK & 0x7E); // Disable timer 0 overflow and timer 2 output compare interrupt TCCR2=0x00; // Switch off Timer 2 counting TCCR0=0x00; // Switch off Timer 0 counting if (Photo_Flag == 0) // Camcorder is present { Pulse_TimeL = Period_PowOnL1; // Copy values from E2PROM for camcorder Pulse_TimeH = Period_PowOnH1; Pulse_Offset = Period_PowOnO1; } else { Pulse_TimeL = Period_PowOnL2; // Copy values from E2PROM for photo camera Pulse_TimeH = Period_PowOnH2; Pulse_Offset = Period_PowOnO2; } if (Pulse_Offset >= 0) // Calculate absolute value of time offset { Pulse_OffsetU = Pulse_Offset; } else { Pulse_OffsetU = -Pulse_Offset; } TIMSK = (TIMSK & 0xFB); // Disable Timer 1 overflow interrupt TCNT1 = 0; // Reset counter 1 TIFR = 0x04; // Clear Timer 1 overflow flag TIMSK = (TIMSK | 0x04); // Enable Timer 1 overflow interrupt if (Pulse_Offset >= 0) { LANC_L_Out = 1; // Generate power-on pulse while (TCNT1 < Pulse_OffsetU) // Wait until offset time passed {} LANC_R_Out = 1; // Generate power-on pulse } else { LANC_R_Out = 1; // Generate power-on pulse while (TCNT1 < Pulse_OffsetU) // Wait until offset time passed {} LANC_L_Out = 1; // Generate power-on pulse } Time_PowerOn = 0; // Reset high value of counter 1 while (Time_PowerOn < Pulse_TimeH) // Wait until high value of pulse time passes {} while (TCNT1 < Pulse_TimeL) // Wait until complete pulse time passes {} TIMSK = (TIMSK & 0xFB); // Disable Timer 1 overflow interrupt TCNT1 = 0; // Reset counter 1 TIFR = 0x04; // Clear Timer 1 overflow flag TIMSK = (TIMSK | 0x04); // Enable Timer 1 overflow interrupt if (Pulse_Offset >= 0) { LANC_L_Out = 0; // Stop generating power-on pulse while (TCNT1 < Pulse_OffsetU) // Wait until offset time passed {} LANC_R_Out = 0; // Stop generating power-on pulse } else { LANC_R_Out = 0; // Stop generating power-on pulse while (TCNT1 < Pulse_OffsetU) // Wait until offset time passed {} LANC_L_Out = 0; // Stop generating power-on pulse } LancL_State = 0; // Reset states LancR_State = 0; GIFR = 0xC0; // clear external interrupt flags 0 and 1 GICR = (GICR | 0xC0); // Switch on external interrupts 0 and 1 Time_PowerOn = 0; // Reset high value of counter 1 Integral_Term = 0; // reset integral term } void E2PROM_Init (void) { #asm ("cli") // Disable interrupts during copying data to variables E2_Cam_Page = E2_Table[0]; // Copy values from E2PROM to variables; E2_Cam_Addr = E2_Table[1]; E2_Cam_Data = E2_Table[2]; Period_PowOnL1 = E2_Table[3]; Period_PowOnH1 = E2_Table[4]; Period_PowOnO1 = E2_Table[5]; Period_PowOnL2 = E2_Table[6]; Period_PowOnH2 = E2_Table[7]; Period_PowOnO2 = E2_Table[8]; User_Command1_Cam = E2_Table[9]; User_Command2_Cam = E2_Table[10]; User_Command3_Cam = E2_Table[11]; User_Command4_Cam = E2_Table[12]; User_Command1_Pho = E2_Table[13]; User_Command2_Pho = E2_Table[14]; User_Command3_Pho = E2_Table[15]; User_Command4_Pho = E2_Table[16]; Proportional_Factor = E2_Table[17]; Integral_Factor = E2_Table[18]; Power_Off_Delay = E2_Table[19]; #asm ("sei") // Enable interrupts } unsigned char calc_repetitions (unsigned char Source1, unsigned char Destination1, unsigned char Base1) { unsigned char Delta1, Delta2, Direct1; Delta1 = Destination1 - Source1; Delta2 = Source1 - Destination1; if (Base1 == 1) // Only one nibble (calculation for Page) { Delta1 = (Delta1 & 0x0F); Delta2 = (Delta2 & 0x0F); } if (Delta1 <= Delta2) { Direct1 = 0; Command_Ammount = Delta1; } else { Direct1 = 1; Command_Ammount = Delta2; } return (Direct1); } void Goto_Page_Addr (unsigned char Page_Desired, unsigned char Addr_Desired) // The procedure finds desired page/address. It works as a state machine. When desired page/address is found, the global variable // Page_Address_Found becomes 1 (TRUE). In between it sends required commands to the camcorder. // Before first execution set Page_Address_State=0. { Page_Address_Found = 0; // Page and address are still not found if (Page_Address_State == 0) // "State machine 0 - initialisation, 1 - find page, 2 - find address" { Command_Execution_Flag = 1; Command0 = 0xFF; // Page/addr null command - required in order to get current page/address Command1 = 0x00; Command_Repetition_Counter = 10; Page_Address_State++; } else if (Page_Address_State == 1) // find page { if (Command_Execution_Flag == 0) // the last command finished { if (calc_repetitions(Command_Page,Page_Desired,1) == 0) // Calculate distance from desired page { Command1 = 0x67; // Increase page } else { Command1 = 0x65; // Decrease page } if (Command_Ammount == 0) { Page_Address_State++; // Page is found, go search for the address } else { Command_Execution_Flag = 1; Command0 = 0xFF; // Page/addr commands Command_Repetition_Counter = 10; } } } else if (Page_Address_State == 2) // find address { if (Command_Execution_Flag == 0) // the last command finished { if (Command_Page == Page_Desired) // Check that page is the right one { if (calc_repetitions((Command_Addr),Addr_Desired,0) == 0) // Calculate distance from desired address { Command1 = 0x38; // Increase address } else { Command1 = 0x36; // Decrease address } if (Command_Ammount == 0) { Command1 = 0x00; // Dummy - stop sending commands Page_Address_Found = 1; // Desired page and address are found } else { Command_Execution_Flag = 1; Command0 = 0xFF; // Page/addr commands Command_Repetition_Counter = 10; } } else { Page_Address_State = 1; // Page is not the right one, go back } } } } unsigned char get_rs232 (void) { unsigned char TmpChar; RS232_New = 0; TmpChar = 0; if ((UCSRA & (1<<7)) != 0) { RS232_New = 1; TmpChar = UDR; } return (TmpChar); } void Process_RS232_Command (void) { unsigned char TmpChar, TmpChar1, First_RS232_Byte; unsigned int TmpInt, TmpInt1; First_RS232_Byte = RS232_Bytes[1]; if (RS232_Counter == 1) // Answer the value to PC { TmpChar = 0; if (First_RS232_Byte < 96) // Read values in E2prom memory { TmpInt = E2_Table[First_RS232_Byte]; TmpChar = TmpInt; RS232_High = (TmpInt>>8); } else if (First_RS232_Byte < 100) // Read captured bytes in tha last LANC frame { TmpChar1 = ((First_RS232_Byte-95) << 1); TmpChar = DataBytes[TmpChar1-1]; RS232_High = DataBytes[TmpChar1]; } else if (First_RS232_Byte == 100) // Read Photo flag, command execution flag and closed-loop flag { TmpChar = (Photo_Flag + 2*Closed_Loop_Flag + 8*Command_Execution_Flag); RS232_High = Command_Repetition_Counter; } else if (First_RS232_Byte == 101) // Read higher byte of requested result { TmpChar = RS232_High; } else if (First_RS232_Byte == 102) // Read LANC commands for tele/wide (first byte is fixed to 0x28!!!) { TmpChar = LANC_Command_Wide; RS232_High = LANC_Command_Tele; } else if (First_RS232_Byte == 103) // Read sync value in us { TmpInt = LANC_Sync; TmpChar = TmpInt; RS232_High = (TmpInt>>8); } else if (First_RS232_Byte == 104) // Read LANC period in us { TmpInt = PeriodL; TmpChar = TmpInt; RS232_High = (TmpInt>>8); } else if (First_RS232_Byte == 105) // Read current Page/Address (if instruction 0xFFxx has been executed) { TmpChar = Command_Page; RS232_High = Command_Addr; } else if (First_RS232_Byte == 106) // Read current Status/Data (if instruction 0xFFxx has been executed) { TmpChar = Command_Status; RS232_High = Command_Data; } else if (First_RS232_Byte == 107) // Read software version { TmpChar = Soft_Version; } } else // Change some values { if (RS232_XOR == 0) // if XOR is OK { TmpChar = 0x01; if (First_RS232_Byte < 224) // Modify values in E2 prom memory { TmpInt = RS232_Bytes[2]; TmpInt = (TmpInt << 8); TmpInt1 = RS232_Bytes[3]; TmpChar1 = (First_RS232_Byte & 0x7F); // TmpChar1 = First_RS232_Byte - 128 E2_Table[TmpChar1] = TmpInt + TmpInt1; } else if (First_RS232_Byte < 226) // Send command to both LANCs (once or repeat 10 times) { if (First_RS232_Byte == 224) { Command_Repetition_Counter = 1; // number of repeated instructions } else { Command_Repetition_Counter = 10; // number of repeated instructions } Command_Execution_Flag = 1; Command0 = RS232_Bytes[2]; // Send command to camcorder/still camera Command1 = RS232_Bytes[3]; } else if (First_RS232_Byte == 226) // Modify wide/tele commands (note that the first byte is fixed t0 0x28!!!) { LANC_Command_Tele = RS232_Bytes[2]; LANC_Command_Wide = RS232_Bytes[3]; } else if (First_RS232_Byte == 227) // Modify the closed-loop flag (switch on/off closed-loop control) { Closed_Loop_Flag = RS232_Bytes[2]; } else if (First_RS232_Byte == 228) // Generate power-on { Power_On_Procedure(); // Generate power-on pulses on both channels } else if (First_RS232_Byte == 229) // Copy values from E2prom to working variables { E2PROM_Init(); } } else { TmpChar = 0x00; } } putchar(TmpChar); } void Change_Data (unsigned char Page_Desired, unsigned char Addr_Desired, unsigned char Data_Desired) // The procedure modifies data at desired page/address. When data is modified as desired, the global variable // Data_Modified becomes 1 (TRUE). In between it sends required commands to the camcorder in order to change data. { Data_Modified = 0; if (Command_Execution_Flag == 0) // the last command executed { if ((Command_Page == Page_Desired) && (Command_Addr == Addr_Desired)) // Check that page and addr are the right one { if (Command_Data == Data_Desired) // Data at particulat page/address is as desired { Data_Modified = 1; } else { if (Command_Data < Data_Desired) // Calculate distance from desired data { Command1 = 0x34; // Increase data } else { Command1 = 0x30; // Decrease data } Command_Execution_Flag = 1; Command0 = 0xFF; // Page/addr commands Command_Repetition_Counter = 10; } } } } void Active_Control (unsigned char Page_Desired, unsigned char Addr_Desired) // Procedure first enables change of camcorder's data by modifying data at page/address 0x00/0x01 to 0x01, then it goes to desired // page/address defined in e2prom and modifies the data according to controller output // Initial value: Closed_Loop_State=0; { // if (Closed_Loop_Flag == 1) // If the closed-loop control is enabled by the keyboard or RS232 // { if (Closed_Loop_State == 10) // Find page/addr 0/1 { Page_Address_State = 0; { Integral_Term = 0; // reset integral term Closed_Loop_State--; } } if (Closed_Loop_State == 9) // Find page/addr 0/1 { Goto_Page_Addr (0x00,0x01); if (Page_Address_Found == 1) { Closed_Loop_State--; } } if (Closed_Loop_State == 8) // Set data to 01 in order to allow data changes at required page/address { if (Closed_Loop_Flag == 1) // Go into closed-loop: enable modifying data { Change_Data (0x00,0x01,0x01); if (Data_Modified == 1) { Page_Address_State = 0; Closed_Loop_State--; } } else // Go into open-loop: disable modifying data { Change_Data (0x00,0x01,0x00); if (Data_Modified == 1) { Page_Address_State = 0; Closed_Loop_State = 5; } } } if (Closed_Loop_State == 7) { Goto_Page_Addr (Page_Desired,Addr_Desired); // Go to required page/address (for changing oscillator frequency) if (Page_Address_Found == 1) { E2_Cam_Data = Command_Data; // Remember command data (to E2PROM) - just in case... E2_Table[2] = Command_Data; Initial_Integral = Command_Data; // Set controller output offset according to first measured value of data Integral_Term = 0; // Reset integral term! Closed_Loop_State--; // Closed_Loop_State = 6 (hurray! :-) } } // } // else // { // Closed_Loop_State = 0; // Initialisation // } } void Keyboard_Processing (void) { if ((Keyboard_Final == 0) && (Keyboard_Old == 8) && (Menu_Shift_Flag == 0)) { Menu_Page++; Pre_Trigger_Toggle = 0; if ((Menu_Page > 2) || ((Menu_Page > 0) && (Photo_Flag == 1))) { Menu_Page = 0; } } Keyboard_Processed_Flag = 0; if ((Keyboard_Final != 0) && (Keyboard_Final != 8)) // First check pressed keys (no page/shift one) { if (Photo_Flag == 1) { if (Menu_Page == 0) { if (Menu_Shift_Flag == 0) // Shift not active { if (Keyboard_Final == 1) { LANC_Byte0_L = 0x1E; // For still cameras - tele higher speed LANC_Byte1_L = 0x98; Pre_Trigger_Toggle = 0; } else if (Keyboard_Final == 2) { LANC_Byte0_L = 0x1E; // For still cameras - wide higher speed LANC_Byte1_L = 0x9A; Pre_Trigger_Toggle = 0; } else if ((Keyboard_Final == 4) && (Keyboard_Old == 0)) { if (Pre_Trigger_Toggle == 1) { LANC_Byte0_L = 0x1E; // For still cameras - Capture LANC_Byte1_L = 0x5A; Pre_Trigger_Toggle = 0; } else if (Keyboard_Old == 0) { LANC_Byte0_L = 0x1E; // For still cameras - Pre-trigger LANC_Byte1_L = 0x52; Pre_Trigger_Toggle = 1; } } else if (Keyboard_Final != 4) { Pre_Trigger_Toggle = 0; } } else // shift active { Pre_Trigger_Toggle = 0; if (Keyboard_Final == 9) { LANC_Byte0_L = 0x1E; // For still cameras - shut off/on LANC_Byte1_L = 0x5E; Shut_Off_Toggle = 1; } else if (Keyboard_Final == 10) { LANC_Byte0_L = 0x1E; // For still cameras - shut off LANC_Byte1_L = 0x5E; //Shut_Off_Toggle = 1; } else if ((Keyboard_Final == 12) && (Keyboard_Old != 12)) { if (Display_Toggle == 0) { Display_Toggle = 1; // Display change (recommended shutter speed) } else { Display_Toggle = 0; // Display change (sync in us) } } } } // if (Menu_Page == 0) } // if (Photo_Flag == 1) else // if camcorder { if (Menu_Page == 0) { if (Menu_Shift_Flag == 0) { if (Keyboard_Final == 1) { LANC_Byte0_L = 0x28; // For camcorders - tele lower speed LANC_Byte1_L = LANC_Command_Tele; } else if (Keyboard_Final == 2) { LANC_Byte0_L = 0x28; // For camcorders - wide LANC_Byte1_L = LANC_Command_Wide; } else if (Keyboard_Final == 4) { LANC_Byte0_L = 0x18; // For camcorders - REC on/off LANC_Byte1_L = 0x33; } } // if (Menu_Shift_Counter < Menu_Shift_Time) else // if SHIFT key is active { if (Keyboard_Final == 9) { LANC_Byte0_L = 0x18; // For camcorders - Shut off/on LANC_Byte1_L = 0x5E; //Command_Repetition_Counter = 20; // just in case 20 repetitions //Command_Execution_Flag = 1; //Command0 = 0x18; // For camcorders - shut off //Command1 = 0x5E; Shut_Off_Toggle = 1; } if (Keyboard_Final == 10) { LANC_Byte0_L = 0x18; // For camcorders - Shut off LANC_Byte1_L = 0x5E; //Command_Repetition_Counter = 20; // just in case 20 repetitions //Command_Execution_Flag = 1; //Command0 = 0x18; // For camcorders - shut off //Command1 = 0x5E; //Shut_Off_Toggle = 1; } else if ((Keyboard_Final == 12) && (Keyboard_Old == 8)) { Closed_Loop_State = 10; // Initialisation if (Closed_Loop_Toggle == 0) { Closed_Loop_Flag = 1; // Start closed-loop control Closed_Loop_Toggle = 1; } else { Closed_Loop_Flag = 2; // Start open-loop control Closed_Loop_Toggle = 0; } } } // else if SHIFT key is active } // if (Menu_Page == 0) else if (Menu_Page == 1) { if (Menu_Shift_Flag == 0) { if (Keyboard_Final == 1) { LANC_Byte0_L = 0x18; // For camcorders - Menu LANC_Byte1_L = 0x9A; } else if (Keyboard_Final == 2) { LANC_Byte0_L = 0x18; // For camcorders - Menu UP LANC_Byte1_L = 0x84; } else if (Keyboard_Final == 4) { LANC_Byte0_L = 0x18; // For camcorders - Menu DOWN LANC_Byte1_L = 0x86; } } else { if (Keyboard_Final == 9) { LANC_Byte0_L = 0x18; // For camcorders - Submenu LANC_Byte1_L = 0xA2; } else if (Keyboard_Final == 10) { LANC_Byte0_L = 0x28; // For camcorders - Focus far LANC_Byte1_L = 0x45; } else if (Keyboard_Final == 12) { LANC_Byte0_L = 0x28; // For camcorders - Focus near LANC_Byte1_L = 0x47; } } } // else if (Menu_Page == 1) else if (Menu_Page == 2) { if (Menu_Shift_Flag == 0) { if (Keyboard_Final == 1) { LANC_Byte1_L = User_Command1_Cam; LANC_Byte0_L = (User_Command1_Cam >> 8); // For camcorders - User command 1 } else if (Keyboard_Final == 2) { LANC_Byte1_L = User_Command2_Cam; LANC_Byte0_L = (User_Command2_Cam >> 8); // For camcorders - User command 2 } else if ((Keyboard_Final == 4) && (Keyboard_Old != 4)) { if (Display_Toggle == 0) { Display_Toggle = 1; // Display change (recommended shutter speed) } else { Display_Toggle = 0; // Display change (sync in us) } } } else { if (Keyboard_Final == 9) { LANC_Byte1_L = User_Command3_Cam; LANC_Byte0_L = (User_Command3_Cam >> 8); // For camcorders - User command 3 } else if (Keyboard_Final == 10) { LANC_Byte1_L = User_Command4_Cam; LANC_Byte0_L = (User_Command4_Cam >> 8); // For camcorders - User command 4 } } } // else if (Menu_Page == 2) } // if (Photo_Flag <> 1) - camcorder is present Keyboard_Processed_Flag = 1; } // if (Keyboard_Final != 0) } void LCD_Menu (void) { lcd_gotoxy(0,0); if (Menu_Page == 0) { if (Photo_Flag == 0) { if (Menu_Shift_Flag == 0) { lcd_putsf("Tel Wid Rec "); } else { lcd_putsf("RST OFF CL "); } } else { if (Menu_Shift_Flag == 0) { if (Pre_Trigger_Toggle == 1) { lcd_putsf("Tel Wid Cap "); } else { lcd_putsf("Tel Wid Prt "); } } else { lcd_putsf("RST OFF Disp "); } } } else if (Menu_Page == 1) { if (Menu_Shift_Flag == 0) { lcd_putsf("Men Up Dwn "); } else { lcd_putsf("Sbm Ffr Fnr "); } } else if (Menu_Page == 2) { if (Menu_Shift_Flag == 0) { lcd_putsf("Cc1 Cc2 Disp "); } else { lcd_putsf("Cc3 Cc4 "); } } lcd_putsf(" "); } // External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { // Place your code here unsigned int Temp_Timer; // Current timer1 value unsigned int Time_Diff; Temp_Timer = ICR1; // Read Input Capture 1 value Time_Diff = Temp_Timer - CamL_Timer; CamL_Timer = Temp_Timer; // Read Timer 1 value if (LancL_State == 0) { LancL_State = 8; LANC_L_Direction = 0; // Define it as input Valid_CaptureL = 0; TCCR2=0x00; // Switch off Timer 2 counting TIMSK = (TIMSK & 0x7F); // Disable timer 2 output compare interrupt LANC_Byte0_L = 0x00; // Reset LANC command LANC_Byte1_L = 0x00; Command_Execution_Flag = 0; // Reset possible execution of command/macro TempTimer = 0; // reset timer Counter0Byte3 = 0; // Counter of empty 3rd bytes received from left LANC Photo_Flag = 0; Integral_Term = 0; // reset integral term } else if (LancL_State == 8) { if ((Time_Diff > 10000) && (Time_Diff < 29000)) // Valid time gap between the last and the first LANC byte (approx. 6..14ms) { LANC_Rem_Write = 1; // Generate pulse on LANC remote // LANC_Rem_Dir = 1; // Define it as output LancL_State = 1; // There will be first LANC byte BitCounterL = 0; // Bit counter in LANC byte (2 for one bit) LANC_Left_Byte = 0; // Initialisation of read byte from LANC remote GICR = (GICR & 0xBF); // Switch off external interrupt 0 TCNT2=0x0A; // Reset counter 2 to 5us (first int - smaller time lag) TCCR2 = 0x0A; // Switch on timer2 counting LANC_Left_Byte_Valid = LANC_Byte0_L; // Place first valid instruction if (Photo_Flag == 1) { if (LANC_Byte0_L == 0) { LANC_Byte0_L = 0x0E; // For still cameras LANC_Left_Byte_Valid = 0x0E; // For still cameras LANC_Byte1_L = 0x00; } } TIMSK = (TIMSK | 0x80); // Enable timer 2 output compare interrupt CaptureL_Time_Old = CaptureL_Time; // Remember old value CaptureL_Time = CamL_Timer; // Copy capture register DeltaL = CaptureL_Time - CaptureL_Time_Old; // Time difference between two frames CaptureL_Time_Mean_Old = CaptureL_Time_Mean; // Copy into old value CaptureL_Time_Mean = CaptureL_Time_Old + (DeltaL >> 1); // Mean value DeltaLR = CaptureL_Time_Mean - CaptureR_Time_Mean; PeriodL = CaptureL_Time_Mean - CaptureL_Time_Mean_Old; FirstFlag = 1; } else { TCCR2=0x00; // Switch off Timer 2 counting TIMSK = (TIMSK & 0x7F); // Disable timer 2 output compare interrupt } } else if (LancL_State < 8) // After 1st valid LANC byte { if ((Time_Diff > 2000) && (Time_Diff < 2900)) // Valid time gap between LANC bytes (usually 1.2 to 1.4 ms) { LANC_Rem_Write = 1; // Generate pulse on LANC remote // LANC_Rem_Dir = 1; // Define it as output LancL_State++; // Increase LANC byte counter BitCounterL = 0; // Reset bit counter within LANC byte (2 for one bit) LANC_Left_Byte = 0; // Reset byte from LANC remote GICR = (GICR & 0xBF); // Switch off external interrupt 0 TCNT2=0x0A; // Reset counter 2 to 5us (first int - smaller time lag) TCCR2 = 0x0A; // Switch on timer2 counting TIMSK = (TIMSK | 0x80); // Enable timer 2 output compare interrupt LANC_Byte2_L = 0x00; if (LancL_State == 2) { LANC_Left_Byte_Valid = LANC_Byte1_L; } else if ((LancL_State == 3) && (Photo_Flag == 1)) { LANC_Remote_Out = DataBytes[3]; if (CounterCatch3 == 3) { LANC_Byte2_L = 0x43; CounterCatch3++; LANC_Remote_Out = 0x00; } else if (CounterCatch3 == 4) { LANC_Byte2_L = 0x53; CounterCatch3++; LANC_Remote_Out = 0x00; } else if (CounterCatch3 == 5) { LANC_Byte2_L = 0x53; CounterCatch3 = 0; LANC_Remote_Out = 0x00; if (CatchByte3 == 0x47) { CatchByte3 = 0x57; } else { CatchByte3 = 0x47; } } LANC_Left_Byte_Valid = LANC_Byte2_L; } else { LANC_Left_Byte_Valid = DataBytes[LancL_State]; LANC_Remote_Out = LANC_Left_Byte_Valid; } } else { LancL_State = 0; // Not valid time gap - reset state! TCCR2=0x00; // Switch off Timer 2 counting TIMSK = (TIMSK & 0x7F); // Disable timer 2 output compare interrupt } } else { LancL_State = 0; // Not valid time gap - reset state! TCCR2=0x00; // Switch off Timer 2 counting TIMSK = (TIMSK & 0x7F); // Disable timer 2 output compare interrupt } Counter_OverflowL = 0; } // External Interrupt 1 service routine interrupt [EXT_INT1] void ext_int1_isr(void) { // Place your code here unsigned int Temp_Timer; // Current timer1 value unsigned int Time_Diff; Temp_Timer = TCNT1; // Read Timer 1 value Time_Diff = Temp_Timer - CamR_Timer; CamR_Timer = Temp_Timer; // Read Timer 1 value if (LancR_State == 0) { LancR_State = 8; LANC_R_Direction = 0; // Define it as input Valid_CaptureR = 0; TCCR0=0x00; // Switch off Timer 0 counting TIMSK = (TIMSK & 0xFE); // Disable timer 0 overflow interrupt LANC_Byte0_R = 0x00; // Reset LANC command LANC_Byte1_R = 0x00; Integral_Term = 0; // reset integral term } else if (LancR_State == 8) { if ((Time_Diff > 10000) && (Time_Diff < 29000)) // Valid time gap between the last and the first LANC byte (approx. 6..14ms) { LancR_State = 1; // There will be first LANC byte BitCounterR = 0; // Bit counter in LANC byte (2 for one bit) GICR = (GICR & 0x7F); // Switch off external interrupt 1 TCNT0=0xA8; // Reset counter to 52us TCCR0 = 0x02; // Switch on timer0 counting if (LANC_Byte0_L == 0xFF) // Command correlated to changing data in pages/addreses (only for left LANC) { LANC_Byte0_R = 0x00; // No command for right LANC when chaging DATA in left LANC LANC_Byte1_R = 0x00; } else { LANC_Byte0_R = LANC_Byte0_L; // Copy command bytes received from lanc remote, RS232, ... LANC_Byte1_R = LANC_Byte1_L; } LANC_Byte2_R = LANC_Byte2_L; LANC_Right_Byte_Valid = LANC_Byte0_R; if (Photo_Flag == 1) { if (LANC_Byte0_R == 0) { LANC_Byte0_R = 0x0E; // For still cameras LANC_Right_Byte_Valid = 0x0E; // For still cameras LANC_Byte1_R = 0x00; } } // Valid_CaptureR = Valid_CaptureL; TIMSK = (TIMSK | 0x01); // Enable timer 0 overflow interrupt CaptureR_Time_Old = CaptureR_Time; // Remember old value CaptureR_Time = CamR_Timer; // Copy capture register DeltaR = CaptureR_Time - CaptureR_Time_Old; CaptureR_Time_Mean_Old = CaptureR_Time_Mean; // Copy into old value CaptureR_Time_Mean = CaptureR_Time_Old + (DeltaR >> 1); // Mean value } else { //LancR_State = 0; // Not valid time gap - reset state! TCCR0=0x00; // Switch off Timer 0 counting TIMSK = (TIMSK & 0xFE); // Disable timer 0 overflow interrupt } } else if (LancR_State < 8) // After 1st valid LANC byte { if ((Time_Diff > 2000) && (Time_Diff < 2900)) // Valid time gap between LANC bytes (usually 1.2 to 1.4 ms) { LancR_State++; // Increase LANC byte counter BitCounterR = 1; // Reset bit counter within LANC byte (2 for one bit) GICR = (GICR & 0x7F); // Switch off external interrupt 1 TCNT0=0xA8; // Reset counter to 52us TCCR0 = 0x02; // Switch on timer0 counting TIMSK = (TIMSK | 0x01); // Enable timer 0 overflow interrupt if (LancR_State == 2) { LANC_Right_Byte_Valid = LANC_Byte1_R; } else if ((LancR_State == 3) && (Photo_Flag == 1)) { if (CounterCatch3R == 3) { LANC_Byte2_R = 0x43; CounterCatch3R++; } else if (CounterCatch3R == 4) { LANC_Byte2_R = 0x53; CounterCatch3R++; } else if (CounterCatch3R == 5) { LANC_Byte2_R = 0x53; CounterCatch3R = 0; if (CatchByte3R == 0x47) { CatchByte3R = 0x57; } else { CatchByte3R = 0x47; } } LANC_Right_Byte_Valid = LANC_Byte2_R; } else { LANC_Right_Byte_Valid = DataBytes[LancR_State]; } } else { LancR_State = 0; // Not valid time gap - reset state! TCCR0=0x00; // Switch off Timer 0 counting TIMSK = (TIMSK & 0xFE); // Disable timer 0 overflow interrupt } } else { LancR_State = 0; // Not valid time gap - reset state! TCCR0=0x00; // Switch off Timer 0 counting TIMSK = (TIMSK & 0xFE); // Disable timer 0 overflow interrupt } Counter_OverflowR = 0; // Clear overflow flag in counter1 routine } // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { // Reinitialize Timer 0 value TCNT0 = TCNT0 + 0x98; // Correct timing according to delay for jumping into int routine // Place your code here if (BitCounterR < 17) { #asm sbrc r9,0 ; skip if bit 0 in BitCounterR is cleared (even number) rjmp __odd_num_1 #endasm // BitCounterR is even number - read from LANC if (LancR_State == 3) // Read from right LANC { #asm sec sbis __PIND_asm,3 ; Skip next instruction if PID.3 is set (right LANC) clc ror r12 ; Rotate through carry LANC_Right_Byte #endasm } #asm rjmp __end_num_1 #endasm #asm __odd_num_1: ; BitCounterL is odd number - write to LANC #endasm if (Valid_CaptureR == 1) { if (LancR_State <= 3) { #asm ror r10 ; rotate right through carry LANC_Left_Byte_Valid brbs 0,__resetflag3 ; if carry flag is set then goto __resetflag2 cbi __PORTC_asm,3 ; clear LANC L signal rjmp __end_valid3 ; goto __end_valid2 __resetflag3: sbi __PORTC_asm,3 ; set LANC L signal __end_valid3: #endasm } } #asm __end_num_1: #endasm } else if (BitCounterR < 19) { LANC_R_Out = 0; // Open collector } else if (BitCounterR == 19) { TCCR0=0x00; // Switch off Timer 0 counting TIMSK = (TIMSK & 0xFE); // Disable timer 0 interrupt if (LancR_State == 8) // If the last byte is received { Valid_CaptureR = 1; // New value is available - captured bytes are valid if (Photo_Flag == 1) { if (LANC_Right_Byte == CatchByte3R) { CounterCatch3R++; } } } // Don't clear external interrupt flag 1, since interrupt flag 0 can be cleared as well (if it occurs during timer 1 int) GIFR = 0x80; // clear ONLY external interrupt flag 1!! GICR = (GICR | 0x80); // Switch on external interrupt 1!!! } else if (BitCounterR == 0) // Do nothing - wait additional 52us for the end of start bit { } else // error { LancR_State = 0; // Reset state TCCR0=0x00; // Switch off Timer 0 counting TIMSK = (TIMSK & 0xFE); // Disable timer 0 overflow interrupt GIFR = 0x80; // clear ONLY external interrupt flag 1!! GICR = (GICR | 0x80); // Switch on external interrupt 1!!! } BitCounterR++; } // Timer 1 overflow interrupt service routine interrupt [TIM1_OVF] void timer1_ovf_isr(void) { // Place your code here if (Counter_OverflowL == 1) { LancL_State = 0; LANC_L_Direction = 0; // Define it as input TCCR2=0x00; // Switch off Timer 2 counting TIMSK = (TIMSK & 0x7F); // Disable timer 2 output compare interrupt GIFR = 0x40; // clear ONLY external interrupt flag 0!! GICR = (GICR | 0x40); // Switch on external interrupt 0!!! } else { Counter_OverflowL = 1; } if (Counter_OverflowR == 1) { LancR_State = 0; LANC_R_Direction = 0; // Define it as input TCCR0=0x00; // Switch off Timer 0 counting TIMSK = (TIMSK & 0xFE); // Disable timer 0 overflow interrupt GIFR = 0x80; // clear ONLY external interrupt flag 1!! GICR = (GICR | 0x80); // Switch on external interrupt 1!!! } else { Counter_OverflowR = 1; } if (RS232_TimeOut > 0) { RS232_TimeOut++; if (RS232_TimeOut > RS232_TimeOut_Max) // RS232 Time-out { RS232_Counter = 0; // reset byte counter and time-out timer RS232_TimeOut = 0; } } Time_PowerOn++; Time_HMI++; Time_Startup++; if (Time_Startup >= 10) { Time_Startup = 10; } } // Timer 2 output compare interrupt service routine interrupt [TIM2_COMP] void timer2_comp_isr(void) { // Place your code here if (BitCounterL < 17) { #asm sbrc r8,0 ; skip if bit 0 in BitCounterL is cleared (even number) rjmp __odd_num_0 #endasm // BitCounterL is even number - read from LANC if (LancL_State < 3) // Read from remote { #asm sec sbis __PINC_asm,4 ; Read LANC remote clc ror r4 #endasm } else // Read from left LANC { #asm sec sbis __PIND_asm,2 clc ror r4 #endasm } #asm rjmp __end_num_0 #endasm #asm __odd_num_0: ; BitCounterL is odd number - write to LANC #endasm if (Valid_CaptureL == 1) { if (LancL_State >= 3) { #asm ; sbi __DDRB_asm,1 ; set LANC remote signal direction to output ror r11 brbs 0,__resetflag cbi __PORTB_asm,1 ; clear LANC remote signal rjmp __end_valid1 __resetflag: sbi __PORTB_asm,1 ; set LANC remote signal __end_valid1: #endasm } else { LANC_Rem_Write = 0; // go into three-state } if (LancL_State <= 3) { #asm ; sbi __DDRB_asm,2 ; set left LANC signal direction to output ror r5 ; rotate right through carry LANC_Left_Byte_Valid brbs 0,__resetflag2 ; if carry flag is set then goto __resetflag2 cbi __PORTB_asm,2 ; clear LANC L signal rjmp __end_valid2 ; goto __end_valid2 __resetflag2: sbi __PORTB_asm,2 ; set LANC L signal __end_valid2: #endasm } } else { LANC_Rem_Write = 0; // go into three-state } #asm __end_num_0: #endasm } else if (BitCounterL < 19) { LANC_Rem_Write = 0; // go into three-state // LANC_Rem_Dir = 1; // Define it as input LANC_L_Out = 0; // Open collector //LANC_L_Write = 1; //LANC_L_Direction = 0; // Define it as input } else if (BitCounterL == 19) { TCCR2=0x00; // Switch off Timer 2 counting TIMSK = (TIMSK & 0x7F); // Disable timer 2 output compare match interrupt DataBytes[LancL_State] = LANC_Left_Byte; // Place received byte into DataBytes array if (LancL_State == 8) // If the last byte is received { Valid_CaptureL = 1; // New value is available - captured bytes are valid LastFlag = 1; // Signalisation to main routine if (Photo_Flag == 0) // Still camera detection { if (DataBytes[3] == 0) { Counter0Byte3++; if (Counter0Byte3 >= 29) // Probably still camera { Photo_Flag = 1; // Photographic camera is present on the left LANC } } else { Counter0Byte3 = 0; // Probably camcorder } } else // Photographic camera handshaking (quite comlicating! :-) { if (DataBytes[3] == CatchByte3) { CounterCatch3++; } } } // If LANC L state = 8 // Don't clear external interrupt flag 0, since interrupt flag 1 can be cleared as well (if it occurs during timer 0 int) GIFR = 0x40; // clear ONLY external interrupt flag 0!! GICR = (GICR | 0x40); // Switch on external interrupt 0!!! } // If bitcounterL == 19 else if (BitCounterL == 0) // Do nothing - wait additional 52us for the end of start bit { } else // error { LancL_State = 0; // Reset state TCCR2=0x00; // Switch off Timer 2 counting TIMSK = (TIMSK & 0x7F); // Disable timer 2 output compare interrupt GIFR = 0x40; // clear ONLY external interrupt flag 0!! GICR = (GICR | 0x40); // Switch on external interrupt 0!!! } BitCounterL++; } // Declare your global variables here char char1; unsigned char TempChar, TempChar1=0; int Int_Tmp1; signed long int SumDeltaLR=0; signed long int SumTimeDeltaLR=0; signed long int SumDeltaLR_Old=0; signed long int SumDeltaLR_Old2=0; signed long int SumDeltaLR_Old3=0; signed long int SumDeltaLR_Old4=0; signed long int DiffDeltaLR=0; signed long int TempIntLong=0; signed long int K1; signed long int n1; unsigned char CounterSum=0; unsigned char CounterDiff=0; void main(void) { // Declare your local variables here unsigned int Tempint1, Tempint2; signed int Tempint4, Tempint5; unsigned char i; // Input/Output Ports initialization // Port B initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTB=0x00; DDRB=0x00; // Port C initialization // Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTC=0x00; DDRC=0x00; // Port D initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTD=0x00; DDRD=0x00; LANC_Rem_Write=0; // Go into three-state LANC_Rem_Dir=1; // Define pin as output (output for LANC remote) LANC_Rem_DirR=0; // Define pin as input (reading LANC remote) LANC_L_OutD = 1; // Left LANC out signal direction = out LANC_R_OutD = 1; // Right LANC out signal direction = out LANC_L_Direction = 0; // Define it as input LANC_R_Direction = 0; // Define it as input delay_time(10); // Wait approx. 320 ms // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 2000,000 kHz //TCCR0=0x02; TCCR0=0x00; // switch off timer TCNT0=0x97; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 2000,000 kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Rising Edge TCCR1A=0x00; TCCR1B=0x42; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: 2000,000 kHz // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; //TCCR2=0x02; TCCR2=0x0A; // Switch off timer 2 counting, compare match output mode TCNT2=0x00; OCR2=0x67; // 51.5 us interrupt // External Interrupt(s) initialization // INT0: On // INT0 Mode: Falling Edge // INT1: On // INT1 Mode: Falling Edge MCUCR=0x0F; // The rising edges of INT0 & INT1 generate interrupt requests GIFR=0xC0; // Reset external int flags GICR|=0xC0; // Enable external interrupts // Timer(s)/Counter(s) Interrupt(s) initialization //TIMSK=0x45; TIMSK=0x04; // Enable timer 1 interrupt (counter) // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity // USART Receiver: On // USART Transmitter: On // USART Mode: Asynchronous // USART Baud rate: 9600 UCSRA=0x00; UCSRB=0x18; UCSRC=0x86; UBRRH=0x00; UBRRL=0x67; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00; // ADC initialization // ADC Clock frequency: 125,000 kHz // ADC Voltage Reference: AREF pin // Only the 8 most significant bits of // the AD conversion result are used ADMUX=ADC_VREF_TYPE; ADCSRA=0x87; // initialize the LCD for // 2 lines & 16 columns lcd_init(16); // go to the second LCD line lcd_gotoxy(0,0); if (E2_Initialisation != 0) // First-time execution after programming { E2_Table[3] = Period_PowOnL1; // Period_PowOnL1 - Power-on pulse width = 100ms; E2_Table[4] = Period_PowOnH1; // Period_PowOnH1; E2_Table[6] = Period_PowOnL2; // Period_PowOnL2 - power-on pulse width = 100ms E2_Table[7] = Period_PowOnH2; // Period_PowOnH2; E2_Table[17] = Proportional_Factor; E2_Table[18] = Integral_Factor; E2_Table[19] = Power_Off_Delay; E2_Initialisation = 0; // Reset initialisation - the next time the variables will be copied FROM E2PROM // Note! Other parameters are already 0 } else { E2PROM_Init(); // Copy values from E2PROM to variables; } TempChar = read_adc(0x05); // Read the value at port PC5 TempChar = read_adc(0x05); // Read again the value at port PC5 (the first conversion is not reliable) //Voltage1 = TempChar; // Remember the measured voltage Voltage1 = 193; // Medium voltage (first measurement) // Add routine for checking voltage. If it's too low, it should go into the sleep mode (before writing 'BATTERY!!!' on LCD). //if (Voltage1 < 153) //{ // Battery_Low(); // Go into power-down mode //} ADCSRA |= 0x60; // Free-running conversion // Global enable interrupts #asm("sei") while (1) { // Place your code here char1=get_rs232(); if (RS232_New == 1) // if new character is received { RS232_Counter++; RS232_Bytes[RS232_Counter] = char1; if (RS232_Counter == 1) { RS232_XOR = char1; } else { RS232_XOR = (RS232_XOR ^ char1); } RS232_TimeOut = 1; if (((RS232_Counter == 1) && (char1 < 128)) || (RS232_Counter >= 4)) { RS232_TimeOut = 0; Process_RS232_Command(); RS232_Counter = 0; } } if (FirstFlag == 1) // after receiving the first start bit in the frame { #asm ("cli") Tempint1 = DeltaLR; Tempint2 = PeriodL; FirstFlag = 0; #asm ("sei") if (Tempint1 > 60000) // Negative value - do nothing { } else if ((Tempint1 > Tempint2) || (Tempint1 > (Tempint2>>1))) { Tempint1 = Tempint1 - Tempint2; } /* else if (Tempint1 > Tempint2) { Tempint1 = Tempint1 - Tempint2; } else if (Tempint1 > (Tempint2>>1)) { Tempint1 = Tempint1 - Tempint2; } */ Tempint4 = (signed int) Tempint1; SumDeltaLR = SumDeltaLR + Tempint4; // Calculate sum of DeltaLR values CounterSum++; // increase counter if (CounterSum >= 64) { //DiffDeltaLR = SumDeltaLR - SumDeltaLR_Old4; //Tempint4 = DiffDeltaLR/64; //K1 = (-3*SumDeltaLR_Old3 - SumDeltaLR_Old2 + SumDeltaLR_Old + 3*SumDeltaLR)/640; // n1 = (-2*SumDeltaLR_Old3 + SumDeltaLR_Old2 + 4*SumDeltaLR_Old + 7*SumDeltaLR)/640; //Tempint4 = K1; LANC_Sync = SumDeltaLR/128; if ((Closed_Loop_Flag == 1) && (Closed_Loop_State == 6)) // Page/address is OK { if ((Command_Page == E2_Cam_Page) && (Command_Addr == E2_Cam_Addr)) // Check again page and addr { Integral_Term = Integral_Term + LANC_Sync; // Integrate the error //Tempint5 = (LANC_Sync>>4) + Initial_Integral + (Integral_Term>>10); // problem with sign!!! Tempint5 = LANC_Sync/Proportional_Factor + Initial_Integral + Integral_Term/Integral_Factor; //Tempint5 = LANC_Sync/16 + Initial_Integral + Integral_Term/1024; if (Tempint5 > 254) { Tempint5 = 0xFE; Integral_Term = Integral_Term - LANC_Sync; // Stop integration if overflow } else if (Tempint5 < 1) { Tempint5 = 1; Integral_Term = Integral_Term - LANC_Sync; // Stop integration if overflow } Controller_Output = Tempint5; } } SumDeltaLR_Old4 = SumDeltaLR_Old3; SumDeltaLR_Old3 = SumDeltaLR_Old2; SumDeltaLR_Old2 = SumDeltaLR_Old; SumDeltaLR_Old = SumDeltaLR; CounterSum = 0; // initialise counter and summator SumDeltaLR = 0; K1 = 7500; char1 = 0; if (LANC_Sync > 0) { K1 = 25000/LANC_Sync; } else if (LANC_Sync < 0) { K1 = -25000/LANC_Sync; char1 = 1; } K1 = K1*4; if (K1 > 30000) K1 = 30000; if (char1 == 0) { Tempint4 = LANC_Sync; } else { Tempint4 = -LANC_Sync; } lcd_gotoxy(0,1); if (Display_Toggle == 0) { Tempint1 = Tempint4; lcd_putsf(Message1); } else { Tempint1 = K1; lcd_putsf(Message2); } if ((LancL_State != 0) && (LancR_State != 0)) // Both camcorders are present { write_LCD_int (Tempint1,char1); } } // if (CounterSum >= 64) } // if (FirstFlag == 1) if (LastFlag == 1) { // if ((Closed_Loop_Flag >= 1) && (Closed_Loop_State < 4)) // Searching for page/address if (Closed_Loop_State > 6) // Searching for page/address { Active_Control (E2_Cam_Page,E2_Cam_Addr); } if (Command_Execution_Flag == 0) { // if ((Closed_Loop_Flag == 1) && (Closed_Loop_State == 4)) // Page/address is OK if ((Closed_Loop_Flag == 1) && (Closed_Loop_State == 6)) // Page/address is OK { if ((Command_Page == E2_Cam_Page) && (Command_Addr == E2_Cam_Addr)) // Check again page and addr { Command_Repetition_Counter = 10; Command_Execution_Flag = 1; if (Controller_Output > Command_Data) { Command0 = 0xFF; Command1 = 0x34; // increase data } else if (Controller_Output < Command_Data) { Command0 = 0xFF; Command1 = 0x30; // decrease data } else { Command_Execution_Flag = 0; // Do nothing } } } } if (Keyboard_Processed_Flag == 0) // no key is pressed { LANC_Byte0_L = 0x00; LANC_Byte1_L = 0x00; TempChar = DataBytes[1]; TempChar1 = DataBytes[2]; if (Pre_Trigger_Toggle == 1) { LANC_Byte0_L = 0x1E; // For still cameras - Pre-trigger LANC_Byte1_L = 0x52; } else if (TempChar != 0) // remote LANC signal is active { LANC_Byte0_L = TempChar; LANC_Byte1_L = TempChar1; } else if (Command_Execution_Flag == 1) // if commands are received via keyboard, RS232 or closed-loop { LANC_Byte0_L = Command0; LANC_Byte1_L = Command1; if (Command_Repetition_Counter > 0) { Command_Repetition_Counter--; // decrease number of remanined repetitions } if (LANC_Byte0_L == 0xFF) // If DATA, ADDR, PAGE changing command present { if (Command_Repetition_Counter <= 3) // For the last few commands { LANC_Byte1_L = 0x00; // Add some additional "dummy" commands (0xFF, 0x00) } else // Copy all status, page, address and data bytes into appropriate variables { Command_Page = ((DataBytes[5])>>4); // High nibble contains page Command_Status = DataBytes[6]; Command_Addr = DataBytes[7]; Command_Data = DataBytes[8]; } } if (Command_Repetition_Counter == 0) { Command_Execution_Flag = 0; // reset flag (the last repetition) } } // else if (Command_Execution_Flag == 1) } // if (Keyboard_Processed_Flag == 0) - no key is pressed LastFlag = 0; // Reset flag } // if (LastFlag == 1) Keyboard_Command = 0; if (Time_HMI >= 4) { // Check battery voltage Sum_Voltage1 = Sum_Voltage1 + ADCH; // Add measured voltage Counter_Voltage1++; // Increase counter if (Counter_Voltage1 >= 16) { Voltage1 = (Sum_Voltage1 >> 4); // Calculate mean value Counter_Voltage1 = 0; // Reset counter Sum_Voltage1 = 0; // Reset summator } if (Voltage1 < 153) { Battery_Low(); // Go into power-down mode } // Reading keyboard should be executed before EACH writing to LCD switch_1_Write = 0; // go into three-state switch_1_Direction = 0; // Switch1 signal = input switch_2_Write = 0; // go into three-state switch_2_Direction = 0; // Switch2 signal = input switch_3_Write = 0; // go into three-state switch_3_Direction = 0; // Switch3 signal = input switch_4_Write = 0; // go into three-state switch_4_Direction = 0; // Switch4 signal = input i = 0; while (i < 8) // wait for signal to settle (4us @ 16MHz). Loop takes 8 instructions { #asm ("nop") i++; } if (switch_1_Read == 0) { Keyboard_Command++; } switch_1_Direction = 1; // Switch1 signal = output if (switch_2_Read == 0) { Keyboard_Command = Keyboard_Command + 2; } switch_2_Direction = 1; // Switch2 signal = output if (switch_3_Read == 0) { Keyboard_Command = Keyboard_Command + 4; } switch_2_Direction = 1; // Switch3 signal = output if (switch_4_Read == 0) { Keyboard_Command = Keyboard_Command + 8; } Keyboard_Old = Keyboard_Final; // Copy old value Keyboard_Final = Keyboard_Command; // Enter new value Time_HMI = 0; // Reset keyboard-reading timer if ((Keyboard_Final >= 8) && (Menu_Shift_Counter < Menu_Shift_Time)) // If Page/shift key is pressed longer than 5 periods { Menu_Shift_Counter++; Pre_Trigger_Toggle = 0; // just in case } else if ((Keyboard_Final == 0) && (Keyboard_Old == 0)) // If keys are de-pressed { Menu_Shift_Counter = 0; } if (Menu_Shift_Counter >= Menu_Shift_Time) { Menu_Shift_Flag = 1; // Set SHIFT flag } else { Menu_Shift_Flag = 0; // Reset SHIFT flag } Keyboard_Processing(); // Do keyboard processing (execution after power-on!!) switch_4_Direction = 1; // Switch4 signal = output lcd_gotoxy(13,1); if (Blinking_Flag == 0) Blinking_Flag = 1; else Blinking_Flag = 0; if ((LancL_State == 0) && (LancR_State == 0)) { lcd_putsf("N"); } else if (LancL_State == 0) { lcd_putsf("L"); } else if (LancR_State == 0) { lcd_putsf("R"); } else { lcd_putsf(" "); } if ((Closed_Loop_State > 6) && (Blinking_Flag == 0)) { lcd_putsf(" "); } else if (Closed_Loop_Flag == 1) { lcd_putsf("C"); } else { lcd_putsf("O"); } /* if (Closed_Loop_Flag == 1) { if ((Closed_Loop_State == 4) || (Blinking_Flag == 1)) lcd_putsf("C"); else lcd_putsf(" "); } else { lcd_putsf("O"); } */ if (Voltage1 >= 153) { TempChar = (Voltage1-153); TempChar = (TempChar >> 3); if (TempChar > 9) TempChar = 9; } else TempChar = 0; if ((TempChar > 1) || (Blinking_Flag == 1)) { lcd_putchar(0x30 + TempChar); } LCD_Menu(); // Write MENU on LCD } if (((Time_PowerOn >= 2) && (Time_Startup >= 10)) || ((Shut_Off_Toggle == 1) && (LancL_State == 0))) { if (Shut_Off_Toggle) { delay_time(Power_Off_Delay); } Power_On_Procedure(); // Generate power-on pulses on both channels while (LANC_Rem_Read == 1) // Wait until power-on pulse on remote ends {} // Time_PowerOn = 0; // reset timer1 } else { if (LANC_Rem_Read == 0) // If there is high level (there is no more power-on signal present) { Time_PowerOn = 0; // reset counter } } }; // while (1) } // main