Modbus multi-machine communication routine

Publisher:qiuxubiaoLatest update time:2015-03-19 Source: diangonKeywords:Modbus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
  Send different instructions to the slave, and the slave will perform different operations. This is just to judge the function code, which is similar to the practical serial port routine we learned earlier. Multi-machine communication is nothing more than adding a device address judgment, which is not very difficult. We found a Modbus debugging wizard. By setting parameters such as the device address, the address of the read and write registers, and the number of values, it can directly replace the serial port debugging assistant and send multiple bytes of data more conveniently, as shown in Figure 1. Let's first further analyze Modbus based on the settings and data in the figure. The data in the figure comes from the interaction between the debugging wizard and the routine we will talk about next.

Modbus Debug Wizard

Figure 1 Modbus Debug Wizard

  As shown in the figure: our USB to 485 module virtualizes COM5, baud rate 9600, no parity bit, 8 data bits, 1 stop bit, and the device address is assumed to be 1.

  When writing registers, if we want to write 01 to a register address of 0000, click "Write", and the sending instruction will appear: 01 06 00 00 00 01 48 0A. Let's analyze this frame of data, where 01 is the device address, 06 is the function code, representing the function of writing registers, followed by 00 00, which indicates the address of the register to be written, 00 01 is the data to be written, and 48 0A is the CRC check code, which is automatically calculated by the software. According to the Modbus protocol, when writing registers, after the slave successfully completes the operation of the instruction, it will directly return the instruction sent by the host, and our debugging wizard will receive a frame of data like this: 01 06 00 00 00 01 48 0A.

  Suppose we want to read registers starting from register address 0002, and the number of registers to be read is 2. Click "Read", and the send instruction will appear: 01 03 00 02 00 02 65 CB. 01 is the device address, 03 is the function code, representing the function of writing registers, 00 02 is the starting address of reading registers, and the latter 00 02 means to read the values ​​of 2 registers, and 65 CB is the CRC check. The received data is: 01 03 04 00 00 00 00 FA 33. 01 is the device address, 03 is the function code, 04 represents that the number of data bytes read later is 4, 00 00 00 00 is the data inside the registers with addresses 00 02 and 00 03, and FA 33 is the CRC check.

  It seems to be getting clearer and clearer. The so-called Modbus communication protocol is nothing more than the host sending different instructions, and the slave performs different operations according to the judgment of the instructions. Since our development board does not have as many corresponding functions as the Modbus function code, we define an array regGroup[5] in the program, which is equivalent to 5 registers. In addition, we define a sixth register to control the buzzer. By sending different instructions, we change the data of the register group or change the switch state of the buzzer. In the Modbus protocol, the address and value of the register are 16 bits, that is, 2 bytes. We default the high byte to 0x00, and the low byte is the value corresponding to the array regGroup. The addresses 0x0000 to 0x0004 correspond to the elements in the regGroup array. When we write, we display the numbers on our LCD1602 liquid crystal. For the address 0x0005, write 0x00, the buzzer will not sound, and write any other number, the buzzer will alarm. The main work of our microcontroller is to parse the data received by the serial port to perform different operations, which is mainly in the RS485.C file.

/***********************RS485.c file program source code****************************/

#include

#include

 

sbit RS485_DIR = P1^7; //RS485 direction selection pin

 

bit flagOnceTxd = 0; // Single transmission completion flag, that is, one byte is sent

bit cmdArrived = 0; //Command arrival flag, that is, receiving the command sent by the host computer

unsigned char cntRxd = 0;

unsigned char pdata bufRxd[40]; //Serial port receive buffer

 

unsigned char regGroup[5]; //Modbus register group, address is 0x00~0x04

 

extern bit flagBuzzOn;

extern void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str);

extern unsigned int GetCRC16(unsigned char *ptr, unsigned char len);

 

void ConfigUART(unsigned int baud) //Serial port configuration function, baud is the baud rate

{

    RS485_DIR = 0; //RS485 is set to receive direction

    SCON = 0x50; //Configure the serial port to mode 1

    TMOD &= 0x0F; // Clear the control bit of T1

    TMOD |= 0x20; //Configure T1 to mode 2

    TH1 = 256 - (11059200/12/32) / baud; //Calculate T1 reload value

    TL1 = TH1; //initial value equals reload value

    ET1 = 0; //Disable T1 interrupt

    ES = 1; // Enable serial port interrupt

    TR1 = 1; //Start T1

}

unsigned char UartRead(unsigned char *buf, unsigned char len) //Serial port data reading function, data receiving pointer buf, read data length len, return value is the actual read data length

{

    unsigned char i;

    

    if (len > cntRxd) //When the read length is greater than the received data length,

    {

        len = cntRxd; //The read length is set to the actual received data length

    }

    for (i=0; i

    {

        *buf = bufRxd[i];

        buf++;

    }

    cntRxd = 0; // Clear the receive counter

    

    return len; //Return the actual read length

}

void DelayX10us(unsigned char t) //Software delay function, delay time (t*10)us

{

    do {

        _nop_();

        _nop_();

        _nop_();

        _nop_();

        _nop_();

        _nop_();

        _nop_();

        _nop_();

    } while (--t);

}

void UartWrite(unsigned char *buf, unsigned char len) //Serial port data writing function, that is, serial port sending function, data pointer buf to be sent, data length len

{

    RS485_DIR = 1; //RS485 is set to send

    while (len--) //send data

    {

        flagOnceTxd = 0;

        SBUF = *buf;

        buf++;

        while (!flagOnceTxd);

    }

    DelayX10us(5); //Wait for the last stop bit to complete, the delay time is determined by the baud rate

    RS485_DIR = 0; // RS485 is set to receive

}

 

void UartDriver() //Serial port driver function, detects received commands and executes corresponding actions

{

    unsigned char i;

    unsigned char cnt;

    unsigned char len;

    unsigned char buf[30];

    unsigned char str[4];

    unsigned int crc;

    unsigned char crch, crcl;

 

    if (cmdArrived) //When a command arrives, read and process the command

    {

        cmdArrived = 0;

        len = UartRead(buf, sizeof(buf)); //Read the received command into the buffer

        if (buf[0] == 0x01) // Check the address to decide whether to respond to the command. In this case, the local address is 0x01

        {

            crc = GetCRC16(buf, len-2); //Calculate CRC check value

            crch = crc >> 8;

            crcl = crc & 0xFF;

            if ((buf[len-2] == crch) && (buf[len-1] == crcl)) //Judge whether the CRC check is correct

            {

                switch (buf[1]) //Execute operation according to function code

                {

                    case 0x03: //Read one or consecutive registers

                        if ((buf[2] == 0x00) && (buf[3] <= 0x05)) //Register address supports 0x0000~0x0005

                        {

                            if (buf[3] <= 0x04)

                            {

                                i = buf[3]; //Extract register address

                                cnt = buf[5]; //Extract the number of registers to be read

                                buf[2] = cnt*2; //The number of bytes of data to read is the number of registers*2, because the register defined by Modbus is 16 bits

                                len = 3;

                                while (cnt--)

                                {

                                    buf[len++] = 0x00; //fill the high byte of the register with 0

                                    buf[len++] = regGroup[i++]; //low byte

                                }

                            }

                            else //Address 0x05 is the buzzer status

                            {

                                buf[2] = 2; //Number of bytes to read

                                buf[3] = 0x00;

                                buf[4] = flagBuzzOn;

                                len = 5;

                            }

                            break;

                        }

                        else //When the register address is not supported, return an error code

                        {

                            buf[1] = 0x83; //Function code highest position 1

                            buf[2] = 0x02; //Set the exception code to 02-invalid address

                            len = 3;

                            break;

                        }

                        

                    case 0x06: //Write a single register

                        if ((buf[2] == 0x00) && (buf[3] <= 0x05)) //Register address supports 0x0000~0x0005

                        {

                            if (buf[3] <= 0x04)

                            {

                                i = buf[3]; //Extract register address

                                regGroup[i] = buf[5]; //Save register data

                                cnt = regGroup[i] >> 4; //Display on LCD

                                if (cnt >= 0xA)

                                    str[0] = cnt - 0xA + 'A';

                                else

                                    str[0] = cnt + '0';

                                cnt = regGroup[i] & 0x0F;

                                if (cnt >= 0xA)

                                    str[1] = cnt - 0xA + 'A';

                                else

                                    str[1] = cnt + '0';

                                str[2] = '';

                                LcdShowStr(i*3, 0, str);

                            }

                            else //Address 0x05 is the buzzer status

                            {

                                flagBuzzOn = (bit)buf[5]; //Convert register value to buzzer on/off

                            }

                            len -= 2; //length -2 to recalculate CRC and return to the original frame

                            break;

                        }

                        else //When the register address is not supported, return an error code

                        {

                            buf[1] = 0x86; //Function code highest position 1

                            buf[2] = 0x02; //Set the exception code to 02-invalid address

                            len = 3;

                            break;

                        }

                        

                    default: //Other unsupported function codes

                        buf[1] |= 0x80; //Function code highest position 1

                        buf[2] = 0x01; //Set the exception code to 01-invalid function

                        len = 3;

                        break;

                }

                crc = GetCRC16(buf, len); //Calculate CRC check value

                buf[len++] = crc >> 8; //CRC high byte

                buf[len++] = crc & 0xFF; //CRC low byte

                UartWrite(buf, len); //Send response frame

            }

        }

    }

}

[page]

void UartRxMonitor(unsigned char ms) //Serial port receiving monitoring function

{

    static unsigned char cntbkp = 0;

    static unsigned char idletmr = 0;

 

    if (cntRxd > 0) //When the receive counter is greater than zero, monitor the bus idle time

    {

        if (cntbkp != cntRxd) //Receive counter changes, that is, when data is just received, clear the idle timer

        {

            cntbkp = cntRxd;

            idletmr = 0;

        }

        else

        {

            if (idletmr < 5) //The receive counter has not changed, that is, when the bus is idle, the accumulated idle time

            {

                idletmr += ms;

                if (idletmr >= 5) //If the idle time exceeds 4 bytes of transmission time, it is considered that a frame of command has been received

                {

                    cmdArrived = 1; //Set command arrival flag

                }

            }

        }

    }

    else

    {

        cntbkp = 0;

    }

}

void InterruptUART() interrupt 4 //UART interrupt service function

{

     if (RI) // Byte received

    {

        RI = 0; //Manually clear the receive interrupt flag

        if (cntRxd < sizeof(bufRxd)) //When the receiving buffer is not exhausted,

        {

            bufRxd[cntRxd++] = SBUF; //Save the received byte and increment the counter

        }

     }

     if (TI) //bytes sent

    {

         TI = 0; //Manually clear the transmit interrupt flag

        flagOnceTxd = 1; //Set the single transmission completion flag

    }

}

/***********************lcd1602.c file program source code****************************/

#include

 

#define LCD1602_DB P0

 

sbit LCD1602_RS = P1^0;

sbit LCD1602_RW = P1^1;

sbit LCD1602_E = P1^5;

 

void LcdWaitReady() //Wait for the LCD to be ready

{

    unsigned char sta;

    

    LCD1602_DB = 0xFF;

    LCD1602_RS = 0;

    LCD1602_RW = 1;

    do

    {

        LCD1602_E = 1;

        sta = LCD1602_DB; //Read status word

        LCD1602_E = 0;

    } while (sta & 0x80); //bit7 is equal to 1, indicating that the LCD is busy. Repeat the test until it is equal to 0.

}

void LcdWriteCmd(unsigned char cmd) //Write command function

{

    LcdWaitReady();

    LCD1602_RS = 0;

    LCD1602_RW = 0;

    LCD1602_DB = cmd;

    LCD1602_E = 1;

    LCD1602_E = 0;

}

void LcdWriteDat(unsigned char dat) //Write data function

{

    LcdWaitReady();

    LCD1602_RS = 1;

    LCD1602_RW = 0;

    LCD1602_DB = dat;

    LCD1602_E = 1;

    LCD1602_E = 0;

}

void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str) //Display string, screen starting coordinates (x, y), string pointer str

{

    unsigned char addr;

    

    //Calculate the display RAM address from the input display coordinates

    if (y == 0)

        addr = 0x00 + x; //The first line of characters starts at 0x00

    else

        addr = 0x40 + x; //The second line of characters starts at 0x40

    

    //Write the string continuously from the starting display RAM address

    LcdWriteCmd(addr | 0x80); //Write the starting address

    while (*str != '') //Continuously write string data until the end character is detected

    {

        LcdWriteDat(*str);

        str++;

    }

}

void LcdInit() //LCD initialization function

{

    LcdWriteCmd(0x38); //16*2 display, 5*7 dot matrix, 8-bit data interface

    LcdWriteCmd(0x0C); //Display on, cursor off

    LcdWriteCmd(0x06); //The text remains unchanged, the address is automatically increased by 1

    LcdWriteCmd(0x01); //Clear screen

}

   Regarding the CRC verification algorithm, if you are not specifically studying the verification algorithm itself, you don’t need to study the details of this program. The document directly provides us with the function, and we can call it directly. 

/***********************CRC16.c file program source code****************************/

unsigned int GetCRC16(unsigned char *ptr, unsigned char len)

    unsigned int index;

    unsigned char crch = 0xFF; //high CRC byte

    unsigned char crcl = 0xFF; //low CRC byte

    unsigned char code TabH[] = { //CRC high byte value table

        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  

        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  

        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  

        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,  

        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  

        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,  

        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  

        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  

        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  

        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,  

        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  

        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,  

        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  

        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,  

        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  

        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,  

        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  

        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  

        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  

        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  

        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  

        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,  

        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  

        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  

        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  

        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40  

    } ;  

    unsigned char code TabL[] = { //CRC low byte value table

        0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,  

        0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,  

        0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,  

        0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,  

        0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,  

        0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,  

        0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,  

        0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,  

        0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,  

        0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,  

        0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, ​​0xED,  

        0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,  

        0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,  

        0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,  

        0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,  

        0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,  

        0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,  

        0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,  

        0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,  

        0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,  

        0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,  

        0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,  

        0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,  

        0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,  

        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,  

        0x43, 0x83, 0x41, 0x81, 0x80, 0x40  

    } ;

 

    while (len--) //Calculate the CRC of the specified length

    {

        index = crch ^ *ptr++;

        crch = crcl ^ TabH[index];

        crcl = TabL[index];

    }

    

    return ((crch<<8) | crcl);  

}                           

/***********************main.c file program source code****************************/

void ConfigTimer0(unsigned int ms);

extern void LcdInit();

extern void ConfigUART(unsigned int baud);

extern void UartRxMonitor(unsigned char ms);

extern void UartDriver();

 

void main ()

{

    EA = 1; // Enable general interrupt

    ConfigTimer0(1); //Configure T0 timing 1ms

    ConfigUART(9600); //Configure the baud rate to 9600

    LcdInit(); //Initialize LCD

    

    while(1)

    {

        UartDriver();

    }

}

 

void ConfigTimer0(unsigned int ms) //T0 configuration function

{

    unsigned long tmp;

    

    tmp = 11059200 / 12; //Timer counting frequency

    tmp = (tmp * ms) / 1000; //Calculate the required count value

    tmp = 65536 - tmp; //Calculate the timer reload value

    tmp = tmp + 34; //Correct the error caused by interrupt response delay

    

    T0RH = (unsigned char)(tmp >> 8); //Timer reload value is split into high and low bytes

    T0RL = (unsigned char)tmp;

    TMOD &= 0xF0; // Clear the control bit of T0

    TMOD |= 0x01; //Configure T0 to mode 1

    TH0 = T0RH; //Load T0 reload value

    TL0 = T0RL;

    ET0 = 1; // Enable T0 interrupt

    TR0 = 1; //Start T0

}

void InterruptTimer0() interrupt 1 //T0 interrupt service function

{

    TH0 = T0RH; //Timer reloads the reload value

    TL0 = T0RL;

    if (flagBuzzOn) //Buzzer on or off

        BUZZ = ~BUZZ;

    else

        BUZZ = 1;

    UartRxMonitor(1); //Serial port receiving monitoring

}

Keywords:Modbus Reference address:Modbus multi-machine communication routine

Previous article:Basic Concepts of A/D and D/A
Next article:Interface circuit for 16-bit microprocessor

Recommended ReadingLatest update time:2024-11-16 16:44

Design of AC voltage peak meter based on Modbus-RTU protocol
The peak value of AC voltage refers to the maximum value (positive peak value) or minimum value (negative peak value) of AC voltage, which is a very important parameter in the industrial production process. In order to ensure the safety of electrical equipment, it is of great significance to detect the peak value
[Power Management]
MODBUS-TCP to Ethernet IP gateway connection air compressor configuration example
This case is a configuration case of using the Ethernet/IP to Modbus-TCP gateway of JM-EIP-TCP to connect Omron PLC and air compressor in industrial field. Equipment used: Omron PLC, JM-EIP-TCP gateway, Electrical connections for ETHERNET/IP ETHERNET/IP uses the standard T568B connection method
[Embedded]
MODBUS-TCP to Ethernet IP gateway connection air compressor configuration example
Ethernet in Automation: Modbus TCP and PROFINET
Ethernet solutions have excellent bandwidth and equipment cost advantages, and can be easily extended to the entire factory, connecting workshop systems and enterprise IT systems with a single network. Based on the third feature, we also began to explore the Converged Plantwide Ethernet Architecture (CPwE) in the seco
[Industrial Control]
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components
Guess you like

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号