etisserant@375: /* etisserant@375: This file is part of CanFestival, a library implementing CanOpen Stack. etisserant@375: etisserant@375: Copyright (C): Edouard TISSERANT and Francis DUPIN etisserant@375: AVR Port: Andreas GLAUSER and Peter CHRISTEN etisserant@375: etisserant@375: See COPYING file for copyrights details. etisserant@375: etisserant@375: This library is free software; you can redistribute it and/or etisserant@375: modify it under the terms of the GNU Lesser General Public etisserant@375: License as published by the Free Software Foundation; either etisserant@375: version 2.1 of the License, or (at your option) any later version. etisserant@375: etisserant@375: This library is distributed in the hope that it will be useful, etisserant@375: but WITHOUT ANY WARRANTY; without even the implied warranty of etisserant@375: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU etisserant@375: Lesser General Public License for more details. etisserant@375: etisserant@375: You should have received a copy of the GNU Lesser General Public etisserant@375: License along with this library; if not, write to the Free Software etisserant@375: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA etisserant@375: */ etisserant@375: /****************************************************************************** etisserant@375: Project description: etisserant@375: Test projekt for a DS 401 slave, running on Atmel's STK500 with AT90CAN128 etisserant@375: Short description: etisserant@375: PORTA: Inputs (Keys, low active) etisserant@375: PORTB: Outputs (LEDs, low active) etisserant@375: PORTC: Node ID (1 BCD switch) etisserant@375: etisserant@375: ******************************************************************************/ etisserant@375: #include "hardware.h" etisserant@375: #include "canfestival.h" etisserant@375: #include "can_AVR.h" etisserant@375: #include "objdict.h" etisserant@375: etisserant@375: unsigned char timer_interrupt = 0; // Set if timer interrupt eclapsed etisserant@375: unsigned char inputs; etisserant@375: etisserant@375: // CAN etisserant@375: unsigned char nodeID; etisserant@375: static Message m = Message_Initializer; // contain a CAN message etisserant@375: etisserant@375: static unsigned char old_input_value; // Inputs, to check if a input has changed etisserant@375: etisserant@375: void sys_init(); etisserant@375: etisserant@375: // macros to handle the schedule timer etisserant@375: #define sys_timer timer_interrupt etisserant@375: #define reset_sys_timer() timer_interrupt = 0 etisserant@375: #define CYCLE_TIME 1000 // Sample Timebase [us] etisserant@375: etisserant@375: int main(void) etisserant@375: { etisserant@375: sys_init(); // Initialize system etisserant@375: canInit(CAN_BAUDRATE); // Initialize the CANopen bus etisserant@375: initTimer(); // Start timer for the CANopen stack etisserant@375: nodeID = read_bcd(); // Read node ID first etisserant@375: setNodeId (&ObjDict_Data, nodeID); etisserant@375: setState(&ObjDict_Data, Initialisation); // Init the state etisserant@375: PDOInit(&ObjDict_Data); etisserant@375: etisserant@375: // Examples for callbacks etisserant@375: // RegisterSetODentryCallBack(d, 0x1005, 0, &OnCOB_ID_SyncUpdate); etisserant@375: // errorCode = setODentry(d, d->transfers[line].index, d->transfers[line].subIndex, etisserant@375: // (void *) d->transfers[line].data, &size, 1); etisserant@375: etisserant@375: for(;;) // forever loop etisserant@375: { etisserant@375: if (sys_timer) // Cycle timer, invoke action on every time slice etisserant@375: { etisserant@375: reset_sys_timer(); // Reset timer etisserant@375: etisserant@375: // Read the input states from the ports etisserant@375: Read_Inputs_8_Bit[0] = get_inputs(); etisserant@375: // Send the new input state if there was a change etisserant@375: if (old_input_value != Read_Inputs_8_Bit[0]) etisserant@375: { etisserant@375: old_input_value = Read_Inputs_8_Bit[0]; etisserant@375: if (getState(&ObjDict_Data) == Operational) etisserant@375: sendPDOevent(&ObjDict_Data); etisserant@375: } etisserant@375: set_outputs(Write_Outputs_8_Bit[0]); etisserant@375: etisserant@375: // Check if CAN address has been changed etisserant@375: if(!( nodeID == read_bcd())) etisserant@375: { etisserant@375: nodeID = read_bcd(); // Save the new CAN adress etisserant@375: setState(&ObjDict_Data, Stopped); // Stop the node, to change the node ID etisserant@375: setNodeId(&ObjDict_Data, nodeID); // Now the CAN adress is changed etisserant@375: setState(&ObjDict_Data, Pre_operational); // Set to Pre_operational, master must boot it again etisserant@375: } etisserant@375: } etisserant@375: // Handle all MOB's at once, if a message was received pass it to the CANstack etisserant@375: if (canReceive(&m)) // a message reveived etisserant@375: canDispatch(&ObjDict_Data, &m); // process it etisserant@375: else etisserant@375: { etisserant@375: // Enter sleep mode etisserant@375: #ifdef WD_SLEEP // Watchdog and Sleep etisserant@375: wdt_reset(); etisserant@375: sleep_enable(); etisserant@375: sleep_cpu(); etisserant@375: #endif // Watchdog and Sleep etisserant@375: } etisserant@375: } etisserant@375: } etisserant@375: etisserant@375: void sys_init() etisserant@375: /****************************************************************************** etisserant@375: Initialize the relays, the main states and the modbus protocol stack. etisserant@375: INPUT LOCK_STATES *lock_states etisserant@375: OUTPUT void etisserant@375: ******************************************************************************/ etisserant@375: { etisserant@375: OSCCAL = 0x43; etisserant@375: etisserant@375: PORTA = 0xFF; // Inputs (Keys, low active) with pullup etisserant@375: DDRA = 0x00; // etisserant@375: PORTB = 0xFF; // Outputs (LEDs, low active) all 1 etisserant@375: DDRB = 0xFF; // etisserant@375: PORTC = 0xFF; // 1 BCD switch with pullup etisserant@375: DDRC = 0x00; // etisserant@375: PORTD = 0x2C; // 2xCOM, unused, CAN, unused etisserant@375: DDRD = 0x2A; // All init 0 or without pullup etisserant@375: PORTE = 0x00; // Output etisserant@375: DDRE = 0x3C; // 2x not used, 2x not used etisserant@375: PORTF = 0x00; // Not used etisserant@375: DDRF = 0xFF; // All output etisserant@375: PORTG = 0x00; // Not used etisserant@375: DDRG = 0x1F; // Output for debug (only 5 pins) etisserant@375: etisserant@375: // Set timer 0 for main schedule time etisserant@375: TCCR0A |= 1 << WGM01 | 1 << CS01 | 1 << CS00;// Timer 0 CTC , Timer 0 mit CK/64 starten etisserant@375: TIMSK0 = 1 << OCIE0A; // Timer Interrupts: Timer 0 Compare etisserant@375: OCR0A = (unsigned char)(F_CPU / 64 * CYCLE_TIME/1000000 - 1); // Reloadvalue for timer 0 etisserant@375: #ifdef WD_SLEEP // Watchdog and Sleep etisserant@375: wdt_reset(); etisserant@375: wdt_enable(WDTO_15MS); // Watchdogtimer start with 16 ms timeout etisserant@375: #endif // Watchdog and Sleep etisserant@375: sei(); // Enable Interrupts etisserant@375: } etisserant@375: etisserant@375: etisserant@375: #ifdef __IAR_SYSTEMS_ICC__ etisserant@375: #pragma type_attribute = __interrupt etisserant@375: #pragma vector=TIMER0_COMP_vect etisserant@375: void TIMER0_COMP_interrupt(void) etisserant@375: #else // GCC etisserant@375: ISR(TIMER0_COMP_vect) etisserant@375: #endif // GCC etisserant@375: /****************************************************************************** etisserant@375: Interruptserviceroutine Timer 2 Compare A for the main cycle etisserant@375: ******************************************************************************/ etisserant@375: etisserant@375: { etisserant@375: timer_interrupt = 1; // Set flag etisserant@375: }