element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Ben Heck Featured Content
  • Challenges & Projects
  • element14 presents
  • element14's The Ben Heck Show
  • Ben Heck Featured Content
  • More
  • Cancel
Ben Heck Featured Content
Forum Engine Management
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Ben Heck Featured Content to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 63 replies
  • Subscribers 46 subscribers
  • Views 4138 views
  • Users 0 members are here
Related

Engine Management

jack.chaney56
jack.chaney56 over 9 years ago

Hi Ben,

I am a programmer with a very small amount of skill with circuits, and am looking to create a platform for an engine management system, using an Arduino Mega 2560. I had done a bit of the coding, when I ran into some timing issues with the built in Arduino manager, so I switched over and started using AVR Studio and a programmer to go directly to the chip itself.  The code looks like it should work ok, but now I need some additional circuits to handle the energy levels of coils and injectors (Something like IGBTs). Sensors are being run through simple dividers (no protection yet), and cam and crank inputs are through a simple comparitor

 

Let me know what you think,

Jack

  • Sign in to reply
  • Cancel

Top Replies

  • jack.chaney56
    jack.chaney56 over 7 years ago +2
    Back again... After a bit of time away seeking enlightenment (and a steady paycheck), I am ready to get back to work on my project. I have continued to play around with the code and a number of components…
  • jack.chaney56
    jack.chaney56 over 7 years ago +2
    I want to start this thing right, so the shopping list for people that want to play along at home: Raspberry Pi - version is not significant if you don't mind a slow response when using Eclipse, but 3B…
  • jack.chaney56
    jack.chaney56 over 7 years ago +2
    Start off with two things. First, I forgot (neglected) to provide instruction on how to get the compiled code onto the Nano. Fault of familiarity; having done the process so many times, I had shifted to…
Parents
  • jack.chaney56
    jack.chaney56 over 7 years ago

    Next part to keep your interest...

    Three files and a modify of the main from before.

    First one, because coding standards don't tend to be standard, I like to have a types.h file so I can work without having to think too much.

     

    /***************************************************************************************************
     All code provided is original and developed by Jack Chaney. Any similarity to code existing in
     another location or form is purely coincidental. The code presented caries with it no guarantee
     outside my statements that IT WORKED FOR ME.
     
     If, in the future this code is used in any products, please provide proper recognition for my
     efforts.
     
     Jack Chaney, 2018 Chaney Firmware
     
     This is the base include file, that pulls in all the AVR components, and standard items to make
     life easier. I also declare some items for variable naming that makes it easier for me
     to run on auto pilot.
    ***************************************************************************************************/
    #ifndef _TYPES_H
    #define _TYPES_H
    #include <stdbool.h>
    #include <stdio.h>
    #include <avr/interrupt.h>
    #include <avr/io.h>
    
    typedef unsigned char  UByte;
    typedef char           SByte;
    typedef unsigned short UWord;
    typedef short          SWord;
    typedef unsigned long  ULong;
    typedef long           SLong;
    
    /* Hardware interfacers */
    #define REG_B(a)      *((volatile UByte* const)(a))
    #define REG_W(a)      *((volatile UWord* const)(a))
    #define REG_L(a)      *((volatile ULong* const)(a))
    #define REG_Bs(a)     *((volatile SByte* const)(a))
    #define REG_Ws(a)     *((volatile SWord* const)(a))
    #define REG_Ls(a)     *((volatile SLong* const)(a))
    #define ARR_B(a)      ((UByte* const)(a))
    #define ARR_W(a)      ((UWord* const)(a))
    #define ARR_L(a)      ((ULong* const)(a))
    #define ARR_Bs(a)     ((SByte* const)(a))
    #define ARR_Ws(a)     ((SWord* const)(a))
    #define ARR_Ls(a)     ((SLong* const)(a))
    
    /* some use while(1) but I found this way compiles to fewer instructions */
    #ifdef forever
    #undef forever
    #endif
    #define forever    for(;;)
    
    /* handy bits */
    #define bit0    1
    #define bit1    2
    #define bit2    4
    #define bit3    8
    #define bit4    16
    #define bit5    32
    #define bit6    64
    #define bit7    128
    #define bit8    256
    #define bit9    512
    #define bit10    1024
    #define bit11    2048
    #define bit12    4096
    #define bit13    8192
    #define bit14    16384
    #define bit15    32768
    
    #endif
    /* end of file */

     

    The second file is a simple configuration for the timers, to provide two components; a mS time base, and a running clock.

    /***************************************************************************************************
     All code provided is original and developed by Jack Chaney. Any similarity to code existing in
     another location or form is purely coincidental. The code presented caries with it no guarantee
     outside my statements that IT WORKED FOR ME.
     
     If, in the future this code is used in any products, please provide proper recognition for my
     efforts.
     
     Jack Chaney, 2018 Chaney Firmware
    ***************************************************************************************************/
    #include "types.h"
    
    #define TIMSK0_INIT  (1<<OCIE0A)
    #define TIMSK2_INIT  0
    #define TIMSK1_INIT  (1<<TOIE1)
    #define TCCR0A_INIT  0
    #define TCCR0B_INIT  (3<<CS00)
    #define TCCR2A_INIT  0
    #define TCCR2B_INIT  (3<<CS00)
    #define TCCR1A_INIT  0
    #define TCCR1B_INIT  (2<<CS10)
    #define TCCR1C_INIT  0
    
    #define mS_UPDATE_8  250
    
    SLong ov0Tic;
    SLong ov2Tic;
    SLong ov1Tic;
    SLong getTime1(void) { ULong rVal; cli(); rVal = (ov1Tic | TCNT1); sei(); return rVal; }
    
    void initTimers(void) {
     TCCR0A = TCCR0A_INIT; TCCR0B = TCCR0B_INIT; TIMSK0 = TIMSK0_INIT;
     TCCR2A = TCCR2A_INIT; TCCR2B = TCCR2B_INIT; TIMSK2 = TIMSK2_INIT;
     TCCR1A = TCCR1A_INIT; TCCR1B = TCCR1B_INIT; TCCR1C = TCCR1C_INIT; TIMSK1 = TIMSK1_INIT;
    }
    
    ISR(TIMER0_COMPA_vect) {
     OCR0A += mS_UPDATE_8;  /* refresh for 1mS Timer Tic */
    }
    
    ISR(TIMER0_OVF_vect) { ov0Tic = (ov0Tic +   256L) & 0x07ffff00; }
    ISR(TIMER2_OVF_vect) { ov2Tic = (ov2Tic +   256L) & 0x07ffff00; }
    ISR(TIMER1_OVF_vect) { ov1Tic = (ov1Tic + 65536L) & 0x3fff0000; }
    /* end of file */

     

    The third uses the 328 interrupt inputs, which will be the cam and crank input signals.

    /***************************************************************************************************
     All code provided is original and developed by Jack Chaney. Any similarity to code existing in
     another location or form is purely coincidental. The code presented caries with it no guarantee
     outside my statements that IT WORKED FOR ME.
     
     If, in the future this code is used in any products, please provide proper recognition for my
     efforts.
     
     Jack Chaney, 2018 Chaney Firmware
    ***************************************************************************************************/
    #include "types.h"
    
    #define EICRA_INIT   (1<<ISC00)|(1<<ISC10) /* Trigger INT0 and INT1 on either edge */
    #define EIMSK_INIT   (1<<INT0)|(1<<INT1)  /* Set INT0 and INT1 active */
    
    bool isCrkRising(void) { return false; } /* these are future calibration values, but for now force the false falling edge */
    bool isCamRising(void) { return false; }
    bool isInt0Low(void) { return ((PIND & (1<<PD2)) != 0); }
    bool isInt1Low(void) { return ((PIND & (1<<PD3)) != 0); }
    
    SLong crkTime;
    SLong crkDiff;
    SLong camTIme;
    SLong camDiff;
    
    UByte toothAfterCam;
    
    void initIgn(void) {
     EICRA = EICRA_INIT;
     EIMSK = EIMSK_INIT;
     crkTime = camTime = 0;
     toothAfterCam = 0;
    }
    void rtUpdateIgn(void) { /* not used yet, but a place holder */
    }
    /**************************************************************************************************
     Crank interrupt
     Interrupt is called on both rising and falling edges of crank signal.
     - Active edge is defined as falling edge, or rising edge
        Active edge is determined as falling and signal low, or rising and signal high.
     - Primary activity for the interrupt is to determine angular velocity and cam angle
       Using high speed clock timer, obtain current time as tempTime
       and using previous time (crkTime) calculate a difference between active signals.
     - Preserve time and difference as crkTime and crkDiff
    **************************************************************************************************/
    ISR(INT0_vect) {
     SLong tmpTime = getTime1();
     SLong tmpDiff = tmpTime + (tmpTime > crkTime ? 0 : 0x40000000) - crkTime;
    /**************************************************************************************************
     Because the timer has a limit of a max value before rollover, the 32 bit number is limited
     to only using 30 bits before rollover. At rollover occurrence a factor is added to retain
     the proper value for DIFF. TIME is unaffected.
    **************************************************************************************************/
     if (isInt0Low() ^ isCrkRising()) {
    /**************************************************************************************************
      use the cam signal to locate the tooth
    **************************************************************************************************/
      toothAfterCam++;
      if (isCamDet()) {
       setCamDet(false); /* cam detected so clear the flag */
       toothAfterCam = 0;
      }
      crkTime = tmpTime;
      crkDiff = tmpDiff;
     }
    }
    /**************************************************************************************************
     Cam interrupt
    **************************************************************************************************/
    ISR(INT1_vect) {
     SLong tmpTime = getTime1();
     SLong tmpDiff = tmpTime + (tmpTime > crkTime ? 0 : 0x40000000) - camTime;
     if (isInt1Low() ^ isCamRising()) {
      setCamDet(true); /* simple signal for now */
      camTime = tmpTime;
      camDiff = tmpDiff;
     }
    }
    /* end of file */

     

    To update the main from before just have it make calls to:

    initTimers(); and initIgn();

     

    there aren't any outputs yet so if you compile and load it on the Nano, you won't get anything visible happening.  The code is presented as a starting point. Read the comments and ask questions.  Each of the sections are going to be expanded.  The cam will add conditional mechanisms for MOPAR, and VVT decoding, and crank will have a missing or filled tooth detection part as well.

     

    If this looks familiar, it's because this part hasn't changed much from my stuff before.

     

    Enjoy,

    Jack

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
Reply
  • jack.chaney56
    jack.chaney56 over 7 years ago

    Next part to keep your interest...

    Three files and a modify of the main from before.

    First one, because coding standards don't tend to be standard, I like to have a types.h file so I can work without having to think too much.

     

    /***************************************************************************************************
     All code provided is original and developed by Jack Chaney. Any similarity to code existing in
     another location or form is purely coincidental. The code presented caries with it no guarantee
     outside my statements that IT WORKED FOR ME.
     
     If, in the future this code is used in any products, please provide proper recognition for my
     efforts.
     
     Jack Chaney, 2018 Chaney Firmware
     
     This is the base include file, that pulls in all the AVR components, and standard items to make
     life easier. I also declare some items for variable naming that makes it easier for me
     to run on auto pilot.
    ***************************************************************************************************/
    #ifndef _TYPES_H
    #define _TYPES_H
    #include <stdbool.h>
    #include <stdio.h>
    #include <avr/interrupt.h>
    #include <avr/io.h>
    
    typedef unsigned char  UByte;
    typedef char           SByte;
    typedef unsigned short UWord;
    typedef short          SWord;
    typedef unsigned long  ULong;
    typedef long           SLong;
    
    /* Hardware interfacers */
    #define REG_B(a)      *((volatile UByte* const)(a))
    #define REG_W(a)      *((volatile UWord* const)(a))
    #define REG_L(a)      *((volatile ULong* const)(a))
    #define REG_Bs(a)     *((volatile SByte* const)(a))
    #define REG_Ws(a)     *((volatile SWord* const)(a))
    #define REG_Ls(a)     *((volatile SLong* const)(a))
    #define ARR_B(a)      ((UByte* const)(a))
    #define ARR_W(a)      ((UWord* const)(a))
    #define ARR_L(a)      ((ULong* const)(a))
    #define ARR_Bs(a)     ((SByte* const)(a))
    #define ARR_Ws(a)     ((SWord* const)(a))
    #define ARR_Ls(a)     ((SLong* const)(a))
    
    /* some use while(1) but I found this way compiles to fewer instructions */
    #ifdef forever
    #undef forever
    #endif
    #define forever    for(;;)
    
    /* handy bits */
    #define bit0    1
    #define bit1    2
    #define bit2    4
    #define bit3    8
    #define bit4    16
    #define bit5    32
    #define bit6    64
    #define bit7    128
    #define bit8    256
    #define bit9    512
    #define bit10    1024
    #define bit11    2048
    #define bit12    4096
    #define bit13    8192
    #define bit14    16384
    #define bit15    32768
    
    #endif
    /* end of file */

     

    The second file is a simple configuration for the timers, to provide two components; a mS time base, and a running clock.

    /***************************************************************************************************
     All code provided is original and developed by Jack Chaney. Any similarity to code existing in
     another location or form is purely coincidental. The code presented caries with it no guarantee
     outside my statements that IT WORKED FOR ME.
     
     If, in the future this code is used in any products, please provide proper recognition for my
     efforts.
     
     Jack Chaney, 2018 Chaney Firmware
    ***************************************************************************************************/
    #include "types.h"
    
    #define TIMSK0_INIT  (1<<OCIE0A)
    #define TIMSK2_INIT  0
    #define TIMSK1_INIT  (1<<TOIE1)
    #define TCCR0A_INIT  0
    #define TCCR0B_INIT  (3<<CS00)
    #define TCCR2A_INIT  0
    #define TCCR2B_INIT  (3<<CS00)
    #define TCCR1A_INIT  0
    #define TCCR1B_INIT  (2<<CS10)
    #define TCCR1C_INIT  0
    
    #define mS_UPDATE_8  250
    
    SLong ov0Tic;
    SLong ov2Tic;
    SLong ov1Tic;
    SLong getTime1(void) { ULong rVal; cli(); rVal = (ov1Tic | TCNT1); sei(); return rVal; }
    
    void initTimers(void) {
     TCCR0A = TCCR0A_INIT; TCCR0B = TCCR0B_INIT; TIMSK0 = TIMSK0_INIT;
     TCCR2A = TCCR2A_INIT; TCCR2B = TCCR2B_INIT; TIMSK2 = TIMSK2_INIT;
     TCCR1A = TCCR1A_INIT; TCCR1B = TCCR1B_INIT; TCCR1C = TCCR1C_INIT; TIMSK1 = TIMSK1_INIT;
    }
    
    ISR(TIMER0_COMPA_vect) {
     OCR0A += mS_UPDATE_8;  /* refresh for 1mS Timer Tic */
    }
    
    ISR(TIMER0_OVF_vect) { ov0Tic = (ov0Tic +   256L) & 0x07ffff00; }
    ISR(TIMER2_OVF_vect) { ov2Tic = (ov2Tic +   256L) & 0x07ffff00; }
    ISR(TIMER1_OVF_vect) { ov1Tic = (ov1Tic + 65536L) & 0x3fff0000; }
    /* end of file */

     

    The third uses the 328 interrupt inputs, which will be the cam and crank input signals.

    /***************************************************************************************************
     All code provided is original and developed by Jack Chaney. Any similarity to code existing in
     another location or form is purely coincidental. The code presented caries with it no guarantee
     outside my statements that IT WORKED FOR ME.
     
     If, in the future this code is used in any products, please provide proper recognition for my
     efforts.
     
     Jack Chaney, 2018 Chaney Firmware
    ***************************************************************************************************/
    #include "types.h"
    
    #define EICRA_INIT   (1<<ISC00)|(1<<ISC10) /* Trigger INT0 and INT1 on either edge */
    #define EIMSK_INIT   (1<<INT0)|(1<<INT1)  /* Set INT0 and INT1 active */
    
    bool isCrkRising(void) { return false; } /* these are future calibration values, but for now force the false falling edge */
    bool isCamRising(void) { return false; }
    bool isInt0Low(void) { return ((PIND & (1<<PD2)) != 0); }
    bool isInt1Low(void) { return ((PIND & (1<<PD3)) != 0); }
    
    SLong crkTime;
    SLong crkDiff;
    SLong camTIme;
    SLong camDiff;
    
    UByte toothAfterCam;
    
    void initIgn(void) {
     EICRA = EICRA_INIT;
     EIMSK = EIMSK_INIT;
     crkTime = camTime = 0;
     toothAfterCam = 0;
    }
    void rtUpdateIgn(void) { /* not used yet, but a place holder */
    }
    /**************************************************************************************************
     Crank interrupt
     Interrupt is called on both rising and falling edges of crank signal.
     - Active edge is defined as falling edge, or rising edge
        Active edge is determined as falling and signal low, or rising and signal high.
     - Primary activity for the interrupt is to determine angular velocity and cam angle
       Using high speed clock timer, obtain current time as tempTime
       and using previous time (crkTime) calculate a difference between active signals.
     - Preserve time and difference as crkTime and crkDiff
    **************************************************************************************************/
    ISR(INT0_vect) {
     SLong tmpTime = getTime1();
     SLong tmpDiff = tmpTime + (tmpTime > crkTime ? 0 : 0x40000000) - crkTime;
    /**************************************************************************************************
     Because the timer has a limit of a max value before rollover, the 32 bit number is limited
     to only using 30 bits before rollover. At rollover occurrence a factor is added to retain
     the proper value for DIFF. TIME is unaffected.
    **************************************************************************************************/
     if (isInt0Low() ^ isCrkRising()) {
    /**************************************************************************************************
      use the cam signal to locate the tooth
    **************************************************************************************************/
      toothAfterCam++;
      if (isCamDet()) {
       setCamDet(false); /* cam detected so clear the flag */
       toothAfterCam = 0;
      }
      crkTime = tmpTime;
      crkDiff = tmpDiff;
     }
    }
    /**************************************************************************************************
     Cam interrupt
    **************************************************************************************************/
    ISR(INT1_vect) {
     SLong tmpTime = getTime1();
     SLong tmpDiff = tmpTime + (tmpTime > crkTime ? 0 : 0x40000000) - camTime;
     if (isInt1Low() ^ isCamRising()) {
      setCamDet(true); /* simple signal for now */
      camTime = tmpTime;
      camDiff = tmpDiff;
     }
    }
    /* end of file */

     

    To update the main from before just have it make calls to:

    initTimers(); and initIgn();

     

    there aren't any outputs yet so if you compile and load it on the Nano, you won't get anything visible happening.  The code is presented as a starting point. Read the comments and ask questions.  Each of the sections are going to be expanded.  The cam will add conditional mechanisms for MOPAR, and VVT decoding, and crank will have a missing or filled tooth detection part as well.

     

    If this looks familiar, it's because this part hasn't changed much from my stuff before.

     

    Enjoy,

    Jack

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
Children
  • jack.chaney56
    jack.chaney56 over 7 years ago in reply to jack.chaney56

    I hate when I have a lapse in content. I was looking through the previous information and noticed a glaring problem... the code for the timers, is practically devoid of comments. I think it is because I was doing a bunch of cut and paste to provide the material in an incremental fashion (not making people drink from a fire hose). I will be sure to be mindful of not letting that happen again, and in the meantime...

     

    First the grouping of 0 and 2 are because the 328 has one 16 bit and two 8 bit timer counters. In some form of infinite wisdom, they made timer 0 an 8 bit, then timer 1 a 16 bit, but went back to an 8 bit for timer 2.  As a result, I made one of the 8 bit timers my 1mS real-time, timekeeper, so I could preserve the 16 bit counter to have special duties. To make the 8 bit work for a 1mS period, I slowed the clock so 250 tics would make for a 1mS elapsed time. Because the 16 bit clock has a wider counter space, I bumped the speed so it is able to have 2000 tics per mS.  This explains the settings for the TCCR registers. For now, I have two interrupts running, one is the timer 0 compare A, which is used for the 1mS timer. The second is the timer 1 overflow. The other timer interrupts will be called into service in a future installment

     

    There are also overflow interrupts, that enable a counter extension, providing the upper 16 bits of a 32 bit counter. For the 16 bit counter, the overflow adds 65536 or 216, and for the 8 bit counter, the overflow adds 256 or 28.

     

    Lastly, because of the speed difference, the slower 8 bit timer actually very closely synchronizes with the 16 bit by shifting the 16 bit right 3 bits. The other element is to limit the size of the counter value to 30 bits for the fast timer, and 27 bits for the slow timer.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • mp2100
    mp2100 over 7 years ago in reply to jack.chaney56

    I will admit I haven't (yet) read through in detail your posts, but, I do like your disclaimer in your code.  If I can remember next time I start a new project, I would like to copy that.  Or a reasonable facsimile.  If you don't object.

     

    1. All code provided is original and developed by Jack Chaney. Any similarity to code existing in
    2. another location or form is purely coincidental. The code presented caries with it no guarantee
    3. outside my statements that IT WORKED FOR ME.
    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • jack.chaney56
    jack.chaney56 over 7 years ago in reply to mp2100

    Hi Allen,

    Sure... I figure as soon as I post stuff here, it is going to be scooped up and used by more than a few people. The important part is actually the next that asks to remember me when you become rich and famous.  I didn't put it in the header, but I usually add a history line.

     

    History: Original Creation, as the earth was cooling.

     

    Which is to say, most of this stuff is derived from methods I have been using for a really long time.

     

    Might as well say it here, the code to this point, will make the Nano into a fully usable device with no non custom code. The Arduino interface is really nice for people learning how to use it, but really slows things down if you are trying to make things run as fast as possible.

     

    Jack

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube