Program to control a LIN interface valve

I'm trying to program a code to control a 3/2 way proportional water valve, it has a LIN interface. I use a arduino uno board to send a USART signal and transceive it into a LIN signal using a mcp2003a chip. And i need to use one of these two lin master library.

But i can't understand how to use these libraries. In the examples, they don't have an accurate pin to send the signal. which of these two libraries should i choose, and can someone explain to me how can i use the library to control the valve?
Thank you!

A guess... fnkn.begin( pin1, pin2 ); as when setting up software serial.

The Uno might not be the best board to use unless you absolutely have to. It only has one UART port and that is used by the USB connection. You might have to disconnect the LIN interface every time you upload and you wouldn't be able to monitor it. It's also not in the tested list they provide.

Which of the examples do you intend to use or start with?

I only have UNO board. I connected the board with a mcp2003b chip, that will make it unneccessary to connect the usb with the LIN interface, will it? As for the exmaples, i'm haven't decided which to use, do you have any suggestions?

The Uno only has one serial port which you'll need for the RS 485 communications. You could try software serial but I don't think I've seen anyone report it working well for this type of application. Unless you know what you're doing already, using an Uno for this is going to be really hard. The one serial the Uno has is needed for uploading the project to the board so it will cause issues.

I'm attaching the project I used to get started. It's using pin 17 which is an additional serial port on the Mega. In addition to getting the serial communications working you'll still need to format and deliver the correct payload information for the valve which will be nearly impossible unless the format's already been provided.

This isn't going to be an easy project and I think you need to prepare yourself for some hard work.

LIN_Awaken.zip (9.1 KB)

Ok, then i will get a mega board for that. So is there a commenly used format? I just want to change the position of the valve like, make it open or closed.

I have the node address of the valve, but not the format.

With just the address you can query the valve for a general response, but you'll need the Hexadecimal payload command to send and control it. That's over 40,000 potential payloads without even taking into account addresses that are less than eight octets long. If you have another device already controlling the same valve elsewhere you could use the LIN chip to sniff the traffic.

Now i get the form of the valve,
image001
it's like this, but how can i change the form to make the valve open larger?

Can you send me the link of the library used in your Awaken?

In your code it's 'lin.send(addr, buf, nBytes, proto);' , how can i change the code to send a signal that suits the need of the valve?
Thanks!

Looking at it, the valves address is 49 decimal, 0x31 Hex. You'll send a single byte followed by X number of 0x00 octets to this address to query the valves status. If the library doesn't work sending zero octets and just the address, you'll have to create a new function under lin.cpp. This is just for querying the valve.

void Lin::send2(uint8_t addr, uint8_t proto)
{
  uint8_t addrbyte = (addr&0x3f) | addrParity(addr);
  //uint8_t cksum = dataChecksum(message,nBytes,(proto==1) ? 0:addrbyte);
  serialBreak();       // Generate the low signal that exceeds 1 char.
  serial.write(0x55);  // Sync byte
  serial.write(addrbyte);  // ID byte
  //serial.write(cksum);  // checksum  
}

And then call it from your main function using:

  if (nBytes != 0) {
    lin.send(addr, buf, nBytes, proto);
  } else {
    lin.send2(addr, proto);
  }
  delay(1);

Make sure to put a delay after the lin.send command or it won't work. I think because the way the library is written.

The "NAD" and Subsystem ID values I'm not sure about. If you have a manual on the part I might be able to make more sense of it. The ID value isn't a single byte octet so it doesn't fit into a standard payload. It might be split into two bytes, but I don't know if it's high/low, little/big endian, etc.

I would try sending something like 0x49 0x3c 0x?? with the question marks being values from 0x00 to 0xFF. The third octet may be the solenoid position. It could be 0 or 1, or a range from 0 - 255 decimal??? Without more information I can only guess at the exact format.

how to send something like 0x49 0x3c 0x??
is this the addr or the Buff?
It's my first time dealing with LIN controling, i am totally unfamiliar with it.

You should start with general web searches of the protocol and how it functions. No one here can convey all that information quickly, easily, or completely.

Look at the lin awaken routine I upload and focus on the line lin.send(addr, buf, nBytes, proto);
Then trace back the elements in that for how to send the payload. It'll make more sense once you read up on the protocol and how it's formatted.

Yeah, i have done some search with the LIN protocol and i have known how it's formatted, but what confuses me is that which byte the variables each correspond to. Really appreciate for your help so far.
What i'm trying to ask is that, i changed your awaken code to send message and it is not working well, could you help me see which part of it is not correct? Or it's still that i haven't understand the format well enough?

#include "Arduino.h"
#include "lin.h"
#include <HardwareSerial.h>

Lin lin(Serial2, 17); // create LIN interface using UART2, RXD = Pin 16, TXD = Pin 17

void setup(void)
{
  Serial.begin(115200); // initialize serial communication with PC for debug

  pinMode(32, OUTPUT); // set pin 32 as output for power control of valve
  digitalWrite(32, HIGH); // set pin 32 high to power on valve

  uint8_t buf[] = {0x01, 0x02}; // payload: set valve position to 50%
  lin.send(0x31, buf, sizeof(buf), 2); // send LIN message to valve with address 0x31, using NAD 0x3C and subsystem ID 0x747

}


void loop(void)
{
  uint8_t addr = 0x31;
  uint8_t buf[8];
  uint8_t nBytes = 8;
  uint8_t proto = 2;
  uint8_t subsystem_id = 0x47; // subsystem ID = 0x747 >> 5 = 0x47
  uint8_t data1 = 0x0F;
  uint8_t data2 = 0x00;
  uint8_t padding_byte = 0xFF;
  
  // Build the message
  buf[0] = addr;  // Address
  buf[1] = (subsystem_id << 3) | 0x01;  // Subsystem ID and Message ID
  buf[2] = data1;  // Data byte 1
  buf[3] = data2;  // Data byte 2
  buf[4] = padding_byte;  // Padding byte
  buf[5] = padding_byte;  // Padding byte
  buf[6] = padding_byte;  // Padding byte
  buf[7] = padding_byte;  // Padding byte
  

  lin.send(0x31, buf, sizeof(buf), 2); // send LIN message to valve with address 0x31, using NAD 0x3C and subsystem ID 0x747

  delay(500);
}

buf[0] - buf[7] are the eight bytes of payload data, your address likely doesn't go in buf[0]. I've worked with a dome light where the address is 0x00, and the payload data is 0x20 0x00 0x50 0x64. The initial 0x00 tells all lights with an address in between addr and buf[0] to respond. That is the only case I've had where I didn't put the address in the addr value though.

So for something like "0x49 0x3c 0x??", I'm assuming 0x49 is the address. 0x3C is the first byte of payload data. Let's say you want to put an additional 0x00 after that.

addr = 0x49;
buf[0] = 0x3C;
buf[1] = 0x00;

lin.send(addr, buf, 2, 2); // addr, buffer contents, 2 bytes of data to send, protocol. 

Does that make sense?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.