Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[AVR] Appending the received UART characters using ATMEGA8 and mikroc

Status
Not open for further replies.

djc

Advanced Member level 1
Joined
Jan 27, 2013
Messages
402
Helped
3
Reputation
6
Reaction score
2
Trophy points
1,298
Location
India
Activity points
4,554
Hello all,

I am writing a program for modbus protocol using Atmega8 and mikroc. I wrote a code to receive characters and store it in an array. Now i want to make a byte of these received characters. Like Received_char[0] and Received char[1] should form a byte, as this is a slave address, and pass this 8 bit byte to a CRC function. I am facing the issue of how to append these received characters to form a byte in mikroc. Plz guide me on this. Below is the code
C:
#define FOSC 8000000//1843200// Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1


sbit LCD_RS at PORTD4_bit;
sbit LCD_EN at PORTD3_bit;
sbit LCD_D4 at PORTD5_bit;
sbit LCD_D5 at PORTD6_bit;
sbit LCD_D6 at PORTD7_bit;
sbit LCD_D7 at PORTB0_bit;

sbit LCD_RS_Direction at DDD4_bit;
sbit LCD_EN_Direction at DDD3_bit;
sbit LCD_D4_Direction at DDD5_bit;
sbit LCD_D5_Direction at DDD6_bit;
sbit LCD_D6_Direction at DDD7_bit;
sbit LCD_D7_Direction at DDB0_bit;


char Mydata[1],i=0,j=0,flag=0;
char Data[15];
int len=8;

char Received_Data[10];
unsigned char cur_crc;

unsigned short ModBus_CRC16( unsigned char * Buffer, unsigned short Length )
{
cur_crc=0xFFFF;
do
{
 unsigned int i = 8;
 cur_crc = cur_crc ^ *Buffer++;
 do
 {
 if (0x0001 & cur_crc)
 {
 cur_crc >>= 1;
cur_crc ^= 0xA001;
 }
 else
 {
 cur_crc >>= 1;
 }
 }
 while (--i);
}
while (--Length);
return cur_crc;
}

void main() {
DDRD |= 1 << PIND1;//pin1 of portD as OUTPUT
DDRD &= ~(1 << PIND0);//pin0 of portD as INPUT
PORTD |= 1 << PIND0;
Lcd_Init();
LCD_Out(1,1,"Test");
UART1_Init(9600);      // initialize UART1 module
Delay_ms(100);
    
    while(1){
        if (UART1_Data_Ready()) {        // If data is received,
        Received_Data[i] = UART1_Read(); // read the received data,
        if(Received_Data[i]=='#'){
                 j=i;
                 flag=1;
                 for(j=0;j<=i;j++){
                 UART1_Write(Received_Data[j]);
                 Delay_ms(2);
                 }
                 i=0;j=0;
                 }
                 else{i++;}
                 //i=0;
                 }
            if(flag==1){
                Mydata[0] = (Received_Data[0]-48)*10 + (Received_Data[1]-48);//Here i am processing first byte of data
                
                IntToStr(Mydata[0], Data); //Convert it into string
                UART1_Write_Text(Data);       //Display it   
                Delay_ms(1);
                
                
                ModBus_CRC16(Data,1);    //Call the function to calculate CRC

                IntToStr(cur_crc, Data); //Convert into string to display
                LCD_Out(2,1,Data); //Display it on LCD
                Delay_ms(1);
                
                UART1_Write_Text(Data); //Display it on UART
                Delay_ms(1);
                flag=0;i=0;
                 }
                 }


}
 

I presume you are trying to decode MODBUS ASCII protocol which uses two hexadecimal digits for one data byte.

The hex decoder needs to distinguish '0' to '9' and 'A' to 'F' digits, like the below quoted function from FreeMODBUS project.

C:
static          UCHAR
prvucMBCHAR2BIN( UCHAR ucCharacter )
{
    if( ( ucCharacter >= '0' ) && ( ucCharacter <= '9' ) )
    {
        return ( UCHAR )( ucCharacter - '0' );
    }
    else if( ( ucCharacter >= 'A' ) && ( ucCharacter <= 'F' ) )
    {
        return ( UCHAR )( ucCharacter - 'A' + 0x0A );
    }
    else
    {
        return 0xFF;
    }
}

Using intostr() in your code is completely wrong, it converts the input into a decimal string. You want however to send the binary data to the CRC function.
 

Hello FVM,
I used IntToStr just to display data onto LCD and UART. Yes you are right, i am trying to decode Modbus ASCII protocol. What you have suggested , itried using following code,
C:
if((Received_Data[0] >= '0') && (Received_Data[0] <= '9' )&&){Base_Char = 48;}
else if((Received_Data[0] >= 'A') && (Received_Data[0] <= 'Z')){Base_Char = 65;}

Received_Data[0] = (Received_Data[0]-Base_Char)*10;
So what it does is when any alphabet occurs, it gives numbers, means if 'A' occurs output is 0, if 'B' ocurs output is 10 and likewise.[/CODE]
 
Last edited by a moderator:

hello,

char Mydata[1];
why using a table for one char only ?
char Mydata ;

Modbus adress in ascii "00" to "FF"
try this :
Code:
 c1=Received_Data[0];
 //  'A' code=65
 if (c1>64)   Mydata=(c1-65+10)*16;  else  Mydata=(c1-48)*16;
 c1=Received_Data[1];
 if (c1>64)   MyData=Mydata+(c1-65+10);    else  MyData=Mydata+(c1-48);
 

Hello paul,
I tried this code
C:
char * result

result =  strncat(Mydata,Received_Data,2);

                 ModBus_CRC16(result,1);

                 UART1_Write_Text(cur_crc);

                 Delay_ms(1);

                 *result = 0;




Though it is working, but i am not sure in which format value is getting passed to CRC generator function. Because i am not getting an unexpected output.
 
Last edited:

you can't add Received_data to MyData
because Mydata size must be a minimum de 3 bytes
a string must allways have a zero terminateur
Code:
char MyData[3];
Mydata{0]=0; // empty string
result =  strncat(Mydata,Received_Data,2);

with Received_Data{0]="x" and with Received_Data{1]='y'
you get a string Mydata => "xy"
 

    djc

    Points: 2
    Helpful Answer Positive Rating
Hello Paul,
I did declare Mydata[5] in the declaration part. To get Mydata = "XY" we have to use "strncat()" function right. Moreover "result" is a character pointer. So that to free it can we use *result = 0? I am using it. But it's not freeing the pointer.
 

Hello,

Why do you want to free this pointer ... you can't ...
to free somme area only specific instruction are used as allocate, freemem ..etc
but you can :
result=0 ; // NULL pointer

if you do :
*result =0; // pointed value =0
the correct writing must be
*(result)=0 ; // means put a zero value at the adress pointed by result

else
you can affect this pointer to another position
example:
char Texte [20];
result=&Texte[0]; // now point to the 1rst char into Texte


i don't know , what do you want to do exactly ?
 

    djc

    Points: 2
    Helpful Answer Positive Rating
Hello paul,
I adopted your method to free up the pointer. Yes it is working now. Why i was trying to free the pointer was when i was concatenating first two bytes of the received characters and display them on serial window, as pointer was holding previous values, new values were getting displayed with previous values too. Now, with freeing up the pointer, only desired values are getting displayed. Here is the code,
C:
*(result) = 0;
                 result =  strncat(Mydata,Received_Data,2);
                                  
                 UART1_Write_Text(result);
                 Delay_ms(2);

Now issue i am facing is, after concatenating i am getting two bytes, instead of single byte. And CRC code generator function accepts only 8 bit single byte. I am stuck with that part now.

Thank you
 

hello,

i think you are following a wrong way with strcat
or you can't explain clearly your goal

Code:
  *(result) = 0;
  c1=Received_Data[0];
  if (c1>64)   *(result)=(c1-65+10)*16;  else  *(result)=(c1-48)*16;
  c1=Received_Data[1]; 
  if (c1>64)   *(result)=*(result)+(c1-65+10)*16;  else  *(result)=*(result)+(c1-48)*16;

result point on the 2 datas in Receveid_data table collapsed into only one byte
this byte represente the binary value of the 2 hexadecimal values in Receveid_data table

after you can use an index to explore all element in the Receive_data table to do the CRC calculus
you have to know the number of elements strored in the Receive_data table
or if last byte of Received_data is Zero !
you can considere this table as a string and use strlen function
Table must contain an even number of data ( +ending zero byte)

Code:
unsigned char Table;
unsigned char *result=&Table[0];

 k=strlen(Received_data);
for (index=0;index<k;index=Index+2) 
{
   k=Index>>1;
    c1=Received_Data[index];
   if (c1>64)   *(result+ k)=(c1-65+10)*16;  else  *(result+k)=(c1-48)*16;
     c1=Received_Data[index+1];
   if (c1>64)   *(result+k)=*(result+k)+(c1-65+10)*16;  else  *(result+k)=*(result+k)+(c1-48)*16;
 }
// .. Table contains the binary values of Receveid_Data ..
// .. then  do CRC calculus with  this  Table
 

Hello paul,
Sorry to bother you again. Please tell me why it is giving segmentation fault.
C:
#include <stdio.h>
char * result=0;
char c1=0;
char Received_Data[2]={'1','B'};
int main()
{
    printf("Hello World");
    printf("\n");
    *(result) = 0;
  c1=Received_Data[0];
  if (c1>64)   *(result)=(c1-65+10)*16;  else  *(result)=(c1-48)*16;
  printf("First value of result is %d",*result);
  c1=Received_Data[1];
  if (c1>64)   *(result)=*(result)+(c1-65+10)*16;  else  *(result)=*(result)+(c1-48)*16;
  printf("\n");
  printf("Second value of result is %d",*result);

    return 0;
}
 

You are writing to *result before assigning actual memory to the pointer. There is no sense in using a pointer in this place. I guess you have copied code snippets without understanding its meaning.

Instead of a pointer, you can use a simple char variable here.

You should take the time to read thoroughly through the "pointers and arrays chapter" in a C text book or tutorial.
 

    djc

    Points: 2
    Helpful Answer Positive Rating
Hello,
Thank you for pointing out my mistakes. Yes i will definitely look into the pointers and array topic thoroughly.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top