By Fernando Koyanagi Visit my Site! Follow
More by the author:About: Do you like technology? Follow my channel on Youtube and my Blog. In them I put videos every week of microcontrollers, arduinos, networks, among other subjects. More About Fernando Koyanagi »
Another subject recently suggested by my YouTube channel’s followers was CAN (Controller Area Network) protocol, which is what we’ll focus on today. It’s important to explain that CAN is a simultaneous serial communication protocol. This means the synchronism between the modules connected to the network is performed in relation to the beginning of each message sent to the bus. We’ll start off by introducing the basic concepts of the CAN protocol and perform a simple assembly with two ESP32s.
In our circuit, the ESPs can act as both Master and Slave. You can have multiple microcontrollers transmitting simultaneously, because the CAN deals with the collision of everything automatically. The source code of this project is super simple. Check it out!
Here, I have the Transceivers. There is one on each side, and they’re connected by a pair of wires. One is responsible for sending and the other for receiving data.
In CAN, the dominant bit is Zero.
Line Differential Detection Reduces Noise Sensitivity (EFI)
Standard format with 11-bit identifier
Extended format with 29-bit identifier
It is important to note that a protocol already calculates the CRC and sends ACK and EOF signals, which are things that are already done by the CAN protocol. This guarantees that the message sent won’t arrive in the wrong way. This is because if it gives a problem in the CRC (Redundant Cyclic Check or Redundancy Check), which is the same as an information check digit, it will be identified by the CRC.
It is important to note that a protocol already calculates the CRC and sends ACK and EOF signals, which are things that are already done by the CAN protocol. This guarantees that the message sent won’t arrive in the wrong way. This is because if it gives a problem in the CRC (Redundant Cyclic Check or Redundancy Check), which is the same as an information check digit, it will be identified by the CRC.
Four types of frames (frames)
The transmission and reception of data in the CAN are based on four types of frames. The frame types will be identified by variations in the control bits or even by changes in the frame writing rules for each case.
Wavelengths obtained for standard CAN with 11-bit ID
Wavelengths obtained for extended CAN with 29-bit ID
Data obtained by the logic analyzer
I show here the two options where you can install the CAN Driver Library
Arduino IDE Library Manager
Source Code: Includes and Setup ()
We’ll include the CAN library, start the serial for debugging, and start the CAN bus at 500 kbps.
#include //Inclui a biblioteca CAN
void setup() < Serial.begin(9600); //inicia a serial para debug while (!Serial); Serial.println("Transmissor CAN"); // Inicia o barramento CAN a 500 kbps if (!CAN.begin(500E3)) < Serial.println("Falha ao iniciar o controlador CAN"); //caso não seja possível iniciar o controlador while (1); >>
Using the standard CAN 2.0, we send a package. The 11-bit ID identifies the message. The data block must have up to 8 bytes. It starts the packet with ID 18 in hexadecimal. It packs 5 bytes and closes the function.
void loop() // Usando o CAN 2.0 padrão //Envia um pacote: o id tem 11 bits e identifica a mensagem (prioridade, evento) //o bloco de dados deve possuir até 8 bytes Serial.println("Enviando pacote. "); CAN.beginPacket(0x12); //id 18 em hexadecimal CAN.write('h'); //1º byte CAN.write('e'); //2º byte CAN.write('l'); //3º byte CAN.write('l'); //4º byte CAN.write('o'); //5º byte CAN.endPacket(); //encerra o pacote para envio Serial.println("Enviado."); delay(1000);
In this step, the ID has 29 bits. It starts sending 24 bits of ID and, once more, packs 5 bytes and quits.
//Usando CAN 2.0 Estendido
//Envia um pacote: o id tem 29 bits e identifica a mensagem (prioridade, evento) //o bloco de dados deve possuir até 8 bytes Serial.println("Enviando pacote estendido. "); CAN.beginExtendedPacket(0xabcdef); //id 11259375 decimal ( abcdef em hexa) = 24 bits preenchidos até aqui CAN.write('w'); //1º byte CAN.write('o'); //2º byte CAN.write('r'); //3º byte CAN.write('l'); //4º byte CAN.write('d'); //5º byte CAN.endPacket(); //encerra o pacote para envio Serial.println("Enviado."); delay(1000); >
Source Code: Includes and Setup ()
Again, we will include the CAN library, start the serial to debug, and start the CAN bus at 500 kbps. If an error occurs, this error will be printed.
#include //Inclui a biblioteca CAN
void setup() < Serial.begin(9600); //inicia a serial para debug while (!Serial); Serial.println("Receptor CAN"); // Inicia o barramento CAN a 500 kbps if (!CAN.begin(500E3)) < Serial.println("Falha ao iniciar o controlador CAN"); //caso não seja possível iniciar o controlador while (1); >>
We tried to check the size of the packet received. The CAN.parsePacket () method shows me the size of this package. So if we have a package, we’ll check whether it is extended or not.
void loop() // Tenta verificar o tamanho do acote recebido int packetSize = CAN.parsePacket(); if (packetSize) < // Se temos um pacote Serial.println("Recebido pacote. "); if (CAN.packetExtended()) < //verifica se o pacote é estendido Serial.println("Estendido"); >
Here, we check if the received packet is a data request. In this case, there is no data.
if (CAN.packetRtr()) //Verifica se o pacote é um pacote remoto (Requisição de dados), neste caso não há dados Serial.print("RTR "); >
If the received packet is a request, we indicate the requested length. We then obtain the Data Length Code (DLC), which indicates the length of the data. Finally, we indicate the length received.
Serial.print("Pacote com id 0x");
Serial.print(CAN.packetId(), HEX); if (CAN.packetRtr()) < //se o pacote recebido é de requisição, indicamos o comprimento solicitado Serial.print(" e requsitou o comprimento "); Serial.println(CAN.packetDlc()); //obtem o DLC (Data Length Code, que indica o comprimento dos dados) >else < Serial.print(" e comprimento "); // aqui somente indica o comprimento recebido Serial.println(packetSize);
We print (on the serial monitor) the data, but only if the received packet is not a request.
//Imprime os dados somente se o pacote recebido não foi de requisição
while (CAN.available()) < Serial.print((char)CAN.read()); >Serial.println(); > Serial.println(); > >