Serial USART - how to write a function

Thread Starter

be80be

Joined Jul 5, 2008
2,072
How would I go about making this better my code is like this
Code:
void UART_Write(char data)
{
  while(!TRMT);
  TXREG = data;
}
Ok that works great for a byte I want send the whole 10 bit's of the ADC value.
If I changed this to write unsigned char I should be good Like this
Code:
void UART_WriteLong(unsigned char data)
{
  while(!TRMT);
  TXREG = data;
}
That didn't do as planed need to figure some changes here too
Code:
unsigned int ADCRead(unsigned char ch)
{
   if(ch>13) return 0;  //Invalid Channel

   ADCON0=0x00;

   ADCON0=(ch<<2);   //Select ADC Channel

   ADON=1;  //switch on the adc module

   GODONE=1;  //Start conversion

   while(GODONE); //wait for the conversion to finish

   ADON=0;  //switch off adc

   return ADRES;
}

 
Last edited:

AlbertHall

Joined Jun 4, 2014
12,347
You will need to send two bytes, calling the UARTWrite function twice, with the data as ADESL and ADRESH, the low and high bytes of the ADC result. You should make sure that the ADC is set up to right justify the result.

You can send the two bytes in either order depending what the receiver needs.
 

JohnInTX

Joined Jun 26, 2012
4,787
You didn't send the 2ed byte. Note that this sends the RAW BINARY ADC result. It won't be printable characters. You would have to do a binary to hex conversion on each byte to make them printable.
C:
void UART_WriteLong(unsigned char dataH, unsigned char dataL)
{
  while(!TRMT);
  TXREG = dataH;
  while(!TRMT);
  TXREG = dataL;
}

// Send it:
UART_WriteLong(ADRESH,ADRESL):
You'll get better performance if you poll TXIF instead of TRMT. TXIF = 1 means that the double buffered USART can accept another character (while the previous one is being shifted out). TRMT = 1 only after the a character has been shifted out and the UART and 1 character buffer is free - you lose the 1 character buffering.

If you are going to treat the ADC result as an unsigned integer you need to combine the two bytes of ADRESULT like this:
C:
unsigned int ADCRead(unsigned char ch)
{
   // do the read ADC then
  return (ADRESH *256 + ADRESL);  // combine the two bytes into an integer
}
Now you have to send the two bytes of the integer as two UART bytes:
C:
void sendADC (unsigned int result)
{
  while(!TXIF);
  TXREG = (unsigned char)(result / 256) ; // send upper byte  - you could say result >> 8
   while(!TXIF);
  TXREG = (unsigned char)(result % 256); // send lower byte
}
I personally am not a fan of combining into an int just for passing the value but if you have any scaling to do or want to use sprintf or itoa to format the result into printable characters, an int is the way to go.
 
Last edited:

Thread Starter

be80be

Joined Jul 5, 2008
2,072
the ADC is returning the whole 10 bits from what i read the xc8 has a built in function that holds them in the variable
return ADRES;
I tried this and its sending 3 255 which is 1023 so thats right.
Code:
void main()
{
   
  OSCCON = 0x70;
  ADCON1 = 0b00001111; //make all analog pins as digital
  CMCON = 0b00000111; //
  TRISB = 0x80; //PORTB as Input
  //nRBPU = 0;
  UART_Init(9600);
   ADCInit();

  do
  {
    ADCRead(0);   //Read Channel 0
    UART_WriteLong(ADRESH,ADRESL);
    __delay_ms(1000);
  }while(1);
}
 
Last edited:

Thread Starter

be80be

Joined Jul 5, 2008
2,072
I'm getting in realterm 00000011 111111111
So now I need to do something like figure how to no which is the high byte which going to have 6 "0" in it.
I'm not going to lie I'm lost here.
cause the lower byte could b 3 or less too.
 

joeyd999

Joined Jun 6, 2011
5,287
I'm getting in realterm 00000011 111111111
So now I need to do something like figure how to no which is the high byte which going to have 6 "0" in it.
I'm not going to lie I'm lost here.
cause the lower byte could b 3 or less too.
I always use SLIP (or a variation) to packetize serial data. Makes the link far more robust and the steam easier to parse.
 

Thread Starter

be80be

Joined Jul 5, 2008
2,072
Ok that's great i get 192 after the upper bit still got figure how to turn that into 3 255 to get 1023
Im thinking
Code:
void getADC (void)
int lowbyte = 0;
int highbyte = 0;
If (UART_Read == 219)
    {
        highByte = UART_Read;
        lowByte = UART_Read;
        if (UART_Read ==192) 
    {
        return (highByte , lowByte);
    }
       
    }
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Your data looks like because the ADC is reading right-justified.

You receive the two bytes as you sent them, say readH and readL. For your values the first byte is 3 then 255 in binary.
You have to reassemble them into an integer. The first byte is the upper byte of the integer and the second byte is the lower byte of the integer so you multiply the first by 256 then add the second:
result = readH*256 +readL. 3*256 +255 = 1023.

I don't use SLIP but joey's right, you need some sort of protocol to encapsulate the raw bytes. It is way easy to get out of sync doing things raw.

I would consider interrupt driven buffered TX and RX to eliminate timing constraints and to ensure that you don't lose characters in RX when you are busy doing something else.
 
Last edited:

Thread Starter

be80be

Joined Jul 5, 2008
2,072
It's a pain in the you no where Thanks I now got figure out the arduino side im sending it like this
"<" readH">" then the low read "<redL">"
 

Picbuster

Joined Dec 2, 2013
1,047
I used the following

int value[2]; // in .h define int value as 8 bits or use char
// in interrupt
value[0] = addresH
value[1] = addresL

// in main
UART_Write(Value[0];
UART_Write(Value[1];
or
printf("%d%d",value[0],value[1]);

// at receiver

received byteH and byteL

Received_value = byteH << 8 + byteL
printf("the value = %d",Received_value);
 
Top