AT90CAN128 can data receiving problems

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Friends,
I am very new to CAN bus protocol, now i am using AT90CAN128 controller to receive the can message.
I have written the source code from some example codes such a way that it will receive the CAN data and put it in to USART1.
I need to check using hyperterminal or procomm.
Can any one look into my source code?
I think the problem is in source code because i`m using ATMEl Development kit for AVR microcontrollers with CAN "DVK90CAN1". Datasheet of it is attached with this post.
I am using IAR Embedded Workbench compiler.

my source code is:

/**************************************************
* Description:
* Copyright 1996 -2005 IAR Systems. All rights reserved.
* $Revision: 1.1 $
**************************************************/
#include 
#include 

char datas[8];
int mob_number;

////// USART INITIALIZATION //////
void USART1_Init()
{
  UCSR1A=0X00;
  UCSR1B=0XD8;
  UCSR1C=0X06;
  UBRR1H=0X00;
  UBRR1L=0X67;
}

////// CAN INITIALIZATION //////
void can_init(void)
{
  CANGCON=0X80;   // Abort request
  while((CANGSTA & 0X04) == 0X04);    // To check if ENFG bit has been cleared.
  CANGIE=0XB0;   // Alternate way is enable RX,TX and all can interrupt
  
  CANEN1=0X00;   // Enable MOB0
  CANEN2=0X01;
  CANIE2=0XFF;   // Enable Mob0 to Mob7
  CANIE1=0XFF;   // Enable Mob8 to Mob15
  
  CANBT1=0X06;   // Set baud rate to 250kb
  CANBT2=0X08;
  CANBT3=0X48;
  
  for(mob_number = 0; mob_number < 15; mob_number++)
  {
    CANPAGE = 1<< 4;   // Select Mob0
    CANCDMOB = 0X00;   // Disable all transmission and reception
    CANSTMOB=0X00;
  }
  
  CANIDM1 = 0X00;   // Clear mask, let all IDs pass
  CANIDM2 = 0X00;
  CANIDM3 = 0X00;
  CANIDM4 = 0X00;
  
  CANGCON = 0X02;   // Enable CAN
  
  while((CANGSTA & 0X04) != 0X04);   // Wait until CAN bus being enabled
}

////// USART TRANSMIT //////
void USART1_Transmit(unsigned char data1)
{
  /* wait for empty transmit buffer */ 
  while(!(UCSR1A & (1<<UDRE1)))
  ;
  /* Put the data into buffer, sends the data */
  UDR1=data1;
}

void USART1_Transmit_string(char *str)
{
  while(*str!='\0')
    USART1_Transmit(*str++);
}

////// CAN RECEIVE //////
void can_rx(void)
{
  CANPAGE = 1<<4;   // select mob0
  CANCDMOB = 0X80;   // enable reception
}

void can_rx_inter(void)
{
  int i;
  if((CANSTMOB & 0X20) == 0X20)   // Check if RXOK flag has been set
  {
    CANSTMOB &= 0XDF;   // Clear RXOK flag
    for(i=0;i<8;i++)
    {
      datas[i] = CANMSG;   // Move data received
    }
    USART1_Transmit_string("datas[]");
  }
}

void main(void)
{
  can_init();
  USART1_Init();
  
  while(1)
  {
    can_rx();
    can_rx_inter();
  }
}

$ Fixed CODE tags - JS $

The incoming can message baud rate is 250kbaud.
I want to receive the CAN data and i need to send it through USART using AT90CAN128.
Please any one help me out.
I would be very thankful if you do mu needy.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In can_init() this is not correct:

  CANEN1=0X00;   // Enable MOB0
  CANEN2=0X01;

Look in the data sheet section 19.10.5 CAN Enable MOb Registers - CANEN2 and CANEN1. The “Read/Write” under the drawing shows all these bits as R, for Read only. Your code cannot write these registers. These registers start out with all bits are zero after initialization. Then after you start a CAN command by setting CANPAGE then writing the CANCDMOB command bits, the CAN hardware automatically sets the MOb bit in the CANEN2 or CANEN1 register. When this CAN command completes (CANSTMOB TXOK or RXOK) or when this CAN command is disabled, the CAN hardware automatically clears the MOb bit in the CANEN2 or CANEN1 register. You need to read the CANEN2 or CANEN1 register too find out if a MOb is busy or not busy before you use the MOb for a new command.

There are other CAN Read only registers and some CAN registers that may only have a few Read only bits. Pay close attention to your data sheet and you will have a better understanding of how the CAN hardware works.

In can_init() this:

  CANGCON=0X80;   // Abort request

makes no sense. The most important operation is clearing the CANGCON.ENASTB bit. Setting the CANGCON.ABRQ bit is meaningless when you are clearing ENASTB and disabling the entire CAN controller.

The most reliable method of initializing the CAN hardware is to set the CANGCON.SWRES bit. When you look at the data sheet “Read/Write” under the drawing also look at the “Initial Value”. When you use SWRES all the General registers assume their initial values shown in the data sheet. Notice, none of the MOb registers have any “Initial Value”, so any MOb registers must be manually initialized/set before use.

In can_init() this:

  CANIDM1 = 0X00;   // Clear mask, let all IDs pass
  CANIDM2 = 0X00;
  CANIDM3 = 0X00;
  CANIDM4 = 0X00;

writes MOb registers that require setting CANPAGE first. Your last CANPAGE value was in the for (mob_number) loop, so CANPAGE is set a value of 14 when you write these CANIDM registers. I do not think this was you intended to do.

In can_rx() this:

  CANPAGE = 1<<4;   // select mob0

actually selects MOb number 1, not MOb number 0. See the data sheet.

In can_rx_inter() you use CANSTMOB (a MOb register) and never set CANPAGE first. Since this is an ISR you have no idea which MOb you might be reading or writing. When you change CANPAGE in an ISR, you must first save the MOb number (CANPAGE value) when you first enter the ISR code and then restore this CANPAGE value last before exiting the ISR code. This prevents the ISR execution from corrupting the CANPAGE value in other non-ISR code.

The CANGIE register enabled both ENRX and ENTX, yet your ISR code does not check for the CANSTMOB TXOK or RXOK bits to tell what type of CAN operation happened. If you really want a can_rx_inter() ISR, then do not set the CANGIE.ENTX bit. When you set ENRX and ENTX this ISR will respond to both CAN Rx and CAN Tx completed operations.

You have USART output code in your can_rx_inter() ISR code. This is really bad. The long wait for the USART to buffer individual characters at the USART baud rate will destroy the can_rx_inter() code ISR availability, This alone may cause bugs in your code. To fix this set a volatile global flag in the ISR, detect when this flag is set in main(), then clear the volatile global flag, and do your USART output in main().

Look at this tutorial. It also has some example code:
https://www.avrfreaks.net/index.p...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Friend,

Thanks for your effort.
i am using the following things.

External Oscillator: 8Mhz Crystal Oscillator
AT90CAN128 AVR development board : dvk90CAN1 (datasheet attached above)
Compiler : IAR Embedded Workbench
CAN Baud rate : 250kbits/sec
CAN DATA : 4 BYTES (MAX 8 BYTES)
USART1 baud : 9600

I wand to read CAN data from the "ON GRID INVERTER". The "CAN Addressing" details of "ON GRID INVERTER" is attached here.

I made all changes what you suggested me.

Now, the Receive LED for CAN data & Transmit LED for RS232 on development board is glowing but i`m not able to receive the data on procomm or hyperterminal.

The following code i made as per your advise:

/**************************************************
* Description:
* Copyright 1996 -2005 IAR Systems. All rights reserved.
* $Revision: 1.1 $
**************************************************/
#include 
#include 

#define   OFF         0
#define   ON          1

char datas[8];
unsigned char rx0end;

////// USART INITIALIZATION //////
void USART1_Init()
{
  UCSR1A=0X00;
  UCSR1B=0XD8;  // Rx & Tx complete Interrupt enable, Receiver & Transmitter Enable
  UCSR1C=0X06;  // 8-bit data
  UBRR1H=0X00;
  UBRR1L=0X33;  // baud rate - 9600bps
}

////// CAN INITIALIZATION //////
void can_init(void)
{
  unsigned char mob;
  
  CANGCON = (1<<SWRES);
  
  for(mob=0; mob<15; mob++)
  {
    CANPAGE = (mob<<MOBNB0);
    CANCDMOB = 0;
    CANSTMOB = 0;
  }
  
  CANBT1 = 0X02;
  CANBT2 = 0X0C;
  CANBT3 = 0X37;
  
  CANGIE = (1<<ENIT) | (1<<ENRX);
  
  CANIE2 = 0XFF;
  CANIE1 = 0X7F;
  
  CANGCON = (1<<ENASTB);
}

////// USART TRANSMIT //////
void USART1_Transmit(unsigned char data1)
{
  /* wait for empty transmit buffer */
  while(!(UCSR1A & (1<<UDRE1)))
  ;
  /* Put the data into buffer, sends the data */
  UDR1=data1;
}

void USART1_Transmit_string(char *str)
{
  while(*str!='\0')
    USART1_Transmit(*str++);
}

////// CAN RECEIVE //////
void can_rx(void)
{
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC = 0 ENABLED
  CANCDMOB = 0X80;   // enable reception
}

void can_rx_inter(void)
{
  int i;
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC =0 ENABLED
  
  if((CANSTMOB & 0X20) == 0X20)   // Check if RXOK flag has been set
  {
    CANSTMOB &= 0XDF;   // Clear RXOK flag
    for(i=0;i<8;i++)
    {
      datas[i] = CANMSG;   // Move data received
    }
    rx0end=ON;
  }
}

void main(void)
{
  can_init();
  USART1_Init();
  rx0end=ON;
  
  while(1)
  {
    can_rx();
    can_rx_inter();
    if(rx0end==ON)
    {
      rx0end=OFF;
      USART1_Transmit_string("datas[]");
    }
  }
}

Now also i am not able to receive the CAN data and send it through UART1.

Can you please send me your source code as per our requirements?
I would be very thankful if you do my needy.

Thanks for your time and consideration.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please use the CODE button when posting code. I have fixed both of the above for you.

Attachment(s): 

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks John. Maybe the OP will notice this time :).

can3791 wrote:
Now, the Receive LED for CAN data & Transmit LED for RS232 on development board is glowing but i`m not able to receive the data on procomm or hyperterminal.
Personally I never found Hyperterminal to be reliable. This one has always worked for me:
https://www.avrfreaks.net/index.p...

First make a test program just for the USART code with no CAN code just filling in test values to the datas[8] array. Get this to work first all by itself. Send some test RS-232 messages to the PC. This involves the dvk90CAN1 on board RS-232 level converter, how you set it all up and the PC data cable must all be correct.

After you are confident this works, then add the CAN software. The reason I'm saying this is your

can3791 wrote:
...i`m not able to receive the data on procomm or hyperterminal.
does not make it clear if your RS-232 serial data is working or not working. Debugging should be methodical as possible, or if not the complexity of multiple unknowns will drive you crazy.

In theory both variables rx0end and datas[8] should be declared as volatile. Some compilers do not “appear” to require this, but when exchanging data between ISR code and non-ISR code variables, the volatile declaration should make sure the compiler generates correct code. Some compilers will not generate correct code unless the volatile declaration is used. For example if this was the WinAVR/AVRGCC compiler then the volatile declaration is required if you want your code to work at all.

volatile unsigned char datas[8];
volatile unsigned char rx0end;

Consider my choice to make datas[8] unsigned. I only changed this for you to consider if you want signed or unsigned values in your CAN bus data.

Is your AVR CKDIV8 fuse programmed or not programmed?

What is the value of your CLKPR register?

If CLKPR is not set to zero, your 8 MHz clock will be divided and your CAN baud rate selection will not work. If CKDIV8 is programmed your CLKPR will not be zero. These will also cause problems for your USART baud rate setup.

Your specification has incorrect information:

specification wrote:
Normal CAN-bus protocol will be used, which defines ID as 11 bit. In normal CAN bus protocol there is 2048 possible identifiers.
Actually this not normal, it is Bosch specification CAN V2.0 part A. Bosch specifies the seven most significant bits of a CAN identifier may not all be one recessive values. This means any 11 bit ID larger then 0x7EF is not allowed. So, there are actually only 2032 possible identifiers. I only found this in your document when trying to figure out if you were using 11 bit or using 29 bit IDs (I did not read all of your document). In CAN V2.0 part B the 29 bit ID maximum value is 0x1FBFFFFF.

You are missing required MOb 0 register setup values. See this example:

////// CAN RECEIVE //////
void can_rx(void)
{
  unsigned int set_id_11f;    // CAN ID
  unsigned int set_id_mask_11f;    // CAN ID mask, 0=force match, 1=normal compare match

  set_id_11f = 0x???;    // put your ID value here, 0x000 to 0x7EF range value

  set_id_mask_11f = 0x7FF;    // Match all ID bits with what is in CANIDT
//  set_id_mask_11f = 0x000;    // This forces all ID bits to Rx and ignores CANIDT

  CANPAGE = (0 << MOBNB0);   // select mob0, AINC = 0 ENABLED

  CANIDT1 = (unsigned char) (set_id_11f >> 3); // Set 11 bit format ID
  CANIDT2 = (unsigned char) (set_id_11f << 5);
  CANIDT3 = 0x00;
  CANIDT4 = (0 << RTRTAG);    // CAN Data Frame

  CANIDM1 = (unsigned char) (set_id_mask_11f >> 3); // Set 11 bit format ID mask
  CANIDM2 = (unsigned char) (set_id_mask_11f << 5);
  CANIDM3 = 0x00;
  CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK);    // Rx only Data Frame 11 bit IDs

  CANCDMOB = 0X88;   // enable reception expecting 8 CANMSG bytes
}

Because the appropriate CANIDM bits are all set to a one value, you will only Rx the ID you saved in the CANIDT registers and since CANIDT4.RTRTAG is zero it will be a CAN Data Frame with CANMSG bytes. To keep this simple I did not pass the ID and ID mask values to the can_rx() function and I do not know what CAN ID value you want to Rx. This is all easy for you to change. I guessed you are expecting 8 CANMSG bytes because you are not checking the CANCDMOB.DLC value after the CANSTMOB.RXOK and your debug is always printing all 8 CANMSG bytes. In can_rx_inter() after CANSTMOB.RXOK is set, you may read the CANCDMOB.DLC value to find out how many CANMSG bytes were actually received.

You failed to save then restore CANPAGE in the can_rx_inter() code. This does not break your program code simply because you are only ever using MOb 0. You need to add this if you ever intend to use more than this one single MOb 0. There are some other suggested changes:

void can_rx_inter(void)
{
  int i;
  unsigned int save_page;    // Pre-interrupt CANPAGE value storage.

  save_page = CANPAGE;    // Save the pre-interrupt CANPAGE value

  CANPAGE = (0 << MOBNB0);   // select mob0, AINC =0 ENABLED
  
  if (CANSTMOB & (1 << RXOK))   // Check if RXOK flag has been set
  {
    CANSTMOB = 0;   // Clear RXOK flag (you are not using the DLCW flag)
    for(i=0;i<8;i++)    // You could read CANCDMOB.DLC instead of using 8
    {
      datas[i] = CANMSG;   // Move data received
    }

    // The RXOK caused the CAN hardware to disable this MOb.

    CANCDMOB = 0;    // Bug fix redundant MOb disable after the RXOK.

    // Warning the 11 bit RXOK will randomize the reserved bits in the CANIDT
    // registers. If desired or needed you may zero the reserved bits here.

    rx0end=ON;
  }

  CANPAGE = save_page;    // Restore the pre-interrupt CANPAGE value.
}

can3791 wrote:
Can you please send me your source code as per our requirements?
Are you offering a paid contract to write your code :wink:?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Friend,

I made all changes what you suggested me.

Now i can receive some "Garbage" value.

My "On Grid Inverter" Baud rate is 250kbaud. Is there any problem in defining the baud rate?

Now i`m using Interrupt method for receiving data on USART. I have also checked RS-232 communication. In my below program in void rs0errstring(void) if i`m using "::ERROR1" as mentioned in comment then it will give ::ERROR1 on RS-232 successfully but if i put CANMSG data (datas[i])as per below program then it will give some "GARBAGE" value.

My Code is:

/**************************************************
* Description:
* Copyright 1996 -2005 IAR Systems. All rights reserved.
* $Revision: 1.1 $
**************************************************/
#include 
#include 

#define   OFF         0
#define   ON          1

#define   FIRSTBYTE 0x3a
#define   LASTBYTE  0x0d

char datas[8];
unsigned char rx0end;
unsigned char msovr1,msovr2,secovr1,mscnt,seccnt1,seccnt2,seccnt,msovr3;

//// Declare your global variables here
// RS-232 Comm. start
unsigned char rx0data[200],tx0data[200];
unsigned char rx0end,rx0start,rs232bccsum,stringnum;
unsigned char rx0count,tx0count,rxtx0count;
// RS-232 Comm. End

////// RS-232 Comm. start //////
/////

/////
void rs0errstring(void)
{
  unsigned char killcount=0;
  tx0data[killcount++]=datas[0];  // ':'
  tx0data[killcount++]=datas[1];  // ':'
  tx0data[killcount++]=datas[2];  // 'E'
  tx0data[killcount++]=datas[3];  // 'R'
  tx0data[killcount++]=datas[4];  // 'R'
  tx0data[killcount++]=datas[5];  // 'O'
  tx0data[killcount++]=datas[6];  // 'R'
  tx0data[killcount++]=datas[7];  // '1'
  tx0data[killcount++]=0x0d;
  tx0data[killcount++]=0x0a;
  tx0data[killcount++]=0x0d;
  rxtx0count=killcount-1;
}

/////
void address(void)
{
  rs0errstring();
  
  tx0count=0;
  UDR0=tx0data[tx0count++];
  UCSR0B_Bit5=1;
}

////// UART INITIALIZATION //////

void USART_Init0(void)
{ 

  rx0count=0;
  tx0count=0;
  rx0start=OFF;
  /* Set baud rate */
  UBRR0 = (unsigned char)51;// Baudrate register for 8 Mhz
  /* Enable receiver and transmitter */
  UCSR0C = 0x86;// USART controll and status register
  UCSR0B = (1<<4)|(1<<3);
  UCSR0B_Bit7=1;// complete intrrupt enable
}
////// Data Receive //////
#pragma vector=USART0_RX_vect
__interrupt void USART0_RX_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg,killdata;
  sreg=SREG;
  UCSR0B_Bit7=0;
  killdata=UDR0;// USART data register
  if(killdata==LASTBYTE)
  {
    rx0data[rx0count++]=killdata;
    rx0end=ON;
  }
  __enable_interrupt();
  SREG=sreg;
}
/////
#pragma vector=USART0_UDRE_vect
__interrupt void USART0_UDRE_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg;
  sreg=SREG;
  UCSR0B_Bit5=0;
  UDR0=tx0data[tx0count++];
  rxtx0count--;
  if(rxtx0count==0)
    UCSR0B_Bit6=1;
  else
    UCSR0B_Bit5=1;
  __enable_interrupt();
  SREG=sreg;
}
/////
#pragma vector=USART0_TX_vect
__interrupt void USART0_TX_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg;
  sreg=SREG;
  USART_Init0();
  UCSR0B_Bit7=1;
  __enable_interrupt();
  SREG=sreg;
}
//Timer-0 Interrupt-10ms
#pragma vector=TIMER0_OVF_vect
__interrupt void TOV0_ISR(void)
{
  mscnt+=1;
  if(mscnt>=10)
  {
    msovr1=ON;
    mscnt = 0;
    seccnt+=1;
    if(seccnt>=10)
    {
      secovr1=ON;
      seccnt = 0;
    }
  }
  TCNT0 = 0xb2;
  TCCR0A = 0x05;		//CLK/1024
  TIMSK0 = 0x01;
  __enable_interrupt();
}

////// CAN INITIALIZATION //////
void can_init(void)
{
  unsigned char mob;
  
  CANGCON = (1<<SWRES);  // Software reset request
  
  for(mob=0; mob<15; mob++)
  {
    CANPAGE = (mob<<MOBNB0);
    CANCDMOB = 0;
    CANSTMOB = 0;
  }
  
  CANBT1 = 0X02;   // Baud rate
  CANBT2 = 0X0C;   // 250 kbits/sec
  CANBT3 = 0X37;   // for 8Mhz Crystal
  
  CANGIE = (1<<ENIT) | (1<<ENRX);  // Enable RXOK interrupt
  
  CANIE2 = 0XFF;  // Enable interrupts on mob 0 to 14
  CANIE1 = 0X7F;
  
  CANGCON = (1<<ENASTB);  // Enable mode
}

////// CAN RECEIVE //////
void can_rx(void)
{
  unsigned int set_id_11f;  // CAN ID
  unsigned int set_id_mask_11f;  // CAN ID mask, 0=force match, 1=normal compare match
  
  set_id_11f = 0x100;  // ID value, 0x000 to 0x7ff range value
  set_id_mask_11f = 0x7FF;  // Match all id bits with what is in CANIDT
  // set_id_mask_11f = 0x000;  // This forces all ID bits to Rx and ignores CANIDT
  
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC = 0 ENABLED
  
  CANIDT1 = (unsigned char) (set_id_11f >> 3);  // Set 11 bit format ID
  CANIDT2 = (unsigned char) (set_id_11f << 5);
  CANIDT3 = 0X00;
  CANIDT4 = (0 << RTRTAG);  // CAN data freme
  
  CANIDM1 = (unsigned char) (set_id_mask_11f >> 3); // Set 11 bit format ID mask
  CANIDM2 = (unsigned char) (set_id_mask_11f << 5);
  CANIDM3 = 0X00;
  CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK);  // Receive only Data Frame 11 bit IDs
  
  CANCDMOB = 0X88;   // enable reception expecting 8 CANMSG bytes
}

void can_rx_inter(void)
{
  int i;
  unsigned int save_page;  // Pre-interrupt CANPAGE value storage
  
  save_page = CANPAGE;  // Save the pre-interrupt CANPAGE value
  
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC =0 ENABLED
  
  if(CANSTMOB & (1 << RXOK))   // Check if RXOK flag has been set
  {
    CANSTMOB = 0;   // Clear RXOK flag (Not using the DLCW flag)
    
    for(i=0;i<8;i++)
    {
      datas[i] = CANMSG;   // Move data received
    }
    // The RXOK caused the CAN hardware to disable this Mob.
    
    CANCDMOB = 0;  // Bug fix redundant Mob disable after the RXOK
    
    // Warning the 11 bit RXOK will randomize the reserved bits in the CANIDT
    // registers. If desired or needed you may zero the reserved bits here.
    
    rx0end=ON;  // Generate flag
    
    DDRA = 0XFF;
    PORTA = 0XFF; // ON all the led`s
  }
  
  CANPAGE = save_page;  // Restore the pre-interrupt CANPAGE value.
}

void main(void)
{
  can_init();
  // RS-232 Communication //
  USART_Init0();
  rx0end=ON;
  //Setting Timer
  TCNT0 = 0xb2;
  TCCR0A = 0x05;		//CLK/1024
  TIMSK0 = 0x01;
  TCNT1 = 0x0000;
  __enable_interrupt();
  
  while(1)
  {
    can_rx();
    can_rx_inter();
    if(rx0end==ON)
    {
      rx0end=OFF;
      address();
    }
  }
}

Now can you suggest me what is the problem.

And i`m not offering you a paid contract to write my code. I just need some help from you.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is a link to a IAR Systems white paper PDF on the volatile declaration:
http://www.iar.com/Global/Resour...

IAR itself said you need to use the volatile declaration.

Since your global datas[8] and rx0end variables are characters (assumed to be 8 bit variables in an embedded 8 bit processor compiler) you do not have any atomic access issues for each character access. Since you ignored my previous help, I had to look up the information for you. The white paper was my very first hit on a Google search for "IAR C compiler volatile".

I am trying to help you, but if you are going to ignore me, we are both wasting our time.

I do not use the IAR compiler, but I assume your #pragma and __interrupt declaration for the CAN IT interrupt vector (your can_rx_inter() code) is missing. I do not know what IAR will do if you enable an interrupt vector in the CAN hardware (CANGIE.ENIT=1) and have no corresponding CAN IT interrupt vector code to execute when the CAN IT interrupt is triggered. Some compilers crash, at least one compiler will start execution over at the begging (address zero). I do not know what IAR does in this missing interrupt code case, but I'm positive it is not what you want assuming you want a working program. I did not notice this before because I'm not an IAR user.

Please declare any global variables that are used in interrupt response code and also in non-interrupt code as volatile. Then make any required fixes for the CAN IT interrupt vector handling.

After you take care of these lets try again. Then I will look at the rest of your corrected code.

BTW, just to be clear please tell me if your USART code is working or not working (after the volatile code declarations are fixed). A simple yes or no would be good.

can3791 wrote:
And i`m not offering you a paid contract to write my code. I just need some help from you.
I was confused because I get paid to write code according to a detailed specification. I have never been asked to do this for free before. Now I understand that was not what you were really asking me to do. I couldn't resist asking :).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mike,

Thank you very much for your help.

My UART code is working correctly.

Now, after adding can software in the program i got some value on hyperterminal.

My code is:

/**************************************************
* Description:
* Copyright 1996 -2005 IAR Systems. All rights reserved.
* $Revision: 1.1 $
**************************************************/
#include 
#include 

#define   OFF         0
#define   ON          1

#define   FIRSTBYTE 0x3a
#define   LASTBYTE  0x0d

volatile unsigned char datas[8];
volatile unsigned char rx0end;
unsigned char msovr1,msovr2,secovr1,mscnt,seccnt1,seccnt2,seccnt,msovr3;

//// Declare your global variables here
// RS-232 Comm. start
volatile unsigned char rx0data[200],tx0data[200];
volatile unsigned char rx0end,rx0start,rs232bccsum,stringnum;
volatile unsigned char rx0count,tx0count,rxtx0count;
// RS-232 Comm. End

////// RS-232 Comm. start //////

/////
unsigned char asciiconv(unsigned char tempdata)
{
  if(tempdata>9)
    tempdata=tempdata+0x37;
  else
    tempdata=tempdata|0x30;
  return  tempdata;
}
/////

/////
unsigned char int2asci(unsigned int tempdata,unsigned char stringcount)
{
  unsigned char rs232ascii;
  rs232ascii=(unsigned char)((tempdata&0xf000)>>12);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=(unsigned char)((tempdata&0x0f00)>>8);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=(unsigned char)((tempdata&0x00f0)>>4);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=(unsigned char)((tempdata&0x000f)>>0);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232bccsum+=((unsigned char)((tempdata&0xff00)>>8));
  rs232bccsum+=((unsigned char)tempdata);
  return stringcount;
}
/////

/////
void rs0errstring(void)
{
  unsigned char killcount=0;
  
  killcount=int2asci(datas[0],killcount);//01
  killcount=int2asci(datas[1],killcount);//02
  killcount=int2asci(datas[2],killcount);//03
  killcount=int2asci(datas[3],killcount);//04
  killcount=int2asci(datas[4],killcount);//05
  killcount=int2asci(datas[5],killcount);//06
  killcount=int2asci(datas[6],killcount);//07
  killcount=int2asci(datas[7],killcount);//08
  tx0data[killcount++]=0x0d;
  tx0data[killcount++]=0x0a;
  tx0data[killcount++]=0x0d;
  rxtx0count=killcount-1;
}

/////
void address(void)
{
  rs0errstring();
  
  tx0count=0;
  UDR0=tx0data[tx0count++];
  UCSR0B_Bit5=1;
}

////// UART INITIALIZATION //////

void USART_Init0(void)
{ 

  rx0count=0;
  tx0count=0;
  rx0start=OFF;
  /* Set baud rate */
  UBRR0 = (unsigned char)51;// Baudrate register for 8 Mhz
  /* Enable receiver and transmitter */
  UCSR0C = 0x86;// USART controll and status register
  UCSR0B = (1<<4)|(1<<3);
  UCSR0B_Bit7=1;// complete intrrupt enable
}
////// Data Receive //////
#pragma vector=USART0_RX_vect
__interrupt void USART0_RX_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg,killdata;
  sreg=SREG;
  UCSR0B_Bit7=0;
  killdata=UDR0;// USART data register
  if(killdata==LASTBYTE)
  {
    rx0data[rx0count++]=killdata;
    rx0end=ON;
  }
  __enable_interrupt();
  SREG=sreg;
}
/////
#pragma vector=USART0_UDRE_vect
__interrupt void USART0_UDRE_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg;
  sreg=SREG;
  UCSR0B_Bit5=0;
  UDR0=tx0data[tx0count++];
  rxtx0count--;
  if(rxtx0count==0)
    UCSR0B_Bit6=1;
  else
    UCSR0B_Bit5=1;
  __enable_interrupt();
  SREG=sreg;
}
/////
#pragma vector=USART0_TX_vect
__interrupt void USART0_TX_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg;
  sreg=SREG;
  USART_Init0();
  UCSR0B_Bit7=1;
  __enable_interrupt();
  SREG=sreg;
}
//Timer-0 Interrupt-10ms
#pragma vector=TIMER0_OVF_vect
__interrupt void TOV0_ISR(void)
{
  mscnt+=1;
  if(mscnt>=10)
  {
    msovr1=ON;
    mscnt = 0;
    seccnt+=1;
    if(seccnt>=10)
    {
      secovr1=ON;
      seccnt = 0;
    }
  }
  TCNT0 = 0xb2;
  TCCR0A = 0x05;		//CLK/1024
  TIMSK0 = 0x01;
  __enable_interrupt();
}

////// CAN INITIALIZATION //////
void can_init(void)
{
  unsigned char mob;
  
  CANGCON = (1<<SWRES);  // Software reset request
  
  for(mob=0; mob<15; mob++)
  {
    CANPAGE = (mob<<MOBNB0);
    CANCDMOB = 0;
    CANSTMOB = 0;
  }
  
  CANBT1 = 0X02;   // Baud rate
  CANBT2 = 0X0C;   // 250 kbits/sec
  CANBT3 = 0X37;   // for 8Mhz Crystal
  
  CANGIE = (1<<ENIT) | (1<<ENRX);  // Enable RXOK interrupt
  
  CANIE2 = 0XFF;  // Enable interrupts on mob 0 to 14
  CANIE1 = 0X7F;
  
  CANGCON = (1<<ENASTB);  // Enable mode
}

////// CAN RECEIVE //////
void can_rx(void)
{
  unsigned int set_id_11f;  // CAN ID
  unsigned int set_id_mask_11f;  // CAN ID mask, 0=force match, 1=normal compare match
  
  set_id_11f = 0x100;  // ID value, 0x000 to 0x7ff range value
  set_id_mask_11f = 0x7FF;  // Match all id bits with what is in CANIDT
  // set_id_mask_11f = 0x000;  // This forces all ID bits to Rx and ignores CANIDT
  
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC = 0 ENABLED
  
  CANIDT1 = (unsigned char) (set_id_11f >> 3);  // Set 11 bit format ID
  CANIDT2 = (unsigned char) (set_id_11f << 5);
  CANIDT3 = 0X00;
  CANIDT4 = (0 << RTRTAG);  // CAN data freme
  
  CANIDM1 = (unsigned char) (set_id_mask_11f >> 3); // Set 11 bit format ID mask
  CANIDM2 = (unsigned char) (set_id_mask_11f << 5);
  CANIDM3 = 0X00;
  CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK);  // Receive only Data Frame 11 bit IDs
  
  CANCDMOB = 0X88;   // enable reception expecting 8 CANMSG bytes
}

void can_rx_inter(void)
{
  int i;
  unsigned int save_page;  // Pre-interrupt CANPAGE value storage
  
  save_page = CANPAGE;  // Save the pre-interrupt CANPAGE value
  
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC =0 ENABLED
  
  if(CANSTMOB & (1 << RXOK))   // Check if RXOK flag has been set
  {
    CANSTMOB = 0;   // Clear RXOK flag (Not using the DLCW flag)
    
    for(i=0;i<8;i++)
    {
      datas[i] = CANMSG;   // Move data received
    }
    // The RXOK caused the CAN hardware to disable this Mob.
    
    CANCDMOB = 0;  // Bug fix redundant Mob disable after the RXOK
    
    // Warning the 11 bit RXOK will randomize the reserved bits in the CANIDT
    // registers. If desired or needed you may zero the reserved bits here.
    
    rx0end=ON;  // Generate flag
    
    DDRA = 0XFF;
    PORTA = 0XFF; // ON all the led`s
  }
  
  CANPAGE = save_page;  // Restore the pre-interrupt CANPAGE value.
}

void main(void)
{
  can_init();
  // RS-232 Communication //
  USART_Init0();
  rx0end=ON;
  //Setting Timer
  TCNT0 = 0xb2;
  TCCR0A = 0x05;		//CLK/1024
  TIMSK0 = 0x01;
  TCNT1 = 0x0000;
  __enable_interrupt();
  
  while(1)
  {
    can_rx();
    can_rx_inter();
    if(rx0end==ON)
    {
      rx0end=OFF;
      address();
    }
  }
}

Now, please see attached pdf. As per pdf In this program i want to read can data of adress [0x100] (network L-N rms voltage for phase U and network L-N rms voltage for phase V).
and it`s range is 0-6553(.)5 Here, the voltage value is 245.5 (practically checked using multimeter) so that as per its range ON GRID INVERTER will give voltage value of 2455. and the same i can receive if i use readymade CAN to MODBUS converter.

so the string should give the voltage values between 2330 to 2450 (with multiplication of 10). But as per below string how i can identify it is right or not?

The strings which i am receiving is as below.

but here i can`t identify any voltage value near by (230 to 245).

007F00090080000900700063007900DA
007F00090080000900700063007900DA
00810009007D000900700063007900DA
008000090080000900700063007900DA
008100090081000900700063007900DA
007F00090081000900700063007900DA
007F0009007E000900700063007900DA

Now, how to resolve this strings?

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your CAN code is not working yet so your analysis of your data is not valid. This code will not work:

void main(void)
{

  ......
  ......

  while(1)
  {
    can_rx();
    can_rx_inter();
    if(rx0end==ON)
    {
      rx0end=OFF;
      address();
    }
  }
}

First you need to figure out the IAR interrupt vector for the AVR CAN IT interrupt. I looked, but I could not find the IAR interrupt vector names on the web. Use your IAR compiler documentation to find out this information, or look in the include file , or contact IAR support (see info below on what IAR vector 19 interrupt names to look for).

The can_rx_inter() code will not work if it is called from main(). It will only work if it is interrupt vector 19 (see below).

Look at the AVR data sheet section 8.1 Interrupt Vectors in AT90CAN32/64/128.

For example these IAR defined names USART0_UDRE_vect and USART0_UDRE_ISR:
#pragma vector=USART0_UDRE_vect
__interrupt void USART0_UDRE_ISR(void)
both refer to the AVR data sheet section 8.1 interrupt vector 23 – 0x002C - USART0, UDRE USART0 Data Register Empty.

You need to get these names:
#pragma vector=????_vect
__interrupt void ????_ISR(void)
that refer to the AVR data sheet section 8.1 interrupt vector 19 – 0x0024 - CANIT CAN Transfer Complete or Error. You need to fill in the correct information where I put the ???? question marks.

Whatever the correct __interrupt void ????_ISR(void) name is will replace the can_rx_inter name.

Since your current void can_rx_inter(void) code is not using the CAN IT interrupt vector 19, you are not reading any actual CAN Rx CANMSG data. You are just reading garbage values from the CANMSG register. Since you were incorrectly calling can_rx_inter() from main() it was filling in garbage CANMSG bytes into the datas[] bytes.

Next your while(1) loop is constantly setting up a new CAN Rx using can_rx() over and over again without checking for any CAN Rx task completion (since the vector 19 interrupt is not working), meaning you keep hitting the CAN hardware with redundant can_rx() commands before the CAN is able to complete any single Rx command. The CAN hardware does not operate this way and it is not possible to say what any CANMSG bytes mean when new CAN Rx commands stream in over currently executing CAN Rx commands.

This code will work:

void main(void)
{

  ......
  ......
  can_rx();    // Start the very first CAN Rx

  while(1)
  {
    if(rx0end==ON)
    {
      rx0end=OFF;
      address();
      can_rx();    // Restart a new CAN Rx
    }
  }
}

The rx0end==ON tells us the interrupt vector 19 CAN completed with a CANSTMOB.RXOK bit set and filled in the correct datas[] bytes. Because we had a RXOK, the MOb is ready to start a new CAN Rx. The RXOK automatically disabled the MOb 0 Rx, so MOb 0 needs to restart another Rx to keep receiving CAN data.

After this you should finally be getting actual CAN bus CANMSG byte values.

Just to be clear, you could setup polling of CANSTMOB for RXOK, which you almost had done, but then you would have to clear CANGIE.ENIT=0 and not use interrupt vector 19. With CANGIE.ENIT=1 set the AVR hardware will use interrupt vector 19. Without any IAR interrupt vector 19 code setup, your program will fail when the AVR hardware executes interrupt vector 19.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mike,

Thank you very much for your help.

Now, i can receive the CAN data on hyperterminal.

This is the final code:

/**************************************************
* Description:
* Copyright 1996 -2005 IAR Systems. All rights reserved.
* $Revision: 1.1 $
**************************************************/
#include 
#include 

#define   OFF         0
#define   ON          1

#define   FIRSTBYTE 0x3a
#define   LASTBYTE  0x0d

char datas[8];
unsigned char rx0end;
unsigned char msovr1,msovr2,secovr1,mscnt,seccnt1,seccnt2,seccnt,msovr3;

//// Declare your global variables here
// RS-232 Comm. start
unsigned char rx0data[200],tx0data[200];
unsigned char rx0end,rx0start,rs232bccsum,stringnum;
unsigned char rx0count,tx0count,rxtx0count;
// RS-232 Comm. End

////// RS-232 Comm. start //////
/////
unsigned char asciiconv(unsigned char tempdata)
{
  if(tempdata>9)
    tempdata=tempdata+0x37;
  else
    tempdata=tempdata|0x30;
  return  tempdata;
}
/////
/////
/*
unsigned char int2asci(unsigned int tempdata,unsigned char stringcount)
{
  unsigned char rs232ascii;
  rs232ascii=(unsigned char)((tempdata&0xf000)>>12);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=(unsigned char)((tempdata&0x0f00)>>8);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=(unsigned char)((tempdata&0x00f0)>>4);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=(unsigned char)((tempdata&0x000f)>>0);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232bccsum+=((unsigned char)((tempdata&0xff00)>>8));
  rs232bccsum+=((unsigned char)tempdata);
  return stringcount;
}
*/

/////
unsigned char ch2asci(unsigned char tempdata,unsigned char stringcount)
{
  unsigned char rs232ascii;
  rs232ascii=(tempdata&0xf0)>>4;
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=tempdata&0x0f;
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232bccsum+=tempdata;
  return stringcount;
}

/////
void rs0errstring(void)
{
  unsigned char killcount=0;
  
  killcount=ch2asci(datas[0],killcount);//01
  killcount=ch2asci(datas[1],killcount);//02
  killcount=ch2asci(datas[2],killcount);//03
  killcount=ch2asci(datas[3],killcount);//04
  killcount=ch2asci(datas[4],killcount);//05
  killcount=ch2asci(datas[5],killcount);//06
  killcount=ch2asci(datas[6],killcount);//07
  killcount=ch2asci(datas[7],killcount);//08
  tx0data[killcount++]=0x0d;
  tx0data[killcount++]=0x0a;
  tx0data[killcount++]=0x0d;
  rxtx0count=killcount-1;
}

/////
void address(void)
{
  rs0errstring();
  
  tx0count=0;
  UDR0=tx0data[tx0count++];
  UCSR0B_Bit5=1;
}

////// UART INITIALIZATION //////

void USART_Init0(void)
{ 

  rx0count=0;
  tx0count=0;
  rx0start=OFF;
  /* Set baud rate */
  UBRR0 = (unsigned char)51;// Baudrate register for 8 Mhz
  /* Enable receiver and transmitter */
  UCSR0C = 0x86;// USART controll and status register
  UCSR0B = (1<<4)|(1<<3);
  UCSR0B_Bit7=1;// complete intrrupt enable
}
////// Data Receive //////
#pragma vector=USART0_RX_vect
__interrupt void USART0_RX_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg,killdata;
  sreg=SREG;
  UCSR0B_Bit7=0;
  killdata=UDR0;// USART data register
  if(killdata==LASTBYTE)
  {
    rx0data[rx0count++]=killdata;
    rx0end=ON;
  }
  __enable_interrupt();
  SREG=sreg;
}
/////
#pragma vector=USART0_UDRE_vect
__interrupt void USART0_UDRE_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg;
  sreg=SREG;
  UCSR0B_Bit5=0;
  UDR0=tx0data[tx0count++];
  rxtx0count--;
  if(rxtx0count==0)
    UCSR0B_Bit6=1;
  else
    UCSR0B_Bit5=1;
  __enable_interrupt();
  SREG=sreg;
}
/////
#pragma vector=USART0_TX_vect
__interrupt void USART0_TX_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg;
  sreg=SREG;
  USART_Init0();
  UCSR0B_Bit7=1;
  __enable_interrupt();
  SREG=sreg;
}
//Timer-0 Interrupt-10ms
#pragma vector=TIMER0_OVF_vect
__interrupt void TOV0_ISR(void)
{
  mscnt+=1;
  if(mscnt>=10)
  {
    msovr1=ON;
    mscnt = 0;
    seccnt+=1;
    if(seccnt>=10)
    {
      secovr1=ON;
      seccnt = 0;
    }
  }
  TCNT0 = 0xb2;
  TCCR0A = 0x05;		//CLK/1024
  TIMSK0 = 0x01;
  __enable_interrupt();
}

////// CAN INITIALIZATION //////
void can_init(void)
{
  unsigned char mob;
  
  CANGCON = (1<<SWRES);  // Software reset request
  
  for(mob=0; mob<15; mob++)
  {
    CANPAGE = (mob<<MOBNB0);
    CANCDMOB = 0;
    CANSTMOB = 0;
  }
  
  CANBT1 = 0X02;   // Baud rate
  CANBT2 = 0X0C;   // 250 kbits/sec
  CANBT3 = 0X37;   // for 8Mhz Crystal
  
  CANGIE = (1<<ENIT) | (1<<ENRX);  // Enable RXOK interrupt
  
  CANIE2 = 0XFF;  // Enable interrupts on mob 0 to 14
  CANIE1 = 0X7F;
  
  CANGCON = (1<<ENASTB);  // Enable mode
}

////// CAN RECEIVE //////
void can_rx(void)
{
  unsigned int set_id_11f;  // CAN ID
  unsigned int set_id_mask_11f;  // CAN ID mask, 0=force match, 1=normal compare match
  
  set_id_11f = 0x100;  // ID value, 0x000 to 0x7ff range value
  set_id_mask_11f = 0x7FF;  // Match all id bits with what is in CANIDT
  // set_id_mask_11f = 0x000;  // This forces all ID bits to Rx and ignores CANIDT
  
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC = 0 ENABLED
  
  CANIDT1 = (unsigned char) (set_id_11f >> 3);  // Set 11 bit format ID
  CANIDT2 = (unsigned char) (set_id_11f << 5);
  CANIDT3 = 0X00;
  CANIDT4 = (0 << RTRTAG);  // CAN data freme
  
  CANIDM1 = (unsigned char) (set_id_mask_11f >> 3); // Set 11 bit format ID mask
  CANIDM2 = (unsigned char) (set_id_mask_11f << 5);
  CANIDM3 = 0X00;
  CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK);  // Receive only Data Frame 11 bit IDs
  
  CANCDMOB = 0X88;   // enable reception expecting 8 CANMSG bytes
}

void can_rx_inter(void)
{
  int i;
  unsigned int save_page;  // Pre-interrupt CANPAGE value storage
  
  save_page = CANPAGE;  // Save the pre-interrupt CANPAGE value
  
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC =0 ENABLED
  
  if(CANSTMOB & (1 << RXOK))   // Check if RXOK flag has been set
  {
    CANSTMOB = 0;   // Clear RXOK flag (Not using the DLCW flag)
    
    for(i=0;i<8;i++)
    {
      datas[i] = CANMSG;   // Move data received
    }
    // The RXOK caused the CAN hardware to disable this Mob.
    
    CANCDMOB = 0;  // Bug fix redundant Mob disable after the RXOK
    
    // Warning the 11 bit RXOK will randomize the reserved bits in the CANIDT
    // registers. If desired or needed you may zero the reserved bits here.
    
    rx0end=ON;  // Generate flag
    
    DDRA = 0XFF;
    PORTA = 0XFF; // ON all the led`s
  }
  
  CANPAGE = save_page;  // Restore the pre-interrupt CANPAGE value.
}

void main(void)
{
  can_init();
  // RS-232 Communication //
  USART_Init0();
  rx0end=ON;
  //Setting Timer
  TCNT0 = 0xb2;
  TCCR0A = 0x05;		//CLK/1024
  TIMSK0 = 0x01;
  TCNT1 = 0x0000;
  __enable_interrupt();
  
  while(1)
  {
    can_rx();
    can_rx_inter();
    if(rx0end==ON)
    {
      rx0end=OFF;
      address();
    }
  }
}

Received strings are as below.
6E096F09706379DE
69096D09706379DE
6C096B09706379DE
6E096E09706379DE
6C096B09706379DE

and it is giving correct voltage values.

Now, i want to read 77 CAN addresses and convert them into RS-232 continuously then what is the procedure?

can you give any idea (hint) to me?

Once again thank you very much for your help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mike

When i`m trying to receive more than CANID using polling method data got overlapped. So, for receiving data from more than 1 CANID interrupt method is must??

Please reply.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ike,

As per my previous post now, i want to read multiple can data and convert it in to RS-232.

For that now, i`m using Interrupt method for receiving CAN data inplace of polling method.

And i`m able to read Single CAN data (of address 0x100) using interrupt method. Code is as below.

Final Code :

/**************************************************
* Description:
* Copyright 1996 -2005 IAR Systems. All rights reserved.
* $Revision: 1.1 $
**************************************************/
#include 
#include 

#define   OFF         0
#define   ON          1

#define   FIRSTBYTE 0x3a
#define   LASTBYTE  0x0d

volatile char datas[8];
volatile unsigned char rx0end;
unsigned char msovr1,msovr2,secovr1,mscnt,seccnt1,seccnt2,seccnt,msovr3;

//// Declare your global variables here
// RS-232 Comm. start
volatile unsigned char rx0data[200],tx0data[200];
volatile unsigned char rx0end,rx0start,rs232bccsum,stringnum;
volatile unsigned char rx0count,tx0count,rxtx0count;
// RS-232 Comm. End

////// RS-232 Comm. start //////
/////
unsigned char asciiconv(unsigned char tempdata)
{
  if(tempdata>9)
    tempdata=tempdata+0x37;
  else
    tempdata=tempdata|0x30;
  return  tempdata;
}
/////
/////
/*
unsigned char int2asci(unsigned int tempdata,unsigned char stringcount)
{
  unsigned char rs232ascii;
  rs232ascii=(unsigned char)((tempdata&0xf000)>>12);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=(unsigned char)((tempdata&0x0f00)>>8);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=(unsigned char)((tempdata&0x00f0)>>4);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=(unsigned char)((tempdata&0x000f)>>0);
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232bccsum+=((unsigned char)((tempdata&0xff00)>>8));
  rs232bccsum+=((unsigned char)tempdata);
  return stringcount;
}
*/

/////
unsigned char ch2asci(unsigned char tempdata,unsigned char stringcount)
{
  unsigned char rs232ascii;
  rs232ascii=(tempdata&0xf0)>>4;
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232ascii=tempdata&0x0f;
  tx0data[stringcount++]=asciiconv(rs232ascii);
  rs232bccsum+=tempdata;
  return stringcount;
}

/////
void rs0errstring(void)
{
  unsigned char killcount=0;
  
  killcount=ch2asci(datas[0],killcount);//01
  killcount=ch2asci(datas[1],killcount);//02
  killcount=ch2asci(datas[2],killcount);//03
  killcount=ch2asci(datas[3],killcount);//04
  killcount=ch2asci(datas[4],killcount);//05
  killcount=ch2asci(datas[5],killcount);//06
  killcount=ch2asci(datas[6],killcount);//07
  killcount=ch2asci(datas[7],killcount);//08
  tx0data[killcount++]=0x0d;
  tx0data[killcount++]=0x0a;
  tx0data[killcount++]=0x0d;
  rxtx0count=killcount-1;
}

/////
void address(void)
{
  rs0errstring();
  
  tx0count=0;
  UDR0=tx0data[tx0count++];
  UCSR0B_Bit5=1;
}

////// UART INITIALIZATION //////

void USART_Init0(void)
{ 

  rx0count=0;
  tx0count=0;
  rx0start=OFF;
  /* Set baud rate */
  UBRR0 = (unsigned char)51;// Baudrate register for 8 Mhz
  /* Enable receiver and transmitter */
  UCSR0C = 0x86;// USART controll and status register
  UCSR0B = (1<<4)|(1<<3);
  UCSR0B_Bit7=1;// complete intrrupt enable
}
////// Data Receive //////
#pragma vector=USART0_RX_vect
__interrupt void USART0_RX_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg,killdata;
  sreg=SREG;
  UCSR0B_Bit7=0;
  killdata=UDR0;// USART data register
  if(killdata==LASTBYTE)
  {
    rx0data[rx0count++]=killdata;
    rx0end=ON;
  }
  __enable_interrupt();
  SREG=sreg;
}
/////
#pragma vector=USART0_UDRE_vect
__interrupt void USART0_UDRE_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg;
  sreg=SREG;
  UCSR0B_Bit5=0;
  UDR0=tx0data[tx0count++];
  rxtx0count--;
  if(rxtx0count==0)
    UCSR0B_Bit6=1;
  else
    UCSR0B_Bit5=1;
  __enable_interrupt();
  SREG=sreg;
}
/////
#pragma vector=USART0_TX_vect
__interrupt void USART0_TX_ISR(void)
{
  __disable_interrupt();
  unsigned char sreg;
  sreg=SREG;
  USART_Init0();
  UCSR0B_Bit7=1;
  __enable_interrupt();
  SREG=sreg;
}
//Timer-0 Interrupt-10ms
#pragma vector=TIMER0_OVF_vect
__interrupt void TOV0_ISR(void)
{
  mscnt+=1;
  if(mscnt>=10)
  {
    msovr1=ON;
    mscnt = 0;
    seccnt+=1;
    if(seccnt>=10)
    {
      secovr1=ON;
      seccnt = 0;
    }
  }
  TCNT0 = 0xb2;
  TCCR0A = 0x05;		//CLK/1024
  TIMSK0 = 0x01;
  __enable_interrupt();
}

////// CAN INITIALIZATION //////
void can_init(void)
{
  unsigned char mob;
  
  CANGCON = (1<<SWRES);  // Software reset request
  
  for(mob=0; mob<15; mob++)
  {
    CANPAGE = (mob<<MOBNB0);
    CANCDMOB = 0;
    CANSTMOB = 0;
  }
  
  CANBT1 = 0X02;   // Baud rate
  CANBT2 = 0X0C;   // 250 kbits/sec
  CANBT3 = 0X37;   // for 8Mhz Crystal
  
  CANGIE = (1<<ENIT) | (1<<ENRX);  // Enable RXOK interrupt
  
  CANIE2 = 0XFF;  // Enable interrupts on mob 0 to 14
  CANIE1 = 0X7F;
  
  CANGCON = (1<<ENASTB);  // Enable mode
}

////// CAN RECEIVE //////
void can_rx(void)
{
  unsigned int set_id_11f;  // CAN ID
  unsigned int set_id_mask_11f;  // CAN ID mask, 0=force match, 1=normal compare match
  
  set_id_11f = 0x100;  // ID value, 0x000 to 0x7ff range value
  set_id_mask_11f = 0x7FF;  // Match all id bits with what is in CANIDT
  // set_id_mask_11f = 0x000;  // This forces all ID bits to Rx and ignores CANIDT
  
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC = 0 ENABLED
  
  CANIDT1 = (unsigned char) (set_id_11f >> 3);  // Set 11 bit format ID
  CANIDT2 = (unsigned char) (set_id_11f << 5);
  CANIDT3 = 0X00;
  CANIDT4 = (0 << RTRTAG);  // CAN data freme
  
  CANIDM1 = (unsigned char) (set_id_mask_11f >> 3); // Set 11 bit format ID mask
  CANIDM2 = (unsigned char) (set_id_mask_11f << 5);
  CANIDM3 = 0X00;
  CANIDM4 = (1 << RTRMSK) | (1 << IDEMSK);  // Receive only Data Frame 11 bit IDs
  
  CANCDMOB = 0X88;   // enable reception expecting 8 CANMSG bytes
}


#pragma vector=CANIT_vect
__interrupt void CANIT_ISR(void)
{
  int i;
  unsigned int save_page;  // Pre-interrupt CANPAGE value storage
  __disable_interrupt();
  
  save_page = CANPAGE;  // Save the pre-interrupt CANPAGE value
  
  CANPAGE = (0 << MOBNB0);   // select mob0, AINC =0 ENABLED
  
  if(CANSTMOB & (1 << RXOK))   // Check if RXOK flag has been set
  {
    CANSTMOB = 0;   // Clear RXOK flag (Not using the DLCW flag)
    
    for(i=0;i<8;i++)
    {
      datas[i] = CANMSG;   // Move data received
    }
    // The RXOK caused the CAN hardware to disable this Mob.
    
    CANCDMOB = 0;  // Bug fix redundant Mob disable after the RXOK
    
    // Warning the 11 bit RXOK will randomize the reserved bits in the CANIDT
    // registers. If desired or needed you may zero the reserved bits here.
    
    rx0end=ON;  // Generate flag
    
    DDRA = 0XFF;
    PORTA = 0XFF; // ON all the led`s
  }
  
  CANPAGE = save_page;  // Restore the pre-interrupt CANPAGE value.
  __enable_interrupt();
  
}

void main(void)
{
  can_init();
  // RS-232 Communication //
  USART_Init0();
  rx0end=ON;
  //Setting Timer
  TCNT0 = 0xb2;
  TCCR0A = 0x05;		//CLK/1024
  TIMSK0 = 0x01;
  TCNT1 = 0x0000;
  __enable_interrupt();
  
  while(1)
  {
    can_rx();
    if(rx0end==ON)
    {
      rx0end=OFF;
      address();
    }
  }
} 

Now, I want to read CAN data of below addresses.
0x100
0x101
0x102
0x104
0x110

I have tried to read all the above data on RS-232 but it will results into "DATA OVERLAPPING".

Please help me for reading multiple CAN datas.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Deleting above.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly