Author Topic: [SOLVED]ADC result to RS232 using XC8 on an PIC16F819-How?  (Read 1101 times)

0 Members and 1 Guest are viewing this topic.

Offline djsbTopic starter

  • Frequent Contributor
  • **
  • Posts: 938
  • Country: gb
I'm struggling with the final steps of sending the results from the 10 bit ADC in a PIC16F819 to RS232. This is my code so far

Code: [Select]
/* File: Main.c
 * Author: David J S Briscoe
 * PIC: 16F819 with INTERNAL RC OSC @ 8MHz, 5v
 * Program: 04_ADC_RS232
 * Compiler: XC8 (v2.46, MPLABX X v6.20)
 * Program Version: 1.0
 *               
 * Program Description: This Program sends the DC voltage applied to AN0 through a 10K potentiometer to RS232 via pin RB2. It uses 1 channel
 * of the 10 bit A/D convertor. RB4 can be used to Receive data FROM the PC if needed. Change these pins as needed.
 * It also shows how to set up the internal pull up resistors.
 *
 * Hardware Description: Pins are connected to the RS232 PCB or a TTL to USB dongle.
 *                       A 10K potentiometer is connected to PIN A0 and ground.
 *                       Timer 2 is used as the timebase for accurate bit timing.
 *                       There is NO hardware USART on the PIC16F819 so this is why the timer is used.
 *                       
 *                       
 *
 * Notes:
 * Set XC8 C compiler to C90 mode (IN C99 MODE BY DEFAULT) in Project properties -> XC8 global options -> C standard -> APPLY.
 * This is so that itoa function can be used.
 *
 * Synopsis
 *#include <stdlib.h>
 *char * itoa (char * buf, int val, int base)
 *Description
 *The function itoa converts the contents of val into a string which is stored into buf.
 *The conversion is performed according to the radix specified in base. buf is assumed
 *to reference a buffer which has sufficient space allocated to it.
 *Example
 *#include <stdlib.h>
 *#include <stdio.h>
 *void
 *main (void)
 *{
 *  char buf[10];
 *  itoa(buf, 1234, 16);
 *  printf("The buffer holds %s\n", buf);
 *}
 *See Also
 *strtol(), utoa(), ltoa(), ultoa()
 *Return Value
 *This routine returns a copy of the buffer into which the result is written.
 *
 * Step size for 5V microcontroller
 * step size = 5V / (1024-1)
 * step size = 4.8 mV
 * Resolution = 4.8875 mV
 *
 * Step size for 3.3V microcontroller
 * step size = 3.3V / (1024-1)
 * step size = 3.2 mV
 * Resolution = 3.2258 mV
 * 10 Bit resolution
 * ADCON0 & ADCON1 are the control registers
 * ADRESL & ADRESH are the data registers.
 *
 * Try ((((ADC*2)+1) *500) +1024) /2048
 * See discussion here [url]https://forum.allaboutcircuits.com/threads/why-adc-1024-is-correct-and-adc-1023-is-just-plain-wrong.80018/[/url]
 *
 *
 *                       
 * Created February 24th, 2023
 * Last Updated: April 25th, 2024
 */

/*******************************************************************************
 Change History:
 Revision            Description
 14th March 2024     Initial code.
 25th April 2024     Corrections to ADC code and merging of Serial code.
                     RS232 RX is on RB4
RS232 TX is on RB2
 
 
*******************************************************************************/

// Configuration bits if NOT using header file 16F819_Internal.h
//#pragma config FOSC = INTOSCIO
//#pragma config WDTE = OFF
//#pragma config PWRTE = OFF
//#pragma config MCLRE = ON
//#pragma config BOREN = OFF
//#pragma config LVP = ON
//#pragma config CPD = OFF
//#pragma config WRT = OFF
//#pragma config CCPMX = RB2
//#pragma config CP = OFF
// *******************************
/*******************************************************************************
 *Includes and defines
 ******************************************************************************/
#include <stdio.h> // Needed for sprintf(see manual page 261 library functions)
#include "16F819_Internal.h" // Include header which sets  config fuses and oscillator frequency (set @ 8MHz) if using a XTAL.

#define _XTAL_FREQ      8000000UL // Needed by compiler.
#define Baudrate        9600      // Adjust as necessary.

#if (Baudrate!=9600) && (Baudrate!=19200) && (Baudrate!=38400)
 #error "Please set a valid baudrate: 9600/19200/38400"
#endif

#define OneBitDelay     ((_XTAL_FREQ/(4*(unsigned long)Baudrate))-1)

#define UART_RX         PORTBbits.RB4
#define UART_RX_DIR     TRISBbits.TRISB4
#define UART_TX         PORTBbits.RB2
#define UART_TX_DIR     TRISBbits.TRISB2

// Bit macros to avoid slow looping (We need it to be as fast as possible)
#define BIT_DELAY()     TMR2IF=0; while(!TMR2IF);
#define TX_BIT(v,n)     if(v & n){UART_TX=1;} else{UART_TX=0;} BIT_DELAY()
#define RX_BIT(v,n)     if(UART_RX){v|=n;} BIT_DELAY()

void SUART_Init(void)
{
 UART_TX = 1;                           // TX pin is high in idle state
 UART_RX_DIR = 1;                       // Input
 UART_TX_DIR = 0;                       // Output
 PR2 = OneBitDelay;                     // Load period counter
 T2CON = 0;                             // Use timer 2 as timebase
 T2CONbits.TMR2ON = 1;                  // Start timer
}

unsigned char SUART_Receive(void)
{
 unsigned char DataValue = 0;

  while(UART_RX==1);            // wait for start bit
  TMR2=OneBitDelay*2/3;         // Preload the timer with at 2/3 of a bitDelay (1/2 might sample too late with this slow mcu)
  BIT_DELAY();                  // Wait for it to expire
  BIT_DELAY();                  // Counter reset, wait for a full bit time now
  RX_BIT(DataValue,0x01);       // Unrolled loop for fastest processing
  RX_BIT(DataValue,0x02);
  RX_BIT(DataValue,0x04);
  RX_BIT(DataValue,0x08);
  RX_BIT(DataValue,0x10);
  RX_BIT(DataValue,0x20);
  RX_BIT(DataValue,0x40);
  RX_BIT(DataValue,0x80);
  return DataValue;
}

void SUART_Transmit(char DataValue)
{
  UART_TX = 0;                                           // Start
  TMR2=0;
  BIT_DELAY();
  TX_BIT(DataValue,0x01);       // Unrolled loop for fastest processing
  TX_BIT(DataValue,0x02);
  TX_BIT(DataValue,0x04);
  TX_BIT(DataValue,0x08);
  TX_BIT(DataValue,0x10);
  TX_BIT(DataValue,0x20);
  TX_BIT(DataValue,0x40);
  TX_BIT(DataValue,0x80);
  UART_TX = 1;                                           //Stop
  BIT_DELAY();
}

void SUART_Write_Text(char *text)
{
  while(*text)
    SUART_Transmit(*text++);
}

void SUART_Read_Text(char *Output, unsigned int length)
{   
  while(length--)
    *Output++ = SUART_Receive();      // Receive char
}



/*******************************************************************************
 * Function: void initMain()
 *
 * Returns: Nothing
 *
 * Description: Contains initializations for main
 *
 * Usage: initMain()
 ******************************************************************************/

void initMain()
{
   
OSCCONbits.IRCF = 0b0111; //Set the Clock to 8MHz when using internal oscillator.
                          /*
                          111 = 8 MHz (8 MHz source drives clock directly)
                          110 = 4 MHz
                          101 = 2 MHz
                          100 = 1 MHz
                          011 = 500 kHz
                          010 = 250 kHz
                          001 = 125 kHz
                          000 = 31.25 kHz (INTRC source drives clock directly)
                          Page 38 of the PIC16F819 data sheet.
                          */
ADCON1bits.PCFG = 0b0110; //See page 82 of data sheet..
   
//#define SW1_PORTB4 PORTBbits.RB4 //Wherever the compiler sees SW1_PORTB4 it substitutes PORTBbits.RB4
//#define LED_PORTB2 PORTBbits.RB2 //Wherever the compiler sees LED_PORTB2 it substitutes PORTBbits.RB2

TRISBbits.TRISB2 = 0;      //Ensure RB2 is an output pin (LED).
TRISBbits.TRISB4 = 1;      //Ensure RB4 is an input pin (Switch).
PORTA = 0x00;              //Clear Port A.
PORTB = 0x00;              //Clear Port B.
   
nRBPU = 0;                 //Enable ALL PORTB internal pull up resistor.
                           //If you comment this line out you need to connect a
                           //10K resistor between +5V and your INPUT pin.
                           // 16F819 can NOT ENABLE INDIVIDUAL PULL UPS ON PORT B.
// Configure the ADC
ADCON0bits.ADCS = 0b11;  // Use the ADCs internal RC oscillator 
ADCON0bits.CHS = 0b000;  // Use ANO as the analogue source
ADCON0bits.ADON = 1;     // Turn on the module

ADCON1bits.PCFG = 0b1110;  // Use AN0 as input, VDD and VSS as ref
ADCON1bits.ADFM = 1;       // Right justified for 10 bit result
ADCON1bits.ADCS2 = 0;      // Normal clock division (don't worry)
}


//********************************
//Main Code
void main(void)
{
//char i;
//char j;
//char k;
unsigned int result;// Change data type as needed.
//unsigned int voltage ;
initMain();
SUART_Init();
__delay_ms(1000);
// Our main loop
while(1)
     {
     // Make an ADC reading
ADCON0bits.GO = 1;
     // Now wait until the ADC has finished
     while(ADCON0bits.GO == 1); // The program stays in this while loop until ADCON0bits.GO == 0 and then control jumps to the next line.
     // Now transfer the two 8 bit readings into a single 10 bit reading
     result = 0x0000;           // Clear the variable.
     result = ADRESH;           // Get the first 8 bits
     result = result << 8;    // Shift left 8 times
     result = result | ADRESL;// Now stick the lower 8 bits in
// Now do any calculations to scale the output of the ADC to represent the voltage actually on the slider of the potentiometer.
// For ASCII output add 0x30 to the value.
// See [url]https://www.youtube.com/watch?v=rKaJGUkjyB4&list=PL_zvrXFdKgZpTrM99mypGVW5JBZ6tQZiR&index=33[/url] for more ideas.

     // Now test the serial link and report the baud rate setting to show signs of life!

/* Simple string tests */

     SUART_Write_Text("Hello!\r\n");
     SUART_Write_Text("Software uart, ");
     #if (Baudrate==9600)
     SUART_Write_Text("9600");
     #elif (Baudrate==19200)
     SUART_Write_Text("19200");
     #elif(Baudrate==38400)
     SUART_Write_Text("38400");
     #else
     SUART_Write_Text("unknown");
     #endif
     SUART_Write_Text(" bauds.\r\n\n");

/* TX/RX loop and serial tests. Comment out when not needed.*/

/* Not needed if you are only SENDING data FROM the PIC. Use this to test the link if you want to SEND and RECEIVE data.
     SUART_Write_Text("Please type in the console now\r\n,you should see the input below.\r\n\n");
     while(1)
      {
          SUART_Transmit(SUART_Receive());
          }
*/
 
     for ( char j = 0; j <= 2; j++) // Send 2 screens of charachters as a test of serial link.
          {
          for ( char k = 'A'; k <= 'Z'; k++)
      {
              SUART_Transmit(k);
              __delay_ms(250);
              }
          for ( char k = 'a'; k <= 'z'; k++)
      {
              SUART_Transmit(k);
              __delay_ms(250);
              }
          for ( char k = '0'; k <= '9'; k++)
      {
              SUART_Transmit(k);
              __delay_ms(250);
              }
          SUART_Write_Text("\r\n");
          }
// Send the data from the Analogue to digital convertor channel 0;
    // voltage = (result * 5.0)/1023;
     // Explore sprintf and buffers for integer to ASCII conversion.
     SUART_Write_Text("\r\n");
SUART_Write_Text("\r\nADC result is: ");  
SUART_Write_Text(result);
SUART_Write_Text(" mV.\r\n\n");


     
     }
}

Code: [Select]
/*
 * File: 16F819_Internal.h
 * Author: David J S Briscoe
 * PIC: 16F819 with INTERNAL OSC @ 8MHz, 5v
 * Program: Header file to setup PIC16F819
 * Compiler: XC8 (v2.40, MPLAX X v6.00)
 * Program Version 1.0
 *               
 *                *Changed comments and layout
 *                 
 * Program Description: This program header will allows setup of configuration
 *                      bits and provides routines for setting up internal
 *                      oscillator and includes all devices and MCU modules
 *
 * Created on February 24th, 2023
 ******************************************************************************/

/*******************************************************************************
 *Includes and defines
 ******************************************************************************/
// PIC16F819 Configuration Bit Settings
/*
Fuses: NOWDT,WDT,PUT,NOPUT,LP,XT,HS,EC_IO,INTRC_IO,INTRC,RC_IO,RC
//////// Fuses: NOMCLR,MCLR,NOBROWNOUT,BROWNOUT,NOLVP,LVP,CPD,NOCPD,WRT_600
//////// Fuses: WRT_400,WRT_200,NOWRT,DEBUG,NODEBUG,CCPB3,CCPB2,PROTECT
//////// Fuses: NOPROTECT
*/

// PIC16F819 Configuration Bit Settings

// 'C' source line config statements

// CONFIG
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = ON       // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB3/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB2      // CCP1 Pin Selection bit (CCP1 function on RB2)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

//XC8 Standard Include
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>

//Other Includes
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <math.h>


//For delay routines WHEN USING A CRYSTAL OSCILLATOR ONLY
//#define _XTAL_FREQ 8000000

//MCU Modules Includes

Its the conversion of the result from the ADC into a form that can be seen on a serial terminal which I'm struggling with. Is there any simple code that I can use to do this that will work with the example above? Thanks.
« Last Edit: May 31, 2024, 12:08:47 pm by djsb »
David
Hertfordshire, UK
University Electronics Technician, London, PIC16/18, CCS PCM C, Arduino UNO, NANO,ESP32, KiCad V8+, Altium Designer 21.4.1, Alibre Design Expert 28 & FreeCAD beginner. LPKF S103,S62 PCB router Operator, Electronics instructor. Credited KiCad French to English translator
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 13026
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #1 on: May 31, 2024, 08:18:51 am »
What's your conceptual problem? 
You know the ADC result is a 16 bit unsigned integer with the lower 10 bits representing the range 0V to Vref,  you know the math needed to convert that to a voltage, you've decided to work in mV so you can use (long) integer math, and you know itoa() can convert an integer into a string (as usual: ASCII, null terminated) which you can pass to your SUART_Write_Text() function.

Why haven't you simply tried:
Code: [Select]
int voltage; // voltage in mV
char buff[7]; // space for (sign) + max. 5 digits + null

// Calculate result in mV
// See: https://forum.allaboutcircuits.com/threads/why-adc-1024-is-correct-and-adc-1023-is-just-plain-wrong.80018/
voltage=(int)(((result*2 +1) *5000L +1024L) /2048L);
// Explicit cast to int avoids integer truncation warning as we know it must fit in an int.

itoa(buff,voltage,10); // convert to base 10 ASCII string

SUART_Write_Text("\r\nADC result is: ");
SUART_Write_Text(buff); // itoa() converted voltage
SUART_Write_Text(" mV.\r\n\n");

If you need to output in units of Volts its a little more complex.  If voltage>999, you need to output the first digit from buff, then output '.' then output the rest of buff, i.e. adjust the start pointer to buff +1 and pass it to SUART_Write_Text().  If its 100 to 999 you write "0." then buff, if 10 to 99 you write "0.0" then buff and finally, if 0 to 9, write "0.00" then buff.

Hint: Rather than wrangling with XC8's C90 mode, why not simply implement your own itoa(), e.g. use the K&R base 10 only version: https://en.wikibooks.org/wiki/C_Programming/stdlib.h/itoa

With a custom itoa function, if you want to output Volts you can also inject the decimal point while building the string, which is considerably simpler than injecting it when outputting the buffer.  To get correct leading zeros, prefill the buffer with "000.0\0" (which will be reversed later) and in the itoa i loop, 'bump' i +1 after the third digit so it doesn't overwrite the '.'.  Only add the terminating '\0' if i>5 (as then you've overwritten the '\0' in the string you prefilled the buffer with.

Outputting fewer decimal places can be handled by adding an appropriate rounding adjustment to the integer before passing it to itoa, and truncating the converted string by stuffing '\0' where you want to end it, or modding the itoa function to skip incrementing i till done with the digits you want to discard, and modifying the 'prestuff' string and the i bump to skip '.' accordingly.


 
« Last Edit: May 31, 2024, 11:12:50 am by Ian.M »
 
The following users thanked this post: djsb

Offline djsbTopic starter

  • Frequent Contributor
  • **
  • Posts: 938
  • Country: gb
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #2 on: May 31, 2024, 09:48:29 am »
Thanks for your reply. Here are the compilation results when compiling with the code snippet you kindly supplied.

Code: [Select]
make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make  -f nbproject/Makefile-default.mk dist/default/production/04_ADC_RS232.X.production.hex
make[2]: Entering directory 'F:/XC8_WORK/XC8_16F819/04_ADC_RS232.X'
"C:\Program Files\Microchip\xc8\v2.46\bin\xc8-cc.exe"  -mcpu=16F819 -c   -mdfp="C:/Program Files/Microchip/MPLABX/v6.20/packs/Microchip/PIC16Fxxx_DFP/1.6.156/xc8"  -fno-short-double -fno-short-float -O0 -fasmfile -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -DXPRJ_default=default  -msummary=-psect,-class,+mem,-hex,-file  -ginhx32 -Wl,--data-init -mno-keep-startup -mno-osccal -mno-resetbits -mno-save-resetbits -mno-download -mno-stackcall -mno-default-config-bits   -std=c90 -gdwarf-3 -mstack=compiled:auto:auto     -o build/default/production/main.p1 main.c
advisory: (2099) legacy C90 library is deprecated and will be discontinued in a future release; consult the release notes for more details
advisory: (2095) legacy HI-TECH support is deprecated and will be discontinued in a future release; consult the release notes for more details
main.c:257:30: warning: (359) illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
main.c:258:35: warning: (359) illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
main.c:260:24: warning: (359) illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
main.c:268:33: warning: (359) illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
main.c:297:24: warning: (359) illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
main.c:308:22: warning: (1385) function "itoa" is deprecated (declared at main.c:308)
main.c:310:39: warning: (359) illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
main.c:311:25: warning: (357) illegal conversion of integer to pointer
main.c:312:30: warning: (359) illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
make[2]: Leaving directory 'F:/XC8_WORK/XC8_16F819/04_ADC_RS232.X'
make[2]: Entering directory 'F:/XC8_WORK/XC8_16F819/04_ADC_RS232.X'
"C:\Program Files\Microchip\xc8\v2.46\bin\xc8-cc.exe"  -mcpu=16F819 -Wl,-Map=dist/default/production/04_ADC_RS232.X.production.map  -DXPRJ_default=default  -Wl,--defsym=__MPLAB_BUILD=1   -mdfp="C:/Program Files/Microchip/MPLABX/v6.20/packs/Microchip/PIC16Fxxx_DFP/1.6.156/xc8"  -fno-short-double -fno-short-float -O0 -fasmfile -maddrqual=ignore -xassembler-with-cpp -mwarn=-3 -Wa,-a -msummary=-psect,-class,+mem,-hex,-file  -ginhx32 -Wl,--data-init -mno-keep-startup -mno-osccal -mno-resetbits -mno-save-resetbits -mno-download -mno-stackcall -mno-default-config-bits -std=c90 -gdwarf-3 -mstack=compiled:auto:auto      -Wl,--memorysummary,dist/default/production/memoryfile.xml -o dist/default/production/04_ADC_RS232.X.production.elf  build/default/production/main.p1     
advisory: (2099) legacy C90 library is deprecated and will be discontinued in a future release; consult the release notes for more details
advisory: (2095) legacy HI-TECH support is deprecated and will be discontinued in a future release; consult the release notes for more details
Non line specific message::: advisory: (1492) using updated 32-bit floating-point libraries; improved accuracy might increase code size
main.c:308:: warning: (1385) function "_itoa" is deprecated (declared at C:\Program Files\Microchip\xc8\v2.46\pic\include\c90\stdlib.h:113)
C:\Program Files\Microchip\xc8\v2.46\pic\sources\c90\common\itoa.c:12:: warning: (1385) function "_utoa" is deprecated (declared at C:\Program Files\Microchip\xc8\v2.46\pic\include\c90\stdlib.h:114)
main.c:125:: warning: (520) function "_SUART_Receive" is never called
main.c:167:: warning: (520) function "_SUART_Read_Text" is never called
main.c:170:: advisory: (1498) pointer (SUART_Read_Text@Output) in expression may have no targets

Memory Summary:
    Program space        used   415h (  1045) of   800h words   ( 51.0%)
    Data space           used    33h (    51) of   100h bytes   ( 19.9%)
    EEPROM space         used     0h (     0) of   100h bytes   (  0.0%)
    Configuration bits   used     1h (     1) of     1h word    (100.0%)
    ID Location space    used     0h (     0) of     4h bytes   (  0.0%)

make[2]: Leaving directory 'F:/XC8_WORK/XC8_16F819/04_ADC_RS232.X'

BUILD SUCCESSFUL (total time: 8s)
Loading code from F:/XC8_WORK/XC8_16F819/04_ADC_RS232.X/dist/default/production/04_ADC_RS232.X.production.hex...
Program loaded with pack,PIC16Fxxx_DFP,1.6.156,Microchip
Loading completed
Connecting to programmer...
Programming target...
Programming completed
Running target...


Here is the terminal output

Code: [Select]
Hello!
Software uart, 9600 bauds.

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789

ADC result is: w mV.


It looks like I might need to implement my ow itoa() routine later but I'd like to avoid that if possible. Just want to get a basic reading from the ADC first. So I just need the "ADC result is: w mv" to read "ADC result is: 5000 mv" for example.

David
Hertfordshire, UK
University Electronics Technician, London, PIC16/18, CCS PCM C, Arduino UNO, NANO,ESP32, KiCad V8+, Altium Designer 21.4.1, Alibre Design Expert 28 & FreeCAD beginner. LPKF S103,S62 PCB router Operator, Electronics instructor. Credited KiCad French to English translator
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 13026
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #3 on: May 31, 2024, 10:31:12 am »
The advisories and depreciated warning can be ignored for now but if you upgrade the compiler may be serious.

All the pointer conversion warnings need to be investigated.  They are scattered over a 65 line number range in your source so cant just be the code snippet I gave you.   Many of them *may* be due to the string literals.

Code: [Select]
main.c:311:25: warning: (357) illegal conversion of integer to pointeris the most serious warning.  It is *RARE* to need to make a pointer from an integer so this is probably a bug.  As itoa() isn't part of the C99 or earlier standards, its implementation varies from compiler to compiler, it is possible the XC8 C90 version of it has arguments in a different order or not of the types you expect, so if this error corresponds to the itoa() conversion line, you need to fix that to match the parameter type and order of the C90 library function.
« Last Edit: May 31, 2024, 10:34:46 am by Ian.M »
 
The following users thanked this post: djsb

Offline djsbTopic starter

  • Frequent Contributor
  • **
  • Posts: 938
  • Country: gb
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #4 on: May 31, 2024, 11:03:48 am »
I've asked for help on the Microchip XC8 subforum. Hoping they can shed some light. Thanks.
David
Hertfordshire, UK
University Electronics Technician, London, PIC16/18, CCS PCM C, Arduino UNO, NANO,ESP32, KiCad V8+, Altium Designer 21.4.1, Alibre Design Expert 28 & FreeCAD beginner. LPKF S103,S62 PCB router Operator, Electronics instructor. Credited KiCad French to English translator
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 13026
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #5 on: May 31, 2024, 11:19:27 am »
Hint: When asking for help (here or elsewhere), attach your zipped project so anyone helping you can open it in MPLAB X, and when posting multiple lines of source in code tags and asking about errors or warnings, flag the offending lines with // comments giving the line number e.g. if you have an error on line 123, flag it in your posted code as:
Code: [Select]
    a_C_statement_causing_an_error; // #123so those reading your source without opening it in MPLAB can match up the errors with the lines of code.

Fix whatever is wrong with line 311 and it should 'just work'.  The 'w' where you should have a number in your output, indicates the string is corrupted which strongly indicates a problem with the itoa() call or the library function code for it.  You could try initialising buff with a test number e.g. declare it as:
Code: [Select]
char buff[7]="-99999"; // space for (sign) + max. 5 digits + nulland see if commenting out the itoa() call will let that test data through, which would validate the rest of your code (except the result to voltage conversion).
« Last Edit: May 31, 2024, 11:29:35 am by Ian.M »
 
The following users thanked this post: djsb

Offline Fenstergucker

  • Contributor
  • Posts: 37
  • Country: at
    • Private Website
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #6 on: May 31, 2024, 11:20:40 am »
In the Microchip forum the code with the line 'SUART_Write_Text(voltage);' is wrong, you want to output the buffer 'buff'.

Peter
 
The following users thanked this post: djsb, Ian.M

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 13026
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #7 on: May 31, 2024, 11:30:30 am »
Yes, that would account for the
Code: [Select]
main.c:311:25: warning: (357) illegal conversion of integer to pointerand the corrupted output.

http://www.catb.org/jargon/html/D/DWIM.html

I may be partially to blame here as I think I may have had an incorrect 'voltage' in that line for a few minutes while I was revising my original post for content and accuracy.  I'm afraid it was a case of PEBKAC error: insufficiently caffeinated!
« Last Edit: May 31, 2024, 11:38:51 am by Ian.M »
 
The following users thanked this post: djsb

Offline djsbTopic starter

  • Frequent Contributor
  • **
  • Posts: 938
  • Country: gb
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #8 on: May 31, 2024, 11:42:30 am »
Thanks everyone. Problem solved. The error messages have gone, and I'm getting a reading between 2mV and 4978mV which is good enough.
David
Hertfordshire, UK
University Electronics Technician, London, PIC16/18, CCS PCM C, Arduino UNO, NANO,ESP32, KiCad V8+, Altium Designer 21.4.1, Alibre Design Expert 28 & FreeCAD beginner. LPKF S103,S62 PCB router Operator, Electronics instructor. Credited KiCad French to English translator
 

Offline djsbTopic starter

  • Frequent Contributor
  • **
  • Posts: 938
  • Country: gb
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #9 on: May 31, 2024, 11:50:29 am »
I may however have to do some research into how to get around the C90 itoa() deprecation issue. What would the recommendation be apart from implementing my own itoa() routine (which I have found a few examples of on the microchip forum). Thanks.






PS I would also like to thank DavidAlfa for the original help with the RS232 code detailed in an earlier post here https://www.eevblog.com/forum/microcontrollers/xc8-soft-uart-on-pic16f819-help-please/msg5477563/#msg5477563
« Last Edit: May 31, 2024, 11:54:44 am by djsb »
David
Hertfordshire, UK
University Electronics Technician, London, PIC16/18, CCS PCM C, Arduino UNO, NANO,ESP32, KiCad V8+, Altium Designer 21.4.1, Alibre Design Expert 28 & FreeCAD beginner. LPKF S103,S62 PCB router Operator, Electronics instructor. Credited KiCad French to English translator
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 13026
Re: ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #10 on: May 31, 2024, 12:10:50 pm »
On more powerful embedded processors, with plenty of program and data memory, if you can tolerate the speed penalty, its common to use printf() family functions for number formatting output, and even use floating point maths for the convenience.  However on the classic midrange 14 bit core PICs there isn't much RAM or FLASH to start with, and you generally cant afford the bloat of the library printf() routines or floating point support routines, so writing your own minimalist number to ASCII string and/or number formatting functions that do *exactly* what you want, and *NOTHING* else, is quite usual.

The only fix for the C90 library itoa() deprecation issue would be to supply an itoa() function with XC8 C99 compliant source .  As Microchip choose not to (and probably for good reason: https://stackoverflow.com/questions/10162733/atoi-is-a-standard-function-but-itoa-is-not-why), that's down to you.  Fortunately a base 10 only itoa() is fairly trivial to implement, and handling base 16 is not much harder.  If you do write your own itoa(), it may be worth extending it to:
Code: [Select]
char* fp_itoa(int num, char* buffer, int base, int dp);with the extra parameter dp to tell it where to conditionally insert a decimal point, by specifying a non-zero number of decimal places.
« Last Edit: May 31, 2024, 12:23:02 pm by Ian.M »
 
The following users thanked this post: djsb

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6178
  • Country: es
Re: [SOLVED]ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #11 on: May 31, 2024, 02:01:18 pm »
You already asked this and got it solved here, with custom itoa or from xc8 lib.
Var result is not a string, but an integer.
Code: [Select]
SUART_Write_Text(result);
You should do something like:
Code: [Select]
        char str[10];
        itoa(str, result, 10);       -> convert integer into array, i.e. '1234' into [1][2][3][4].
SUART_Write_Text(str);
« Last Edit: May 31, 2024, 09:35:11 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: djsb

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 13026
Re: [SOLVED]ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #12 on: May 31, 2024, 04:43:47 pm »
Please explain where my version of that calculation overflows.  result is initially in the range 0 to 1023, so plenty of room to double it.   The multiplication by 5000L an explicit long numeric constant, according to the 'Usual Arithmetic Conversions' of C should (as I understand it) force the multiplication operator to promote to long.  The rest of the calculation up until the cast (int) maintains long.  XC8 int is 16 bits, and (unless you set a depreciated compiler flag to override to 24 bit) long is 32 bit.  Admittedly, it *will* overflow a 24 bit int, but they aren't the default.
« Last Edit: May 31, 2024, 04:47:00 pm by Ian.M »
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6178
  • Country: es
Re: [SOLVED]ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #13 on: May 31, 2024, 06:14:23 pm »
Edit: Deleted the pointless answer!
« Last Edit: May 31, 2024, 09:36:15 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 13026
Re: [SOLVED]ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #14 on: May 31, 2024, 07:00:06 pm »
Doesn't *5000L promote the result of the bracketed expression preceding the * operator to long?
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6762
  • Country: fi
    • My home page and email address
Re: [SOLVED]ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #15 on: May 31, 2024, 07:18:42 pm »
If reference voltages are \$V_\max\$ and \$V_\min\$ in millivolts, and you have an \$N\$-bit ADC, the reading \$x\$ corresponds to \$v\$ millivolts,
$$v = \left\lfloor V_\min + (V_\max - V_\min) \frac{x \, + \, 2^{N-1}}{2^N} \right\rfloor$$

For 0..5V,
$$v = \left\lfloor \frac{5000 x + 512}{1024} \right\rfloor = \left\lfloor \frac{1250 x + 128}{256} \right\rfloor = \left\lfloor \frac{625 x + 64}{128} \right\rfloor$$
because 5000/1024 = 1250/256 =625/128 exactly.  In C, I'd use ((uint32_t)x * (uint32_t)1250 + 128) >> 8.

For 0..3.3V,
$$v = \left\lfloor \frac{3300 x + 512}{1024} \right\rfloor = \left\lfloor \frac{825 x + 128}{256} \right\rfloor$$
because 3300/1024 = 825/256 exactly.  In C, I'd use ((uint32_t)x * (uint32_t)825 + 128) >> 8.

Doesn't *5000L promote the result of the bracketed expression preceding the * operator to long?
For (a + b) * 825L, the sum is promoted to long before multiplication, yes.  (That is, the addition is done at the range and precision dictated by the types of a and b, but the result is promoted to long and the multiplication is long×long=long.)
And you are right, DavidAlfa missed the promotion.

To make things as clear to us humans as they are to the compiler, I do like to explicitly cast both sides of multiplications and divisions.  Less cognitive load.

The C integer promotion and casting rules are a bit funky.  For example, given int x, (int)(char)x is only equivalent to the original x if the value also fits in a char.
« Last Edit: May 31, 2024, 07:20:16 pm by Nominal Animal »
 
The following users thanked this post: Ian.M

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6178
  • Country: es
Re: [SOLVED]ADC result to RS232 using XC8 on an PIC16F819-How?
« Reply #16 on: May 31, 2024, 09:33:17 pm »
Yep I missed it!  :-+

djsb, always start with simple tests before going further.
Like:
Code: [Select]
        char str[10];

SUART_Write_Text("itoa result of 1234 is: ");
        itoa(str, 1234L, 10);
SUART_Write_Text(str);
SUART_Write_Text("\r\n");
        while(1);
« Last Edit: May 31, 2024, 09:41:22 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: djsb, Ian.M


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf