2

I am trying to communicate arduino uno with CAN bus using MCP2515 shield. Data sending and receiving both things are done. Whatever data received is displayed on LCD. CAN bus receive is done using interrupt of timer1 and LCD updating using interrupt of timer2. I think LCD does not get enough time for updating hence garbage data appears on LCD. So please suggest me solution so that I can get Both CAN communication and LCD updation. I am posting my code for your reference.

#include <Wire.h>
#include <CAN.h>
#include <Adafruit_ADS1015.h>
#include <EEPROM.h>
#include <LiquidCrystal.h>

 Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */

 int timer2_counter;
 int timer1_counter;
 uint16_t adc0;
 uint8_t adch,adcl;
 char receive;
 uint8_t dlc = 0;
 int addr = 0;
 long sensorValue = 0;         // the sensor value
 float rpm;
 uint16_t count = 0;

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

 
void setup(void) 
{
  Serial.begin(9600);
  while (!Serial);

  
  
  // initialize timer1 
  noInterrupts();           // disable all interrupts

  //---------------------TIMER_1---------------------------------------//
  TCCR1A = 0;
  TCCR1B = 0;

  //timer1_counter = 64930;   // preload timer 65536-16MHz/256/100Hz   10ms 64911
  //timer1_counter = 64911;   // preload timer 65536-16MHz/256/100Hz
  timer1_counter = 64286;   // preload timer 65536-16MHz/256/50Hz
 // timer1_counter = 34286;   // preload timer 65536-16MHz/256/2Hz
 //timer1_counter = 62411;   // preload timer 65536-16MHz/256/20Hz   100msec
  
  TCNT1 = timer1_counter;   // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt

   //Setup Timer2 to fire every 1ms
  TCCR2B = 0x00;        //Disbale Timer2 while we set it up
  TCNT2  = 130;         //Reset Timer Count to 130 out of 255
  TIFR2  = 0x00;        //Timer2 INT Flag Reg: Clear Timer Overflow Flag
  TIMSK2 = 0x01;        //Timer2 INT Reg: Timer2 Overflow Interrupt Enable
  TCCR2A = 0x00;        //Timer2 Control Reg A: Wave Gen Mode normal
  TCCR2B = 0x05;        //Timer2 Control Reg B: Timer Prescaler set to 128
  
  interrupts();             // enable all interrupts
  
  Serial.println("CAN Sender");
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("DYNALEC CONTROLS"); 
  

  ads.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
  ads.begin();
  // start the CAN bus at 500 kbps
  if (!CAN.begin(500E3)) {
    Serial.println("Starting CAN failed!");
    while (1);
  }
  
}

ISR(TIMER2_OVF_vect)
{
  
  TCNT2 = timer2_counter;   // preload time
  count++;
  if(count >= 20000)
  {
     Serial.println("LCD");
    lcd_write();
    count = 0;
  }
}

ISR(TIMER1_OVF_vect)        // interrupt service routine 
{
  TCNT1 = timer1_counter;   // preload time
 
  if(dlc == 1)
  {
    Serial.print("packet with id 0x");
    Serial.print(CAN.packetId(), HEX);
    dlc = 0;
    CAN.beginExtendedPacket(0x0C00DAEF); //(PGN-0 Priority-3 src Addr- EF Dest Addr-DA)
    CAN.write(0x00);
    CAN.write(adch);
    CAN.write(adcl);
    CAN.write(0x00);
    CAN.write(0x00);
    CAN.write(0x00);
    CAN.write(0x00);
    CAN.write(0x00);
    CAN.endPacket();
    Serial.println(" ");
  }
   else{
  CAN.beginExtendedPacket(0x0C00DAEF); //(PGN-0 Priority-3 src Addr- EF Dest Addr-DA)
  CAN.write(0xFF);
  CAN.write(adch);
  CAN.write(adcl);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.write(0xFF);
  CAN.endPacket();
  Serial.println(" ");
  }

}
//------------------------------------while_loop-------------------------------------------//
void loop(void) 
{
  //lcd_write();
  read_ads();
  read_can();
  calibration();
}
// ------------------------------lcd_write---------------------------------------------------//
void lcd_write(void)
{
  noInterrupts(); 
  
  //Serial.println("LCD");
  lcd.setCursor(0, 1);
  delay(10);
  lcd.print("RPM: ");
  lcd.print(rpm);
  delay(10);
  interrupts(); 
  
}
//--------------------------ads_read--------------------------------------------------------//
void read_ads(void)
{
  adc0 = ads.readADC_SingleEnded(0);// 10v = 64255 = 8031.875 max value speed. adjust 10v = 32127 counts.
  adc0 = adc0 * 2;
  sensorValue = adc0 - offset;
  sensorValue = sensorValue * slope;
  sensorValue = sensorValue / 10000;
  Serial.println(sensorValue);
  rpm = sensorValue * 0.125;
  Serial.println("RPM:");
  Serial.println(rpm);

  /*adch = adc0 >> 8;
  adcl = adc0 & 0x00FF;
  Serial.print("AIN0: "); Serial.println(adc0);
  Serial.println(adch);
  Serial.println(adcl);*/
}
//--------------------------------------can_read-----------------------------------------------------//
void read_can(void)
{
   // try to parse packet
  int packetSize = CAN.parsePacket();

  if (packetSize) {
    // received a packet
    Serial.print("Received ");

    if (CAN.packetExtended()) {
      Serial.print("extended ");
    }

    if (CAN.packetRtr()) {
      // Remote transmission request, packet contains no data
      Serial.print("RTR ");
    }

    Serial.print("packet with id 0x");
    Serial.print(CAN.packetId(), HEX);

    if (CAN.packetRtr()) {
      Serial.print(" and requested length ");
      Serial.println(CAN.packetDlc());
    } else {
      Serial.print(" and length ");
      Serial.println(packetSize);

      // only print packet data for non-RTR packets
      while (CAN.available()) {
        Serial.print(CAN.read(),HEX);
      }
      Serial.println();
    }
    if((CAN.packetDlc() == 3) && (CAN.packetId() == 0x3AEF))
    {
      dlc = 1;
    }

    Serial.println();
  }
}
2
  • Interrupts are difficult. You need to write your code such that you do not share resources or are protecting resources between the normal code and the interrupt code. I almost always recommend beginners to stay away from interrupts for this reason. Even seasoned programmers can find them selves in unexpected situations due to interrupts. – st2000 Nov 25 '20 at 16:49
  • To add to that: There are also things that are not well behaved inside interrupts. To take one example from your code: Serial.print("packet with id 0x"); If there's not currently enough room in Serial's transmit buffer, it will wait until there is some. However, the only way room becomes available is if another interrupt runs to take data out of it and put it into the serial peripheral. But that can't happen while you're currently servicing another interrupt. As a result, writing to Serial inside an ISR can lock up indefinitely if you fill the transmit buffer. – timemage Nov 27 '20 at 2:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.