I am trying to learn Nano coding using a an existing program called component tester which uses the ADC pins extensively.
The simple way of reading an analog pin is via analogRead() but this program is using a different method of reading a pin possibly via assembly language coding from inside the sketch.
Here is a small extract which appears to be doing this job:
unsigned int ReadADC (uint8_t Probe) {
unsigned int U; // return value (mV)
uint8_t Samples; // loop counter
unsigned long Value; // ADC value
Probe |= (1 << REFS0); // use internal reference anyway
Can any body direct me to am area where this is discussed and explained please?
Sorry. the sketch itself is more than 5000 lines long so in order not to complicate matters I opted to keep it simple.
Here is a more extensive extract:
unsigned int ReadADC (uint8_t Probe) {
unsigned int U; // return value (mV)
uint8_t Samples; // loop counter
unsigned long Value; // ADC value
Probe |= (1 << REFS0); // use internal reference anyway
#ifdef AUTOSCALE_ADC
sample:
#endif
ADMUX = Probe; // set input channel and U reference
#ifdef AUTOSCALE_ADC
// if voltage reference changes, wait for voltage stabilization
if ((Probe & (1 << REFS1)) != 0) {
// switch to 1.1V Reference
#ifdef NO_AREF_CAP
wait100us(); // time for voltage stabilization
#else
wait_about10ms(); // time for voltage stabilization
#endif
}
#endif
// allways do one dummy read of ADC, 112us
StartADCwait(); // start ADC and wait
// sample ADC readings
Value = 0UL; // reset sampling variable
Samples = 0; // number of samples to take
while (Samples < ADCconfig.Samples) { // take samples
StartADCwait(); // start ADC and wait
Value += ADCW; // add ADC reading
#ifdef AUTOSCALE_ADC
// auto-switch voltage reference for low readings
if ((Samples == 4) && (ADCconfig.U_Bandgap > 255) && ((uint16_t)Value < 1024) && !(Probe & (1 << REFS1))) {
Probe |= (1 << REFS1); // select internal bandgap reference
#if PROCESSOR_TYP == 1280
Probe &= ~(1 << REFS0); // ATmega640/1280/2560 1.1V Reference with REFS0=0
#endif
goto sample; // re-run sampling
}
#endif
Samples++; // one more done
}
#ifdef AUTOSCALE_ADC
// convert ADC reading to voltage - single sample: U = ADC reading * U_ref / 1024
// get voltage of reference used
if (Probe & (1 << REFS1)) U = ADCconfig.U_Bandgap; // bandgap reference
else U = ADCconfig.U_AVCC; // Vcc reference
#else
U = ADCconfig.U_AVCC; // Vcc reference
#endif
// convert to voltage
Value *= U; // ADC readings * U_ref
Value /= 1023; // / 1024 for 10bit ADC
// de-sample to get average voltage
Value /= ADCconfig.Samples;
U = (unsigned int)Value;
return U;
//return ((unsigned int)(Value / (1023 * (unsigned long)ADCconfig.Samples)));
}
I am guessing REFS0, REFS1 ADCW refer to registers.
REFS0 and REFS1 are bits in the ADMUX register. ADCW is a variable defined somewhere else in the program
ADCW is the ADC data it reads both the ADCL and ADCH registers
You will find the 328 datasheet and app notes here
If your code is 5K long, and you have only just come to this problem your code development skills are sadly lacking. You should test as you add more code, not try and write it all at once.
Your best bet is to write some sample code that illustrates you problem in a much smaller way. Doing this often makes you spot the mistake yourself.
If it does not then post your code for us to try, along with a schematic (not pictures joined by lines or a Fritzing diagram.
Let us Ch-1 (A1):
Store 0000 into MUX3-MUX0 positions of ADMUX Register without disturbing other bits: Codes:
ADMUX = 0x00;
ADMUX |= bit(MUX0);
4. Select reference voltage (5V) for the ADC.
Store 01 into REFS1-REFS0 bits of ADMUX Register without disturbing other bits: codes:
ADMUX |= bit(REFS0); // or ADMUX |= _BV(REFS0); or ADMUX |= 1<<REFS0;
5. Select ADC converso clock tp 125 kHz with the help of ADCSRA Register (Fig-1).
Store 111 into ASPS2-ASPS0 bits to divide the system clock frequency (16 MHz) by 128 (16 MHz /128 = 125 kHz). Codes:
Sorry I think you have not read my messages from the beginning. The 5000+ line code is not code that I wrote myself, who as I said, is a beginner in the Arduino world. It would be madness for a beginner to start off writing all that code.
It is code which I have downloaded from the internet and is supposed to work off the shelf. It is available from various sources.
I am using it to help me expand my coding in C as well as with using the Atmega328p. So far I have managed to adapt the software to work with an SH1106 oled display which was not envisaged with the original code.
I have of course looked into the examples in the IDE but these all use the analogRead() method. Not useful at all to me.
Clearly this programmer, who appears quite accomplished to me, opted to access the ADC from a lower level, probable to gain better accuracy.
For those who are intrigued by this method here is a link from Github to the full program which uses this method:
To learn about low-level ADC on an Arduino you might like:
If you are trying to learn about low-level register usage, the essential resource is the datasheet--if you see a confusing all-caps constant used but not defined in the code, try searching for it in the appropriate datasheet.
@xuraax Despite all the above. Your original post suggested the lines of code you posted were doing some alternate form of ADC read. I asked for more context, as you were incorrect. The line I quote here is the actual register read of a new value, being summed in order to do some averaging. Hope that helps.
You need to understand that due to your failure to provide that context up front several hours have passed, several volunteers have tried, and only now you have an answer- which only points you to the data sheet for a deeper read. Could have been answered in post #2 or #3.
/*
* AVR IO.c
*
* Created: 03/01/2018 11:25:21
* Author : RobinLaptop
*/
#define F_CPU 1000000UL
#define TRIGPOINT 128
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
// Configure PORT D bit 0 to an output
DDRD = 0b00000001;
// Configure PORT C bit 0 to an input
DDRC = 0b00000000;
// Configure ADC to be left justified, use AVCC as reference, and select ADC0 as ADC input
ADMUX = 0b01100000;
// Enable the ADC and set the prescaler to max value (128)
ADCSRA = 0b10000111;
// Main program loop
while (1)
{
// Start an ADC conversion by setting ADSC bit (bit 6)
ADCSRA = ADCSRA | (1 << ADSC);
// Wait until the ADSC bit has been cleared
while(ADCSRA & (1 << ADSC));
if(ADCH > TRIGPOINT)
{
// Turn LED on
PORTD = PORTD | (1 << PD0);
}
else
{
// Turn LED off
PORTD = PORTD & ~(1 << PD0);
}
}
}
@xuraax
As you can see from DaveX link the code does make provision for a lot of different Atmega chips .
Still don't know why you don't want to use analogRead.
Where exactly analogRead source code is ? I must try and find it again.
That is exactly it in #17. I find my way to things like that by googling something like "github arduino core analogWrite" and click on the the line-numbers to get a permalink.